wolfSSL SSL/TLS library, support up to TLS1.3

Dependents:   CyaSSL-Twitter-OAuth4Tw Example-client-tls-cert TwitterReader TweetTest ... more

Files at this revision

API Documentation at this revision

Comitter:
wolfSSL
Date:
Fri Jun 26 00:39:20 2015 +0000
Child:
1:e27310ce7654
Commit message:
wolfSSL 3.6.0

Changed in this revision

src/crl.c Show annotated file Show diff for this revision Revisions of this file
src/internal.c Show annotated file Show diff for this revision Revisions of this file
src/io.c Show annotated file Show diff for this revision Revisions of this file
src/keys.c Show annotated file Show diff for this revision Revisions of this file
src/ocsp.c Show annotated file Show diff for this revision Revisions of this file
src/sniffer.c Show annotated file Show diff for this revision Revisions of this file
src/ssl.c Show annotated file Show diff for this revision Revisions of this file
src/tls.c Show annotated file Show diff for this revision Revisions of this file
user_settings.h Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/aes.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/arc4.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/asm.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/asn.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/blake2b.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/camellia.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/chacha.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/chacha20_poly1305.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/coding.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/compress.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/curve25519.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/des3.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/dh.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/dsa.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/ecc.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/ecc_fp.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/ed25519.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/error.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/fe_low_mem.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/fe_operations.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/fp_mul_comba_7.i Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/ge_low_mem.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/ge_operations.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/hash.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/hc128.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/hmac.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/include.am Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/integer.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/logging.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/md2.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/md4.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/md5.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/memory.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/misc.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/pkcs7.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/poly1305.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/pwdbased.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/rabbit.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/random.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/ripemd.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/rsa.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/sha.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/sha256.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/sha512.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/tfm.c Show annotated file Show diff for this revision Revisions of this file
wolfcrypt/src/wc_port.c Show annotated file Show diff for this revision Revisions of this file
wolfssl/callbacks.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/certs_test.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/crl.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/error-ssl.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/internal.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/ocsp.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/options.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/sniffer.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/sniffer_error.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/ssl.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/test.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/version.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/version.h.in Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/aes.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/arc4.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/asn.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/asn_public.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/blake2-impl.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/blake2-int.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/blake2.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/camellia.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/chacha.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/chacha20_poly1305.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/coding.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/compress.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/curve25519.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/des3.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/dh.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/dsa.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/ecc.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/ed25519.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/error-crypt.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/fe_operations.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/fips_test.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/ge_operations.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/hash.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/hc128.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/hmac.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/integer.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/logging.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/md2.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/md4.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/md5.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/memory.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/misc.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/mpi_class.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/mpi_superclass.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/pkcs7.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/poly1305.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/pwdbased.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/rabbit.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/random.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/ripemd.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/rsa.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/settings.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/sha.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/sha256.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/sha512.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/tfm.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/types.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/visibility.h Show annotated file Show diff for this revision Revisions of this file
wolfssl/wolfcrypt/wc_port.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/crl.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,791 @@
+/* crl.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+  /* Name change compatibility layer no longer needs included here */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_CRL
+
+#include <wolfssl/internal.h>
+#include <wolfssl/error-ssl.h>
+
+#include <dirent.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#ifdef HAVE_CRL_MONITOR
+    static int StopMonitor(int mfd);
+#endif
+
+
+/* Initialze CRL members */
+int InitCRL(WOLFSSL_CRL* crl, WOLFSSL_CERT_MANAGER* cm)
+{
+    WOLFSSL_ENTER("InitCRL");
+
+    crl->cm = cm;
+    crl->crlList = NULL;
+    crl->monitors[0].path = NULL;
+    crl->monitors[1].path = NULL;
+#ifdef HAVE_CRL_MONITOR
+    crl->tid =  0;
+    crl->mfd = -1;   /* mfd for bsd is kqueue fd, eventfd for linux */
+#endif
+    if (InitMutex(&crl->crlLock) != 0)
+        return BAD_MUTEX_E; 
+
+    return 0;
+}
+
+
+/* Initialze CRL Entry */
+static int InitCRL_Entry(CRL_Entry* crle, DecodedCRL* dcrl)
+{
+    WOLFSSL_ENTER("InitCRL_Entry");
+
+    XMEMCPY(crle->issuerHash, dcrl->issuerHash, CRL_DIGEST_SIZE);
+    /* XMEMCPY(crle->crlHash, dcrl->crlHash, CRL_DIGEST_SIZE);
+     *   copy the hash here if needed for optimized comparisons */
+    XMEMCPY(crle->lastDate, dcrl->lastDate, MAX_DATE_SIZE);
+    XMEMCPY(crle->nextDate, dcrl->nextDate, MAX_DATE_SIZE);
+    crle->lastDateFormat = dcrl->lastDateFormat;
+    crle->nextDateFormat = dcrl->nextDateFormat;
+
+    crle->certs = dcrl->certs;   /* take ownsership */
+    dcrl->certs = NULL;
+    crle->totalCerts = dcrl->totalCerts;
+
+    return 0;
+}
+
+
+/* Free all CRL Entry resources */
+static void FreeCRL_Entry(CRL_Entry* crle)
+{
+    RevokedCert* tmp = crle->certs; 
+
+    WOLFSSL_ENTER("FreeCRL_Entry");
+
+    while(tmp) {
+        RevokedCert* next = tmp->next;
+        XFREE(tmp, NULL, DYNAMIC_TYPE_REVOKED);
+        tmp = next;
+    }
+}
+
+
+
+/* Free all CRL resources */
+void FreeCRL(WOLFSSL_CRL* crl, int dynamic)
+{
+    CRL_Entry* tmp = crl->crlList;
+
+    WOLFSSL_ENTER("FreeCRL");
+
+    if (crl->monitors[0].path)
+        XFREE(crl->monitors[0].path, NULL, DYNAMIC_TYPE_CRL_MONITOR);
+
+    if (crl->monitors[1].path)
+        XFREE(crl->monitors[1].path, NULL, DYNAMIC_TYPE_CRL_MONITOR);
+
+    while(tmp) {
+        CRL_Entry* next = tmp->next;
+        FreeCRL_Entry(tmp);
+        XFREE(tmp, NULL, DYNAMIC_TYPE_CRL_ENTRY);
+        tmp = next;
+    }	
+
+#ifdef HAVE_CRL_MONITOR
+    if (crl->tid != 0) {
+        WOLFSSL_MSG("stopping monitor thread");
+        if (StopMonitor(crl->mfd) == 0)
+            pthread_join(crl->tid, NULL);
+        else {
+            WOLFSSL_MSG("stop monitor failed, cancel instead");
+            pthread_cancel(crl->tid);
+        }
+    }
+#endif
+    FreeMutex(&crl->crlLock);
+    if (dynamic)   /* free self */
+        XFREE(crl, NULL, DYNAMIC_TYPE_CRL);
+}
+
+
+/* Is the cert ok with CRL, return 0 on success */
+int CheckCertCRL(WOLFSSL_CRL* crl, DecodedCert* cert)
+{
+    CRL_Entry* crle;
+    int        foundEntry = 0;
+    int        ret = 0;
+
+    WOLFSSL_ENTER("CheckCertCRL");
+
+    if (LockMutex(&crl->crlLock) != 0) {
+        WOLFSSL_MSG("LockMutex failed");
+        return BAD_MUTEX_E;
+    }
+
+    crle = crl->crlList;
+
+    while (crle) {
+        if (XMEMCMP(crle->issuerHash, cert->issuerHash, CRL_DIGEST_SIZE) == 0) {
+            WOLFSSL_MSG("Found CRL Entry on list");
+            WOLFSSL_MSG("Checking next date validity");
+
+            if (!ValidateDate(crle->nextDate, crle->nextDateFormat, AFTER)) {
+                WOLFSSL_MSG("CRL next date is no longer valid");
+                ret = ASN_AFTER_DATE_E;
+            }
+            else
+                foundEntry = 1;
+            break;
+        }
+        crle = crle->next;
+    }
+
+    if (foundEntry) {
+        RevokedCert* rc = crle->certs;
+
+        while (rc) {
+            if (XMEMCMP(rc->serialNumber, cert->serial, rc->serialSz) == 0) {
+                WOLFSSL_MSG("Cert revoked");
+                ret = CRL_CERT_REVOKED;
+                break;
+            }
+            rc = rc->next;	
+        }
+    }
+
+    UnLockMutex(&crl->crlLock);
+
+    if (foundEntry == 0) {
+        WOLFSSL_MSG("Couldn't find CRL for status check");
+        ret = CRL_MISSING;
+        if (crl->cm->cbMissingCRL) {
+            char url[256];
+
+            WOLFSSL_MSG("Issuing missing CRL callback");
+            url[0] = '\0';
+            if (cert->extCrlInfoSz < (int)sizeof(url) -1 ) {
+                XMEMCPY(url, cert->extCrlInfo, cert->extCrlInfoSz);
+                url[cert->extCrlInfoSz] = '\0';
+            }
+            else  {
+                WOLFSSL_MSG("CRL url too long");
+            }
+            crl->cm->cbMissingCRL(url);
+        }
+    }
+
+
+    return ret;	
+}
+
+
+/* Add Decoded CRL, 0 on success */
+static int AddCRL(WOLFSSL_CRL* crl, DecodedCRL* dcrl)
+{
+    CRL_Entry* crle;
+
+    WOLFSSL_ENTER("AddCRL");
+
+    crle = (CRL_Entry*)XMALLOC(sizeof(CRL_Entry), NULL, DYNAMIC_TYPE_CRL_ENTRY);
+    if (crle == NULL) {
+        WOLFSSL_MSG("alloc CRL Entry failed");
+        return -1;
+    }
+
+    if (InitCRL_Entry(crle, dcrl) < 0) {
+        WOLFSSL_MSG("Init CRL Entry failed");
+        XFREE(crle, NULL, DYNAMIC_TYPE_CRL_ENTRY);
+        return -1;
+    }
+
+    if (LockMutex(&crl->crlLock) != 0) {
+        WOLFSSL_MSG("LockMutex failed");
+        FreeCRL_Entry(crle);
+        XFREE(crle, NULL, DYNAMIC_TYPE_CRL_ENTRY);
+        return BAD_MUTEX_E;
+    }
+    crle->next = crl->crlList;
+    crl->crlList = crle;
+    UnLockMutex(&crl->crlLock);
+
+    return 0;
+}
+
+
+/* Load CRL File of type, SSL_SUCCESS on ok */
+int BufferLoadCRL(WOLFSSL_CRL* crl, const byte* buff, long sz, int type)
+{
+    int          ret = SSL_SUCCESS;
+    const byte*  myBuffer = buff;    /* if DER ok, otherwise switch */
+    buffer       der;
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCRL*  dcrl;
+#else
+    DecodedCRL   dcrl[1];
+#endif
+
+    der.buffer = NULL;
+
+    WOLFSSL_ENTER("BufferLoadCRL");
+
+    if (crl == NULL || buff == NULL || sz == 0)
+        return BAD_FUNC_ARG;
+
+    if (type == SSL_FILETYPE_PEM) {
+        int eccKey = 0;   /* not used */
+        EncryptedInfo info;
+        info.ctx = NULL;
+
+        ret = PemToDer(buff, sz, CRL_TYPE, &der, NULL, &info, &eccKey);
+        if (ret == 0) {
+            myBuffer = der.buffer;
+            sz = der.length;
+        }
+        else {
+            WOLFSSL_MSG("Pem to Der failed");
+            return -1;
+        }
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    dcrl = (DecodedCRL*)XMALLOC(sizeof(DecodedCRL), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (dcrl == NULL) {
+        if (der.buffer)
+            XFREE(der.buffer, NULL, DYNAMIC_TYPE_CRL);
+
+        return MEMORY_E;
+    }
+#endif
+
+    InitDecodedCRL(dcrl);
+    ret = ParseCRL(dcrl, myBuffer, (word32)sz, crl->cm);
+    if (ret != 0) {
+        WOLFSSL_MSG("ParseCRL error");
+    }
+    else {
+        ret = AddCRL(crl, dcrl);
+        if (ret != 0) {
+            WOLFSSL_MSG("AddCRL error");
+        }
+    }
+
+    FreeDecodedCRL(dcrl);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(dcrl, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    if (der.buffer)
+        XFREE(der.buffer, NULL, DYNAMIC_TYPE_CRL);
+
+    return ret ? ret : SSL_SUCCESS; /* convert 0 to SSL_SUCCESS */
+}
+
+
+#ifdef HAVE_CRL_MONITOR
+
+
+/* read in new CRL entries and save new list */
+static int SwapLists(WOLFSSL_CRL* crl)
+{
+    int        ret;
+    CRL_Entry* newList;
+#ifdef WOLFSSL_SMALL_STACK
+    WOLFSSL_CRL* tmp;    
+#else
+    WOLFSSL_CRL tmp[1];
+#endif
+    
+#ifdef WOLFSSL_SMALL_STACK
+    tmp = (WOLFSSL_CRL*)XMALLOC(sizeof(WOLFSSL_CRL), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (tmp == NULL)
+        return MEMORY_E;
+#endif   
+
+    if (InitCRL(tmp, crl->cm) < 0) {
+        WOLFSSL_MSG("Init tmp CRL failed");
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return -1;
+    }
+
+    if (crl->monitors[0].path) {
+        ret = LoadCRL(tmp, crl->monitors[0].path, SSL_FILETYPE_PEM, 0);
+        if (ret != SSL_SUCCESS) {
+            WOLFSSL_MSG("PEM LoadCRL on dir change failed");
+            FreeCRL(tmp, 0);
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return -1;
+        }
+    }
+
+    if (crl->monitors[1].path) {
+        ret = LoadCRL(tmp, crl->monitors[1].path, SSL_FILETYPE_ASN1, 0);
+        if (ret != SSL_SUCCESS) {
+            WOLFSSL_MSG("DER LoadCRL on dir change failed");
+            FreeCRL(tmp, 0);
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return -1;
+        }
+    }
+
+    if (LockMutex(&crl->crlLock) != 0) {
+        WOLFSSL_MSG("LockMutex failed");
+        FreeCRL(tmp, 0);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return -1;
+    }
+
+    newList = tmp->crlList;
+
+    /* swap lists */
+    tmp->crlList  = crl->crlList;
+    crl->crlList = newList;
+
+    UnLockMutex(&crl->crlLock);
+
+    FreeCRL(tmp, 0);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return 0;
+}
+
+
+#if (defined(__MACH__) || defined(__FreeBSD__))
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef __MACH__
+    #define XEVENT_MODE O_EVTONLY
+#elif defined(__FreeBSD__)
+    #define XEVENT_MODE EVFILT_VNODE
+#endif
+
+
+/* we need a unique kqueue user filter fd for crl in case user is doing custom
+ * events too */
+#ifndef CRL_CUSTOM_FD
+    #define CRL_CUSTOM_FD 123456
+#endif
+
+
+/* shutdown monitor thread, 0 on success */
+static int StopMonitor(int mfd)
+{
+    struct kevent change;
+
+    /* trigger custom shutdown */
+    EV_SET(&change, CRL_CUSTOM_FD, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
+    if (kevent(mfd, &change, 1, NULL, 0, NULL) < 0) {
+        WOLFSSL_MSG("kevent trigger customer event failed");
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/* OS X  monitoring */
+static void* DoMonitor(void* arg)
+{
+    int fPEM, fDER;
+    struct kevent change;
+
+    WOLFSSL_CRL* crl = (WOLFSSL_CRL*)arg;
+
+    WOLFSSL_ENTER("DoMonitor");
+
+    crl->mfd = kqueue();
+    if (crl->mfd == -1) {
+        WOLFSSL_MSG("kqueue failed");
+        return NULL;
+    }
+
+    /* listen for custom shutdown event */
+    EV_SET(&change, CRL_CUSTOM_FD, EVFILT_USER, EV_ADD, 0, 0, NULL);
+    if (kevent(crl->mfd, &change, 1, NULL, 0, NULL) < 0) {
+        WOLFSSL_MSG("kevent monitor customer event failed");
+        close(crl->mfd);
+        return NULL;
+    }
+
+    fPEM = -1;
+    fDER = -1;
+
+    if (crl->monitors[0].path) {
+        fPEM = open(crl->monitors[0].path, XEVENT_MODE);
+        if (fPEM == -1) {
+            WOLFSSL_MSG("PEM event dir open failed");
+            close(crl->mfd);
+            return NULL;
+        }
+    }
+
+    if (crl->monitors[1].path) {
+        fDER = open(crl->monitors[1].path, XEVENT_MODE);
+        if (fDER == -1) {
+            WOLFSSL_MSG("DER event dir open failed");
+            close(crl->mfd);
+            return NULL;
+        }
+    }
+
+    if (fPEM != -1)
+        EV_SET(&change, fPEM, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
+                NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB, 0, 0);
+
+    if (fDER != -1)
+        EV_SET(&change, fDER, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
+                NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB, 0, 0);
+
+    for (;;) {
+        struct kevent event;
+        int           numEvents = kevent(crl->mfd, &change, 1, &event, 1, NULL);
+       
+        WOLFSSL_MSG("Got kevent");
+
+        if (numEvents == -1) {
+            WOLFSSL_MSG("kevent problem, continue");
+            continue;
+        }
+
+        if (event.filter == EVFILT_USER) {
+            WOLFSSL_MSG("Got user shutdown event, breaking out");
+            break;
+        }
+
+        if (SwapLists(crl) < 0) {
+            WOLFSSL_MSG("SwapLists problem, continue");
+        }
+    }
+
+    if (fPEM != -1)
+        close(fPEM);
+    if (fDER != -1)
+        close(fDER);
+
+    close(crl->mfd);
+
+    return NULL;
+}
+
+
+#elif defined(__linux__)
+
+#include <sys/types.h>
+#include <sys/inotify.h>
+#include <sys/eventfd.h>
+#include <unistd.h>
+
+
+#ifndef max
+    static INLINE int max(int a, int b)
+    {
+        return a > b ? a : b;
+    }
+#endif /* max */
+
+
+/* shutdown monitor thread, 0 on success */
+static int StopMonitor(int mfd)
+{
+    word64 w64 = 1;
+
+    /* write to our custom event */
+    if (write(mfd, &w64, sizeof(w64)) < 0) {
+        WOLFSSL_MSG("StopMonitor write failed");
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/* linux monitoring */
+static void* DoMonitor(void* arg)
+{
+    int         notifyFd;
+    int         wd  = -1;
+    WOLFSSL_CRL* crl = (WOLFSSL_CRL*)arg;
+#ifdef WOLFSSL_SMALL_STACK
+    char*       buff;
+#else
+    char        buff[8192];
+#endif
+
+    WOLFSSL_ENTER("DoMonitor");
+
+    crl->mfd = eventfd(0, 0);  /* our custom shutdown event */
+    if (crl->mfd < 0) {
+        WOLFSSL_MSG("eventfd failed");
+        return NULL;
+    }
+
+    notifyFd = inotify_init();
+    if (notifyFd < 0) {
+        WOLFSSL_MSG("inotify failed");
+        close(crl->mfd);
+        return NULL;
+    }
+
+    if (crl->monitors[0].path) {
+        wd = inotify_add_watch(notifyFd, crl->monitors[0].path, IN_CLOSE_WRITE |
+                                                                IN_DELETE);
+        if (wd < 0) {
+            WOLFSSL_MSG("PEM notify add watch failed");
+            close(crl->mfd);
+            close(notifyFd);
+            return NULL;
+        }
+    }
+
+    if (crl->monitors[1].path) {
+        wd = inotify_add_watch(notifyFd, crl->monitors[1].path, IN_CLOSE_WRITE |
+                                                                IN_DELETE);
+        if (wd < 0) {
+            WOLFSSL_MSG("DER notify add watch failed");
+            close(crl->mfd);
+            close(notifyFd);
+            return NULL;
+        }
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    buff = (char*)XMALLOC(8192, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (buff == NULL)
+        return NULL;
+#endif
+
+    for (;;) {
+        fd_set readfds;
+        int    result;
+        int    length;
+
+        FD_ZERO(&readfds);
+        FD_SET(notifyFd, &readfds);
+        FD_SET(crl->mfd, &readfds);
+
+        result = select(max(notifyFd, crl->mfd) + 1, &readfds, NULL, NULL,NULL);
+       
+        WOLFSSL_MSG("Got notify event");
+
+        if (result < 0) {
+            WOLFSSL_MSG("select problem, continue");
+            continue;
+        }
+
+        if (FD_ISSET(crl->mfd, &readfds)) {
+            WOLFSSL_MSG("got custom shutdown event, breaking out");
+            break;
+        }
+
+        length = read(notifyFd, buff, 8192);
+        if (length < 0) {
+            WOLFSSL_MSG("notify read problem, continue");
+            continue;
+        } 
+
+        if (SwapLists(crl) < 0) {
+            WOLFSSL_MSG("SwapLists problem, continue");
+        }
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    if (wd > 0)
+        inotify_rm_watch(notifyFd, wd);
+    close(crl->mfd);
+    close(notifyFd);
+
+    return NULL;
+}
+
+
+#else
+
+#error "CRL monitor only currently supported on linux or mach"
+
+#endif /* MACH or linux */
+
+
+/* Start Monitoring the CRL path(s) in a thread */
+static int StartMonitorCRL(WOLFSSL_CRL* crl)
+{
+    pthread_attr_t attr;
+
+    WOLFSSL_ENTER("StartMonitorCRL");
+
+    if (crl == NULL) 
+        return BAD_FUNC_ARG;
+
+    if (crl->tid != 0) {
+        WOLFSSL_MSG("Monitor thread already running");
+        return MONITOR_RUNNING_E;
+    }
+
+    pthread_attr_init(&attr);
+
+    if (pthread_create(&crl->tid, &attr, DoMonitor, crl) != 0) {
+        WOLFSSL_MSG("Thread creation error");
+        return THREAD_CREATE_E;
+    }
+
+    return SSL_SUCCESS;
+}
+
+
+#else /* HAVE_CRL_MONITOR */
+
+static int StartMonitorCRL(WOLFSSL_CRL* crl)
+{
+    (void)crl;
+
+    WOLFSSL_ENTER("StartMonitorCRL");
+    WOLFSSL_MSG("Not compiled in");
+
+    return NOT_COMPILED_IN;
+}
+
+#endif  /* HAVE_CRL_MONITOR */
+
+
+/* Load CRL path files of type, SSL_SUCCESS on ok */ 
+int LoadCRL(WOLFSSL_CRL* crl, const char* path, int type, int monitor)
+{
+    struct dirent* entry;
+    DIR*           dir;
+    int            ret = SSL_SUCCESS;
+#ifdef WOLFSSL_SMALL_STACK
+    char*          name;
+#else
+    char           name[MAX_FILENAME_SZ];
+#endif
+
+    WOLFSSL_ENTER("LoadCRL");
+    if (crl == NULL)
+        return BAD_FUNC_ARG;
+
+    dir = opendir(path);
+    if (dir == NULL) {
+        WOLFSSL_MSG("opendir path crl load failed");
+        return BAD_PATH_ERROR;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    name = (char*)XMALLOC(MAX_FILENAME_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (name == NULL)
+        return MEMORY_E;
+#endif
+
+    while ( (entry = readdir(dir)) != NULL) {
+        struct stat s;
+
+        XMEMSET(name, 0, MAX_FILENAME_SZ);
+        XSTRNCPY(name, path, MAX_FILENAME_SZ/2 - 2);
+        XSTRNCAT(name, "/", 1);
+        XSTRNCAT(name, entry->d_name, MAX_FILENAME_SZ/2);
+
+        if (stat(name, &s) != 0) {
+            WOLFSSL_MSG("stat on name failed");
+            continue;
+        }
+        if (s.st_mode & S_IFREG) {
+
+            if (type == SSL_FILETYPE_PEM) {
+                if (strstr(entry->d_name, ".pem") == NULL) {
+                    WOLFSSL_MSG("not .pem file, skipping");
+                    continue;
+                }
+            }
+            else {
+                if (strstr(entry->d_name, ".der") == NULL &&
+                    strstr(entry->d_name, ".crl") == NULL) {
+
+                    WOLFSSL_MSG("not .der or .crl file, skipping");
+                    continue;
+                }
+            }
+
+            if (ProcessFile(NULL, name, type, CRL_TYPE, NULL, 0, crl)
+                                                               != SSL_SUCCESS) {
+                WOLFSSL_MSG("CRL file load failed, continuing");
+            }
+        }
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(name, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    if (monitor & WOLFSSL_CRL_MONITOR) {
+        WOLFSSL_MSG("monitor path requested");
+
+        if (type == SSL_FILETYPE_PEM) {
+            crl->monitors[0].path = strdup(path);
+            crl->monitors[0].type = SSL_FILETYPE_PEM;
+            if (crl->monitors[0].path == NULL)
+                ret = MEMORY_E;
+        } else {
+            crl->monitors[1].path = strdup(path);
+            crl->monitors[1].type = SSL_FILETYPE_ASN1;
+            if (crl->monitors[1].path == NULL)
+                ret = MEMORY_E;
+        }
+      
+        if (monitor & WOLFSSL_CRL_START_MON) {
+            WOLFSSL_MSG("start monitoring requested");
+    
+            ret = StartMonitorCRL(crl);
+       } 
+    }
+    
+    closedir(dir);
+
+    return ret;
+}
+
+#endif /* HAVE_CRL */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internal.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,14389 @@
+/* internal.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#include <wolfssl/internal.h>
+#include <wolfssl/error-ssl.h>
+#include <wolfssl/wolfcrypt/asn.h>
+#include <wolfssl/wolfcrypt/dh.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+#ifdef HAVE_LIBZ
+    #include "zlib.h"
+#endif
+
+#ifdef HAVE_NTRU
+    #include "ntru_crypto.h"
+#endif
+
+#if defined(DEBUG_WOLFSSL) || defined(SHOW_SECRETS) || defined(CHACHA_AEAD_TEST)
+    #ifdef FREESCALE_MQX
+        #include <fio.h>
+    #else
+        #include <stdio.h>
+    #endif
+#endif
+
+#ifdef __sun
+    #include <sys/filio.h>
+#endif
+
+#ifndef TRUE
+    #define TRUE  1
+#endif
+#ifndef FALSE
+    #define FALSE 0
+#endif
+
+#ifdef _MSC_VER
+    /* disable for while(0) cases at the .c level for now */
+    #pragma warning(disable:4127)
+#endif
+
+#if defined(WOLFSSL_CALLBACKS) && !defined(LARGE_STATIC_BUFFERS)
+    #error \
+WOLFSSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS
+#endif
+
+#if defined(HAVE_SECURE_RENEGOTIATION) && defined(HAVE_RENEGOTIATION_INDICATION)
+    #error Cannot use both secure-renegotiation and renegotiation-indication
+#endif
+
+static int BuildMessage(WOLFSSL* ssl, byte* output, int outSz,
+                        const byte* input, int inSz, int type);
+
+#ifndef NO_WOLFSSL_CLIENT
+    static int DoHelloVerifyRequest(WOLFSSL* ssl, const byte* input, word32*,
+                                                                        word32);
+    static int DoServerHello(WOLFSSL* ssl, const byte* input, word32*, word32);
+    static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, word32*,
+                                                                        word32);
+    #ifndef NO_CERTS
+        static int DoCertificateRequest(WOLFSSL* ssl, const byte* input, word32*,
+                                                                        word32);
+    #endif
+    #ifdef HAVE_SESSION_TICKET
+        static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32*,
+                                                                        word32);
+    #endif
+#endif
+
+
+#ifndef NO_WOLFSSL_SERVER
+    static int DoClientHello(WOLFSSL* ssl, const byte* input, word32*, word32);
+    static int DoClientKeyExchange(WOLFSSL* ssl, byte* input, word32*, word32);
+    #if !defined(NO_RSA) || defined(HAVE_ECC)
+        static int DoCertificateVerify(WOLFSSL* ssl, byte*, word32*, word32);
+    #endif
+#endif
+
+
+#ifdef WOLFSSL_DTLS
+    static INLINE int DtlsCheckWindow(DtlsState* state);
+    static INLINE int DtlsUpdateWindow(DtlsState* state);
+#endif
+
+
+typedef enum {
+    doProcessInit = 0,
+#ifndef NO_WOLFSSL_SERVER
+    runProcessOldClientHello,
+#endif
+    getRecordLayerHeader,
+    getData,
+    runProcessingOneMessage
+} processReply;
+
+#ifndef NO_OLD_TLS
+static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
+                    int content, int verify);
+
+#endif
+
+#ifndef NO_CERTS
+static int BuildCertHashes(WOLFSSL* ssl, Hashes* hashes);
+#endif
+
+static void PickHashSigAlgo(WOLFSSL* ssl,
+                                const byte* hashSigAlgo, word32 hashSigAlgoSz);
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* WOLFSSL_HAVE_MIN */
+
+
+int IsTLS(const WOLFSSL* ssl)
+{
+    if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_MINOR)
+        return 1;
+
+    return 0;
+}
+
+
+int IsAtLeastTLSv1_2(const WOLFSSL* ssl)
+{
+    if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_2_MINOR)
+        return 1;
+    if (ssl->version.major == DTLS_MAJOR && ssl->version.minor <= DTLSv1_2_MINOR)
+        return 1;
+
+    return 0;
+}
+
+
+#ifdef HAVE_NTRU
+
+static byte GetEntropy(ENTROPY_CMD cmd, byte* out)
+{
+    /* TODO: add locking? */
+    static RNG rng;
+
+    if (cmd == INIT)
+        return (wc_InitRng(&rng) == 0) ? 1 : 0;
+
+    if (out == NULL)
+        return 0;
+
+    if (cmd == GET_BYTE_OF_ENTROPY)
+        return (wc_RNG_GenerateBlock(&rng, out, 1) == 0) ? 1 : 0;
+
+    if (cmd == GET_NUM_BYTES_PER_BYTE_OF_ENTROPY) {
+        *out = 1;
+        return 1;
+    }
+
+    return 0;
+}
+
+#endif /* HAVE_NTRU */
+
+/* used by ssl.c too */
+void c32to24(word32 in, word24 out)
+{
+    out[0] = (in >> 16) & 0xff;
+    out[1] = (in >>  8) & 0xff;
+    out[2] =  in & 0xff;
+}
+
+
+#ifdef WOLFSSL_DTLS
+
+static INLINE void c32to48(word32 in, byte out[6])
+{
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = (in >> 24) & 0xff;
+    out[3] = (in >> 16) & 0xff;
+    out[4] = (in >>  8) & 0xff;
+    out[5] =  in & 0xff;
+}
+
+#endif /* WOLFSSL_DTLS */
+
+
+/* convert 16 bit integer to opaque */
+static INLINE void c16toa(word16 u16, byte* c)
+{
+    c[0] = (u16 >> 8) & 0xff;
+    c[1] =  u16 & 0xff;
+}
+
+
+#if !defined(NO_OLD_TLS) || defined(HAVE_CHACHA) || defined(HAVE_AESCCM) \
+    || defined(HAVE_AESGCM)
+/* 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;
+}
+#endif
+
+
+/* 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];
+}
+
+
+/* convert opaque to 16 bit integer */
+static INLINE void ato16(const byte* c, word16* u16)
+{
+    *u16 = (word16) ((c[0] << 8) | (c[1]));
+}
+
+
+#if defined(WOLFSSL_DTLS) || defined(HAVE_SESSION_TICKET)
+
+/* 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];
+}
+
+#endif /* WOLFSSL_DTLS */
+
+
+#ifdef HAVE_LIBZ
+
+    /* alloc user allocs to work with zlib */
+    static void* myAlloc(void* opaque, unsigned int item, unsigned int size)
+    {
+        (void)opaque;
+        return XMALLOC(item * size, opaque, DYNAMIC_TYPE_LIBZ);
+    }
+
+
+    static void myFree(void* opaque, void* memory)
+    {
+        (void)opaque;
+        XFREE(memory, opaque, DYNAMIC_TYPE_LIBZ);
+    }
+
+
+    /* init zlib comp/decomp streams, 0 on success */
+    static int InitStreams(WOLFSSL* ssl)
+    {
+        ssl->c_stream.zalloc = (alloc_func)myAlloc;
+        ssl->c_stream.zfree  = (free_func)myFree;
+        ssl->c_stream.opaque = (voidpf)ssl->heap;
+
+        if (deflateInit(&ssl->c_stream, Z_DEFAULT_COMPRESSION) != Z_OK)
+            return ZLIB_INIT_ERROR;
+
+        ssl->didStreamInit = 1;
+
+        ssl->d_stream.zalloc = (alloc_func)myAlloc;
+        ssl->d_stream.zfree  = (free_func)myFree;
+        ssl->d_stream.opaque = (voidpf)ssl->heap;
+
+        if (inflateInit(&ssl->d_stream) != Z_OK) return ZLIB_INIT_ERROR;
+
+        return 0;
+    }
+
+
+    static void FreeStreams(WOLFSSL* ssl)
+    {
+        if (ssl->didStreamInit) {
+            deflateEnd(&ssl->c_stream);
+            inflateEnd(&ssl->d_stream);
+        }
+    }
+
+
+    /* compress in to out, return out size or error */
+    static int myCompress(WOLFSSL* ssl, byte* in, int inSz, byte* out, int outSz)
+    {
+        int    err;
+        int    currTotal = (int)ssl->c_stream.total_out;
+
+        ssl->c_stream.next_in   = in;
+        ssl->c_stream.avail_in  = inSz;
+        ssl->c_stream.next_out  = out;
+        ssl->c_stream.avail_out = outSz;
+
+        err = deflate(&ssl->c_stream, Z_SYNC_FLUSH);
+        if (err != Z_OK && err != Z_STREAM_END) return ZLIB_COMPRESS_ERROR;
+
+        return (int)ssl->c_stream.total_out - currTotal;
+    }
+
+
+    /* decompress in to out, returnn out size or error */
+    static int myDeCompress(WOLFSSL* ssl, byte* in,int inSz, byte* out,int outSz)
+    {
+        int    err;
+        int    currTotal = (int)ssl->d_stream.total_out;
+
+        ssl->d_stream.next_in   = in;
+        ssl->d_stream.avail_in  = inSz;
+        ssl->d_stream.next_out  = out;
+        ssl->d_stream.avail_out = outSz;
+
+        err = inflate(&ssl->d_stream, Z_SYNC_FLUSH);
+        if (err != Z_OK && err != Z_STREAM_END) return ZLIB_DECOMPRESS_ERROR;
+
+        return (int)ssl->d_stream.total_out - currTotal;
+    }
+
+#endif /* HAVE_LIBZ */
+
+
+void InitSSL_Method(WOLFSSL_METHOD* method, ProtocolVersion pv)
+{
+    method->version    = pv;
+    method->side       = WOLFSSL_CLIENT_END;
+    method->downgrade  = 0;
+}
+
+
+/* Initialze SSL context, return 0 on success */
+int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method)
+{
+    XMEMSET(ctx, 0, sizeof(WOLFSSL_CTX));
+
+    ctx->method   = method;
+    ctx->refCount = 1;          /* so either CTX_free or SSL_free can release */
+    ctx->heap     = ctx;        /* defaults to self */
+    ctx->timeout  = WOLFSSL_SESSION_TIMEOUT;
+    ctx->minDowngrade = TLSv1_MINOR;     /* current default */
+
+    if (InitMutex(&ctx->countMutex) < 0) {
+        WOLFSSL_MSG("Mutex error on CTX init");
+        return BAD_MUTEX_E;
+    }
+
+#ifndef NO_DH
+    ctx->minDhKeySz = MIN_DHKEY_SZ;
+#endif
+
+#ifdef HAVE_ECC
+    ctx->eccTempKeySz = ECDHE_SIZE;
+#endif
+
+#ifndef WOLFSSL_USER_IO
+    ctx->CBIORecv = EmbedReceive;
+    ctx->CBIOSend = EmbedSend;
+    #ifdef WOLFSSL_DTLS
+        if (method->version.major == DTLS_MAJOR) {
+            ctx->CBIORecv   = EmbedReceiveFrom;
+            ctx->CBIOSend   = EmbedSendTo;
+            ctx->CBIOCookie = EmbedGenerateCookie;
+        }
+    #endif
+#endif /* WOLFSSL_USER_IO */
+
+#ifdef HAVE_NETX
+    ctx->CBIORecv = NetX_Receive;
+    ctx->CBIOSend = NetX_Send;
+#endif
+
+#ifdef HAVE_NTRU
+    if (method->side == WOLFSSL_CLIENT_END)
+        ctx->haveNTRU = 1;           /* always on cliet 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->haveStaticECC = 1;        /* server can turn on by loading key */
+    }
+#endif
+
+#ifdef HAVE_CAVIUM
+    ctx->devId = NO_CAVIUM_DEVICE;
+#endif
+
+#ifndef NO_CERTS
+    ctx->cm = wolfSSL_CertManagerNew();
+    if (ctx->cm == NULL) {
+        WOLFSSL_MSG("Bad Cert Manager New");
+        return BAD_CERT_MANAGER_ERROR;
+    }
+#endif
+
+#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER)
+    ctx->ticketHint = SESSION_TICKET_HINT_DEFAULT;
+#endif
+
+    return 0;
+}
+
+
+/* In case contexts are held in array and don't want to free actual ctx */
+void SSL_CtxResourceFree(WOLFSSL_CTX* ctx)
+{
+    XFREE(ctx->method, ctx->heap, DYNAMIC_TYPE_METHOD);
+    if (ctx->suites)
+        XFREE(ctx->suites, ctx->heap, DYNAMIC_TYPE_SUITES);
+
+#ifndef NO_DH
+    XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_DH);
+    XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_DH);
+#endif
+#ifndef NO_CERTS
+    XFREE(ctx->privateKey.buffer, ctx->heap, DYNAMIC_TYPE_KEY);
+    XFREE(ctx->certificate.buffer, ctx->heap, DYNAMIC_TYPE_CERT);
+    XFREE(ctx->certChain.buffer, ctx->heap, DYNAMIC_TYPE_CERT);
+    wolfSSL_CertManagerFree(ctx->cm);
+#endif
+#ifdef HAVE_TLS_EXTENSIONS
+    TLSX_FreeAll(ctx->extensions);
+#endif
+}
+
+
+void FreeSSL_Ctx(WOLFSSL_CTX* ctx)
+{
+    int doFree = 0;
+
+    if (LockMutex(&ctx->countMutex) != 0) {
+        WOLFSSL_MSG("Couldn't lock count mutex");
+        return;
+    }
+    ctx->refCount--;
+    if (ctx->refCount == 0)
+        doFree = 1;
+    UnLockMutex(&ctx->countMutex);
+
+    if (doFree) {
+        WOLFSSL_MSG("CTX ref count down to 0, doing full free");
+        SSL_CtxResourceFree(ctx);
+        FreeMutex(&ctx->countMutex);
+        XFREE(ctx, ctx->heap, DYNAMIC_TYPE_CTX);
+    }
+    else {
+        (void)ctx;
+        WOLFSSL_MSG("CTX ref count not 0 yet, no free");
+    }
+}
+
+
+/* Set cipher pointers to null */
+void InitCiphers(WOLFSSL* ssl)
+{
+#ifdef BUILD_ARC4
+    ssl->encrypt.arc4 = NULL;
+    ssl->decrypt.arc4 = NULL;
+#endif
+#ifdef BUILD_DES3
+    ssl->encrypt.des3 = NULL;
+    ssl->decrypt.des3 = NULL;
+#endif
+#ifdef BUILD_AES
+    ssl->encrypt.aes = NULL;
+    ssl->decrypt.aes = NULL;
+#endif
+#ifdef HAVE_CAMELLIA
+    ssl->encrypt.cam = NULL;
+    ssl->decrypt.cam = NULL;
+#endif
+#ifdef HAVE_HC128
+    ssl->encrypt.hc128 = NULL;
+    ssl->decrypt.hc128 = NULL;
+#endif
+#ifdef BUILD_RABBIT
+    ssl->encrypt.rabbit = NULL;
+    ssl->decrypt.rabbit = NULL;
+#endif
+#ifdef HAVE_CHACHA
+    ssl->encrypt.chacha = NULL;
+    ssl->decrypt.chacha = NULL;
+#endif
+#ifdef HAVE_POLY1305
+    ssl->auth.poly1305 = NULL;
+#endif
+    ssl->encrypt.setup = 0;
+    ssl->decrypt.setup = 0;
+#ifdef HAVE_ONE_TIME_AUTH
+    ssl->auth.setup    = 0;
+#endif
+}
+
+
+/* Free ciphers */
+void FreeCiphers(WOLFSSL* ssl)
+{
+    (void)ssl;
+#ifdef BUILD_ARC4
+    #ifdef HAVE_CAVIUM
+    if (ssl->devId != NO_CAVIUM_DEVICE) {
+        wc_Arc4FreeCavium(ssl->encrypt.arc4);
+        wc_Arc4FreeCavium(ssl->decrypt.arc4);
+    }
+    #endif
+    XFREE(ssl->encrypt.arc4, ssl->heap, DYNAMIC_TYPE_CIPHER);
+    XFREE(ssl->decrypt.arc4, ssl->heap, DYNAMIC_TYPE_CIPHER);
+#endif
+#ifdef BUILD_DES3
+    #ifdef HAVE_CAVIUM
+    if (ssl->devId != NO_CAVIUM_DEVICE) {
+        wc_Des3_FreeCavium(ssl->encrypt.des3);
+        wc_Des3_FreeCavium(ssl->decrypt.des3);
+    }
+    #endif
+    XFREE(ssl->encrypt.des3, ssl->heap, DYNAMIC_TYPE_CIPHER);
+    XFREE(ssl->decrypt.des3, ssl->heap, DYNAMIC_TYPE_CIPHER);
+#endif
+#ifdef BUILD_AES
+    #ifdef HAVE_CAVIUM
+    if (ssl->devId != NO_CAVIUM_DEVICE) {
+        wc_AesFreeCavium(ssl->encrypt.aes);
+        wc_AesFreeCavium(ssl->decrypt.aes);
+    }
+    #endif
+    XFREE(ssl->encrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER);
+    XFREE(ssl->decrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER);
+#endif
+#ifdef HAVE_CAMELLIA
+    XFREE(ssl->encrypt.cam, ssl->heap, DYNAMIC_TYPE_CIPHER);
+    XFREE(ssl->decrypt.cam, ssl->heap, DYNAMIC_TYPE_CIPHER);
+#endif
+#ifdef HAVE_HC128
+    XFREE(ssl->encrypt.hc128, ssl->heap, DYNAMIC_TYPE_CIPHER);
+    XFREE(ssl->decrypt.hc128, ssl->heap, DYNAMIC_TYPE_CIPHER);
+#endif
+#ifdef BUILD_RABBIT
+    XFREE(ssl->encrypt.rabbit, ssl->heap, DYNAMIC_TYPE_CIPHER);
+    XFREE(ssl->decrypt.rabbit, ssl->heap, DYNAMIC_TYPE_CIPHER);
+#endif
+#ifdef HAVE_CHACHA
+    XFREE(ssl->encrypt.chacha, ssl->heap, DYNAMIC_TYPE_CIPHER);
+    XFREE(ssl->decrypt.chacha, ssl->heap, DYNAMIC_TYPE_CIPHER);
+#endif
+#ifdef HAVE_POLY1305
+    XFREE(ssl->auth.poly1305, ssl->heap, DYNAMIC_TYPE_CIPHER);
+#endif
+}
+
+
+void InitCipherSpecs(CipherSpecs* cs)
+{
+    cs->bulk_cipher_algorithm = INVALID_BYTE;
+    cs->cipher_type           = INVALID_BYTE;
+    cs->mac_algorithm         = INVALID_BYTE;
+    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;
+}
+
+static void InitSuitesHashSigAlgo(Suites* suites, int haveECDSAsig,
+                                                  int haveRSAsig, int haveAnon)
+{
+    int idx = 0;
+
+    if (haveECDSAsig) {
+        #ifdef WOLFSSL_SHA512
+            suites->hashSigAlgo[idx++] = sha512_mac;
+            suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo;
+        #endif
+        #ifdef WOLFSSL_SHA384
+            suites->hashSigAlgo[idx++] = sha384_mac;
+            suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo;
+        #endif
+        #ifndef NO_SHA256
+            suites->hashSigAlgo[idx++] = sha256_mac;
+            suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo;
+        #endif
+        #ifndef NO_SHA
+            suites->hashSigAlgo[idx++] = sha_mac;
+            suites->hashSigAlgo[idx++] = ecc_dsa_sa_algo;
+        #endif
+    }
+
+    if (haveRSAsig) {
+        #ifdef WOLFSSL_SHA512
+            suites->hashSigAlgo[idx++] = sha512_mac;
+            suites->hashSigAlgo[idx++] = rsa_sa_algo;
+        #endif
+        #ifdef WOLFSSL_SHA384
+            suites->hashSigAlgo[idx++] = sha384_mac;
+            suites->hashSigAlgo[idx++] = rsa_sa_algo;
+        #endif
+        #ifndef NO_SHA256
+            suites->hashSigAlgo[idx++] = sha256_mac;
+            suites->hashSigAlgo[idx++] = rsa_sa_algo;
+        #endif
+        #ifndef NO_SHA
+            suites->hashSigAlgo[idx++] = sha_mac;
+            suites->hashSigAlgo[idx++] = rsa_sa_algo;
+        #endif
+    }
+
+    if (haveAnon) {
+        #ifdef HAVE_ANON
+            suites->hashSigAlgo[idx++] = sha_mac;
+            suites->hashSigAlgo[idx++] = anonymous_sa_algo;
+        #endif
+    }
+
+    suites->hashSigAlgoSz = (word16)idx;
+}
+
+void InitSuites(Suites* suites, ProtocolVersion pv, word16 haveRSA,
+                word16 havePSK, word16 haveDH, word16 haveNTRU,
+                word16 haveECDSAsig, word16 haveStaticECC, int side)
+{
+    word16 idx = 0;
+    int    tls    = pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_MINOR;
+    int    tls1_2 = pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_2_MINOR;
+    int    haveRSAsig = 1;
+
+    (void)tls;  /* shut up compiler */
+    (void)tls1_2;
+    (void)haveDH;
+    (void)havePSK;
+    (void)haveNTRU;
+    (void)haveStaticECC;
+
+    if (suites == NULL) {
+        WOLFSSL_MSG("InitSuites pointer error");
+        return;
+    }
+
+    if (suites->setSuites)
+        return;      /* trust user settings, don't override */
+
+    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 */
+    }
+
+#ifdef WOLFSSL_DTLS
+    if (pv.major == DTLS_MAJOR) {
+        tls    = 1;
+        tls1_2 = pv.minor <= DTLSv1_2_MINOR;
+    }
+#endif
+
+#ifdef HAVE_RENEGOTIATION_INDICATION
+    if (side == WOLFSSL_CLIENT_END) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV;
+    }
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    if (tls && haveNTRU && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+    if (tls && haveNTRU && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+    if (tls && haveNTRU && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_RC4_128_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    if (tls && haveNTRU && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+    if (tls1_2 && haveECDSAsig) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+    if (tls1_2 && haveECDSAsig) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+    if (tls1_2 && haveRSA) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+    if (tls1_2 && haveRSA) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+    if (tls1_2 && haveDH && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_GCM_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+    if (tls1_2 && haveDH && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_GCM_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384
+    if (tls1_2 && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_AES_256_GCM_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256
+    if (tls1_2 && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_AES_128_GCM_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+    if (tls1_2 && haveECDSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+    if (tls1_2 && haveECDSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+    if (tls1_2 && haveRSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+    if (tls1_2 && haveRSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
+    if (tls1_2 && haveDH && havePSK) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_256_GCM_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
+    if (tls1_2 && haveDH && havePSK) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_128_GCM_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_GCM_SHA384
+    if (tls1_2 && havePSK) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_PSK_WITH_AES_256_GCM_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256
+    if (tls1_2 && havePSK) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_PSK_WITH_AES_128_GCM_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
+    if (tls1_2 && haveECDSAsig) {
+        suites->suites[idx++] = CHACHA_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+    if (tls && haveRSA) {
+        suites->suites[idx++] = CHACHA_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+    if (tls && haveRSA) {
+        suites->suites[idx++] = CHACHA_BYTE;
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+    if (tls1_2 && haveRSAsig) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+    if (tls1_2 && haveECDSAsig) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
+    if (tls1_2 && haveRSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
+    if (tls1_2 && haveECDSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+    if (tls1_2 && haveRSAsig) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+    if (tls1_2 && haveECDSAsig) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
+    if (tls1_2 && haveRSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
+    if (tls1_2 && haveECDSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+    if (tls && haveECDSAsig) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
+    if (tls && haveECDSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+    if (tls && haveECDSAsig) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
+    if (tls && haveECDSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+    if (tls && haveECDSAsig) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
+    if (tls && haveECDSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+    if (tls && haveECDSAsig) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
+    if (tls && haveECDSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
+    if (tls && haveRSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
+    if (tls && haveRSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA
+    if (tls && haveRSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_RSA_WITH_RC4_128_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+    if (tls && haveRSAsig && haveStaticECC) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+    if (tls1_2 && haveECDSAsig) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
+    if (tls1_2 && haveECDSAsig) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8
+    if (tls1_2 && haveRSA) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_RSA_WITH_AES_128_CCM_8;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8
+    if (tls1_2 && haveRSA) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_RSA_WITH_AES_256_CCM_8;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
+    if (tls1_2 && haveDH && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
+    if (tls1_2 && haveDH && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+    if (tls && haveDH && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+    if (tls && haveDH && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256
+    if (tls1_2 && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256
+    if (tls1_2 && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_NULL_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_NULL_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_NULL_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
+    if (tls && havePSK) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_PSK_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
+    if (tls && haveDH && havePSK) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_256_CBC_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA384
+    if (tls && havePSK) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_PSK_WITH_AES_256_CBC_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
+    if (tls && haveDH && havePSK) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_128_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256
+    if (tls && havePSK) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_PSK_WITH_AES_128_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
+    if (tls && havePSK) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_PSK_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CCM
+    if (tls && haveDH && havePSK) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_128_CCM;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CCM
+    if (tls && haveDH && havePSK) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_DHE_PSK_WITH_AES_256_CCM;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM
+    if (tls && havePSK) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_PSK_WITH_AES_128_CCM;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM
+    if (tls && havePSK) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_PSK_WITH_AES_256_CCM;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8
+    if (tls && havePSK) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_PSK_WITH_AES_128_CCM_8;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8
+    if (tls && havePSK) {
+        suites->suites[idx++] = ECC_BYTE;
+        suites->suites[idx++] = TLS_PSK_WITH_AES_256_CCM_8;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA384
+    if (tls && haveDH && havePSK) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_PSK_WITH_NULL_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_NULL_SHA384
+    if (tls && havePSK) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA384;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA256
+    if (tls && haveDH && havePSK) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_PSK_WITH_NULL_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256
+    if (tls && havePSK) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_NULL_SHA
+    if (tls && havePSK) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_PSK_WITH_NULL_SHA;
+    }
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
+    if (haveRSA ) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = SSL_RSA_WITH_RC4_128_SHA;
+    }
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
+    if (haveRSA ) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = SSL_RSA_WITH_RC4_128_MD5;
+    }
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+    if (haveRSA ) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = SSL_RSA_WITH_3DES_EDE_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_HC_128_MD5;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_HC_128_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_HC_128_B2B256;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_B2B256;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_B2B256;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_RABBIT_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+    if (tls && haveDH && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_WITH_RSA_CAMELLIA_256_CBC_SHA
+    if (tls && haveDH && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+    if (tls && haveDH && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
+    if (tls && haveDH && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256;
+    }
+#endif
+
+    suites->suiteSz = idx;
+
+    InitSuitesHashSigAlgo(suites, haveECDSAsig, haveRSAsig, 0);
+}
+
+
+#ifndef NO_CERTS
+
+
+void InitX509Name(WOLFSSL_X509_NAME* name, int dynamicFlag)
+{
+    (void)dynamicFlag;
+
+    if (name != NULL) {
+        name->name        = name->staticName;
+        name->dynamicName = 0;
+#ifdef OPENSSL_EXTRA
+        XMEMSET(&name->fullName, 0, sizeof(DecodedName));
+#endif /* OPENSSL_EXTRA */
+    }
+}
+
+
+void FreeX509Name(WOLFSSL_X509_NAME* name)
+{
+    if (name != NULL) {
+        if (name->dynamicName)
+            XFREE(name->name, NULL, DYNAMIC_TYPE_SUBJECT_CN);
+#ifdef OPENSSL_EXTRA
+        if (name->fullName.fullName != NULL)
+            XFREE(name->fullName.fullName, NULL, DYNAMIC_TYPE_X509);
+#endif /* OPENSSL_EXTRA */
+    }
+}
+
+
+/* Initialize wolfSSL X509 type */
+void InitX509(WOLFSSL_X509* x509, int dynamicFlag)
+{
+    InitX509Name(&x509->issuer, 0);
+    InitX509Name(&x509->subject, 0);
+    x509->version        = 0;
+    x509->pubKey.buffer  = NULL;
+    x509->sig.buffer     = NULL;
+    x509->derCert.buffer = 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 */
+}
+
+
+/* Free wolfSSL X509 type */
+void FreeX509(WOLFSSL_X509* x509)
+{
+    if (x509 == NULL)
+        return;
+
+    FreeX509Name(&x509->issuer);
+    FreeX509Name(&x509->subject);
+    if (x509->pubKey.buffer)
+        XFREE(x509->pubKey.buffer, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
+    XFREE(x509->derCert.buffer, NULL, DYNAMIC_TYPE_SUBJECT_CN);
+    XFREE(x509->sig.buffer, NULL, DYNAMIC_TYPE_SIGNATURE);
+    #ifdef OPENSSL_EXTRA
+        XFREE(x509->authKeyId, NULL, 0);
+        XFREE(x509->subjKeyId, NULL, 0);
+    #endif /* OPENSSL_EXTRA */
+    if (x509->altNames)
+        FreeAltNames(x509->altNames, NULL);
+    if (x509->dynamicMemory)
+        XFREE(x509, NULL, DYNAMIC_TYPE_X509);
+}
+
+#endif /* NO_CERTS */
+
+
+/* init everything to 0, NULL, default values before calling anything that may
+   fail so that desctructor has a "good" state to cleanup */
+int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx)
+{
+    int  ret;
+    byte haveRSA = 0;
+    byte havePSK = 0;
+    byte haveAnon = 0;
+
+    (void) haveAnon;
+
+    XMEMSET(ssl, 0, sizeof(WOLFSSL));
+
+    ssl->ctx     = ctx; /* only for passing to calls, options could change */
+    ssl->version = ctx->method->version;
+
+#ifndef NO_RSA
+    haveRSA = 1;
+#endif
+
+    ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer;
+    ssl->buffers.inputBuffer.bufferSize  = STATIC_BUFFER_LEN;
+
+    ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer;
+    ssl->buffers.outputBuffer.bufferSize  = STATIC_BUFFER_LEN;
+
+#ifdef KEEP_PEER_CERT
+    InitX509(&ssl->peerCert, 0);
+#endif
+
+#ifdef HAVE_ECC
+    ssl->eccTempKeySz = ctx->eccTempKeySz;
+    ssl->pkCurveOID = ctx->pkCurveOID;
+#endif
+
+    ssl->timeout = ctx->timeout;
+    ssl->rfd = -1;   /* set to invalid descriptor */
+    ssl->wfd = -1;
+
+    ssl->IOCB_ReadCtx  = &ssl->rfd;  /* prevent invalid pointer access if not */
+    ssl->IOCB_WriteCtx = &ssl->wfd;  /* correctly set */
+
+#ifdef HAVE_NETX
+    ssl->IOCB_ReadCtx  = &ssl->nxCtx;  /* default NetX IO ctx, same for read */
+    ssl->IOCB_WriteCtx = &ssl->nxCtx;  /* and write */
+#endif
+#ifdef WOLFSSL_DTLS
+    ssl->dtls_expected_rx = MAX_MTU;
+#endif
+
+    ssl->verifyCallback    = ctx->verifyCallback;
+    ssl->options.side      = ctx->method->side;
+    ssl->options.downgrade    = ctx->method->downgrade;
+    ssl->options.minDowngrade = ctx->minDowngrade;
+
+    if (ssl->options.side == WOLFSSL_SERVER_END)
+        ssl->options.haveDH = ctx->haveDH;
+
+    ssl->options.haveNTRU      = ctx->haveNTRU;
+    ssl->options.haveECDSAsig  = ctx->haveECDSAsig;
+    ssl->options.haveStaticECC = ctx->haveStaticECC;
+
+#ifndef NO_PSK
+    havePSK = ctx->havePSK;
+    ssl->options.havePSK   = ctx->havePSK;
+    ssl->options.client_psk_cb = ctx->client_psk_cb;
+    ssl->options.server_psk_cb = ctx->server_psk_cb;
+#endif /* NO_PSK */
+
+#ifdef HAVE_ANON
+    haveAnon = ctx->haveAnon;
+    ssl->options.haveAnon = ctx->haveAnon;
+#endif
+
+    ssl->options.serverState = NULL_STATE;
+    ssl->options.clientState = NULL_STATE;
+    ssl->options.connectState = CONNECT_BEGIN;
+    ssl->options.acceptState  = ACCEPT_BEGIN;
+    ssl->options.handShakeState  = NULL_STATE;
+    ssl->options.processReply = doProcessInit;
+
+#ifndef NO_DH
+    ssl->options.minDhKeySz = ctx->minDhKeySz;
+#endif
+
+#ifdef WOLFSSL_DTLS
+    ssl->dtls_timeout_init              = DTLS_TIMEOUT_INIT;
+    ssl->dtls_timeout_max               = DTLS_TIMEOUT_MAX;
+    ssl->dtls_timeout                   = ssl->dtls_timeout_init;
+#endif
+
+    ssl->options.sessionCacheOff      = ctx->sessionCacheOff;
+    ssl->options.sessionCacheFlushOff = ctx->sessionCacheFlushOff;
+
+    ssl->options.verifyPeer = ctx->verifyPeer;
+    ssl->options.verifyNone = ctx->verifyNone;
+    ssl->options.failNoCert = ctx->failNoCert;
+    ssl->options.sendVerify = ctx->sendVerify;
+
+    #ifndef NO_OLD_TLS
+        ssl->hmac = SSL_hmac; /* default to SSLv3 */
+    #else
+        ssl->hmac = TLS_hmac;
+    #endif
+
+    ssl->heap = ctx->heap;    /* defaults to self */
+
+    ssl->options.dtls = ssl->version.major == DTLS_MAJOR;
+    ssl->options.partialWrite  = ctx->partialWrite;
+    ssl->options.quietShutdown = ctx->quietShutdown;
+    ssl->options.groupMessages = ctx->groupMessages;
+
+#ifndef NO_DH
+    if (ssl->options.side == WOLFSSL_SERVER_END) {
+        ssl->buffers.serverDH_P = ctx->serverDH_P;
+        ssl->buffers.serverDH_G = ctx->serverDH_G;
+    }
+#endif
+#ifndef NO_CERTS
+    /* ctx still owns certificate, certChain, key, dh, and cm */
+    ssl->buffers.certificate = ctx->certificate;
+    ssl->buffers.certChain = ctx->certChain;
+    ssl->buffers.key = ctx->privateKey;
+#endif
+
+#ifdef WOLFSSL_DTLS
+    ssl->buffers.dtlsCtx.fd = -1;
+#endif
+
+    ssl->cipher.ssl = ssl;
+
+#ifdef HAVE_CAVIUM
+    ssl->devId = ctx->devId;
+#endif
+
+#ifdef HAVE_TLS_EXTENSIONS
+#ifdef HAVE_MAX_FRAGMENT
+    ssl->max_fragment = MAX_RECORD_SIZE;
+#endif
+#endif
+
+    /* default alert state (none) */
+    ssl->alert_history.last_rx.code  = -1;
+    ssl->alert_history.last_rx.level = -1;
+    ssl->alert_history.last_tx.code  = -1;
+    ssl->alert_history.last_tx.level = -1;
+
+    InitCiphers(ssl);
+    InitCipherSpecs(&ssl->specs);
+
+    /* all done with init, now can return errors, call other stuff */
+
+    /* hsHashes */
+    ssl->hsHashes = (HS_Hashes*)XMALLOC(sizeof(HS_Hashes), ssl->heap,
+                                                           DYNAMIC_TYPE_HASHES);
+    if (ssl->hsHashes == NULL) {
+        WOLFSSL_MSG("HS_Hashes Memory error");
+        return MEMORY_E;
+    }
+
+#ifndef NO_OLD_TLS
+#ifndef NO_MD5
+    wc_InitMd5(&ssl->hsHashes->hashMd5);
+#endif
+#ifndef NO_SHA
+    ret = wc_InitSha(&ssl->hsHashes->hashSha);
+    if (ret != 0) {
+        return ret;
+    }
+#endif
+#endif
+#ifndef NO_SHA256
+    ret = wc_InitSha256(&ssl->hsHashes->hashSha256);
+    if (ret != 0) {
+        return ret;
+    }
+#endif
+#ifdef WOLFSSL_SHA384
+    ret = wc_InitSha384(&ssl->hsHashes->hashSha384);
+    if (ret != 0) {
+        return ret;
+    }
+#endif
+#ifdef WOLFSSL_SHA512
+    ret = wc_InitSha512(&ssl->hsHashes->hashSha512);
+    if (ret != 0) {
+        return ret;
+    }
+#endif
+
+    /* increment CTX reference count */
+    if (LockMutex(&ctx->countMutex) != 0) {
+        WOLFSSL_MSG("Couldn't lock CTX count mutex");
+        return BAD_MUTEX_E;
+    }
+    ctx->refCount++;
+    UnLockMutex(&ctx->countMutex);
+
+    /* arrays */
+    ssl->arrays = (Arrays*)XMALLOC(sizeof(Arrays), ssl->heap,
+                                                           DYNAMIC_TYPE_ARRAYS);
+    if (ssl->arrays == NULL) {
+        WOLFSSL_MSG("Arrays Memory error");
+        return MEMORY_E;
+    }
+    XMEMSET(ssl->arrays, 0, sizeof(Arrays));
+
+#ifndef NO_PSK
+    if (ctx->server_hint[0]) {   /* set in CTX */
+        XSTRNCPY(ssl->arrays->server_hint, ctx->server_hint, MAX_PSK_ID_LEN);
+        ssl->arrays->server_hint[MAX_PSK_ID_LEN - 1] = '\0';
+    }
+#endif /* NO_PSK */
+
+    /* RNG */
+    ssl->rng = (RNG*)XMALLOC(sizeof(RNG), ssl->heap, DYNAMIC_TYPE_RNG);
+    if (ssl->rng == NULL) {
+        WOLFSSL_MSG("RNG Memory error");
+        return MEMORY_E;
+    }
+
+    if ( (ret = wc_InitRng(ssl->rng)) != 0) {
+        WOLFSSL_MSG("RNG Init error");
+        return ret;
+    }
+
+    /* suites */
+    ssl->suites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap,
+                                   DYNAMIC_TYPE_SUITES);
+    if (ssl->suites == NULL) {
+        WOLFSSL_MSG("Suites Memory error");
+        return MEMORY_E;
+    }
+    if (ctx->suites)
+        *ssl->suites = *ctx->suites;
+    else
+        XMEMSET(ssl->suites, 0, sizeof(Suites));
+
+
+#ifndef NO_CERTS
+    /* make sure server has cert and key unless using PSK or Anon */
+    if (ssl->options.side == WOLFSSL_SERVER_END && !havePSK && !haveAnon)
+        if (!ssl->buffers.certificate.buffer || !ssl->buffers.key.buffer) {
+            WOLFSSL_MSG("Server missing certificate and/or private key");
+            return NO_PRIVATE_KEY;
+        }
+#endif
+#ifdef HAVE_SECRET_CALLBACK
+    ssl->sessionSecretCb  = NULL;
+    ssl->sessionSecretCtx = NULL;
+#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, haveRSA, havePSK,
+                   ssl->options.haveDH, ssl->options.haveNTRU,
+                   ssl->options.haveECDSAsig, ssl->options.haveStaticECC,
+                   ssl->options.side);
+    else
+        InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, TRUE,
+                   ssl->options.haveNTRU, ssl->options.haveECDSAsig,
+                   ssl->options.haveStaticECC, ssl->options.side);
+
+    return 0;
+}
+
+
+/* free use of temporary arrays */
+void FreeArrays(WOLFSSL* ssl, int keep)
+{
+    if (ssl->arrays && keep) {
+        /* keeps session id for user retrieval */
+        XMEMCPY(ssl->session.sessionID, ssl->arrays->sessionID, ID_LEN);
+        ssl->session.sessionIDSz = ssl->arrays->sessionIDSz;
+    }
+    XFREE(ssl->arrays, ssl->heap, DYNAMIC_TYPE_ARRAYS);
+    ssl->arrays = NULL;
+}
+
+
+/* In case holding SSL object in array and don't want to free actual ssl */
+void SSL_ResourceFree(WOLFSSL* ssl)
+{
+    /* Note: any resources used during the handshake should be released in the
+     * function FreeHandshakeResources(). Be careful with the special cases
+     * like the RNG which may optionally be kept for the whole session. (For
+     * example with the RNG, it isn't used beyond the handshake except when
+     * using stream ciphers where it is retained. */
+
+    FreeCiphers(ssl);
+    FreeArrays(ssl, 0);
+    wc_FreeRng(ssl->rng);
+    XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG);
+    XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES);
+    XFREE(ssl->hsHashes, ssl->heap, DYNAMIC_TYPE_HASHES);
+    XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN);
+
+#ifndef NO_DH
+    XFREE(ssl->buffers.serverDH_Priv.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+    XFREE(ssl->buffers.serverDH_Pub.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+    /* parameters (p,g) may be owned by ctx */
+    if (ssl->buffers.weOwnDH || ssl->options.side == WOLFSSL_CLIENT_END) {
+        XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+        XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+    }
+#endif
+#ifndef NO_CERTS
+    if (ssl->buffers.weOwnCert)
+        XFREE(ssl->buffers.certificate.buffer, ssl->heap, DYNAMIC_TYPE_CERT);
+    if (ssl->buffers.weOwnCertChain)
+        XFREE(ssl->buffers.certChain.buffer, ssl->heap, DYNAMIC_TYPE_CERT);
+    if (ssl->buffers.weOwnKey)
+        XFREE(ssl->buffers.key.buffer, ssl->heap, DYNAMIC_TYPE_KEY);
+#endif
+#ifndef NO_RSA
+    if (ssl->peerRsaKey) {
+        wc_FreeRsaKey(ssl->peerRsaKey);
+        XFREE(ssl->peerRsaKey, ssl->heap, DYNAMIC_TYPE_RSA);
+    }
+#endif
+    if (ssl->buffers.inputBuffer.dynamicFlag)
+        ShrinkInputBuffer(ssl, FORCED_FREE);
+    if (ssl->buffers.outputBuffer.dynamicFlag)
+        ShrinkOutputBuffer(ssl);
+#ifdef WOLFSSL_DTLS
+    if (ssl->dtls_pool != NULL) {
+        DtlsPoolReset(ssl);
+        XFREE(ssl->dtls_pool, ssl->heap, DYNAMIC_TYPE_NONE);
+    }
+    if (ssl->dtls_msg_list != NULL) {
+        DtlsMsgListDelete(ssl->dtls_msg_list, ssl->heap);
+        ssl->dtls_msg_list = NULL;
+    }
+    XFREE(ssl->buffers.dtlsCtx.peer.sa, ssl->heap, DYNAMIC_TYPE_SOCKADDR);
+    ssl->buffers.dtlsCtx.peer.sa = NULL;
+#endif
+#if defined(KEEP_PEER_CERT) || defined(GOAHEAD_WS)
+    FreeX509(&ssl->peerCert);
+#endif
+#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+    wolfSSL_BIO_free(ssl->biord);
+    if (ssl->biord != ssl->biowr)        /* in case same as write */
+        wolfSSL_BIO_free(ssl->biowr);
+#endif
+#ifdef HAVE_LIBZ
+    FreeStreams(ssl);
+#endif
+#ifdef HAVE_ECC
+    if (ssl->peerEccKey) {
+        if (ssl->peerEccKeyPresent)
+            wc_ecc_free(ssl->peerEccKey);
+        XFREE(ssl->peerEccKey, ssl->heap, DYNAMIC_TYPE_ECC);
+    }
+    if (ssl->peerEccDsaKey) {
+        if (ssl->peerEccDsaKeyPresent)
+            wc_ecc_free(ssl->peerEccDsaKey);
+        XFREE(ssl->peerEccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC);
+    }
+    if (ssl->eccTempKey) {
+        if (ssl->eccTempKeyPresent)
+            wc_ecc_free(ssl->eccTempKey);
+        XFREE(ssl->eccTempKey, ssl->heap, DYNAMIC_TYPE_ECC);
+    }
+#endif
+#ifdef HAVE_PK_CALLBACKS
+    #ifdef HAVE_ECC
+        XFREE(ssl->buffers.peerEccDsaKey.buffer, ssl->heap, DYNAMIC_TYPE_ECC);
+    #endif /* HAVE_ECC */
+    #ifndef NO_RSA
+        XFREE(ssl->buffers.peerRsaKey.buffer, ssl->heap, DYNAMIC_TYPE_RSA);
+    #endif /* NO_RSA */
+#endif /* HAVE_PK_CALLBACKS */
+#ifdef HAVE_TLS_EXTENSIONS
+    TLSX_FreeAll(ssl->extensions);
+#endif
+#ifdef HAVE_NETX
+    if (ssl->nxCtx.nxPacket)
+        nx_packet_release(ssl->nxCtx.nxPacket);
+#endif
+}
+
+#ifdef WOLFSSL_TI_HASH
+static void HashFinal(WOLFSSL * ssl) {
+    byte dummyHash[32] ;
+#ifndef NO_MD5
+    wc_Md5Final(&(ssl->hsHashes->hashMd5), dummyHash) ;
+#endif
+#ifndef NO_SHA
+    wc_ShaFinal(&(ssl->hsHashes->hashSha), dummyHash) ;
+#endif
+#ifndef NO_SHA256
+    wc_Sha256Final(&(ssl->hsHashes->hashSha256), dummyHash) ;
+#endif
+}
+#else
+
+    #define HashFinal(ssl)
+
+#endif
+
+/* Free any handshake resources no longer needed */
+void FreeHandshakeResources(WOLFSSL* ssl)
+{
+
+    HashFinal(ssl) ;
+#ifdef HAVE_SECURE_RENEGOTIATION
+    if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled) {
+        WOLFSSL_MSG("Secure Renegotiation needs to retain handshake resources");
+        return;
+    }
+#endif
+
+    /* input buffer */
+    if (ssl->buffers.inputBuffer.dynamicFlag)
+        ShrinkInputBuffer(ssl, NO_FORCED_FREE);
+
+    /* suites */
+    XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES);
+    ssl->suites = NULL;
+
+    /* hsHashes */
+    XFREE(ssl->hsHashes, ssl->heap, DYNAMIC_TYPE_HASHES);
+    ssl->hsHashes = NULL;
+
+    /* RNG */
+    if (ssl->specs.cipher_type == stream || ssl->options.tls1_1 == 0) {
+        wc_FreeRng(ssl->rng);
+        XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG);
+        ssl->rng = NULL;
+    }
+
+#ifdef WOLFSSL_DTLS
+    /* DTLS_POOL */
+    if (ssl->options.dtls && ssl->dtls_pool != NULL) {
+        DtlsPoolReset(ssl);
+        XFREE(ssl->dtls_pool, ssl->heap, DYNAMIC_TYPE_DTLS_POOL);
+        ssl->dtls_pool = NULL;
+    }
+#endif
+
+    /* arrays */
+    if (ssl->options.saveArrays == 0)
+        FreeArrays(ssl, 1);
+
+#ifndef NO_RSA
+    /* peerRsaKey */
+    if (ssl->peerRsaKey) {
+        wc_FreeRsaKey(ssl->peerRsaKey);
+        XFREE(ssl->peerRsaKey, ssl->heap, DYNAMIC_TYPE_RSA);
+        ssl->peerRsaKey = NULL;
+    }
+#endif
+
+#ifdef HAVE_ECC
+    if (ssl->peerEccKey)
+    {
+        if (ssl->peerEccKeyPresent) {
+            wc_ecc_free(ssl->peerEccKey);
+            ssl->peerEccKeyPresent = 0;
+        }
+        XFREE(ssl->peerEccKey, ssl->heap, DYNAMIC_TYPE_ECC);
+        ssl->peerEccKey = NULL;
+    }
+    if (ssl->peerEccDsaKey)
+    {
+        if (ssl->peerEccDsaKeyPresent) {
+            wc_ecc_free(ssl->peerEccDsaKey);
+            ssl->peerEccDsaKeyPresent = 0;
+        }
+        XFREE(ssl->peerEccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC);
+        ssl->peerEccDsaKey = NULL;
+    }
+    if (ssl->eccTempKey)
+    {
+        if (ssl->eccTempKeyPresent) {
+            wc_ecc_free(ssl->eccTempKey);
+            ssl->eccTempKeyPresent = 0;
+        }
+        XFREE(ssl->eccTempKey, ssl->heap, DYNAMIC_TYPE_ECC);
+        ssl->eccTempKey = NULL;
+    }
+#endif
+#ifndef NO_DH
+    XFREE(ssl->buffers.serverDH_Priv.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+    ssl->buffers.serverDH_Priv.buffer = NULL;
+    XFREE(ssl->buffers.serverDH_Pub.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+    ssl->buffers.serverDH_Pub.buffer = NULL;
+    /* parameters (p,g) may be owned by ctx */
+    if (ssl->buffers.weOwnDH || ssl->options.side == WOLFSSL_CLIENT_END) {
+        XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+        ssl->buffers.serverDH_G.buffer = NULL;
+        XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+        ssl->buffers.serverDH_P.buffer = NULL;
+    }
+#endif
+#ifndef NO_CERTS
+    if (ssl->buffers.weOwnCert) {
+        XFREE(ssl->buffers.certificate.buffer, ssl->heap, DYNAMIC_TYPE_CERT);
+        ssl->buffers.certificate.buffer = NULL;
+    }
+    if (ssl->buffers.weOwnCertChain) {
+        XFREE(ssl->buffers.certChain.buffer, ssl->heap, DYNAMIC_TYPE_CERT);
+        ssl->buffers.certChain.buffer = NULL;
+    }
+    if (ssl->buffers.weOwnKey) {
+        XFREE(ssl->buffers.key.buffer, ssl->heap, DYNAMIC_TYPE_KEY);
+        ssl->buffers.key.buffer = NULL;
+    }
+#endif
+#ifdef HAVE_PK_CALLBACKS
+    #ifdef HAVE_ECC
+        XFREE(ssl->buffers.peerEccDsaKey.buffer, ssl->heap, DYNAMIC_TYPE_ECC);
+        ssl->buffers.peerEccDsaKey.buffer = NULL;
+    #endif /* HAVE_ECC */
+    #ifndef NO_RSA
+        XFREE(ssl->buffers.peerRsaKey.buffer, ssl->heap, DYNAMIC_TYPE_RSA);
+        ssl->buffers.peerRsaKey.buffer = NULL;
+    #endif /* NO_RSA */
+#endif /* HAVE_PK_CALLBACKS */
+}
+
+
+void FreeSSL(WOLFSSL* ssl)
+{
+    FreeSSL_Ctx(ssl->ctx);  /* will decrement and free underyling CTX if 0 */
+    SSL_ResourceFree(ssl);
+    XFREE(ssl, ssl->heap, DYNAMIC_TYPE_SSL);
+}
+
+
+#ifdef WOLFSSL_DTLS
+
+int DtlsPoolInit(WOLFSSL* ssl)
+{
+    if (ssl->dtls_pool == NULL) {
+        DtlsPool *pool = (DtlsPool*)XMALLOC(sizeof(DtlsPool),
+                                             ssl->heap, DYNAMIC_TYPE_DTLS_POOL);
+        if (pool == NULL) {
+            WOLFSSL_MSG("DTLS Buffer Pool Memory error");
+            return MEMORY_E;
+        }
+        else {
+            int i;
+
+            for (i = 0; i < DTLS_POOL_SZ; i++) {
+                pool->buf[i].length = 0;
+                pool->buf[i].buffer = NULL;
+            }
+            pool->used = 0;
+            ssl->dtls_pool = pool;
+        }
+    }
+    return 0;
+}
+
+
+int DtlsPoolSave(WOLFSSL* ssl, const byte *src, int sz)
+{
+    DtlsPool *pool = ssl->dtls_pool;
+    if (pool != NULL && pool->used < DTLS_POOL_SZ) {
+        buffer *pBuf = &pool->buf[pool->used];
+        pBuf->buffer = (byte*)XMALLOC(sz, ssl->heap, DYNAMIC_TYPE_DTLS_POOL);
+        if (pBuf->buffer == NULL) {
+            WOLFSSL_MSG("DTLS Buffer Memory error");
+            return MEMORY_ERROR;
+        }
+        XMEMCPY(pBuf->buffer, src, sz);
+        pBuf->length = (word32)sz;
+        pool->used++;
+    }
+    return 0;
+}
+
+
+void DtlsPoolReset(WOLFSSL* ssl)
+{
+    DtlsPool *pool = ssl->dtls_pool;
+    if (pool != NULL) {
+        buffer *pBuf;
+        int i, used;
+
+        used = pool->used;
+        for (i = 0, pBuf = &pool->buf[0]; i < used; i++, pBuf++) {
+            XFREE(pBuf->buffer, ssl->heap, DYNAMIC_TYPE_DTLS_POOL);
+            pBuf->buffer = NULL;
+            pBuf->length = 0;
+        }
+        pool->used = 0;
+    }
+    ssl->dtls_timeout = ssl->dtls_timeout_init;
+}
+
+
+int DtlsPoolTimeout(WOLFSSL* ssl)
+{
+    int result = -1;
+    if (ssl->dtls_timeout <  ssl->dtls_timeout_max) {
+        ssl->dtls_timeout *= DTLS_TIMEOUT_MULTIPLIER;
+        result = 0;
+    }
+    return result;
+}
+
+
+int DtlsPoolSend(WOLFSSL* ssl)
+{
+    int ret;
+    DtlsPool *pool = ssl->dtls_pool;
+
+    if (pool != NULL && pool->used > 0) {
+        int i;
+        for (i = 0; i < pool->used; i++) {
+            int sendResult;
+            buffer* buf = &pool->buf[i];
+
+            DtlsRecordLayerHeader* dtls = (DtlsRecordLayerHeader*)buf->buffer;
+
+            word16 message_epoch;
+            ato16(dtls->epoch, &message_epoch);
+            if (message_epoch == ssl->keys.dtls_epoch) {
+                /* Increment record sequence number on retransmitted handshake
+                 * messages */
+                c32to48(ssl->keys.dtls_sequence_number, dtls->sequence_number);
+                ssl->keys.dtls_sequence_number++;
+            }
+            else {
+                /* The Finished message is sent with the next epoch, keep its
+                 * sequence number */
+            }
+
+            if ((ret = CheckAvailableSize(ssl, buf->length)) != 0)
+                return ret;
+
+            XMEMCPY(ssl->buffers.outputBuffer.buffer, buf->buffer, buf->length);
+            ssl->buffers.outputBuffer.idx = 0;
+            ssl->buffers.outputBuffer.length = buf->length;
+
+            sendResult = SendBuffered(ssl);
+            if (sendResult < 0) {
+                return sendResult;
+            }
+        }
+    }
+    return 0;
+}
+
+
+/* functions for managing DTLS datagram reordering */
+
+/* Need to allocate space for the handshake message header. The hashing
+ * routines assume the message pointer is still within the buffer that
+ * has the headers, and will include those headers in the hash. The store
+ * routines need to take that into account as well. New will allocate
+ * extra space for the headers. */
+DtlsMsg* DtlsMsgNew(word32 sz, void* heap)
+{
+    DtlsMsg* msg = NULL;
+
+    msg = (DtlsMsg*)XMALLOC(sizeof(DtlsMsg), heap, DYNAMIC_TYPE_DTLS_MSG);
+
+    if (msg != NULL) {
+        msg->buf = (byte*)XMALLOC(sz + DTLS_HANDSHAKE_HEADER_SZ,
+                                                     heap, DYNAMIC_TYPE_NONE);
+        if (msg->buf != NULL) {
+            msg->next = NULL;
+            msg->seq = 0;
+            msg->sz = sz;
+            msg->fragSz = 0;
+            msg->msg = msg->buf + DTLS_HANDSHAKE_HEADER_SZ;
+        }
+        else {
+            XFREE(msg, heap, DYNAMIC_TYPE_DTLS_MSG);
+            msg = NULL;
+        }
+    }
+
+    return msg;
+}
+
+void DtlsMsgDelete(DtlsMsg* item, void* heap)
+{
+    (void)heap;
+
+    if (item != NULL) {
+        if (item->buf != NULL)
+            XFREE(item->buf, heap, DYNAMIC_TYPE_NONE);
+        XFREE(item, heap, DYNAMIC_TYPE_DTLS_MSG);
+    }
+}
+
+
+void DtlsMsgListDelete(DtlsMsg* head, void* heap)
+{
+    DtlsMsg* next;
+    while (head) {
+        next = head->next;
+        DtlsMsgDelete(head, heap);
+        head = next;
+    }
+}
+
+
+void DtlsMsgSet(DtlsMsg* msg, word32 seq, const byte* data, byte type,
+                                              word32 fragOffset, word32 fragSz)
+{
+    if (msg != NULL && data != NULL && msg->fragSz <= msg->sz &&
+                    fragOffset <= msg->sz && (fragOffset + fragSz) <= msg->sz) {
+
+        msg->seq = seq;
+        msg->type = type;
+        msg->fragSz += fragSz;
+        /* If fragOffset is zero, this is either a full message that is out
+         * of order, or the first fragment of a fragmented message. Copy the
+         * handshake message header with the message data. Zero length messages
+         * like Server Hello Done should be saved as well. */
+        if (fragOffset == 0)
+            XMEMCPY(msg->buf, data - DTLS_HANDSHAKE_HEADER_SZ,
+                                            fragSz + DTLS_HANDSHAKE_HEADER_SZ);
+        else {
+            /* If fragOffet is non-zero, this is an additional fragment that
+             * needs to be copied to its location in the message buffer. Also
+             * copy the total size of the message over the fragment size. The
+             * hash routines look at a defragmented message if it had actually
+             * come across as a single handshake message. */
+            XMEMCPY(msg->msg + fragOffset, data, fragSz);
+        }
+        c32to24(msg->sz, msg->msg - DTLS_HANDSHAKE_FRAG_SZ);
+    }
+}
+
+
+DtlsMsg* DtlsMsgFind(DtlsMsg* head, word32 seq)
+{
+    while (head != NULL && head->seq != seq) {
+        head = head->next;
+    }
+    return head;
+}
+
+
+DtlsMsg* DtlsMsgStore(DtlsMsg* head, word32 seq, const byte* data,
+        word32 dataSz, byte type, word32 fragOffset, word32 fragSz, void* heap)
+{
+
+    /* See if seq exists in the list. If it isn't in the list, make
+     * a new item of size dataSz, copy fragSz bytes from data to msg->msg
+     * starting at offset fragOffset, and add fragSz to msg->fragSz. If
+     * the seq is in the list and it isn't full, copy fragSz bytes from
+     * data to msg->msg starting at offset fragOffset, and add fragSz to
+     * msg->fragSz. The new item should be inserted into the list in its
+     * proper position.
+     *
+     * 1. Find seq in list, or where seq should go in list. If seq not in
+     *    list, create new item and insert into list. Either case, keep
+     *    pointer to item.
+     * 2. If msg->fragSz + fragSz < sz, copy data to msg->msg at offset
+     *    fragOffset. Add fragSz to msg->fragSz.
+     */
+
+    if (head != NULL) {
+        DtlsMsg* cur = DtlsMsgFind(head, seq);
+        if (cur == NULL) {
+            cur = DtlsMsgNew(dataSz, heap);
+            if (cur != NULL) {
+                DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz);
+                head = DtlsMsgInsert(head, cur);
+            }
+        }
+        else {
+            DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz);
+        }
+    }
+    else {
+        head = DtlsMsgNew(dataSz, heap);
+        DtlsMsgSet(head, seq, data, type, fragOffset, fragSz);
+    }
+
+    return head;
+}
+
+
+/* DtlsMsgInsert() is an in-order insert. */
+DtlsMsg* DtlsMsgInsert(DtlsMsg* head, DtlsMsg* item)
+{
+    if (head == NULL || item->seq < head->seq) {
+        item->next = head;
+        head = item;
+    }
+    else if (head->next == NULL) {
+        head->next = item;
+    }
+    else {
+        DtlsMsg* cur = head->next;
+        DtlsMsg* prev = head;
+        while (cur) {
+            if (item->seq < cur->seq) {
+                item->next = cur;
+                prev->next = item;
+                break;
+            }
+            prev = cur;
+            cur = cur->next;
+        }
+        if (cur == NULL) {
+            prev->next = item;
+        }
+    }
+
+    return head;
+}
+
+#endif /* WOLFSSL_DTLS */
+
+#ifndef NO_OLD_TLS
+
+ProtocolVersion MakeSSLv3(void)
+{
+    ProtocolVersion pv;
+    pv.major = SSLv3_MAJOR;
+    pv.minor = SSLv3_MINOR;
+
+    return pv;
+}
+
+#endif /* NO_OLD_TLS */
+
+
+#ifdef WOLFSSL_DTLS
+
+ProtocolVersion MakeDTLSv1(void)
+{
+    ProtocolVersion pv;
+    pv.major = DTLS_MAJOR;
+    pv.minor = DTLS_MINOR;
+
+    return pv;
+}
+
+ProtocolVersion MakeDTLSv1_2(void)
+{
+    ProtocolVersion pv;
+    pv.major = DTLS_MAJOR;
+    pv.minor = DTLSv1_2_MINOR;
+
+    return pv;
+}
+
+#endif /* WOLFSSL_DTLS */
+
+
+
+
+#ifdef USE_WINDOWS_API
+
+    word32 LowResTimer(void)
+    {
+        static int           init = 0;
+        static LARGE_INTEGER freq;
+        LARGE_INTEGER        count;
+
+        if (!init) {
+            QueryPerformanceFrequency(&freq);
+            init = 1;
+        }
+
+        QueryPerformanceCounter(&count);
+
+        return (word32)(count.QuadPart / freq.QuadPart);
+    }
+
+#elif defined(HAVE_RTP_SYS)
+
+    #include "rtptime.h"
+
+    word32 LowResTimer(void)
+    {
+        return (word32)rtp_get_system_sec();
+    }
+
+
+#elif defined(MICRIUM)
+
+    word32 LowResTimer(void)
+    {
+        NET_SECURE_OS_TICK  clk;
+
+        #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+            clk = NetSecure_OS_TimeGet();
+        #endif
+        return (word32)clk;
+    }
+
+
+#elif defined(MICROCHIP_TCPIP_V5)
+
+    word32 LowResTimer(void)
+    {
+        return (word32) TickGet();
+    }
+
+
+#elif defined(MICROCHIP_TCPIP)
+
+    #if defined(MICROCHIP_MPLAB_HARMONY)
+
+        #include <system/tmr/sys_tmr.h>
+
+        word32 LowResTimer(void)
+        {
+            return (word32) SYS_TMR_TickCountGet();
+        }
+
+    #else
+
+        word32 LowResTimer(void)
+        {
+            return (word32) SYS_TICK_Get();
+        }
+
+    #endif
+
+#elif defined(FREESCALE_MQX)
+
+    word32 LowResTimer(void)
+    {
+        TIME_STRUCT mqxTime;
+
+        _time_get_elapsed(&mqxTime);
+
+        return (word32) mqxTime.SECONDS;
+    }
+
+#elif defined(WOLFSSL_TIRTOS)
+
+    word32 LowResTimer(void)
+    {
+        return (word32) Seconds_get();
+    }
+
+#elif defined(USER_TICKS)
+#if 0
+    word32 LowResTimer(void)
+    {
+        /*
+        write your own clock tick function if don't want time(0)
+        needs second accuracy but doesn't have to correlated to EPOCH
+        */
+    }
+#endif
+
+#elif defined(TIME_OVERRIDES)
+
+    /* use same asn time overrides unless user wants tick override above */
+
+    #ifndef HAVE_TIME_T_TYPE
+        typedef long time_t;
+    #endif
+    extern time_t XTIME(time_t * timer);
+
+    word32 LowResTimer(void)
+    {
+        return (word32) XTIME(0);
+    }
+
+#else /* !USE_WINDOWS_API && !HAVE_RTP_SYS && !MICRIUM && !USER_TICKS */
+
+    #include <time.h>
+
+    word32 LowResTimer(void)
+    {
+        return (word32)time(0);
+    }
+
+
+#endif /* USE_WINDOWS_API */
+
+
+/* add output to md5 and sha handshake hashes, exclude record header */
+static int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz)
+{
+    const byte* adj = output + RECORD_HEADER_SZ + ivSz;
+    sz -= RECORD_HEADER_SZ;
+
+#ifdef HAVE_FUZZER
+    if (ssl->fuzzerCb)
+        ssl->fuzzerCb(ssl, output, sz, FUZZ_HASH, ssl->fuzzerCtx);
+#endif
+#ifdef WOLFSSL_DTLS
+    if (ssl->options.dtls) {
+        adj += DTLS_RECORD_EXTRA;
+        sz  -= DTLS_RECORD_EXTRA;
+    }
+#endif
+#ifndef NO_OLD_TLS
+#ifndef NO_SHA
+    wc_ShaUpdate(&ssl->hsHashes->hashSha, adj, sz);
+#endif
+#ifndef NO_MD5
+    wc_Md5Update(&ssl->hsHashes->hashMd5, adj, sz);
+#endif
+#endif
+
+    if (IsAtLeastTLSv1_2(ssl)) {
+        int ret;
+
+#ifndef NO_SHA256
+        ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, adj, sz);
+        if (ret != 0)
+            return ret;
+#endif
+#ifdef WOLFSSL_SHA384
+        ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, adj, sz);
+        if (ret != 0)
+            return ret;
+#endif
+#ifdef WOLFSSL_SHA512
+        ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, adj, sz);
+        if (ret != 0)
+            return ret;
+#endif
+    }
+
+    return 0;
+}
+
+
+/* add input to md5 and sha handshake hashes, include handshake header */
+static int HashInput(WOLFSSL* ssl, const byte* input, int sz)
+{
+    const byte* adj = input - HANDSHAKE_HEADER_SZ;
+    sz += HANDSHAKE_HEADER_SZ;
+
+#ifdef WOLFSSL_DTLS
+    if (ssl->options.dtls) {
+        adj -= DTLS_HANDSHAKE_EXTRA;
+        sz  += DTLS_HANDSHAKE_EXTRA;
+    }
+#endif
+
+#ifndef NO_OLD_TLS
+#ifndef NO_SHA
+    wc_ShaUpdate(&ssl->hsHashes->hashSha, adj, sz);
+#endif
+#ifndef NO_MD5
+    wc_Md5Update(&ssl->hsHashes->hashMd5, adj, sz);
+#endif
+#endif
+
+    if (IsAtLeastTLSv1_2(ssl)) {
+        int ret;
+
+#ifndef NO_SHA256
+        ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, adj, sz);
+        if (ret != 0)
+            return ret;
+#endif
+#ifdef WOLFSSL_SHA384
+        ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, adj, sz);
+        if (ret != 0)
+            return ret;
+#endif
+#ifdef WOLFSSL_SHA512
+        ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, adj, sz);
+        if (ret != 0)
+            return ret;
+#endif
+    }
+
+    return 0;
+}
+
+
+/* add record layer header for message */
+static void AddRecordHeader(byte* output, word32 length, byte type, WOLFSSL* ssl)
+{
+    RecordLayerHeader* rl;
+
+    /* record layer header */
+    rl = (RecordLayerHeader*)output;
+    rl->type    = type;
+    rl->pvMajor = ssl->version.major;       /* type and version same in each */
+    rl->pvMinor = ssl->version.minor;
+
+    if (!ssl->options.dtls)
+        c16toa((word16)length, rl->length);
+    else {
+#ifdef WOLFSSL_DTLS
+        DtlsRecordLayerHeader* dtls;
+
+        /* dtls record layer header extensions */
+        dtls = (DtlsRecordLayerHeader*)output;
+        c16toa(ssl->keys.dtls_epoch, dtls->epoch);
+        c32to48(ssl->keys.dtls_sequence_number++, dtls->sequence_number);
+        c16toa((word16)length, dtls->length);
+#endif
+    }
+}
+
+
+/* add handshake header for message */
+static void AddHandShakeHeader(byte* output, word32 length, byte type,
+                               WOLFSSL* ssl)
+{
+    HandShakeHeader* hs;
+    (void)ssl;
+
+    /* handshake header */
+    hs = (HandShakeHeader*)output;
+    hs->type = type;
+    c32to24(length, hs->length);         /* type and length same for each */
+#ifdef WOLFSSL_DTLS
+    if (ssl->options.dtls) {
+        DtlsHandShakeHeader* dtls;
+
+        /* dtls handshake header extensions */
+        dtls = (DtlsHandShakeHeader*)output;
+        c16toa(ssl->keys.dtls_handshake_number++, dtls->message_seq);
+        c32to24(0, dtls->fragment_offset);
+        c32to24(length, dtls->fragment_length);
+    }
+#endif
+}
+
+
+/* add both headers for handshake message */
+static void AddHeaders(byte* output, word32 length, byte type, WOLFSSL* ssl)
+{
+    if (!ssl->options.dtls) {
+        AddRecordHeader(output, length + HANDSHAKE_HEADER_SZ, handshake, ssl);
+        AddHandShakeHeader(output + RECORD_HEADER_SZ, length, type, ssl);
+    }
+#ifdef WOLFSSL_DTLS
+    else  {
+        AddRecordHeader(output, length+DTLS_HANDSHAKE_HEADER_SZ, handshake,ssl);
+        AddHandShakeHeader(output + DTLS_RECORD_HEADER_SZ, length, type, ssl);
+    }
+#endif
+}
+
+
+/* return bytes received, -1 on error */
+static int Receive(WOLFSSL* ssl, byte* buf, word32 sz)
+{
+    int recvd;
+
+    if (ssl->ctx->CBIORecv == NULL) {
+        WOLFSSL_MSG("Your IO Recv callback is null, please set");
+        return -1;
+    }
+
+retry:
+    recvd = ssl->ctx->CBIORecv(ssl, (char *)buf, (int)sz, ssl->IOCB_ReadCtx);
+    if (recvd < 0)
+        switch (recvd) {
+            case WOLFSSL_CBIO_ERR_GENERAL:        /* general/unknown error */
+                return -1;
+
+            case WOLFSSL_CBIO_ERR_WANT_READ:      /* want read, would block */
+                return WANT_READ;
+
+            case WOLFSSL_CBIO_ERR_CONN_RST:       /* connection reset */
+                #ifdef USE_WINDOWS_API
+                if (ssl->options.dtls) {
+                    goto retry;
+                }
+                #endif
+                ssl->options.connReset = 1;
+                return -1;
+
+            case WOLFSSL_CBIO_ERR_ISR:            /* interrupt */
+                /* see if we got our timeout */
+                #ifdef WOLFSSL_CALLBACKS
+                    if (ssl->toInfoOn) {
+                        struct itimerval timeout;
+                        getitimer(ITIMER_REAL, &timeout);
+                        if (timeout.it_value.tv_sec == 0 &&
+                                                timeout.it_value.tv_usec == 0) {
+                            XSTRNCPY(ssl->timeoutInfo.timeoutName,
+                                    "recv() timeout", MAX_TIMEOUT_NAME_SZ);
+                            WOLFSSL_MSG("Got our timeout");
+                            return WANT_READ;
+                        }
+                    }
+                #endif
+                goto retry;
+
+            case WOLFSSL_CBIO_ERR_CONN_CLOSE:     /* peer closed connection */
+                ssl->options.isClosed = 1;
+                return -1;
+
+            case WOLFSSL_CBIO_ERR_TIMEOUT:
+#ifdef WOLFSSL_DTLS
+                if (DtlsPoolTimeout(ssl) == 0 && DtlsPoolSend(ssl) == 0)
+                    goto retry;
+                else
+#endif
+                    return -1;
+
+            default:
+                return recvd;
+        }
+
+    return recvd;
+}
+
+
+/* Switch dynamic output buffer back to static, buffer is assumed clear */
+void ShrinkOutputBuffer(WOLFSSL* ssl)
+{
+    WOLFSSL_MSG("Shrinking output buffer\n");
+    XFREE(ssl->buffers.outputBuffer.buffer - ssl->buffers.outputBuffer.offset,
+          ssl->heap, DYNAMIC_TYPE_OUT_BUFFER);
+    ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer;
+    ssl->buffers.outputBuffer.bufferSize  = STATIC_BUFFER_LEN;
+    ssl->buffers.outputBuffer.dynamicFlag = 0;
+    ssl->buffers.outputBuffer.offset      = 0;
+}
+
+
+/* Switch dynamic input buffer back to static, keep any remaining input */
+/* forced free means cleaning up */
+void ShrinkInputBuffer(WOLFSSL* ssl, int forcedFree)
+{
+    int usedLength = ssl->buffers.inputBuffer.length -
+                     ssl->buffers.inputBuffer.idx;
+    if (!forcedFree && usedLength > STATIC_BUFFER_LEN)
+        return;
+
+    WOLFSSL_MSG("Shrinking input buffer\n");
+
+    if (!forcedFree && usedLength)
+        XMEMCPY(ssl->buffers.inputBuffer.staticBuffer,
+               ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx,
+               usedLength);
+
+    XFREE(ssl->buffers.inputBuffer.buffer - ssl->buffers.inputBuffer.offset,
+          ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+    ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer;
+    ssl->buffers.inputBuffer.bufferSize  = STATIC_BUFFER_LEN;
+    ssl->buffers.inputBuffer.dynamicFlag = 0;
+    ssl->buffers.inputBuffer.offset      = 0;
+    ssl->buffers.inputBuffer.idx = 0;
+    ssl->buffers.inputBuffer.length = usedLength;
+}
+
+int SendBuffered(WOLFSSL* ssl)
+{
+    if (ssl->ctx->CBIOSend == NULL) {
+        WOLFSSL_MSG("Your IO Send callback is null, please set");
+        return SOCKET_ERROR_E;
+    }
+
+    while (ssl->buffers.outputBuffer.length > 0) {
+        int sent = ssl->ctx->CBIOSend(ssl,
+                                      (char*)ssl->buffers.outputBuffer.buffer +
+                                      ssl->buffers.outputBuffer.idx,
+                                      (int)ssl->buffers.outputBuffer.length,
+                                      ssl->IOCB_WriteCtx);
+        if (sent < 0) {
+            switch (sent) {
+
+                case WOLFSSL_CBIO_ERR_WANT_WRITE:        /* would block */
+                    return WANT_WRITE;
+
+                case WOLFSSL_CBIO_ERR_CONN_RST:          /* connection reset */
+                    ssl->options.connReset = 1;
+                    break;
+
+                case WOLFSSL_CBIO_ERR_ISR:               /* interrupt */
+                    /* see if we got our timeout */
+                    #ifdef WOLFSSL_CALLBACKS
+                        if (ssl->toInfoOn) {
+                            struct itimerval timeout;
+                            getitimer(ITIMER_REAL, &timeout);
+                            if (timeout.it_value.tv_sec == 0 &&
+                                                timeout.it_value.tv_usec == 0) {
+                                XSTRNCPY(ssl->timeoutInfo.timeoutName,
+                                        "send() timeout", MAX_TIMEOUT_NAME_SZ);
+                                WOLFSSL_MSG("Got our timeout");
+                                return WANT_WRITE;
+                            }
+                        }
+                    #endif
+                    continue;
+
+                case WOLFSSL_CBIO_ERR_CONN_CLOSE: /* epipe / conn closed */
+                    ssl->options.connReset = 1;  /* treat same as reset */
+                    break;
+
+                default:
+                    return SOCKET_ERROR_E;
+            }
+
+            return SOCKET_ERROR_E;
+        }
+
+        if (sent > (int)ssl->buffers.outputBuffer.length) {
+            WOLFSSL_MSG("SendBuffered() out of bounds read");
+            return SEND_OOB_READ_E;
+        }
+
+        ssl->buffers.outputBuffer.idx += sent;
+        ssl->buffers.outputBuffer.length -= sent;
+    }
+
+    ssl->buffers.outputBuffer.idx = 0;
+
+    if (ssl->buffers.outputBuffer.dynamicFlag)
+        ShrinkOutputBuffer(ssl);
+
+    return 0;
+}
+
+
+/* Grow the output buffer */
+static INLINE int GrowOutputBuffer(WOLFSSL* ssl, int size)
+{
+    byte* tmp;
+    byte  hdrSz = ssl->options.dtls ? DTLS_RECORD_HEADER_SZ :
+                                      RECORD_HEADER_SZ;
+    byte  align = WOLFSSL_GENERAL_ALIGNMENT;
+    /* the encrypted data will be offset from the front of the buffer by
+       the header, if the user wants encrypted alignment they need
+       to define their alignment requirement */
+
+    if (align) {
+       while (align < hdrSz)
+           align *= 2;
+    }
+
+    tmp = (byte*) XMALLOC(size + ssl->buffers.outputBuffer.length + align,
+                          ssl->heap, DYNAMIC_TYPE_OUT_BUFFER);
+    WOLFSSL_MSG("growing output buffer\n");
+
+    if (!tmp) return MEMORY_E;
+    if (align)
+        tmp += align - hdrSz;
+
+    if (ssl->buffers.outputBuffer.length)
+        XMEMCPY(tmp, ssl->buffers.outputBuffer.buffer,
+               ssl->buffers.outputBuffer.length);
+
+    if (ssl->buffers.outputBuffer.dynamicFlag)
+        XFREE(ssl->buffers.outputBuffer.buffer -
+              ssl->buffers.outputBuffer.offset, ssl->heap,
+              DYNAMIC_TYPE_OUT_BUFFER);
+    ssl->buffers.outputBuffer.dynamicFlag = 1;
+    if (align)
+        ssl->buffers.outputBuffer.offset = align - hdrSz;
+    else
+        ssl->buffers.outputBuffer.offset = 0;
+    ssl->buffers.outputBuffer.buffer = tmp;
+    ssl->buffers.outputBuffer.bufferSize = size +
+                                           ssl->buffers.outputBuffer.length;
+    return 0;
+}
+
+
+/* Grow the input buffer, should only be to read cert or big app data */
+int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength)
+{
+    byte* tmp;
+    byte  hdrSz = DTLS_RECORD_HEADER_SZ;
+    byte  align = ssl->options.dtls ? WOLFSSL_GENERAL_ALIGNMENT : 0;
+    /* the encrypted data will be offset from the front of the buffer by
+       the dtls record header, if the user wants encrypted alignment they need
+       to define their alignment requirement. in tls we read record header
+       to get size of record and put actual data back at front, so don't need */
+
+    if (align) {
+       while (align < hdrSz)
+           align *= 2;
+    }
+    tmp = (byte*) XMALLOC(size + usedLength + align, ssl->heap,
+                          DYNAMIC_TYPE_IN_BUFFER);
+    WOLFSSL_MSG("growing input buffer\n");
+
+    if (!tmp) return MEMORY_E;
+    if (align)
+        tmp += align - hdrSz;
+
+    if (usedLength)
+        XMEMCPY(tmp, ssl->buffers.inputBuffer.buffer +
+                    ssl->buffers.inputBuffer.idx, usedLength);
+
+    if (ssl->buffers.inputBuffer.dynamicFlag)
+        XFREE(ssl->buffers.inputBuffer.buffer - ssl->buffers.inputBuffer.offset,
+              ssl->heap,DYNAMIC_TYPE_IN_BUFFER);
+
+    ssl->buffers.inputBuffer.dynamicFlag = 1;
+    if (align)
+        ssl->buffers.inputBuffer.offset = align - hdrSz;
+    else
+        ssl->buffers.inputBuffer.offset = 0;
+    ssl->buffers.inputBuffer.buffer = tmp;
+    ssl->buffers.inputBuffer.bufferSize = size + usedLength;
+    ssl->buffers.inputBuffer.idx    = 0;
+    ssl->buffers.inputBuffer.length = usedLength;
+
+    return 0;
+}
+
+
+/* check available size into output buffer, make room if needed */
+int CheckAvailableSize(WOLFSSL *ssl, int size)
+{
+
+    if (size < 0) {
+        WOLFSSL_MSG("CheckAvailableSize() called with negative number");
+        return BAD_FUNC_ARG;
+    }
+
+    if (ssl->buffers.outputBuffer.bufferSize - ssl->buffers.outputBuffer.length
+                                             < (word32)size) {
+        if (GrowOutputBuffer(ssl, size) < 0)
+            return MEMORY_E;
+    }
+
+    return 0;
+}
+
+
+/* do all verify and sanity checks on record header */
+static int GetRecordHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
+                           RecordLayerHeader* rh, word16 *size)
+{
+    if (!ssl->options.dtls) {
+#ifdef HAVE_FUZZER
+        if (ssl->fuzzerCb)
+            ssl->fuzzerCb(ssl, input + *inOutIdx, RECORD_HEADER_SZ, FUZZ_HEAD,
+                    ssl->fuzzerCtx);
+#endif
+        XMEMCPY(rh, input + *inOutIdx, RECORD_HEADER_SZ);
+        *inOutIdx += RECORD_HEADER_SZ;
+        ato16(rh->length, size);
+    }
+    else {
+#ifdef WOLFSSL_DTLS
+        /* type and version in same sport */
+        XMEMCPY(rh, input + *inOutIdx, ENUM_LEN + VERSION_SZ);
+        *inOutIdx += ENUM_LEN + VERSION_SZ;
+        ato16(input + *inOutIdx, &ssl->keys.dtls_state.curEpoch);
+        *inOutIdx += 4; /* advance past epoch, skip first 2 seq bytes for now */
+        ato32(input + *inOutIdx, &ssl->keys.dtls_state.curSeq);
+        *inOutIdx += 4;  /* advance past rest of seq */
+        ato16(input + *inOutIdx, size);
+        *inOutIdx += LENGTH_SZ;
+#ifdef HAVE_FUZZER
+        if (ssl->fuzzerCb)
+            ssl->fuzzerCb(ssl, input + *inOutIdx - LENGTH_SZ - 8 - ENUM_LEN -
+                           VERSION_SZ, ENUM_LEN + VERSION_SZ + 8 + LENGTH_SZ,
+                           FUZZ_HEAD, ssl->fuzzerCtx);
+#endif
+#endif
+    }
+
+    /* catch version mismatch */
+    if (rh->pvMajor != ssl->version.major || rh->pvMinor != ssl->version.minor){
+        if (ssl->options.side == WOLFSSL_SERVER_END &&
+            ssl->options.acceptState == ACCEPT_BEGIN)
+            WOLFSSL_MSG("Client attempting to connect with different version");
+        else if (ssl->options.side == WOLFSSL_CLIENT_END &&
+                                 ssl->options.downgrade &&
+                                 ssl->options.connectState < FIRST_REPLY_DONE)
+            WOLFSSL_MSG("Server attempting to accept with different version");
+        else {
+            WOLFSSL_MSG("SSL version error");
+            return VERSION_ERROR;              /* only use requested version */
+        }
+    }
+
+#ifdef WOLFSSL_DTLS
+    if (ssl->options.dtls) {
+        if (DtlsCheckWindow(&ssl->keys.dtls_state) != 1)
+            return SEQUENCE_ERROR;
+    }
+#endif
+
+    /* record layer length check */
+#ifdef HAVE_MAX_FRAGMENT
+    if (*size > (ssl->max_fragment + MAX_COMP_EXTRA + MAX_MSG_EXTRA)) {
+        SendAlert(ssl, alert_fatal, record_overflow);
+        return LENGTH_ERROR;
+    }
+#else
+    if (*size > (MAX_RECORD_SIZE + MAX_COMP_EXTRA + MAX_MSG_EXTRA))
+        return LENGTH_ERROR;
+#endif
+
+    /* verify record type here as well */
+    switch (rh->type) {
+        case handshake:
+        case change_cipher_spec:
+        case application_data:
+        case alert:
+            break;
+        case no_type:
+        default:
+            WOLFSSL_MSG("Unknown Record Type");
+            return UNKNOWN_RECORD_TYPE;
+    }
+
+    /* haven't decrypted this record yet */
+    ssl->keys.decryptedCur = 0;
+
+    return 0;
+}
+
+
+static int GetHandShakeHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
+                              byte *type, word32 *size, word32 totalSz)
+{
+    const byte *ptr = input + *inOutIdx;
+    (void)ssl;
+
+    *inOutIdx += HANDSHAKE_HEADER_SZ;
+    if (*inOutIdx > totalSz)
+        return BUFFER_E;
+
+    *type = ptr[0];
+    c24to32(&ptr[1], size);
+
+    return 0;
+}
+
+
+#ifdef WOLFSSL_DTLS
+static int GetDtlsHandShakeHeader(WOLFSSL* ssl, const byte* input,
+                                  word32* inOutIdx, byte *type, word32 *size,
+                                  word32 *fragOffset, word32 *fragSz,
+                                  word32 totalSz)
+{
+    word32 idx = *inOutIdx;
+
+    *inOutIdx += HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA;
+    if (*inOutIdx > totalSz)
+        return BUFFER_E;
+
+    *type = input[idx++];
+    c24to32(input + idx, size);
+    idx += BYTE3_LEN;
+
+    ato16(input + idx, &ssl->keys.dtls_peer_handshake_number);
+    idx += DTLS_HANDSHAKE_SEQ_SZ;
+
+    c24to32(input + idx, fragOffset);
+    idx += DTLS_HANDSHAKE_FRAG_SZ;
+    c24to32(input + idx, fragSz);
+
+    return 0;
+}
+#endif
+
+
+#ifndef NO_OLD_TLS
+/* fill with MD5 pad size since biggest required */
+static const byte PAD1[PAD_MD5] =
+                              { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
+                              };
+static const byte PAD2[PAD_MD5] =
+                              { 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c
+                              };
+
+/* calculate MD5 hash for finished */
+#ifdef WOLFSSL_TI_HASH
+#include <wolfssl/wolfcrypt/hash.h>
+#endif
+
+static void BuildMD5(WOLFSSL* ssl, Hashes* hashes, const byte* sender)
+{
+
+    byte md5_result[MD5_DIGEST_SIZE];
+
+#ifdef WOLFSSL_SMALL_STACK
+        Md5* md5   = (Md5*)XMALLOC(sizeof(Md5), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        Md5* md5_2 = (Md5*)XMALLOC(sizeof(Md5), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#else
+        Md5 md5[1];
+        Md5 md5_2[1];
+#endif
+
+    /* make md5 inner */
+    md5[0] = ssl->hsHashes->hashMd5 ; /* Save current position */
+
+    wc_Md5Update(&ssl->hsHashes->hashMd5, sender, SIZEOF_SENDER);
+    wc_Md5Update(&ssl->hsHashes->hashMd5, ssl->arrays->masterSecret,SECRET_LEN);
+    wc_Md5Update(&ssl->hsHashes->hashMd5, PAD1, PAD_MD5);
+    wc_Md5GetHash(&ssl->hsHashes->hashMd5, md5_result);
+    wc_Md5RestorePos(&ssl->hsHashes->hashMd5, md5) ; /* Restore current position */
+
+    /* make md5 outer */
+    wc_InitMd5(md5_2) ;
+    wc_Md5Update(md5_2, ssl->arrays->masterSecret,SECRET_LEN);
+    wc_Md5Update(md5_2, PAD2, PAD_MD5);
+    wc_Md5Update(md5_2, md5_result, MD5_DIGEST_SIZE);
+    wc_Md5Final(md5_2, hashes->md5);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(md5_2, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+}
+
+
+/* calculate SHA hash for finished */
+static void BuildSHA(WOLFSSL* ssl, Hashes* hashes, const byte* sender)
+{
+    byte sha_result[SHA_DIGEST_SIZE];
+
+#ifdef WOLFSSL_SMALL_STACK
+        Sha* sha = (Sha*)XMALLOC(sizeof(Sha), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        Sha* sha2 = (Sha*)XMALLOC(sizeof(Sha), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#else
+        Sha sha[1];
+        Sha sha2[1] ;
+#endif
+    /* make sha inner */
+    sha[0] = ssl->hsHashes->hashSha ; /* Save current position */
+
+    wc_ShaUpdate(&ssl->hsHashes->hashSha, sender, SIZEOF_SENDER);
+    wc_ShaUpdate(&ssl->hsHashes->hashSha, ssl->arrays->masterSecret,SECRET_LEN);
+    wc_ShaUpdate(&ssl->hsHashes->hashSha, PAD1, PAD_SHA);
+    wc_ShaGetHash(&ssl->hsHashes->hashSha, sha_result);
+    wc_ShaRestorePos(&ssl->hsHashes->hashSha, sha) ; /* Restore current position */
+
+    /* make sha outer */
+    wc_InitSha(sha2) ;
+    wc_ShaUpdate(sha2, ssl->arrays->masterSecret,SECRET_LEN);
+    wc_ShaUpdate(sha2, PAD2, PAD_SHA);
+    wc_ShaUpdate(sha2, sha_result, SHA_DIGEST_SIZE);
+    wc_ShaFinal(sha2, hashes->sha);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(sha2, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+}
+#endif
+
+/* 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_SMALL_STACK
+    #ifdef WOLFSSL_SHA384
+        Sha384* sha384 = (Sha384*)XMALLOC(sizeof(Sha384), NULL,                                                                        DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+#else
+    #ifdef WOLFSSL_SHA384
+        Sha384 sha384[1];
+    #endif
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    if (ssl == NULL
+    #ifdef WOLFSSL_SHA384
+        || sha384 == NULL
+    #endif
+        ) {
+    #ifdef WOLFSSL_SHA384
+        XFREE(sha384, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+        return MEMORY_E;
+    }
+#endif
+
+    /* store current states, building requires get_digest which resets state */
+#ifdef WOLFSSL_SHA384
+    sha384[0] = ssl->hsHashes->hashSha384;
+#endif
+
+#ifndef NO_TLS
+    if (ssl->options.tls) {
+        ret = BuildTlsFinished(ssl, hashes, sender);
+    }
+#endif
+#ifndef NO_OLD_TLS
+    if (!ssl->options.tls) {
+        BuildMD5(ssl, hashes, sender);
+        BuildSHA(ssl, hashes, sender);
+    }
+#endif
+
+    /* restore */
+    if (IsAtLeastTLSv1_2(ssl)) {
+    #ifdef WOLFSSL_SHA384
+        ssl->hsHashes->hashSha384 = sha384[0];
+    #endif
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+#ifdef WOLFSSL_SHA384
+    XFREE(sha384, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+#endif
+
+    return ret;
+}
+
+
+    /* cipher requirements */
+    enum {
+        REQUIRES_RSA,
+        REQUIRES_DHE,
+        REQUIRES_ECC_DSA,
+        REQUIRES_ECC_STATIC,
+        REQUIRES_PSK,
+        REQUIRES_NTRU,
+        REQUIRES_RSA_SIG
+    };
+
+
+
+    /* Does this cipher suite (first, second) have the requirement
+       an ephemeral key exchange will still require the key for signing
+       the key exchange so ECHDE_RSA requires an rsa key thus rsa_kea */
+    static int CipherRequires(byte first, byte second, int requirement)
+    {
+
+        if (first == CHACHA_BYTE) {
+
+        switch (second) {
+
+        case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            if (requirement == REQUIRES_DHE)
+                return 1;
+            break;
+            }
+        }
+
+        /* ECC extensions */
+        if (first == ECC_BYTE) {
+
+        switch (second) {
+
+#ifndef NO_RSA
+        case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            break;
+
+#ifndef NO_DES3
+        case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            break;
+#endif
+
+#ifndef NO_RC4
+        case TLS_ECDHE_RSA_WITH_RC4_128_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_RSA_WITH_RC4_128_SHA :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            break;
+#endif
+#endif /* NO_RSA */
+
+#ifndef NO_DES3
+        case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+#endif
+#ifndef NO_RC4
+        case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_ECDSA_WITH_RC4_128_SHA :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+#endif
+#ifndef NO_RSA
+        case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            break;
+#endif
+
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+
+        case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+
+        case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+
+#ifndef NO_RSA
+        case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            break;
+
+        case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_AES_128_CCM_8 :
+        case TLS_RSA_WITH_AES_256_CCM_8 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            break;
+
+        case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 :
+        case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            break;
+
+        case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 :
+        case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 :
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+#endif
+
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 :
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 :
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 :
+        case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+
+        case TLS_PSK_WITH_AES_128_CCM:
+        case TLS_PSK_WITH_AES_256_CCM:
+        case TLS_PSK_WITH_AES_128_CCM_8:
+        case TLS_PSK_WITH_AES_256_CCM_8:
+            if (requirement == REQUIRES_PSK)
+                return 1;
+            break;
+
+        case TLS_DHE_PSK_WITH_AES_128_CCM:
+        case TLS_DHE_PSK_WITH_AES_256_CCM:
+            if (requirement == REQUIRES_PSK)
+                return 1;
+            if (requirement == REQUIRES_DHE)
+                return 1;
+            break;
+
+        default:
+            WOLFSSL_MSG("Unsupported cipher suite, CipherRequires ECC");
+            return 0;
+        }   /* switch */
+        }   /* if     */
+        if (first != ECC_BYTE) {   /* normal suites */
+        switch (second) {
+
+#ifndef NO_RSA
+        case SSL_RSA_WITH_RC4_128_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_NTRU_RSA_WITH_RC4_128_SHA :
+            if (requirement == REQUIRES_NTRU)
+                return 1;
+            break;
+
+        case SSL_RSA_WITH_RC4_128_MD5 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case SSL_RSA_WITH_3DES_EDE_CBC_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA :
+            if (requirement == REQUIRES_NTRU)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_AES_128_CBC_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_AES_128_CBC_SHA256 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA :
+            if (requirement == REQUIRES_NTRU)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_AES_256_CBC_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_AES_256_CBC_SHA256 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_NULL_SHA :
+        case TLS_RSA_WITH_NULL_SHA256 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA :
+            if (requirement == REQUIRES_NTRU)
+                return 1;
+            break;
+#endif
+
+        case TLS_PSK_WITH_AES_128_GCM_SHA256 :
+        case TLS_PSK_WITH_AES_256_GCM_SHA384 :
+        case TLS_PSK_WITH_AES_128_CBC_SHA256 :
+        case TLS_PSK_WITH_AES_256_CBC_SHA384 :
+        case TLS_PSK_WITH_AES_128_CBC_SHA :
+        case TLS_PSK_WITH_AES_256_CBC_SHA :
+        case TLS_PSK_WITH_NULL_SHA384 :
+        case TLS_PSK_WITH_NULL_SHA256 :
+        case TLS_PSK_WITH_NULL_SHA :
+            if (requirement == REQUIRES_PSK)
+                return 1;
+            break;
+
+        case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 :
+        case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 :
+        case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 :
+        case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 :
+        case TLS_DHE_PSK_WITH_NULL_SHA384 :
+        case TLS_DHE_PSK_WITH_NULL_SHA256 :
+            if (requirement == REQUIRES_DHE)
+                return 1;
+            if (requirement == REQUIRES_PSK)
+                return 1;
+            break;
+
+#ifndef NO_RSA
+        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            if (requirement == REQUIRES_DHE)
+                return 1;
+            break;
+
+        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            if (requirement == REQUIRES_DHE)
+                return 1;
+            break;
+
+        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            if (requirement == REQUIRES_DHE)
+                return 1;
+            break;
+
+        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            if (requirement == REQUIRES_DHE)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_HC_128_MD5 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_HC_128_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_HC_128_B2B256:
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_AES_128_CBC_B2B256:
+        case TLS_RSA_WITH_AES_256_CBC_B2B256:
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_RABBIT_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_AES_128_GCM_SHA256 :
+        case TLS_RSA_WITH_AES_256_GCM_SHA384 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 :
+        case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            if (requirement == REQUIRES_DHE)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA :
+        case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA :
+        case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 :
+        case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA :
+        case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA :
+        case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 :
+        case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            if (requirement == REQUIRES_DHE)
+                return 1;
+            break;
+#endif
+#ifdef HAVE_ANON
+        case TLS_DH_anon_WITH_AES_128_CBC_SHA :
+            if (requirement == REQUIRES_DHE)
+                return 1;
+            break;
+#endif
+
+        default:
+            WOLFSSL_MSG("Unsupported cipher suite, CipherRequires");
+            return 0;
+        }  /* switch */
+        }  /* if ECC / Normal suites else */
+
+        return 0;
+    }
+
+
+#ifndef NO_CERTS
+
+
+/* Match names with wildcards, each wildcard can represent a single name
+   component or fragment but not mulitple names, i.e.,
+   *.z.com matches y.z.com but not x.y.z.com
+
+   return 1 on success */
+static int MatchDomainName(const char* pattern, int len, const char* str)
+{
+    char p, s;
+
+    if (pattern == NULL || str == NULL || len <= 0)
+        return 0;
+
+    while (len > 0) {
+
+        p = (char)XTOLOWER((unsigned char)*pattern++);
+        if (p == 0)
+            break;
+
+        if (p == '*') {
+            while (--len > 0 &&
+                         (p = (char)XTOLOWER((unsigned char)*pattern++)) == '*')
+                ;
+
+            if (len == 0)
+                p = '\0';
+
+            while ( (s = (char)XTOLOWER((unsigned char) *str)) != '\0') {
+                if (s == p)
+                    break;
+                if (s == '.')
+                    return 0;
+                str++;
+            }
+        }
+        else {
+            if (p != (char)XTOLOWER((unsigned char) *str))
+                return 0;
+        }
+
+        if (*str != '\0')
+            str++;
+
+        if (len > 0)
+            len--;
+    }
+
+    return *str == '\0';
+}
+
+
+/* try to find an altName match to domain, return 1 on success */
+static int CheckAltNames(DecodedCert* dCert, char* domain)
+{
+    int        match = 0;
+    DNS_entry* altName = NULL;
+
+    WOLFSSL_MSG("Checking AltNames");
+
+    if (dCert)
+        altName = dCert->altNames;
+
+    while (altName) {
+        WOLFSSL_MSG("    individual AltName check");
+
+        if (MatchDomainName(altName->name,(int)XSTRLEN(altName->name), domain)){
+            match = 1;
+            break;
+        }
+
+        altName = altName->next;
+    }
+
+    return match;
+}
+
+
+#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
+
+/* Copy parts X509 needs from Decoded cert, 0 on success */
+int CopyDecodedToX509(WOLFSSL_X509* x509, DecodedCert* dCert)
+{
+    int ret = 0;
+
+    if (x509 == NULL || dCert == NULL)
+        return BAD_FUNC_ARG;
+
+    x509->version = dCert->version + 1;
+
+    XSTRNCPY(x509->issuer.name, dCert->issuer, ASN_NAME_MAX);
+    x509->issuer.name[ASN_NAME_MAX - 1] = '\0';
+    x509->issuer.sz = (int)XSTRLEN(x509->issuer.name) + 1;
+#ifdef OPENSSL_EXTRA
+    if (dCert->issuerName.fullName != NULL) {
+        XMEMCPY(&x509->issuer.fullName,
+                                       &dCert->issuerName, sizeof(DecodedName));
+        x509->issuer.fullName.fullName = (char*)XMALLOC(
+                        dCert->issuerName.fullNameLen, NULL, DYNAMIC_TYPE_X509);
+        if (x509->issuer.fullName.fullName != NULL)
+            XMEMCPY(x509->issuer.fullName.fullName,
+                     dCert->issuerName.fullName, dCert->issuerName.fullNameLen);
+    }
+#endif /* OPENSSL_EXTRA */
+
+    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 (dCert->subjectName.fullName != NULL) {
+        XMEMCPY(&x509->subject.fullName,
+                                      &dCert->subjectName, sizeof(DecodedName));
+        x509->subject.fullName.fullName = (char*)XMALLOC(
+                       dCert->subjectName.fullNameLen, NULL, DYNAMIC_TYPE_X509);
+        if (x509->subject.fullName.fullName != NULL)
+            XMEMCPY(x509->subject.fullName.fullName,
+                   dCert->subjectName.fullName, dCert->subjectName.fullNameLen);
+    }
+#endif /* OPENSSL_EXTRA */
+
+    XMEMCPY(x509->serial, dCert->serial, EXTERNAL_SERIAL_SIZE);
+    x509->serialSz = dCert->serialSz;
+    if (dCert->subjectCNLen < ASN_NAME_MAX) {
+        XMEMCPY(x509->subjectCN, dCert->subjectCN, dCert->subjectCNLen);
+        x509->subjectCN[dCert->subjectCNLen] = '\0';
+    }
+    else
+        x509->subjectCN[0] = '\0';
+
+#ifdef WOLFSSL_SEP
+    {
+        int minSz = min(dCert->deviceTypeSz, EXTERNAL_SERIAL_SIZE);
+        if (minSz > 0) {
+            x509->deviceTypeSz = minSz;
+            XMEMCPY(x509->deviceType, dCert->deviceType, minSz);
+        }
+        else
+            x509->deviceTypeSz = 0;
+        minSz = min(dCert->hwTypeSz, EXTERNAL_SERIAL_SIZE);
+        if (minSz != 0) {
+            x509->hwTypeSz = minSz;
+            XMEMCPY(x509->hwType, dCert->hwType, minSz);
+        }
+        else
+            x509->hwTypeSz = 0;
+        minSz = min(dCert->hwSerialNumSz, EXTERNAL_SERIAL_SIZE);
+        if (minSz != 0) {
+            x509->hwSerialNumSz = minSz;
+            XMEMCPY(x509->hwSerialNum, dCert->hwSerialNum, minSz);
+        }
+        else
+            x509->hwSerialNumSz = 0;
+    }
+#endif /* WOLFSSL_SEP */
+    {
+        int minSz = min(dCert->beforeDateLen, MAX_DATE_SZ);
+        if (minSz != 0) {
+            x509->notBeforeSz = minSz;
+            XMEMCPY(x509->notBefore, dCert->beforeDate, minSz);
+        }
+        else
+            x509->notBeforeSz = 0;
+        minSz = min(dCert->afterDateLen, MAX_DATE_SZ);
+        if (minSz != 0) {
+            x509->notAfterSz = minSz;
+            XMEMCPY(x509->notAfter, dCert->afterDate, minSz);
+        }
+        else
+            x509->notAfterSz = 0;
+    }
+
+    if (dCert->publicKey != NULL && dCert->pubKeySize != 0) {
+        x509->pubKey.buffer = (byte*)XMALLOC(
+                              dCert->pubKeySize, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
+        if (x509->pubKey.buffer != NULL) {
+            x509->pubKeyOID = dCert->keyOID;
+            x509->pubKey.length = dCert->pubKeySize;
+            XMEMCPY(x509->pubKey.buffer, dCert->publicKey, dCert->pubKeySize);
+        }
+        else
+            ret = MEMORY_E;
+    }
+
+    if (dCert->signature != NULL && dCert->sigLength != 0) {
+        x509->sig.buffer = (byte*)XMALLOC(
+                                dCert->sigLength, NULL, DYNAMIC_TYPE_SIGNATURE);
+        if (x509->sig.buffer == NULL) {
+            ret = MEMORY_E;
+        }
+        else {
+            XMEMCPY(x509->sig.buffer, dCert->signature, dCert->sigLength);
+            x509->sig.length = dCert->sigLength;
+            x509->sigOID = dCert->signatureOID;
+        }
+    }
+
+    /* store cert for potential retrieval */
+    x509->derCert.buffer = (byte*)XMALLOC(dCert->maxIdx, NULL,
+                                          DYNAMIC_TYPE_CERT);
+    if (x509->derCert.buffer == NULL) {
+        ret = MEMORY_E;
+    }
+    else {
+        XMEMCPY(x509->derCert.buffer, dCert->source, dCert->maxIdx);
+        x509->derCert.length = dCert->maxIdx;
+    }
+
+    x509->altNames       = dCert->altNames;
+    dCert->weOwnAltNames = 0;
+    x509->altNamesNext   = x509->altNames;  /* index hint */
+
+    x509->isCa = dCert->isCA;
+#ifdef OPENSSL_EXTRA
+    x509->pathLength = dCert->pathLength;
+    x509->keyUsage = dCert->extKeyUsage;
+
+    x509->basicConstSet = dCert->extBasicConstSet;
+    x509->basicConstCrit = dCert->extBasicConstCrit;
+    x509->basicConstPlSet = dCert->extBasicConstPlSet;
+    x509->subjAltNameSet = dCert->extSubjAltNameSet;
+    x509->subjAltNameCrit = dCert->extSubjAltNameCrit;
+    x509->authKeyIdSet = dCert->extAuthKeyIdSet;
+    x509->authKeyIdCrit = dCert->extAuthKeyIdCrit;
+    if (dCert->extAuthKeyIdSrc != NULL && dCert->extAuthKeyIdSz != 0) {
+        x509->authKeyId = (byte*)XMALLOC(dCert->extAuthKeyIdSz, NULL, 0);
+        if (x509->authKeyId != NULL) {
+            XMEMCPY(x509->authKeyId,
+                                 dCert->extAuthKeyIdSrc, dCert->extAuthKeyIdSz);
+            x509->authKeyIdSz = dCert->extAuthKeyIdSz;
+        }
+        else
+            ret = MEMORY_E;
+    }
+    x509->subjKeyIdSet = dCert->extSubjKeyIdSet;
+    x509->subjKeyIdCrit = dCert->extSubjKeyIdCrit;
+    if (dCert->extSubjKeyIdSrc != NULL && dCert->extSubjKeyIdSz != 0) {
+        x509->subjKeyId = (byte*)XMALLOC(dCert->extSubjKeyIdSz, NULL, 0);
+        if (x509->subjKeyId != NULL) {
+            XMEMCPY(x509->subjKeyId,
+                                 dCert->extSubjKeyIdSrc, dCert->extSubjKeyIdSz);
+            x509->subjKeyIdSz = dCert->extSubjKeyIdSz;
+        }
+        else
+            ret = MEMORY_E;
+    }
+    x509->keyUsageSet = dCert->extKeyUsageSet;
+    x509->keyUsageCrit = dCert->extKeyUsageCrit;
+    #ifdef WOLFSSL_SEP
+        x509->certPolicySet = dCert->extCertPolicySet;
+        x509->certPolicyCrit = dCert->extCertPolicyCrit;
+    #endif /* WOLFSSL_SEP */
+#endif /* OPENSSL_EXTRA */
+#ifdef HAVE_ECC
+    x509->pkCurveOID = dCert->pkCurveOID;
+#endif /* HAVE_ECC */
+
+    return ret;
+}
+
+#endif /* KEEP_PEER_CERT || SESSION_CERTS */
+
+
+static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx,
+                                                                    word32 size)
+{
+    word32 listSz;
+    word32 begin = *inOutIdx;
+    int    ret = 0;
+    int    anyError = 0;
+    int    totalCerts = 0;    /* number of certs in certs buffer */
+    int    count;
+    buffer certs[MAX_CHAIN_DEPTH];
+
+#ifdef WOLFSSL_SMALL_STACK
+    char*                  domain = NULL;
+    DecodedCert*           dCert  = NULL;
+    WOLFSSL_X509_STORE_CTX* store  = NULL;
+#else
+    char                   domain[ASN_NAME_MAX];
+    DecodedCert            dCert[1];
+    WOLFSSL_X509_STORE_CTX  store[1];
+#endif
+
+    #ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("Certificate", &ssl->timeoutInfo);
+    #endif
+
+    if ((*inOutIdx - begin) + OPAQUE24_LEN > size)
+        return BUFFER_ERROR;
+
+    c24to32(input + *inOutIdx, &listSz);
+    *inOutIdx += OPAQUE24_LEN;
+
+#ifdef HAVE_MAX_FRAGMENT
+    if (listSz > ssl->max_fragment) {
+        SendAlert(ssl, alert_fatal, record_overflow);
+        return BUFFER_E;
+    }
+#else
+    if (listSz > MAX_RECORD_SIZE)
+        return BUFFER_E;
+#endif
+
+    if ((*inOutIdx - begin) + listSz != size)
+        return BUFFER_ERROR;
+
+    WOLFSSL_MSG("Loading peer's cert chain");
+    /* first put cert chain into buffer so can verify top down
+       we're sent bottom up */
+    while (listSz) {
+        word32 certSz;
+
+        if (totalCerts >= MAX_CHAIN_DEPTH)
+            return MAX_CHAIN_ERROR;
+
+        if ((*inOutIdx - begin) + OPAQUE24_LEN > size)
+            return BUFFER_ERROR;
+
+        c24to32(input + *inOutIdx, &certSz);
+        *inOutIdx += OPAQUE24_LEN;
+
+        if ((*inOutIdx - begin) + certSz > size)
+            return BUFFER_ERROR;
+
+        certs[totalCerts].length = certSz;
+        certs[totalCerts].buffer = input + *inOutIdx;
+
+#ifdef SESSION_CERTS
+        if (ssl->session.chain.count < MAX_CHAIN_DEPTH &&
+                                       certSz < MAX_X509_SIZE) {
+            ssl->session.chain.certs[ssl->session.chain.count].length = certSz;
+            XMEMCPY(ssl->session.chain.certs[ssl->session.chain.count].buffer,
+                    input + *inOutIdx, certSz);
+            ssl->session.chain.count++;
+        } else {
+            WOLFSSL_MSG("Couldn't store chain cert for session");
+        }
+#endif
+
+        *inOutIdx += certSz;
+        listSz -= certSz + CERT_HEADER_SZ;
+
+        totalCerts++;
+        WOLFSSL_MSG("    Put another cert into chain");
+    }
+
+    count = totalCerts;
+
+#ifdef WOLFSSL_SMALL_STACK
+    dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (dCert == NULL)
+        return MEMORY_E;
+#endif
+
+    /* verify up to peer's first */
+    while (count > 1) {
+        buffer myCert = certs[count - 1];
+        byte* subjectHash;
+
+        InitDecodedCert(dCert, myCert.buffer, myCert.length, ssl->heap);
+        ret = ParseCertRelative(dCert, CERT_TYPE, !ssl->options.verifyNone,
+                                ssl->ctx->cm);
+        #ifndef NO_SKID
+            subjectHash = dCert->extSubjKeyId;
+        #else
+            subjectHash = dCert->subjectHash;
+        #endif
+
+        if (ret == 0 && dCert->isCA == 0) {
+            WOLFSSL_MSG("Chain cert is not a CA, not adding as one");
+        }
+        else if (ret == 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)) {
+            buffer add;
+            add.length = myCert.length;
+            add.buffer = (byte*)XMALLOC(myCert.length, ssl->heap,
+                                        DYNAMIC_TYPE_CA);
+            WOLFSSL_MSG("Adding CA from chain");
+
+            if (add.buffer == NULL)
+                return MEMORY_E;
+            XMEMCPY(add.buffer, myCert.buffer, myCert.length);
+
+            ret = AddCA(ssl->ctx->cm, add, WOLFSSL_CHAIN_CA,
+                        ssl->ctx->verifyPeer);
+            if (ret == 1) ret = 0;   /* SSL_SUCCESS for external */
+        }
+        else if (ret != 0) {
+            WOLFSSL_MSG("Failed to verify CA from chain");
+        }
+        else {
+            WOLFSSL_MSG("Verified CA from chain and already had it");
+        }
+
+#if defined(HAVE_OCSP) || defined(HAVE_CRL)
+        if (ret == 0) {
+            int doCrlLookup = 1;
+            (void)doCrlLookup;
+#ifdef HAVE_OCSP
+            if (ssl->ctx->cm->ocspEnabled && ssl->ctx->cm->ocspCheckAll) {
+                WOLFSSL_MSG("Doing Non Leaf OCSP check");
+                ret = CheckCertOCSP(ssl->ctx->cm->ocsp, dCert);
+                doCrlLookup = (ret == OCSP_CERT_UNKNOWN);
+                if (ret != 0) {
+                    doCrlLookup = 0;
+                    WOLFSSL_MSG("\tOCSP Lookup not ok");
+                }
+            }
+#endif /* HAVE_OCSP */
+
+#ifdef HAVE_CRL
+            if (doCrlLookup && ssl->ctx->cm->crlEnabled
+                                                 && ssl->ctx->cm->crlCheckAll) {
+                WOLFSSL_MSG("Doing Non Leaf CRL check");
+                ret = CheckCertCRL(ssl->ctx->cm->crl, dCert);
+
+                if (ret != 0) {
+                    WOLFSSL_MSG("\tCRL check not ok");
+                }
+            }
+#endif /* HAVE_CRL */
+        }
+#endif /* HAVE_OCSP || HAVE_CRL */
+
+        if (ret != 0 && anyError == 0)
+            anyError = ret;   /* save error from last time */
+
+        FreeDecodedCert(dCert);
+        count--;
+    }
+
+    /* peer's, may not have one if blank client cert sent by TLSv1.2 */
+    if (count) {
+        buffer myCert = certs[0];
+        int    fatal  = 0;
+
+        WOLFSSL_MSG("Verifying Peer's cert");
+
+        InitDecodedCert(dCert, myCert.buffer, myCert.length, ssl->heap);
+        ret = ParseCertRelative(dCert, CERT_TYPE, !ssl->options.verifyNone,
+                                ssl->ctx->cm);
+        if (ret == 0) {
+            WOLFSSL_MSG("Verified Peer's cert");
+            fatal = 0;
+        }
+        else if (ret == ASN_PARSE_E) {
+            WOLFSSL_MSG("Got Peer cert ASN PARSE ERROR, fatal");
+            fatal = 1;
+        }
+        else {
+            WOLFSSL_MSG("Failed to verify Peer's cert");
+            if (ssl->verifyCallback) {
+                WOLFSSL_MSG("\tCallback override available, will continue");
+                fatal = 0;
+            }
+            else {
+                WOLFSSL_MSG("\tNo callback override available, fatal");
+                fatal = 1;
+            }
+        }
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+        if (fatal == 0 && ssl->secure_renegotiation
+                       && ssl->secure_renegotiation->enabled) {
+
+            if (ssl->keys.encryptionOn) {
+                /* compare against previous time */
+                if (XMEMCMP(dCert->subjectHash,
+                            ssl->secure_renegotiation->subject_hash,
+                            SHA_DIGEST_SIZE) != 0) {
+                    WOLFSSL_MSG("Peer sent different cert during scr, fatal");
+                    fatal = 1;
+                    ret   = SCR_DIFFERENT_CERT_E;
+                }
+            }
+
+            /* cache peer's hash */
+            if (fatal == 0) {
+                XMEMCPY(ssl->secure_renegotiation->subject_hash,
+                        dCert->subjectHash, SHA_DIGEST_SIZE);
+            }
+        }
+#endif
+
+#if defined(HAVE_OCSP) || defined(HAVE_CRL)
+        if (fatal == 0) {
+            int doCrlLookup = 1;
+            (void)doCrlLookup;
+#ifdef HAVE_OCSP
+            if (ssl->ctx->cm->ocspEnabled) {
+                ret = CheckCertOCSP(ssl->ctx->cm->ocsp, dCert);
+                doCrlLookup = (ret == OCSP_CERT_UNKNOWN);
+                if (ret != 0) {
+                    WOLFSSL_MSG("\tOCSP Lookup not ok");
+                    fatal = 0;
+                }
+            }
+#endif /* HAVE_OCSP */
+
+#ifdef HAVE_CRL
+            if (doCrlLookup && ssl->ctx->cm->crlEnabled) {
+                WOLFSSL_MSG("Doing Leaf CRL check");
+                ret = CheckCertCRL(ssl->ctx->cm->crl, dCert);
+                if (ret != 0) {
+                    WOLFSSL_MSG("\tCRL check not ok");
+                    fatal = 0;
+                }
+            }
+#endif /* HAVE_CRL */
+        }
+#endif /* HAVE_OCSP || HAVE_CRL */
+
+#ifdef KEEP_PEER_CERT
+        {
+        /* set X509 format for peer cert even if fatal */
+        int copyRet = CopyDecodedToX509(&ssl->peerCert, dCert);
+        if (copyRet == MEMORY_E)
+            fatal = 1;
+        }
+#endif
+
+#ifndef IGNORE_KEY_EXTENSIONS
+        if (dCert->extKeyUsageSet) {
+            if ((ssl->specs.kea == rsa_kea) &&
+                (dCert->extKeyUsage & KEYUSE_KEY_ENCIPHER) == 0) {
+                ret = KEYUSE_ENCIPHER_E;
+            }
+            if ((ssl->specs.sig_algo == rsa_sa_algo ||
+                    (ssl->specs.sig_algo == ecc_dsa_sa_algo &&
+                         !ssl->specs.static_ecdh)) &&
+                (dCert->extKeyUsage & KEYUSE_DIGITAL_SIG) == 0) {
+                WOLFSSL_MSG("KeyUse Digital Sig not set");
+                ret = KEYUSE_SIGNATURE_E;
+            }
+        }
+
+        if (dCert->extExtKeyUsageSet) {
+            if (ssl->options.side == WOLFSSL_CLIENT_END) {
+                if ((dCert->extExtKeyUsage &
+                        (EXTKEYUSE_ANY | EXTKEYUSE_SERVER_AUTH)) == 0) {
+                    WOLFSSL_MSG("ExtKeyUse Server Auth not set");
+                    ret = EXTKEYUSE_AUTH_E;
+                }
+            }
+            else {
+                if ((dCert->extExtKeyUsage &
+                        (EXTKEYUSE_ANY | EXTKEYUSE_CLIENT_AUTH)) == 0) {
+                    WOLFSSL_MSG("ExtKeyUse Client Auth not set");
+                    ret = EXTKEYUSE_AUTH_E;
+                }
+            }
+        }
+#endif /* IGNORE_KEY_EXTENSIONS */
+
+        if (fatal) {
+            FreeDecodedCert(dCert);
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+            ssl->error = ret;
+            return ret;
+        }
+        ssl->options.havePeerCert = 1;
+
+#ifdef WOLFSSL_SMALL_STACK
+        domain = (char*)XMALLOC(ASN_NAME_MAX, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (domain == NULL) {
+            FreeDecodedCert(dCert);
+            XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            return MEMORY_E;
+        }
+#endif
+        /* store for callback use */
+        if (dCert->subjectCNLen < ASN_NAME_MAX) {
+            XMEMCPY(domain, dCert->subjectCN, dCert->subjectCNLen);
+            domain[dCert->subjectCNLen] = '\0';
+        }
+        else
+            domain[0] = '\0';
+
+        if (!ssl->options.verifyNone && ssl->buffers.domainName.buffer) {
+            if (MatchDomainName(dCert->subjectCN, dCert->subjectCNLen,
+                                (char*)ssl->buffers.domainName.buffer) == 0) {
+                WOLFSSL_MSG("DomainName match on common name failed");
+                if (CheckAltNames(dCert,
+                                 (char*)ssl->buffers.domainName.buffer) == 0 ) {
+                    WOLFSSL_MSG("DomainName match on alt names failed too");
+                    ret = DOMAIN_NAME_MISMATCH; /* try to get peer key still */
+                }
+            }
+        }
+
+        /* decode peer key */
+        switch (dCert->keyOID) {
+        #ifndef NO_RSA
+            case RSAk:
+                {
+                    word32 idx = 0;
+                    int    keyRet = 0;
+
+                    if (ssl->peerRsaKey == NULL) {
+                        ssl->peerRsaKey = (RsaKey*)XMALLOC(sizeof(RsaKey),
+                                                   ssl->heap, DYNAMIC_TYPE_RSA);
+                        if (ssl->peerRsaKey == NULL) {
+                            WOLFSSL_MSG("PeerRsaKey Memory error");
+                            keyRet = MEMORY_E;
+                        } else {
+                            keyRet = wc_InitRsaKey(ssl->peerRsaKey,
+                                                   ssl->ctx->heap);
+                        }
+                    } else if (ssl->peerRsaKeyPresent) {
+                        /* don't leak on reuse */
+                        wc_FreeRsaKey(ssl->peerRsaKey);
+                        ssl->peerRsaKeyPresent = 0;
+                        keyRet = wc_InitRsaKey(ssl->peerRsaKey, ssl->heap);
+                    }
+
+                    if (keyRet != 0 || wc_RsaPublicKeyDecode(dCert->publicKey,
+                               &idx, ssl->peerRsaKey, dCert->pubKeySize) != 0) {
+                        ret = PEER_KEY_ERROR;
+                    }
+                    else {
+                        ssl->peerRsaKeyPresent = 1;
+                        #ifdef HAVE_PK_CALLBACKS
+                            #ifndef NO_RSA
+                                ssl->buffers.peerRsaKey.buffer =
+                                       (byte*)XMALLOC(dCert->pubKeySize,
+                                               ssl->heap, DYNAMIC_TYPE_RSA);
+                                if (ssl->buffers.peerRsaKey.buffer == NULL)
+                                    ret = MEMORY_ERROR;
+                                else {
+                                    XMEMCPY(ssl->buffers.peerRsaKey.buffer,
+                                           dCert->publicKey, dCert->pubKeySize);
+                                    ssl->buffers.peerRsaKey.length =
+                                            dCert->pubKeySize;
+                                }
+                            #endif /* NO_RSA */
+                        #endif /*HAVE_PK_CALLBACKS */
+                    }
+                }
+                break;
+        #endif /* NO_RSA */
+        #ifdef HAVE_NTRU
+            case NTRUk:
+                {
+                    if (dCert->pubKeySize > sizeof(ssl->peerNtruKey)) {
+                        ret = PEER_KEY_ERROR;
+                    }
+                    else {
+                        XMEMCPY(ssl->peerNtruKey, dCert->publicKey,
+                                                             dCert->pubKeySize);
+                        ssl->peerNtruKeyLen = (word16)dCert->pubKeySize;
+                        ssl->peerNtruKeyPresent = 1;
+                    }
+                }
+                break;
+        #endif /* HAVE_NTRU */
+        #ifdef HAVE_ECC
+            case ECDSAk:
+                {
+                    if (ssl->peerEccDsaKey == NULL) {
+                        /* alloc/init on demand */
+                        ssl->peerEccDsaKey = (ecc_key*)XMALLOC(sizeof(ecc_key),
+                                              ssl->ctx->heap, DYNAMIC_TYPE_ECC);
+                        if (ssl->peerEccDsaKey == NULL) {
+                            WOLFSSL_MSG("PeerEccDsaKey Memory error");
+                            return MEMORY_E;
+                        }
+                        wc_ecc_init(ssl->peerEccDsaKey);
+                    } else if (ssl->peerEccDsaKeyPresent) {
+                        /* don't leak on reuse */
+                        wc_ecc_free(ssl->peerEccDsaKey);
+                        ssl->peerEccDsaKeyPresent = 0;
+                        wc_ecc_init(ssl->peerEccDsaKey);
+                    }
+                    if (wc_ecc_import_x963(dCert->publicKey, dCert->pubKeySize,
+                                        ssl->peerEccDsaKey) != 0) {
+                        ret = PEER_KEY_ERROR;
+                    }
+                    else {
+                        ssl->peerEccDsaKeyPresent = 1;
+                        #ifdef HAVE_PK_CALLBACKS
+                            #ifdef HAVE_ECC
+                                ssl->buffers.peerEccDsaKey.buffer =
+                                       (byte*)XMALLOC(dCert->pubKeySize,
+                                               ssl->heap, DYNAMIC_TYPE_ECC);
+                                if (ssl->buffers.peerEccDsaKey.buffer == NULL)
+                                    ret = MEMORY_ERROR;
+                                else {
+                                    XMEMCPY(ssl->buffers.peerEccDsaKey.buffer,
+                                           dCert->publicKey, dCert->pubKeySize);
+                                    ssl->buffers.peerEccDsaKey.length =
+                                            dCert->pubKeySize;
+                                }
+                            #endif /* HAVE_ECC */
+                        #endif /*HAVE_PK_CALLBACKS */
+                    }
+                }
+                break;
+        #endif /* HAVE_ECC */
+            default:
+                break;
+        }
+
+        FreeDecodedCert(dCert);
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    store = (WOLFSSL_X509_STORE_CTX*)XMALLOC(sizeof(WOLFSSL_X509_STORE_CTX),
+                                                 NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (store == NULL) {
+        XFREE(domain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    if (anyError != 0 && ret == 0)
+        ret = anyError;
+
+    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 = totalCerts;
+                store->discardSessionCerts = 0;
+                store->domain = domain;
+                store->userCtx = ssl->verifyCbCtx;
+#ifdef KEEP_PEER_CERT
+                store->current_cert = &ssl->peerCert;
+#else
+                store->current_cert = NULL;
+#endif
+#ifdef 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;
+                }
+                #endif
+            }
+            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;
+            store->error_depth = totalCerts;
+            store->discardSessionCerts = 0;
+            store->domain = domain;
+            store->userCtx = ssl->verifyCbCtx;
+#ifdef KEEP_PEER_CERT
+            store->current_cert = &ssl->peerCert;
+#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;
+            }
+            #endif
+        }
+    }
+#endif
+
+    if (ssl->options.verifyNone &&
+                              (ret == CRL_MISSING || ret == CRL_CERT_REVOKED)) {
+        WOLFSSL_MSG("Ignoring CRL problem based on verify setting");
+        ret = ssl->error = 0;
+    }
+
+    if (ret == 0 && ssl->options.side == WOLFSSL_CLIENT_END)
+        ssl->options.serverState = SERVER_CERT_COMPLETE;
+
+    if (ssl->keys.encryptionOn) {
+        *inOutIdx += ssl->keys.padSz;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(store,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(domain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+#endif /* !NO_CERTS */
+
+
+static int DoHelloRequest(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
+                                                    word32 size, word32 totalSz)
+{
+    (void)input;
+
+    if (size) /* must be 0 */
+        return BUFFER_ERROR;
+
+    if (ssl->keys.encryptionOn) {
+        /* access beyond input + size should be checked against totalSz */
+        if (*inOutIdx + ssl->keys.padSz > totalSz)
+            return BUFFER_E;
+
+        *inOutIdx += ssl->keys.padSz;
+    }
+
+    if (ssl->options.side == WOLFSSL_SERVER_END) {
+        SendAlert(ssl, alert_fatal, unexpected_message); /* try */
+        return FATAL_ERROR;
+    }
+#ifdef HAVE_SECURE_RENEGOTIATION
+    else if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled) {
+        ssl->secure_renegotiation->startScr = 1;
+        return 0;
+    }
+#endif
+    else {
+        return SendAlert(ssl, alert_warning, no_renegotiation);
+    }
+}
+
+
+int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size,
+                                                      word32 totalSz, int sniff)
+{
+    word32 finishedSz = (ssl->options.tls ? TLS_FINISHED_SZ : FINISHED_SZ);
+
+    if (finishedSz != size)
+        return BUFFER_ERROR;
+
+    /* check against totalSz */
+    if (*inOutIdx + size + ssl->keys.padSz > totalSz)
+        return BUFFER_E;
+
+    #ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo);
+    #endif
+
+    if (sniff == NO_SNIFF) {
+        if (XMEMCMP(input + *inOutIdx, &ssl->hsHashes->verifyHashes,size) != 0){
+            WOLFSSL_MSG("Verify finished error on hashes");
+            return VERIFY_FINISHED_ERROR;
+        }
+    }
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+    if (ssl->secure_renegotiation) {
+        /* save peer's state */
+        if (ssl->options.side == WOLFSSL_CLIENT_END)
+            XMEMCPY(ssl->secure_renegotiation->server_verify_data,
+                    input + *inOutIdx, TLS_FINISHED_SZ);
+        else
+            XMEMCPY(ssl->secure_renegotiation->client_verify_data,
+                    input + *inOutIdx, TLS_FINISHED_SZ);
+    }
+#endif
+
+    /* force input exhaustion at ProcessReply consuming padSz */
+    *inOutIdx += size + ssl->keys.padSz;
+
+    if (ssl->options.side == WOLFSSL_CLIENT_END) {
+        ssl->options.serverState = SERVER_FINISHED_COMPLETE;
+        if (!ssl->options.resuming) {
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+            ssl->options.handShakeDone  = 1;
+
+#ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls) {
+                /* Other side has received our Finished, go to next epoch */
+                ssl->keys.dtls_epoch++;
+                ssl->keys.dtls_sequence_number = 1;
+            }
+#endif
+        }
+    }
+    else {
+        ssl->options.clientState = CLIENT_FINISHED_COMPLETE;
+        if (ssl->options.resuming) {
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+            ssl->options.handShakeDone  = 1;
+
+#ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls) {
+                /* Other side has received our Finished, go to next epoch */
+                ssl->keys.dtls_epoch++;
+                ssl->keys.dtls_sequence_number = 1;
+            }
+#endif
+        }
+    }
+
+    return 0;
+}
+
+
+/* Make sure no duplicates, no fast forward, or other problems; 0 on success */
+static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type)
+{
+    /* verify not a duplicate, mark received, check state */
+    switch (type) {
+
+#ifndef NO_WOLFSSL_CLIENT
+        case hello_request:
+            if (ssl->msgsReceived.got_hello_request) {
+                WOLFSSL_MSG("Duplicate HelloRequest received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_hello_request = 1;
+
+            break;
+#endif
+
+#ifndef NO_WOLFSSL_SERVER
+        case client_hello:
+            if (ssl->msgsReceived.got_client_hello) {
+                WOLFSSL_MSG("Duplicate ClientHello received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_client_hello = 1;
+
+            break;
+#endif
+
+#ifndef NO_WOLFSSL_CLIENT
+        case server_hello:
+            if (ssl->msgsReceived.got_server_hello) {
+                WOLFSSL_MSG("Duplicate ServerHello received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_server_hello = 1;
+
+            break;
+#endif
+
+#ifndef NO_WOLFSSL_CLIENT
+        case hello_verify_request:
+            if (ssl->msgsReceived.got_hello_verify_request) {
+                WOLFSSL_MSG("Duplicate HelloVerifyRequest received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_hello_verify_request = 1;
+
+            break;
+#endif
+
+#ifndef NO_WOLFSSL_CLIENT
+        case session_ticket:
+            if (ssl->msgsReceived.got_session_ticket) {
+                WOLFSSL_MSG("Duplicate SessionTicket received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_session_ticket = 1;
+
+            break;
+#endif
+
+        case certificate:
+            if (ssl->msgsReceived.got_certificate) {
+                WOLFSSL_MSG("Duplicate Certificate received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_certificate = 1;
+
+#ifndef NO_WOLFSSL_CLIENT
+            if (ssl->options.side == WOLFSSL_CLIENT_END) {
+                if ( ssl->msgsReceived.got_server_hello == 0) {
+                    WOLFSSL_MSG("No ServerHello before Cert");
+                    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");
+                    return OUT_OF_ORDER_E;
+                }
+            }
+#endif
+            break;
+
+#ifndef NO_WOLFSSL_CLIENT
+        case server_key_exchange:
+            if (ssl->msgsReceived.got_server_key_exchange) {
+                WOLFSSL_MSG("Duplicate ServerKeyExchange received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_server_key_exchange = 1;
+
+            if ( ssl->msgsReceived.got_server_hello == 0) {
+                WOLFSSL_MSG("No ServerHello before Cert");
+                return OUT_OF_ORDER_E;
+            }
+
+            break;
+#endif
+
+#ifndef NO_WOLFSSL_CLIENT
+        case certificate_request:
+            if (ssl->msgsReceived.got_certificate_request) {
+                WOLFSSL_MSG("Duplicate CertificateRequest received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_certificate_request = 1;
+
+            break;
+#endif
+
+#ifndef NO_WOLFSSL_CLIENT
+        case server_hello_done:
+            if (ssl->msgsReceived.got_server_hello_done) {
+                WOLFSSL_MSG("Duplicate ServerHelloDone received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_server_hello_done = 1;
+
+            if (ssl->msgsReceived.got_certificate == 0) {
+                if (ssl->specs.kea == psk_kea ||
+                    ssl->specs.kea == dhe_psk_kea ||
+                    ssl->options.usingAnon_cipher) {
+                    WOLFSSL_MSG("No Cert required");
+                } else {
+                    WOLFSSL_MSG("No Certificate before ServerHelloDone");
+                    return OUT_OF_ORDER_E;
+                }
+            }
+            if (ssl->msgsReceived.got_server_key_exchange == 0) {
+                if (ssl->specs.static_ecdh == 1 ||
+                    ssl->specs.kea == rsa_kea ||
+                    ssl->specs.kea == ntru_kea) {
+                    WOLFSSL_MSG("No KeyExchange required");
+                } else {
+                    WOLFSSL_MSG("No ServerKeyExchange before ServerDone");
+                    return OUT_OF_ORDER_E;
+                }
+            }
+            break;
+#endif
+
+#ifndef NO_WOLFSSL_SERVER
+        case certificate_verify:
+            if (ssl->msgsReceived.got_certificate_verify) {
+                WOLFSSL_MSG("Duplicate CertificateVerify received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_certificate_verify = 1;
+
+            if ( ssl->msgsReceived.got_certificate == 0) {
+                WOLFSSL_MSG("No Cert before CertVerify");
+                return OUT_OF_ORDER_E;
+            }
+            break;
+#endif
+
+#ifndef NO_WOLFSSL_SERVER
+        case client_key_exchange:
+            if (ssl->msgsReceived.got_client_key_exchange) {
+                WOLFSSL_MSG("Duplicate ClientKeyExchange received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_client_key_exchange = 1;
+
+            if (ssl->msgsReceived.got_client_hello == 0) {
+                WOLFSSL_MSG("No ClientHello before ClientKeyExchange");
+                return OUT_OF_ORDER_E;
+            }
+            break;
+#endif
+
+        case finished:
+            if (ssl->msgsReceived.got_finished) {
+                WOLFSSL_MSG("Duplicate Finished received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_finished = 1;
+
+            if (ssl->msgsReceived.got_change_cipher == 0) {
+                WOLFSSL_MSG("Finished received before ChangeCipher");
+                return NO_CHANGE_CIPHER_E;
+            }
+
+            break;
+
+        case change_cipher_hs:
+            if (ssl->msgsReceived.got_change_cipher) {
+                WOLFSSL_MSG("Duplicate ChangeCipher received");
+                return DUPLICATE_MSG_E;
+            }
+            ssl->msgsReceived.got_change_cipher = 1;
+
+#ifndef NO_WOLFSSL_CLIENT
+            if (ssl->options.side == WOLFSSL_CLIENT_END) {
+                if (!ssl->options.resuming &&
+                                 ssl->msgsReceived.got_server_hello_done == 0) {
+                    WOLFSSL_MSG("No ServerHelloDone before ChangeCipher");
+                    return OUT_OF_ORDER_E;
+                }
+            }
+#endif
+#ifndef NO_WOLFSSL_SERVER
+            if (ssl->options.side == WOLFSSL_SERVER_END) {
+                if (!ssl->options.resuming &&
+                               ssl->msgsReceived.got_client_key_exchange == 0) {
+                    WOLFSSL_MSG("No ClientKeyExchange before ChangeCipher");
+                    return OUT_OF_ORDER_E;
+                }
+            }
+#endif
+
+            break;
+
+        default:
+            WOLFSSL_MSG("Unknown message type");
+            return SANITY_MSG_E;
+    }
+
+    return 0;
+}
+
+
+static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
+                          byte type, word32 size, word32 totalSz)
+{
+    int ret = 0;
+    (void)totalSz;
+
+    WOLFSSL_ENTER("DoHandShakeMsgType");
+
+    /* make sure can read the message */
+    if (*inOutIdx + size > totalSz)
+        return INCOMPLETE_DATA;
+
+    /* sanity check msg received */
+    if ( (ret = SanityCheckMsgReceived(ssl, type)) != 0) {
+        WOLFSSL_MSG("Sanity Check on handshake message type received failed");
+        return ret;
+    }
+
+#ifdef WOLFSSL_CALLBACKS
+    /* 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);
+        AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo);
+    }
+#endif
+
+    if (ssl->options.handShakeState == HANDSHAKE_DONE && type != hello_request){
+        WOLFSSL_MSG("HandShake message after handshake complete");
+        SendAlert(ssl, alert_fatal, unexpected_message);
+        return OUT_OF_ORDER_E;
+    }
+
+    if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->options.dtls == 0 &&
+               ssl->options.serverState == NULL_STATE && type != server_hello) {
+        WOLFSSL_MSG("First server message not server hello");
+        SendAlert(ssl, alert_fatal, unexpected_message);
+        return OUT_OF_ORDER_E;
+    }
+
+    if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->options.dtls &&
+            type == server_hello_done &&
+            ssl->options.serverState < SERVER_HELLO_COMPLETE) {
+        WOLFSSL_MSG("Server hello done received before server hello in DTLS");
+        SendAlert(ssl, alert_fatal, unexpected_message);
+        return OUT_OF_ORDER_E;
+    }
+
+    if (ssl->options.side == WOLFSSL_SERVER_END &&
+               ssl->options.clientState == NULL_STATE && type != client_hello) {
+        WOLFSSL_MSG("First client message not client hello");
+        SendAlert(ssl, alert_fatal, unexpected_message);
+        return OUT_OF_ORDER_E;
+    }
+
+    /* above checks handshake state */
+    /* hello_request not hashed */
+    if (type != hello_request) {
+        ret = HashInput(ssl, input + *inOutIdx, size);
+        if (ret != 0) return ret;
+    }
+
+    switch (type) {
+
+    case hello_request:
+        WOLFSSL_MSG("processing hello request");
+        ret = DoHelloRequest(ssl, input, inOutIdx, size, totalSz);
+        break;
+
+#ifndef NO_WOLFSSL_CLIENT
+    case hello_verify_request:
+        WOLFSSL_MSG("processing hello verify request");
+        ret = DoHelloVerifyRequest(ssl, input,inOutIdx, size);
+        break;
+
+    case server_hello:
+        WOLFSSL_MSG("processing server hello");
+        ret = DoServerHello(ssl, input, inOutIdx, size);
+        break;
+
+#ifndef NO_CERTS
+    case certificate_request:
+        WOLFSSL_MSG("processing certificate request");
+        ret = DoCertificateRequest(ssl, input, inOutIdx, size);
+        break;
+#endif
+
+    case server_key_exchange:
+        WOLFSSL_MSG("processing server key exchange");
+        ret = DoServerKeyExchange(ssl, input, inOutIdx, size);
+        break;
+
+#ifdef HAVE_SESSION_TICKET
+    case session_ticket:
+        WOLFSSL_MSG("processing session ticket");
+        ret = DoSessionTicket(ssl, input, inOutIdx, size);
+        break;
+#endif /* HAVE_SESSION_TICKET */
+#endif
+
+#ifndef NO_CERTS
+    case certificate:
+        WOLFSSL_MSG("processing certificate");
+        ret =  DoCertificate(ssl, input, inOutIdx, size);
+        break;
+#endif
+
+    case server_hello_done:
+        WOLFSSL_MSG("processing server hello done");
+        #ifdef WOLFSSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("ServerHelloDone", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("ServerHelloDone", &ssl->timeoutInfo);
+        #endif
+        ssl->options.serverState = SERVER_HELLODONE_COMPLETE;
+        if (ssl->keys.encryptionOn) {
+            *inOutIdx += ssl->keys.padSz;
+        }
+        if (ssl->options.resuming) {
+            WOLFSSL_MSG("Not resuming as thought");
+            ssl->options.resuming = 0;
+        }
+        break;
+
+    case finished:
+        WOLFSSL_MSG("processing finished");
+        ret = DoFinished(ssl, input, inOutIdx, size, totalSz, NO_SNIFF);
+        break;
+
+#ifndef NO_WOLFSSL_SERVER
+    case client_hello:
+        WOLFSSL_MSG("processing client hello");
+        ret = DoClientHello(ssl, input, inOutIdx, size);
+        break;
+
+    case client_key_exchange:
+        WOLFSSL_MSG("processing client key exchange");
+        ret = DoClientKeyExchange(ssl, input, inOutIdx, size);
+        break;
+
+#if !defined(NO_RSA) || defined(HAVE_ECC)
+    case certificate_verify:
+        WOLFSSL_MSG("processing certificate verify");
+        ret = DoCertificateVerify(ssl, input, inOutIdx, size);
+        break;
+#endif /* !NO_RSA || HAVE_ECC */
+
+#endif /* !NO_WOLFSSL_SERVER */
+
+    default:
+        WOLFSSL_MSG("Unknown handshake message type");
+        ret = UNKNOWN_HANDSHAKE_TYPE;
+        break;
+    }
+
+    WOLFSSL_LEAVE("DoHandShakeMsgType()", ret);
+    return ret;
+}
+
+
+static int DoHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,
+                          word32 totalSz)
+{
+    byte   type;
+    word32 size;
+    int    ret = 0;
+
+    WOLFSSL_ENTER("DoHandShakeMsg()");
+
+    if (GetHandShakeHeader(ssl, input, inOutIdx, &type, &size, totalSz) != 0)
+        return PARSE_ERROR;
+
+    ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz);
+
+    WOLFSSL_LEAVE("DoHandShakeMsg()", ret);
+    return ret;
+}
+
+
+#ifdef WOLFSSL_DTLS
+
+static INLINE int DtlsCheckWindow(DtlsState* state)
+{
+    word32 cur;
+    word32 next;
+    DtlsSeq window;
+
+    if (state->curEpoch == state->nextEpoch) {
+        next = state->nextSeq;
+        window = state->window;
+    }
+    else if (state->curEpoch < state->nextEpoch) {
+        next = state->prevSeq;
+        window = state->prevWindow;
+    }
+    else {
+        return 0;
+    }
+
+    cur = state->curSeq;
+
+    if ((next > DTLS_SEQ_BITS) && (cur < next - DTLS_SEQ_BITS)) {
+        return 0;
+    }
+    else if ((cur < next) && (window & ((DtlsSeq)1 << (next - cur - 1)))) {
+        return 0;
+    }
+
+    return 1;
+}
+
+
+static INLINE int DtlsUpdateWindow(DtlsState* state)
+{
+    word32 cur;
+    word32* next;
+    DtlsSeq* window;
+
+    if (state->curEpoch == state->nextEpoch) {
+        next = &state->nextSeq;
+        window = &state->window;
+    }
+    else {
+        next = &state->prevSeq;
+        window = &state->prevWindow;
+    }
+
+    cur = state->curSeq;
+
+    if (cur < *next) {
+        *window |= ((DtlsSeq)1 << (*next - cur - 1));
+    }
+    else {
+        *window <<= (1 + cur - *next);
+        *window |= 1;
+        *next = cur + 1;
+    }
+
+    return 1;
+}
+
+
+static int DtlsMsgDrain(WOLFSSL* ssl)
+{
+    DtlsMsg* item = ssl->dtls_msg_list;
+    int ret = 0;
+
+    /* 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... */
+    while (item != NULL &&
+            ssl->keys.dtls_expected_peer_handshake_number == item->seq &&
+            item->fragSz == item->sz &&
+            ret == 0) {
+        word32 idx = 0;
+        ssl->keys.dtls_expected_peer_handshake_number++;
+        ret = DoHandShakeMsgType(ssl, item->msg,
+                                 &idx, item->type, item->sz, item->sz);
+        ssl->dtls_msg_list = item->next;
+        DtlsMsgDelete(item, ssl->heap);
+        item = ssl->dtls_msg_list;
+    }
+
+    return ret;
+}
+
+
+static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,
+                          word32 totalSz)
+{
+    byte type;
+    word32 size;
+    word32 fragOffset, fragSz;
+    int ret = 0;
+
+    WOLFSSL_ENTER("DoDtlsHandShakeMsg()");
+    if (GetDtlsHandShakeHeader(ssl, input, inOutIdx, &type,
+                               &size, &fragOffset, &fragSz, totalSz) != 0)
+        return PARSE_ERROR;
+
+    if (*inOutIdx + fragSz > totalSz)
+        return INCOMPLETE_DATA;
+
+    /* Check the handshake sequence number first. If out of order,
+     * add the current message to the list. If the message is in order,
+     * but it is a fragment, add the current message to the list, then
+     * check the head of the list to see if it is complete, if so, pop
+     * it out as the current message. If the message is complete and in
+     * order, process it. Check the head of the list to see if it is in
+     * order, if so, process it. (Repeat until list exhausted.) If the
+     * head is out of order, return for more processing.
+     */
+    if (ssl->keys.dtls_peer_handshake_number >
+                                ssl->keys.dtls_expected_peer_handshake_number) {
+        /* Current message is out of order. It will get stored in the list.
+         * Storing also takes care of defragmentation. */
+        ssl->dtls_msg_list = DtlsMsgStore(ssl->dtls_msg_list,
+                        ssl->keys.dtls_peer_handshake_number, input + *inOutIdx,
+                        size, type, fragOffset, fragSz, ssl->heap);
+        *inOutIdx += fragSz;
+        ret = 0;
+    }
+    else if (ssl->keys.dtls_peer_handshake_number <
+                                ssl->keys.dtls_expected_peer_handshake_number) {
+        /* Already saw this message and processed it. It can be ignored. */
+        *inOutIdx += fragSz;
+        ret = 0;
+    }
+    else if (fragSz < size) {
+        /* Since this branch is in order, but fragmented, dtls_msg_list will be
+         * pointing to the message with this fragment in it. Check it to see
+         * if it is completed. */
+        ssl->dtls_msg_list = DtlsMsgStore(ssl->dtls_msg_list,
+                        ssl->keys.dtls_peer_handshake_number, input + *inOutIdx,
+                        size, type, fragOffset, fragSz, ssl->heap);
+        *inOutIdx += fragSz;
+        ret = 0;
+        if (ssl->dtls_msg_list != NULL &&
+            ssl->dtls_msg_list->fragSz >= ssl->dtls_msg_list->sz)
+            ret = DtlsMsgDrain(ssl);
+    }
+    else {
+        /* This branch is in order next, and a complete message. */
+        ssl->keys.dtls_expected_peer_handshake_number++;
+        ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz);
+        if (ret == 0 && ssl->dtls_msg_list != NULL)
+            ret = DtlsMsgDrain(ssl);
+    }
+
+    WOLFSSL_LEAVE("DoDtlsHandShakeMsg()", ret);
+    return ret;
+}
+#endif
+
+
+#if !defined(NO_OLD_TLS) || defined(HAVE_CHACHA) || defined(HAVE_AESCCM) \
+    || defined(HAVE_AESGCM)
+static INLINE word32 GetSEQIncrement(WOLFSSL* ssl, int verify)
+{
+#ifdef WOLFSSL_DTLS
+    if (ssl->options.dtls) {
+        if (verify)
+            return ssl->keys.dtls_state.curSeq; /* explicit from peer */
+        else
+            return ssl->keys.dtls_sequence_number - 1; /* already incremented */
+    }
+#endif
+    if (verify)
+        return ssl->keys.peer_sequence_number++;
+    else
+        return ssl->keys.sequence_number++;
+}
+#endif
+
+
+#ifdef HAVE_AEAD
+static INLINE void AeadIncrementExpIV(WOLFSSL* ssl)
+{
+    int i;
+    for (i = AEAD_EXP_IV_SZ-1; i >= 0; i--) {
+        if (++ssl->keys.aead_exp_IV[i]) return;
+    }
+}
+
+
+#if defined(HAVE_POLY1305) && defined(HAVE_CHACHA)
+/*more recent rfc's concatonate input for poly1305 differently*/
+static int Poly1305Tag(WOLFSSL* ssl, byte* additional, const byte* out,
+                       byte* cipher, word16 sz, byte* tag)
+{
+    int ret       = 0;
+    int paddingSz = 0;
+    int msglen    = (sz - ssl->specs.aead_mac_size);
+    word32 keySz  = 32;
+    int blockSz   = 16;
+    byte padding[16];
+
+    if (msglen < 0)
+        return INPUT_CASE_ERROR;
+
+    XMEMSET(padding, 0, sizeof(padding));
+
+    if ((ret = wc_Poly1305SetKey(ssl->auth.poly1305, cipher, keySz)) != 0)
+        return ret;
+
+    /* additional input to poly1305 */
+    if ((ret = wc_Poly1305Update(ssl->auth.poly1305, additional, blockSz)) != 0)
+        return ret;
+
+    /* cipher input */
+    if ((ret = wc_Poly1305Update(ssl->auth.poly1305, out, msglen)) != 0)
+        return ret;
+
+    /* handle padding for cipher input to make it 16 bytes long */
+    if (msglen % 16 != 0) {
+          paddingSz = (16 - (sz - ssl->specs.aead_mac_size) % 16);
+          if (paddingSz < 0)
+              return INPUT_CASE_ERROR;
+
+          if ((ret = wc_Poly1305Update(ssl->auth.poly1305, padding, paddingSz))
+                 != 0)
+              return ret;
+    }
+
+    /* add size of AD and size of cipher to poly input */
+    XMEMSET(padding, 0, sizeof(padding));
+    padding[0] = blockSz;
+
+    /* 32 bit size of cipher to 64 bit endian */
+    padding[8]  =  msglen       & 0xff;
+    padding[9]  = (msglen >> 8) & 0xff;
+    padding[10] = (msglen >>16) & 0xff;
+    padding[11] = (msglen >>24) & 0xff;
+    if ((ret = wc_Poly1305Update(ssl->auth.poly1305, padding, sizeof(padding)))
+                != 0)
+        return ret;
+
+    /* generate tag */
+    if ((ret = wc_Poly1305Final(ssl->auth.poly1305, tag)) != 0)
+        return ret;
+
+    return ret;
+}
+
+
+/* Used for the older version of creating AEAD tags with Poly1305 */
+static int Poly1305TagOld(WOLFSSL* ssl, byte* additional, const byte* out,
+                       byte* cipher, word16 sz, byte* tag)
+{
+    int ret       = 0;
+    int msglen    = (sz - ssl->specs.aead_mac_size);
+    word32 keySz  = 32;
+    byte padding[8]; /* used to temporarly store lengths */
+
+#ifdef CHACHA_AEAD_TEST
+      printf("Using old version of poly1305 input.\n");
+#endif
+
+    if (msglen < 0)
+        return INPUT_CASE_ERROR;
+
+    if ((ret = wc_Poly1305SetKey(ssl->auth.poly1305, cipher, keySz)) != 0)
+        return ret;
+
+    /* add TLS compressed length and additional input to poly1305 */
+    additional[AEAD_AUTH_DATA_SZ - 2] = (msglen >> 8) & 0xff;
+    additional[AEAD_AUTH_DATA_SZ - 1] =  msglen       & 0xff;
+    if ((ret = wc_Poly1305Update(ssl->auth.poly1305, additional,
+                   AEAD_AUTH_DATA_SZ)) != 0)
+        return ret;
+
+    /* length of additional input plus padding */
+    XMEMSET(padding, 0, sizeof(padding));
+    padding[0] = AEAD_AUTH_DATA_SZ;
+    if ((ret = wc_Poly1305Update(ssl->auth.poly1305, padding,
+                    sizeof(padding))) != 0)
+        return ret;
+
+
+    /* add cipher info and then its length */
+    XMEMSET(padding, 0, sizeof(padding));
+    if ((ret = wc_Poly1305Update(ssl->auth.poly1305, out, msglen)) != 0)
+        return ret;
+
+    /* 32 bit size of cipher to 64 bit endian */
+    padding[0] =  msglen        & 0xff;
+    padding[1] = (msglen >>  8) & 0xff;
+    padding[2] = (msglen >> 16) & 0xff;
+    padding[3] = (msglen >> 24) & 0xff;
+    if ((ret = wc_Poly1305Update(ssl->auth.poly1305, padding, sizeof(padding)))
+        != 0)
+        return ret;
+
+    /* generate tag */
+    if ((ret = wc_Poly1305Final(ssl->auth.poly1305, tag)) != 0)
+        return ret;
+
+    return ret;
+}
+
+
+static int  ChachaAEADEncrypt(WOLFSSL* ssl, byte* out, const byte* input,
+                              word16 sz)
+{
+    const byte* additionalSrc = input - RECORD_HEADER_SZ;
+    int ret = 0;
+    byte tag[POLY1305_AUTH_SZ];
+    byte additional[CHACHA20_BLOCK_SIZE];
+    byte nonce[AEAD_NONCE_SZ];
+    byte cipher[CHACHA20_256_KEY_SIZE]; /* generated key for poly1305 */
+    #ifdef CHACHA_AEAD_TEST
+        int i;
+    #endif
+
+    XMEMSET(tag, 0, sizeof(tag));
+    XMEMSET(nonce, 0, AEAD_NONCE_SZ);
+    XMEMSET(cipher, 0, sizeof(cipher));
+    XMEMSET(additional, 0, CHACHA20_BLOCK_SIZE);
+
+    /* get nonce */
+    c32toa(ssl->keys.sequence_number, nonce + AEAD_IMP_IV_SZ
+           + AEAD_SEQ_OFFSET);
+
+    /* opaque SEQ number stored for AD */
+    c32toa(GetSEQIncrement(ssl, 0), additional + AEAD_SEQ_OFFSET);
+
+    /* Store the type, version. Unfortunately, they are in
+     * the input buffer ahead of the plaintext. */
+    #ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls) {
+            c16toa(ssl->keys.dtls_epoch, additional);
+            additionalSrc -= DTLS_HANDSHAKE_EXTRA;
+        }
+    #endif
+
+    XMEMCPY(additional + AEAD_TYPE_OFFSET, additionalSrc, 3);
+
+    #ifdef CHACHA_AEAD_TEST
+        printf("Encrypt Additional : ");
+        for (i = 0; i < CHACHA20_BLOCK_SIZE; i++) {
+            printf("%02x", additional[i]);
+        }
+        printf("\n\n");
+        printf("input before encryption :\n");
+        for (i = 0; i < sz; i++) {
+            printf("%02x", input[i]);
+            if ((i + 1) % 16 == 0)
+                printf("\n");
+        }
+        printf("\n");
+    #endif
+
+    /* set the nonce for chacha and get poly1305 key */
+    if ((ret = wc_Chacha_SetIV(ssl->encrypt.chacha, nonce, 0)) != 0)
+        return ret;
+
+        if ((ret = wc_Chacha_Process(ssl->encrypt.chacha, cipher,
+                    cipher, sizeof(cipher))) != 0)
+        return ret;
+
+    /* encrypt the plain text */
+    if ((ret = wc_Chacha_Process(ssl->encrypt.chacha, out, input,
+                   sz - ssl->specs.aead_mac_size)) != 0)
+        return ret;
+
+    /* get the tag : future use of hmac could go here*/
+    if (ssl->options.oldPoly == 1) {
+        if ((ret = Poly1305TagOld(ssl, additional, (const byte* )out,
+                    cipher, sz, tag)) != 0)
+            return ret;
+    }
+    else {
+        if ((ret = Poly1305Tag(ssl, additional, (const byte* )out,
+                    cipher, sz, tag)) != 0)
+            return ret;
+    }
+
+    /* append tag to ciphertext */
+    XMEMCPY(out + sz - ssl->specs.aead_mac_size, tag, sizeof(tag));
+
+    AeadIncrementExpIV(ssl);
+    ForceZero(nonce, AEAD_NONCE_SZ);
+
+    #ifdef CHACHA_AEAD_TEST
+       printf("mac tag :\n");
+        for (i = 0; i < 16; i++) {
+           printf("%02x", tag[i]);
+           if ((i + 1) % 16 == 0)
+               printf("\n");
+        }
+       printf("\n\noutput after encrypt :\n");
+        for (i = 0; i < sz; i++) {
+           printf("%02x", out[i]);
+           if ((i + 1) % 16 == 0)
+               printf("\n");
+        }
+        printf("\n");
+    #endif
+
+    return ret;
+}
+
+
+static int ChachaAEADDecrypt(WOLFSSL* ssl, byte* plain, const byte* input,
+                           word16 sz)
+{
+    byte additional[CHACHA20_BLOCK_SIZE];
+    byte nonce[AEAD_NONCE_SZ];
+    byte tag[POLY1305_AUTH_SZ];
+    byte cipher[CHACHA20_256_KEY_SIZE]; /* generated key for mac */
+    int ret = 0;
+
+    XMEMSET(tag, 0, sizeof(tag));
+    XMEMSET(cipher, 0, sizeof(cipher));
+    XMEMSET(nonce, 0, AEAD_NONCE_SZ);
+    XMEMSET(additional, 0, CHACHA20_BLOCK_SIZE);
+
+    #ifdef CHACHA_AEAD_TEST
+       int i;
+       printf("input before decrypt :\n");
+        for (i = 0; i < sz; i++) {
+           printf("%02x", input[i]);
+           if ((i + 1) % 16 == 0)
+               printf("\n");
+        }
+        printf("\n");
+    #endif
+
+    /* get nonce */
+    c32toa(ssl->keys.peer_sequence_number, nonce + AEAD_IMP_IV_SZ
+            + AEAD_SEQ_OFFSET);
+
+    /* sequence number field is 64-bits, we only use 32-bits */
+    c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET);
+
+    /* get AD info */
+    additional[AEAD_TYPE_OFFSET] = ssl->curRL.type;
+    additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor;
+    additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor;
+
+    /* Store the type, version. */
+    #ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls)
+            c16toa(ssl->keys.dtls_state.curEpoch, additional);
+    #endif
+
+    #ifdef CHACHA_AEAD_TEST
+        printf("Decrypt Additional : ");
+        for (i = 0; i < CHACHA20_BLOCK_SIZE; i++) {
+            printf("%02x", additional[i]);
+        }
+        printf("\n\n");
+    #endif
+
+    /* set nonce and get poly1305 key */
+    if ((ret = wc_Chacha_SetIV(ssl->decrypt.chacha, nonce, 0)) != 0)
+        return ret;
+
+    if ((ret = wc_Chacha_Process(ssl->decrypt.chacha, cipher,
+                    cipher, sizeof(cipher))) != 0)
+        return ret;
+
+    /* get the tag : future use of hmac could go here*/
+    if (ssl->options.oldPoly == 1) {
+        if ((ret = Poly1305TagOld(ssl, additional, input, cipher,
+                        sz, tag)) != 0)
+            return ret;
+    }
+    else {
+        if ((ret = Poly1305Tag(ssl, additional, input, cipher,
+                        sz, tag)) != 0)
+            return ret;
+    }
+
+    /* check mac sent along with packet */
+    if (ConstantCompare(input + sz - ssl->specs.aead_mac_size, tag,
+                ssl->specs.aead_mac_size) != 0) {
+        WOLFSSL_MSG("Mac did not match");
+        SendAlert(ssl, alert_fatal, bad_record_mac);
+        ForceZero(nonce, AEAD_NONCE_SZ);
+        return VERIFY_MAC_ERROR;
+    }
+
+    /* if mac was good decrypt message */
+    if ((ret = wc_Chacha_Process(ssl->decrypt.chacha, plain, input,
+                   sz - ssl->specs.aead_mac_size)) != 0)
+        return ret;
+
+    #ifdef CHACHA_AEAD_TEST
+       printf("plain after decrypt :\n");
+        for (i = 0; i < sz; i++) {
+           printf("%02x", plain[i]);
+           if ((i + 1) % 16 == 0)
+               printf("\n");
+        }
+        printf("\n");
+    #endif
+
+    return ret;
+}
+#endif /* HAVE_CHACHA && HAVE_POLY1305 */
+#endif /* HAVE_AEAD */
+
+
+static INLINE int Encrypt(WOLFSSL* ssl, byte* out, const byte* input, word16 sz)
+{
+    int ret = 0;
+
+    (void)out;
+    (void)input;
+    (void)sz;
+
+    if (ssl->encrypt.setup == 0) {
+        WOLFSSL_MSG("Encrypt ciphers not setup");
+        return ENCRYPT_ERROR;
+    }
+
+#ifdef HAVE_FUZZER
+    if (ssl->fuzzerCb)
+        ssl->fuzzerCb(ssl, input, sz, FUZZ_ENCRYPT, ssl->fuzzerCtx);
+#endif
+
+    switch (ssl->specs.bulk_cipher_algorithm) {
+        #ifdef BUILD_ARC4
+            case wolfssl_rc4:
+                wc_Arc4Process(ssl->encrypt.arc4, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_DES3
+            case wolfssl_triple_des:
+                ret = wc_Des3_CbcEncrypt(ssl->encrypt.des3, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_AES
+            case wolfssl_aes:
+                ret = wc_AesCbcEncrypt(ssl->encrypt.aes, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_AESGCM
+            case wolfssl_aes_gcm:
+                {
+                    byte additional[AEAD_AUTH_DATA_SZ];
+                    byte nonce[AEAD_NONCE_SZ];
+                    const byte* additionalSrc = input - 5;
+
+                    XMEMSET(additional, 0, AEAD_AUTH_DATA_SZ);
+
+                    /* sequence number field is 64-bits, we only use 32-bits */
+                    c32toa(GetSEQIncrement(ssl, 0),
+                                            additional + AEAD_SEQ_OFFSET);
+
+                    /* Store the type, version. Unfortunately, they are in
+                     * the input buffer ahead of the plaintext. */
+                    #ifdef WOLFSSL_DTLS
+                        if (ssl->options.dtls) {
+                            c16toa(ssl->keys.dtls_epoch, additional);
+                            additionalSrc -= DTLS_HANDSHAKE_EXTRA;
+                        }
+                    #endif
+                    XMEMCPY(additional + AEAD_TYPE_OFFSET, additionalSrc, 3);
+
+                    /* Store the length of the plain text minus the explicit
+                     * IV length minus the authentication tag size. */
+                    c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
+                                                additional + AEAD_LEN_OFFSET);
+                    XMEMCPY(nonce,
+                                 ssl->keys.aead_enc_imp_IV, AEAD_IMP_IV_SZ);
+                    XMEMCPY(nonce + AEAD_IMP_IV_SZ,
+                                     ssl->keys.aead_exp_IV, AEAD_EXP_IV_SZ);
+                    ret = wc_AesGcmEncrypt(ssl->encrypt.aes,
+                                 out + AEAD_EXP_IV_SZ, input + AEAD_EXP_IV_SZ,
+                                 sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
+                                 nonce, AEAD_NONCE_SZ,
+                                 out + sz - ssl->specs.aead_mac_size,
+                                 ssl->specs.aead_mac_size,
+                                 additional, AEAD_AUTH_DATA_SZ);
+                    if (ret == 0)
+                        AeadIncrementExpIV(ssl);
+                    ForceZero(nonce, AEAD_NONCE_SZ);
+                }
+                break;
+        #endif
+
+        #ifdef HAVE_AESCCM
+            case wolfssl_aes_ccm:
+                {
+                    byte additional[AEAD_AUTH_DATA_SZ];
+                    byte nonce[AEAD_NONCE_SZ];
+                    const byte* additionalSrc = input - 5;
+
+                    XMEMSET(additional, 0, AEAD_AUTH_DATA_SZ);
+
+                    /* sequence number field is 64-bits, we only use 32-bits */
+                    c32toa(GetSEQIncrement(ssl, 0),
+                                            additional + AEAD_SEQ_OFFSET);
+
+                    /* Store the type, version. Unfortunately, they are in
+                     * the input buffer ahead of the plaintext. */
+                    #ifdef WOLFSSL_DTLS
+                        if (ssl->options.dtls) {
+                            c16toa(ssl->keys.dtls_epoch, additional);
+                            additionalSrc -= DTLS_HANDSHAKE_EXTRA;
+                        }
+                    #endif
+                    XMEMCPY(additional + AEAD_TYPE_OFFSET, additionalSrc, 3);
+
+                    /* Store the length of the plain text minus the explicit
+                     * IV length minus the authentication tag size. */
+                    c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
+                                                additional + AEAD_LEN_OFFSET);
+                    XMEMCPY(nonce,
+                                 ssl->keys.aead_enc_imp_IV, AEAD_IMP_IV_SZ);
+                    XMEMCPY(nonce + AEAD_IMP_IV_SZ,
+                                     ssl->keys.aead_exp_IV, AEAD_EXP_IV_SZ);
+                    wc_AesCcmEncrypt(ssl->encrypt.aes,
+                        out + AEAD_EXP_IV_SZ, input + AEAD_EXP_IV_SZ,
+                            sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
+                        nonce, AEAD_NONCE_SZ,
+                        out + sz - ssl->specs.aead_mac_size,
+                        ssl->specs.aead_mac_size,
+                        additional, AEAD_AUTH_DATA_SZ);
+                    AeadIncrementExpIV(ssl);
+                    ForceZero(nonce, AEAD_NONCE_SZ);
+                }
+                break;
+        #endif
+
+        #ifdef HAVE_CAMELLIA
+            case wolfssl_camellia:
+                wc_CamelliaCbcEncrypt(ssl->encrypt.cam, out, input, sz);
+                break;
+        #endif
+
+        #ifdef HAVE_HC128
+            case wolfssl_hc128:
+                ret = wc_Hc128_Process(ssl->encrypt.hc128, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_RABBIT
+            case wolfssl_rabbit:
+                ret = wc_RabbitProcess(ssl->encrypt.rabbit, out, input, sz);
+                break;
+        #endif
+
+        #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
+            case wolfssl_chacha:
+                ret = ChachaAEADEncrypt(ssl, out, input, sz);
+                break;
+        #endif
+
+        #ifdef HAVE_NULL_CIPHER
+            case wolfssl_cipher_null:
+                if (input != out) {
+                    XMEMMOVE(out, input, sz);
+                }
+                break;
+        #endif
+
+            default:
+                WOLFSSL_MSG("wolfSSL Encrypt programming error");
+                ret = ENCRYPT_ERROR;
+    }
+
+    return ret;
+}
+
+
+
+static INLINE int Decrypt(WOLFSSL* ssl, byte* plain, const byte* input,
+                           word16 sz)
+{
+    int ret = 0;
+
+    (void)plain;
+    (void)input;
+    (void)sz;
+
+    if (ssl->decrypt.setup == 0) {
+        WOLFSSL_MSG("Decrypt ciphers not setup");
+        return DECRYPT_ERROR;
+    }
+
+    switch (ssl->specs.bulk_cipher_algorithm) {
+        #ifdef BUILD_ARC4
+            case wolfssl_rc4:
+                wc_Arc4Process(ssl->decrypt.arc4, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_DES3
+            case wolfssl_triple_des:
+                ret = wc_Des3_CbcDecrypt(ssl->decrypt.des3, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_AES
+            case wolfssl_aes:
+                ret = wc_AesCbcDecrypt(ssl->decrypt.aes, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_AESGCM
+            case wolfssl_aes_gcm:
+            {
+                byte additional[AEAD_AUTH_DATA_SZ];
+                byte nonce[AEAD_NONCE_SZ];
+
+                XMEMSET(additional, 0, AEAD_AUTH_DATA_SZ);
+
+                /* sequence number field is 64-bits, we only use 32-bits */
+                c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET);
+
+                #ifdef WOLFSSL_DTLS
+                    if (ssl->options.dtls)
+                        c16toa(ssl->keys.dtls_state.curEpoch, additional);
+                #endif
+
+                additional[AEAD_TYPE_OFFSET] = ssl->curRL.type;
+                additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor;
+                additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor;
+
+                c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
+                                        additional + AEAD_LEN_OFFSET);
+                XMEMCPY(nonce, ssl->keys.aead_dec_imp_IV, AEAD_IMP_IV_SZ);
+                XMEMCPY(nonce + AEAD_IMP_IV_SZ, input, AEAD_EXP_IV_SZ);
+                if (wc_AesGcmDecrypt(ssl->decrypt.aes,
+                            plain + AEAD_EXP_IV_SZ,
+                            input + AEAD_EXP_IV_SZ,
+                                sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
+                            nonce, AEAD_NONCE_SZ,
+                            input + sz - ssl->specs.aead_mac_size,
+                            ssl->specs.aead_mac_size,
+                            additional, AEAD_AUTH_DATA_SZ) < 0) {
+                    SendAlert(ssl, alert_fatal, bad_record_mac);
+                    ret = VERIFY_MAC_ERROR;
+                }
+                ForceZero(nonce, AEAD_NONCE_SZ);
+            }
+            break;
+        #endif
+
+        #ifdef HAVE_AESCCM
+            case wolfssl_aes_ccm:
+            {
+                byte additional[AEAD_AUTH_DATA_SZ];
+                byte nonce[AEAD_NONCE_SZ];
+
+                XMEMSET(additional, 0, AEAD_AUTH_DATA_SZ);
+
+                /* sequence number field is 64-bits, we only use 32-bits */
+                c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET);
+
+                #ifdef WOLFSSL_DTLS
+                    if (ssl->options.dtls)
+                        c16toa(ssl->keys.dtls_state.curEpoch, additional);
+                #endif
+
+                additional[AEAD_TYPE_OFFSET] = ssl->curRL.type;
+                additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor;
+                additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor;
+
+                c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
+                                        additional + AEAD_LEN_OFFSET);
+                XMEMCPY(nonce, ssl->keys.aead_dec_imp_IV, AEAD_IMP_IV_SZ);
+                XMEMCPY(nonce + AEAD_IMP_IV_SZ, input, AEAD_EXP_IV_SZ);
+                if (wc_AesCcmDecrypt(ssl->decrypt.aes,
+                            plain + AEAD_EXP_IV_SZ,
+                            input + AEAD_EXP_IV_SZ,
+                                sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
+                            nonce, AEAD_NONCE_SZ,
+                            input + sz - ssl->specs.aead_mac_size,
+                            ssl->specs.aead_mac_size,
+                            additional, AEAD_AUTH_DATA_SZ) < 0) {
+                    SendAlert(ssl, alert_fatal, bad_record_mac);
+                    ret = VERIFY_MAC_ERROR;
+                }
+                ForceZero(nonce, AEAD_NONCE_SZ);
+            }
+            break;
+        #endif
+
+        #ifdef HAVE_CAMELLIA
+            case wolfssl_camellia:
+                wc_CamelliaCbcDecrypt(ssl->decrypt.cam, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef HAVE_HC128
+            case wolfssl_hc128:
+                ret = wc_Hc128_Process(ssl->decrypt.hc128, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_RABBIT
+            case wolfssl_rabbit:
+                ret = wc_RabbitProcess(ssl->decrypt.rabbit, plain, input, sz);
+                break;
+        #endif
+
+        #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
+            case wolfssl_chacha:
+                ret = ChachaAEADDecrypt(ssl, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef HAVE_NULL_CIPHER
+            case wolfssl_cipher_null:
+                if (input != plain) {
+                    XMEMMOVE(plain, input, sz);
+                }
+                break;
+        #endif
+
+            default:
+                WOLFSSL_MSG("wolfSSL Decrypt programming error");
+                ret = DECRYPT_ERROR;
+    }
+
+    return ret;
+}
+
+
+/* check cipher text size for sanity */
+static int SanityCheckCipherText(WOLFSSL* ssl, word32 encryptSz)
+{
+#ifdef HAVE_TRUNCATED_HMAC
+    word32 minLength = ssl->truncated_hmac ? TRUNCATED_HMAC_SZ
+                                           : ssl->specs.hash_size;
+#else
+    word32 minLength = ssl->specs.hash_size; /* covers stream */
+#endif
+
+    if (ssl->specs.cipher_type == block) {
+        if (encryptSz % ssl->specs.block_size) {
+            WOLFSSL_MSG("Block ciphertext not block size");
+            return SANITY_CIPHER_E;
+        }
+
+        minLength++;  /* pad byte */
+
+        if (ssl->specs.block_size > minLength)
+            minLength = ssl->specs.block_size;
+
+        if (ssl->options.tls1_1)
+            minLength += ssl->specs.block_size;  /* explicit IV */
+    }
+    else if (ssl->specs.cipher_type == aead) {
+        minLength = ssl->specs.aead_mac_size;    /* authTag size */
+        if (ssl->specs.bulk_cipher_algorithm != wolfssl_chacha)
+           minLength += AEAD_EXP_IV_SZ;          /* explicit IV  */
+    }
+
+    if (encryptSz < minLength) {
+        WOLFSSL_MSG("Ciphertext not minimum size");
+        return SANITY_CIPHER_E;
+    }
+
+    return 0;
+}
+
+
+#ifndef NO_OLD_TLS
+
+static INLINE void Md5Rounds(int rounds, const byte* data, int sz)
+{
+    Md5 md5;
+    int i;
+
+    wc_InitMd5(&md5);
+
+    for (i = 0; i < rounds; i++)
+        wc_Md5Update(&md5, data, sz);
+}
+
+
+
+/* do a dummy sha round */
+static INLINE void ShaRounds(int rounds, const byte* data, int sz)
+{
+    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);
+}
+#endif
+
+
+#ifndef NO_SHA256
+
+static INLINE void Sha256Rounds(int rounds, const byte* data, int sz)
+{
+    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 */
+    }
+
+}
+
+#endif
+
+
+#ifdef WOLFSSL_SHA384
+
+static INLINE void Sha384Rounds(int rounds, const byte* data, int sz)
+{
+    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 */
+    }
+}
+
+#endif
+
+
+#ifdef WOLFSSL_SHA512
+
+static INLINE void Sha512Rounds(int rounds, const byte* data, int sz)
+{
+    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 */
+    }
+}
+
+#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)
+{
+    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);
+}
+
+
+/* check all length bytes for the pad value, return 0 on success */
+static int PadCheck(const byte* a, byte pad, int length)
+{
+    int i;
+    int compareSum = 0;
+
+    for (i = 0; i < length; i++) {
+        compareSum |= a[i] ^ pad;
+    }
+
+    return compareSum;
+}
+
+
+/* get compression extra rounds */
+static INLINE int GetRounds(int pLen, int padLen, int t)
+{
+    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;
+}
+
+
+/* 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)
+{
+    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;
+    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;
+    }
+
+    if (ret != 0)
+        return VERIFY_MAC_ERROR;
+    return 0;
+}
+
+
+int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx)
+{
+    word32 msgSz   = ssl->keys.encryptSz;
+    word32 idx     = *inOutIdx;
+    int    dataSz;
+    int    ivExtra = 0;
+    byte*  rawData = input + idx;  /* keep current  for hmac */
+#ifdef HAVE_LIBZ
+    byte   decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
+#endif
+
+    if (ssl->options.handShakeDone == 0) {
+        WOLFSSL_MSG("Received App data before a handshake completed");
+        SendAlert(ssl, alert_fatal, unexpected_message);
+        return OUT_OF_ORDER_E;
+    }
+
+    if (ssl->specs.cipher_type == block) {
+        if (ssl->options.tls1_1)
+            ivExtra = ssl->specs.block_size;
+    }
+    else if (ssl->specs.cipher_type == aead) {
+        if (ssl->specs.bulk_cipher_algorithm != wolfssl_chacha)
+            ivExtra = AEAD_EXP_IV_SZ;
+    }
+
+    dataSz = msgSz - ivExtra - ssl->keys.padSz;
+    if (dataSz < 0) {
+        WOLFSSL_MSG("App data buffer error, malicious input?");
+        return BUFFER_ERROR;
+    }
+
+    /* read data */
+    if (dataSz) {
+        int rawSz = dataSz;       /* keep raw size for idx adjustment */
+
+#ifdef HAVE_LIBZ
+        if (ssl->options.usingCompression) {
+            dataSz = myDeCompress(ssl, rawData, dataSz, decomp, sizeof(decomp));
+            if (dataSz < 0) return dataSz;
+        }
+#endif
+        idx += rawSz;
+
+        ssl->buffers.clearOutputBuffer.buffer = rawData;
+        ssl->buffers.clearOutputBuffer.length = dataSz;
+    }
+
+    idx += ssl->keys.padSz;
+
+#ifdef HAVE_LIBZ
+    /* decompress could be bigger, overwrite after verify */
+    if (ssl->options.usingCompression)
+        XMEMMOVE(rawData, decomp, dataSz);
+#endif
+
+    *inOutIdx = idx;
+    return 0;
+}
+
+
+/* process alert, return level */
+static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type,
+                   word32 totalSz)
+{
+    byte level;
+    byte code;
+
+    #ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("Alert", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            /* add record header back on to info + 2 byte level, data */
+            AddPacketInfo("Alert", &ssl->timeoutInfo, input + *inOutIdx -
+                          RECORD_HEADER_SZ, 2 + RECORD_HEADER_SZ, ssl->heap);
+    #endif
+
+    /* make sure can read the message */
+    if (*inOutIdx + ALERT_SIZE > totalSz)
+        return BUFFER_E;
+
+    level = input[(*inOutIdx)++];
+    code  = input[(*inOutIdx)++];
+    ssl->alert_history.last_rx.code = code;
+    ssl->alert_history.last_rx.level = level;
+    *type = code;
+    if (level == alert_fatal) {
+        ssl->options.isClosed = 1;  /* Don't send close_notify */
+    }
+
+    WOLFSSL_MSG("Got alert");
+    if (*type == close_notify) {
+        WOLFSSL_MSG("    close notify");
+        ssl->options.closeNotify = 1;
+    }
+    WOLFSSL_ERROR(*type);
+    if (ssl->keys.encryptionOn) {
+        if (*inOutIdx + ssl->keys.padSz > totalSz)
+            return BUFFER_E;
+        *inOutIdx += ssl->keys.padSz;
+    }
+
+    return level;
+}
+
+static int GetInputData(WOLFSSL *ssl, word32 size)
+{
+    int in;
+    int inSz;
+    int maxLength;
+    int usedLength;
+    int dtlsExtra = 0;
+
+
+    /* check max input length */
+    usedLength = ssl->buffers.inputBuffer.length - ssl->buffers.inputBuffer.idx;
+    maxLength  = ssl->buffers.inputBuffer.bufferSize - usedLength;
+    inSz       = (int)(size - usedLength);      /* from last partial read */
+
+#ifdef WOLFSSL_DTLS
+    if (ssl->options.dtls) {
+        if (size < ssl->dtls_expected_rx)
+            dtlsExtra = (int)(ssl->dtls_expected_rx - size);
+        inSz = ssl->dtls_expected_rx;
+    }
+#endif
+
+    if (inSz > maxLength) {
+        if (GrowInputBuffer(ssl, size + dtlsExtra, usedLength) < 0)
+            return MEMORY_E;
+    }
+
+    if (inSz <= 0)
+        return BUFFER_ERROR;
+
+    /* Put buffer data at start if not there */
+    if (usedLength > 0 && ssl->buffers.inputBuffer.idx != 0)
+        XMEMMOVE(ssl->buffers.inputBuffer.buffer,
+                ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx,
+                usedLength);
+
+    /* remove processed data */
+    ssl->buffers.inputBuffer.idx    = 0;
+    ssl->buffers.inputBuffer.length = usedLength;
+
+    /* read data from network */
+    do {
+        in = Receive(ssl,
+                     ssl->buffers.inputBuffer.buffer +
+                     ssl->buffers.inputBuffer.length,
+                     inSz);
+        if (in == -1)
+            return SOCKET_ERROR_E;
+
+        if (in == WANT_READ)
+            return WANT_READ;
+
+        if (in > inSz)
+            return RECV_OVERFLOW_E;
+
+        ssl->buffers.inputBuffer.length += in;
+        inSz -= in;
+
+    } while (ssl->buffers.inputBuffer.length < size);
+
+    return 0;
+}
+
+
+static INLINE int VerifyMac(WOLFSSL* ssl, const byte* input, word32 msgSz,
+                            int content, word32* padSz)
+{
+    int    ivExtra = 0;
+    int    ret;
+    word32 pad     = 0;
+    word32 padByte = 0;
+#ifdef HAVE_TRUNCATED_HMAC
+    word32 digestSz = ssl->truncated_hmac ? TRUNCATED_HMAC_SZ
+                                          : ssl->specs.hash_size;
+#else
+    word32 digestSz = ssl->specs.hash_size;
+#endif
+    byte   verify[MAX_DIGEST_SIZE];
+
+    if (ssl->specs.cipher_type == block) {
+        if (ssl->options.tls1_1)
+            ivExtra = ssl->specs.block_size;
+        pad = *(input + msgSz - ivExtra - 1);
+        padByte = 1;
+
+        if (ssl->options.tls) {
+            ret = TimingPadVerify(ssl, input, pad, digestSz, msgSz - ivExtra,
+                                  content);
+            if (ret != 0)
+                return ret;
+        }
+        else {  /* sslv3, some implementations have bad padding, but don't
+                 * allow bad read */
+            int  badPadLen = 0;
+            byte dmy[sizeof(WOLFSSL) >= MAX_PAD_SIZE ? 1 : MAX_PAD_SIZE] = {0};
+            byte* dummy = sizeof(dmy) < MAX_PAD_SIZE ? (byte*) ssl : dmy;
+
+            (void)dmy;
+
+            if (pad > (msgSz - digestSz - 1)) {
+                WOLFSSL_MSG("Plain Len not long enough for pad/mac");
+                pad       = 0;  /* no bad read */
+                badPadLen = 1;
+            }
+            PadCheck(dummy, (byte)pad, MAX_PAD_SIZE);  /* timing only */
+            ret = ssl->hmac(ssl, verify, input, msgSz - digestSz - pad - 1,
+                            content, 1);
+            if (ConstantCompare(verify, input + msgSz - digestSz - pad - 1,
+                                digestSz) != 0)
+                return VERIFY_MAC_ERROR;
+            if (ret != 0 || badPadLen)
+                return VERIFY_MAC_ERROR;
+        }
+    }
+    else if (ssl->specs.cipher_type == stream) {
+        ret = ssl->hmac(ssl, verify, input, msgSz - digestSz, content, 1);
+        if (ConstantCompare(verify, input + msgSz - digestSz, digestSz) != 0){
+            return VERIFY_MAC_ERROR;
+        }
+        if (ret != 0)
+            return VERIFY_MAC_ERROR;
+    }
+
+    if (ssl->specs.cipher_type == aead) {
+        *padSz = ssl->specs.aead_mac_size;
+    }
+    else {
+        *padSz = digestSz + pad + padByte;
+    }
+
+    return 0;
+}
+
+
+/* process input requests, return 0 is done, 1 is call again to complete, and
+   negative number is error */
+int ProcessReply(WOLFSSL* ssl)
+{
+    int    ret = 0, type, readSz;
+    int    atomicUser = 0;
+    word32 startIdx = 0;
+#ifdef WOLFSSL_DTLS
+    int    used;
+#endif
+
+#ifdef ATOMIC_USER
+    if (ssl->ctx->DecryptVerifyCb)
+        atomicUser = 1;
+#endif
+
+    if (ssl->error != 0 && ssl->error != WANT_READ && ssl->error != WANT_WRITE){
+        WOLFSSL_MSG("ProcessReply retry in error state, not allowed");
+        return ssl->error;
+    }
+
+    for (;;) {
+        switch (ssl->options.processReply) {
+
+        /* in the WOLFSSL_SERVER case, get the first byte for detecting
+         * old client hello */
+        case doProcessInit:
+
+            readSz = RECORD_HEADER_SZ;
+
+            #ifdef WOLFSSL_DTLS
+                if (ssl->options.dtls)
+                    readSz = DTLS_RECORD_HEADER_SZ;
+            #endif
+
+            /* get header or return error */
+            if (!ssl->options.dtls) {
+                if ((ret = GetInputData(ssl, readSz)) < 0)
+                    return ret;
+            } else {
+            #ifdef WOLFSSL_DTLS
+                /* read ahead may already have header */
+                used = ssl->buffers.inputBuffer.length -
+                       ssl->buffers.inputBuffer.idx;
+                if (used < readSz)
+                    if ((ret = GetInputData(ssl, readSz)) < 0)
+                        return ret;
+            #endif
+            }
+
+#ifdef OLD_HELLO_ALLOWED
+
+            /* see if sending SSLv2 client hello */
+            if ( ssl->options.side == WOLFSSL_SERVER_END &&
+                 ssl->options.clientState == NULL_STATE &&
+                 ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx]
+                         != handshake) {
+                byte b0, b1;
+
+                ssl->options.processReply = runProcessOldClientHello;
+
+                /* sanity checks before getting size at front */
+                if (ssl->buffers.inputBuffer.buffer[
+                          ssl->buffers.inputBuffer.idx + 2] != OLD_HELLO_ID) {
+                    WOLFSSL_MSG("Not a valid old client hello");
+                    return PARSE_ERROR;
+                }
+
+                if (ssl->buffers.inputBuffer.buffer[
+                          ssl->buffers.inputBuffer.idx + 3] != SSLv3_MAJOR &&
+                    ssl->buffers.inputBuffer.buffer[
+                          ssl->buffers.inputBuffer.idx + 3] != DTLS_MAJOR) {
+                    WOLFSSL_MSG("Not a valid version in old client hello");
+                    return PARSE_ERROR;
+                }
+
+                /* how many bytes need ProcessOldClientHello */
+                b0 =
+                ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++];
+                b1 =
+                ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++];
+                ssl->curSize = (word16)(((b0 & 0x7f) << 8) | b1);
+            }
+            else {
+                ssl->options.processReply = getRecordLayerHeader;
+                continue;
+            }
+
+        /* in the WOLFSSL_SERVER case, run the old client hello */
+        case runProcessOldClientHello:
+
+            /* get sz bytes or return error */
+            if (!ssl->options.dtls) {
+                if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
+                    return ret;
+            } else {
+            #ifdef WOLFSSL_DTLS
+                /* read ahead may already have */
+                used = ssl->buffers.inputBuffer.length -
+                       ssl->buffers.inputBuffer.idx;
+                if (used < ssl->curSize)
+                    if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
+                        return ret;
+            #endif  /* WOLFSSL_DTLS */
+            }
+
+            ret = ProcessOldClientHello(ssl, ssl->buffers.inputBuffer.buffer,
+                                        &ssl->buffers.inputBuffer.idx,
+                                        ssl->buffers.inputBuffer.length -
+                                        ssl->buffers.inputBuffer.idx,
+                                        ssl->curSize);
+            if (ret < 0)
+                return ret;
+
+            else if (ssl->buffers.inputBuffer.idx ==
+                     ssl->buffers.inputBuffer.length) {
+                ssl->options.processReply = doProcessInit;
+                return 0;
+            }
+
+#endif  /* OLD_HELLO_ALLOWED */
+
+        /* get the record layer header */
+        case getRecordLayerHeader:
+
+            ret = GetRecordHeader(ssl, ssl->buffers.inputBuffer.buffer,
+                                       &ssl->buffers.inputBuffer.idx,
+                                       &ssl->curRL, &ssl->curSize);
+#ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls && ret == SEQUENCE_ERROR) {
+                ssl->options.processReply = doProcessInit;
+                ssl->buffers.inputBuffer.length = 0;
+                ssl->buffers.inputBuffer.idx = 0;
+                continue;
+            }
+#endif
+            if (ret != 0)
+                return ret;
+
+            ssl->options.processReply = getData;
+
+        /* retrieve record layer data */
+        case getData:
+
+            /* get sz bytes or return error */
+            if (!ssl->options.dtls) {
+                if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
+                    return ret;
+            } else {
+#ifdef WOLFSSL_DTLS
+                /* read ahead may already have */
+                used = ssl->buffers.inputBuffer.length -
+                       ssl->buffers.inputBuffer.idx;
+                if (used < ssl->curSize)
+                    if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
+                        return ret;
+#endif
+            }
+
+            ssl->options.processReply = runProcessingOneMessage;
+            startIdx = ssl->buffers.inputBuffer.idx;  /* in case > 1 msg per */
+
+        /* the record layer is here */
+        case runProcessingOneMessage:
+
+            #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls &&
+                ssl->keys.dtls_state.curEpoch < ssl->keys.dtls_state.nextEpoch)
+                ssl->keys.decryptedCur = 1;
+            #endif
+
+            if (ssl->keys.encryptionOn && ssl->keys.decryptedCur == 0)
+            {
+                ret = SanityCheckCipherText(ssl, ssl->curSize);
+                if (ret < 0)
+                    return ret;
+
+                if (atomicUser) {
+                #ifdef ATOMIC_USER
+                    ret = ssl->ctx->DecryptVerifyCb(ssl,
+                                  ssl->buffers.inputBuffer.buffer +
+                                  ssl->buffers.inputBuffer.idx,
+                                  ssl->buffers.inputBuffer.buffer +
+                                  ssl->buffers.inputBuffer.idx,
+                                  ssl->curSize, ssl->curRL.type, 1,
+                                  &ssl->keys.padSz, ssl->DecryptVerifyCtx);
+                    if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
+                        ssl->buffers.inputBuffer.idx += ssl->specs.block_size;
+                        /* go past TLSv1.1 IV */
+                    if (ssl->specs.cipher_type == aead &&
+                            ssl->specs.bulk_cipher_algorithm != wolfssl_chacha)
+                        ssl->buffers.inputBuffer.idx += AEAD_EXP_IV_SZ;
+                #endif /* ATOMIC_USER */
+                }
+                else {
+                    ret = Decrypt(ssl, ssl->buffers.inputBuffer.buffer +
+                                  ssl->buffers.inputBuffer.idx,
+                                  ssl->buffers.inputBuffer.buffer +
+                                  ssl->buffers.inputBuffer.idx,
+                                  ssl->curSize);
+                    if (ret < 0) {
+                        WOLFSSL_ERROR(ret);
+                        return DECRYPT_ERROR;
+                    }
+                    if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
+                        ssl->buffers.inputBuffer.idx += ssl->specs.block_size;
+                        /* go past TLSv1.1 IV */
+                    if (ssl->specs.cipher_type == aead &&
+                            ssl->specs.bulk_cipher_algorithm != wolfssl_chacha)
+                        ssl->buffers.inputBuffer.idx += AEAD_EXP_IV_SZ;
+
+                    ret = VerifyMac(ssl, ssl->buffers.inputBuffer.buffer +
+                                    ssl->buffers.inputBuffer.idx,
+                                    ssl->curSize, ssl->curRL.type,
+                                    &ssl->keys.padSz);
+                }
+                if (ret < 0) {
+                    WOLFSSL_ERROR(ret);
+                    return DECRYPT_ERROR;
+                }
+                ssl->keys.encryptSz    = ssl->curSize;
+                ssl->keys.decryptedCur = 1;
+            }
+
+            if (ssl->options.dtls) {
+            #ifdef WOLFSSL_DTLS
+                DtlsUpdateWindow(&ssl->keys.dtls_state);
+            #endif /* WOLFSSL_DTLS */
+            }
+
+            WOLFSSL_MSG("received record layer msg");
+
+            switch (ssl->curRL.type) {
+                case handshake :
+                    /* debugging in DoHandShakeMsg */
+                    if (!ssl->options.dtls) {
+                        ret = DoHandShakeMsg(ssl,
+                                            ssl->buffers.inputBuffer.buffer,
+                                            &ssl->buffers.inputBuffer.idx,
+                                            ssl->buffers.inputBuffer.length);
+                    }
+                    else {
+#ifdef WOLFSSL_DTLS
+                        ret = DoDtlsHandShakeMsg(ssl,
+                                            ssl->buffers.inputBuffer.buffer,
+                                            &ssl->buffers.inputBuffer.idx,
+                                            ssl->buffers.inputBuffer.length);
+#endif
+                    }
+                    if (ret != 0)
+                        return ret;
+                    break;
+
+                case change_cipher_spec:
+                    WOLFSSL_MSG("got CHANGE CIPHER SPEC");
+                    #ifdef WOLFSSL_CALLBACKS
+                        if (ssl->hsInfoOn)
+                            AddPacketName("ChangeCipher", &ssl->handShakeInfo);
+                        /* add record header back on info */
+                        if (ssl->toInfoOn) {
+                            AddPacketInfo("ChangeCipher", &ssl->timeoutInfo,
+                                ssl->buffers.inputBuffer.buffer +
+                                ssl->buffers.inputBuffer.idx - RECORD_HEADER_SZ,
+                                1 + RECORD_HEADER_SZ, ssl->heap);
+                            AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo);
+                        }
+                    #endif
+
+                    ret = SanityCheckMsgReceived(ssl, change_cipher_hs);
+                    if (ret != 0)
+                        return ret;
+
+#ifdef HAVE_SESSION_TICKET
+                    if (ssl->options.side == WOLFSSL_CLIENT_END &&
+                                                  ssl->expect_session_ticket) {
+                        WOLFSSL_MSG("Expected session ticket missing");
+                        return SESSION_TICKET_EXPECT_E;
+                    }
+#endif
+
+                    if (ssl->keys.encryptionOn && ssl->options.handShakeDone) {
+                        ssl->buffers.inputBuffer.idx += ssl->keys.padSz;
+                        ssl->curSize -= (word16) ssl->buffers.inputBuffer.idx;
+                    }
+
+                    if (ssl->curSize != 1) {
+                        WOLFSSL_MSG("Malicious or corrupted ChangeCipher msg");
+                        return LENGTH_ERROR;
+                    }
+                    #ifndef NO_CERTS
+                        if (ssl->options.side == WOLFSSL_SERVER_END &&
+                                 ssl->options.verifyPeer &&
+                                 ssl->options.havePeerCert)
+                            if (!ssl->options.havePeerVerify) {
+                                WOLFSSL_MSG("client didn't send cert verify");
+                                return NO_PEER_VERIFY;
+                            }
+                    #endif
+
+
+                    ssl->buffers.inputBuffer.idx++;
+                    ssl->keys.encryptionOn = 1;
+
+                    /* setup decrypt keys for following messages */
+                    if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0)
+                        return ret;
+
+                    #ifdef WOLFSSL_DTLS
+                        if (ssl->options.dtls) {
+                            DtlsPoolReset(ssl);
+                            ssl->keys.dtls_state.nextEpoch++;
+                            ssl->keys.dtls_state.nextSeq = 0;
+                        }
+                    #endif
+
+                    #ifdef HAVE_LIBZ
+                        if (ssl->options.usingCompression)
+                            if ( (ret = InitStreams(ssl)) != 0)
+                                return ret;
+                    #endif
+                    ret = BuildFinished(ssl, &ssl->hsHashes->verifyHashes,
+                                       ssl->options.side == WOLFSSL_CLIENT_END ?
+                                       server : client);
+                    if (ret != 0)
+                        return ret;
+                    break;
+
+                case application_data:
+                    WOLFSSL_MSG("got app DATA");
+                    if ((ret = DoApplicationData(ssl,
+                                                ssl->buffers.inputBuffer.buffer,
+                                               &ssl->buffers.inputBuffer.idx))
+                                                                         != 0) {
+                        WOLFSSL_ERROR(ret);
+                        return ret;
+                    }
+                    break;
+
+                case alert:
+                    WOLFSSL_MSG("got ALERT!");
+                    ret = DoAlert(ssl, ssl->buffers.inputBuffer.buffer,
+                                  &ssl->buffers.inputBuffer.idx, &type,
+                                   ssl->buffers.inputBuffer.length);
+                    if (ret == alert_fatal)
+                        return FATAL_ERROR;
+                    else if (ret < 0)
+                        return ret;
+
+                    /* catch warnings that are handled as errors */
+                    if (type == close_notify)
+                        return ssl->error = ZERO_RETURN;
+
+                    if (type == decrypt_error)
+                        return FATAL_ERROR;
+                    break;
+
+                default:
+                    WOLFSSL_ERROR(UNKNOWN_RECORD_TYPE);
+                    return UNKNOWN_RECORD_TYPE;
+            }
+
+            ssl->options.processReply = doProcessInit;
+
+            /* input exhausted? */
+            if (ssl->buffers.inputBuffer.idx == ssl->buffers.inputBuffer.length)
+                return 0;
+
+            /* more messages per record */
+            else if ((ssl->buffers.inputBuffer.idx - startIdx) < ssl->curSize) {
+                WOLFSSL_MSG("More messages in record");
+                #ifdef WOLFSSL_DTLS
+                    /* read-ahead but dtls doesn't bundle messages per record */
+                    if (ssl->options.dtls) {
+                        ssl->options.processReply = doProcessInit;
+                        continue;
+                    }
+                #endif
+                ssl->options.processReply = runProcessingOneMessage;
+
+                if (ssl->keys.encryptionOn) {
+                    WOLFSSL_MSG("Bundled encrypted messages, remove middle pad");
+                    ssl->buffers.inputBuffer.idx -= ssl->keys.padSz;
+                }
+
+                continue;
+            }
+            /* more records */
+            else {
+                WOLFSSL_MSG("More records in input");
+                ssl->options.processReply = doProcessInit;
+                continue;
+            }
+
+        default:
+            WOLFSSL_MSG("Bad process input state, programming error");
+            return INPUT_CASE_ERROR;
+        }
+    }
+}
+
+
+int SendChangeCipher(WOLFSSL* ssl)
+{
+    byte              *output;
+    int                sendSz = RECORD_HEADER_SZ + ENUM_LEN;
+    int                idx    = RECORD_HEADER_SZ;
+    int                ret;
+
+    #ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls) {
+            sendSz += DTLS_RECORD_EXTRA;
+            idx    += DTLS_RECORD_EXTRA;
+        }
+    #endif
+
+    /* are we in scr */
+    if (ssl->keys.encryptionOn && ssl->options.handShakeDone) {
+        sendSz += MAX_MSG_EXTRA;
+    }
+
+    /* check for avalaible size */
+    if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
+        return ret;
+
+    /* get ouput buffer */
+    output = ssl->buffers.outputBuffer.buffer +
+             ssl->buffers.outputBuffer.length;
+
+    AddRecordHeader(output, 1, change_cipher_spec, ssl);
+
+    output[idx] = 1;             /* turn it on */
+
+    if (ssl->keys.encryptionOn && ssl->options.handShakeDone) {
+        byte input[ENUM_LEN];
+        int  inputSz = ENUM_LEN;
+
+        input[0] = 1;  /* turn it on */
+        sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
+                              change_cipher_spec);
+        if (sendSz < 0)
+            return sendSz;
+    }
+
+    #ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls) {
+            if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                return ret;
+        }
+    #endif
+    #ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("ChangeCipher", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("ChangeCipher", &ssl->timeoutInfo, output, sendSz,
+                           ssl->heap);
+    #endif
+    ssl->buffers.outputBuffer.length += sendSz;
+
+    if (ssl->options.groupMessages)
+        return 0;
+    #ifdef WOLFSSL_DTLS
+    else if (ssl->options.dtls) {
+        /* If using DTLS, force the ChangeCipherSpec message to be in the
+         * same datagram as the finished message. */
+        return 0;
+    }
+    #endif
+    else
+        return SendBuffered(ssl);
+}
+
+
+#ifndef NO_OLD_TLS
+static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
+                 int content, int verify)
+{
+    byte   result[MAX_DIGEST_SIZE];
+    word32 digestSz = ssl->specs.hash_size;            /* actual sizes */
+    word32 padSz    = ssl->specs.pad_size;
+    int    ret      = 0;
+
+    Md5 md5;
+    Sha sha;
+
+    /* data */
+    byte seq[SEQ_SZ];
+    byte conLen[ENUM_LEN + LENGTH_SZ];     /* content & length */
+    const byte* macSecret = wolfSSL_GetMacSecret(ssl, verify);
+
+#ifdef HAVE_FUZZER
+    if (ssl->fuzzerCb)
+        ssl->fuzzerCb(ssl, in, sz, FUZZ_HMAC, ssl->fuzzerCtx);
+#endif
+
+    XMEMSET(seq, 0, SEQ_SZ);
+    conLen[0] = (byte)content;
+    c16toa((word16)sz, &conLen[ENUM_LEN]);
+    c32toa(GetSEQIncrement(ssl, verify), &seq[sizeof(word32)]);
+
+    if (ssl->specs.mac_algorithm == md5_mac) {
+        wc_InitMd5(&md5);
+        /* inner */
+        wc_Md5Update(&md5, macSecret, digestSz);
+        wc_Md5Update(&md5, PAD1, padSz);
+        wc_Md5Update(&md5, seq, SEQ_SZ);
+        wc_Md5Update(&md5, conLen, sizeof(conLen));
+        /* in buffer */
+        wc_Md5Update(&md5, in, sz);
+        wc_Md5Final(&md5, result);
+        /* outer */
+        wc_Md5Update(&md5, macSecret, digestSz);
+        wc_Md5Update(&md5, PAD2, padSz);
+        wc_Md5Update(&md5, result, digestSz);
+        wc_Md5Final(&md5, digest);
+    }
+    else {
+        ret = wc_InitSha(&sha);
+        if (ret != 0)
+            return ret;
+        /* inner */
+        wc_ShaUpdate(&sha, macSecret, digestSz);
+        wc_ShaUpdate(&sha, PAD1, padSz);
+        wc_ShaUpdate(&sha, seq, SEQ_SZ);
+        wc_ShaUpdate(&sha, conLen, sizeof(conLen));
+        /* in buffer */
+        wc_ShaUpdate(&sha, in, sz);
+        wc_ShaFinal(&sha, result);
+        /* outer */
+        wc_ShaUpdate(&sha, macSecret, digestSz);
+        wc_ShaUpdate(&sha, PAD2, padSz);
+        wc_ShaUpdate(&sha, result, digestSz);
+        wc_ShaFinal(&sha, digest);
+    }
+    return 0;
+}
+
+#ifndef NO_CERTS
+static void BuildMD5_CertVerify(WOLFSSL* ssl, byte* digest)
+{
+    byte md5_result[MD5_DIGEST_SIZE];
+
+#ifdef WOLFSSL_SMALL_STACK
+        Md5* md5   = (Md5*)XMALLOC(sizeof(Md5), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        Md5* md5_2 = (Md5*)XMALLOC(sizeof(Md5), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#else
+        Md5 md5[1];
+        Md5 md5_2[1];
+#endif
+
+    /* make md5 inner */
+    md5[0] = ssl->hsHashes->hashMd5 ; /* Save current position */
+    wc_Md5Update(&ssl->hsHashes->hashMd5, ssl->arrays->masterSecret,SECRET_LEN);
+    wc_Md5Update(&ssl->hsHashes->hashMd5, PAD1, PAD_MD5);
+    wc_Md5GetHash(&ssl->hsHashes->hashMd5, md5_result);
+    wc_Md5RestorePos(&ssl->hsHashes->hashMd5, md5) ; /* Restore current position */
+
+    /* make md5 outer */
+    wc_InitMd5(md5_2) ;
+    wc_Md5Update(md5_2, ssl->arrays->masterSecret, SECRET_LEN);
+    wc_Md5Update(md5_2, PAD2, PAD_MD5);
+    wc_Md5Update(md5_2, md5_result, MD5_DIGEST_SIZE);
+
+    wc_Md5Final(md5_2, digest);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(md5_2, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+}
+
+
+static void BuildSHA_CertVerify(WOLFSSL* ssl, byte* digest)
+{
+    byte sha_result[SHA_DIGEST_SIZE];
+
+#ifdef WOLFSSL_SMALL_STACK
+        Sha* sha   = (Sha*)XMALLOC(sizeof(Sha), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        Sha* sha2 = (Sha*)XMALLOC(sizeof(Sha), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#else
+        Sha sha[1];
+        Sha sha2[1];
+#endif
+
+    /* make sha inner */
+    sha[0] = ssl->hsHashes->hashSha ; /* Save current position */
+    wc_ShaUpdate(&ssl->hsHashes->hashSha, ssl->arrays->masterSecret,SECRET_LEN);
+    wc_ShaUpdate(&ssl->hsHashes->hashSha, PAD1, PAD_SHA);
+    wc_ShaGetHash(&ssl->hsHashes->hashSha, sha_result);
+    wc_ShaRestorePos(&ssl->hsHashes->hashSha, sha) ; /* Restore current position */
+
+    /* make sha outer */
+    wc_InitSha(sha2) ;
+    wc_ShaUpdate(sha2, ssl->arrays->masterSecret,SECRET_LEN);
+    wc_ShaUpdate(sha2, PAD2, PAD_SHA);
+    wc_ShaUpdate(sha2, sha_result, SHA_DIGEST_SIZE);
+
+    wc_ShaFinal(sha2, digest);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(sha2, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+}
+#endif /* NO_CERTS */
+#endif /* NO_OLD_TLS */
+
+
+#ifndef NO_CERTS
+
+static int BuildCertHashes(WOLFSSL* ssl, Hashes* hashes)
+{
+    /* store current states, building requires get_digest which resets state */
+    #ifdef WOLFSSL_SHA384
+        Sha384 sha384 = ssl->hsHashes->hashSha384;
+    #endif
+    #ifdef WOLFSSL_SHA512
+        Sha512 sha512 = ssl->hsHashes->hashSha512;
+    #endif
+
+    if (ssl->options.tls) {
+#if ! defined( NO_OLD_TLS )
+        wc_Md5GetHash(&ssl->hsHashes->hashMd5, hashes->md5);
+        wc_ShaGetHash(&ssl->hsHashes->hashSha, hashes->sha);
+#endif
+        if (IsAtLeastTLSv1_2(ssl)) {
+            int ret;
+
+            #ifndef NO_SHA256
+                ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256,hashes->sha256);
+                if (ret != 0)
+                    return ret;
+            #endif
+            #ifdef WOLFSSL_SHA384
+                ret = wc_Sha384Final(&ssl->hsHashes->hashSha384,hashes->sha384);
+                if (ret != 0)
+                    return ret;
+            #endif
+            #ifdef WOLFSSL_SHA512
+                ret = wc_Sha512Final(&ssl->hsHashes->hashSha512,hashes->sha512);
+                if (ret != 0)
+                    return ret;
+            #endif
+        }
+    }
+#if ! defined( NO_OLD_TLS )
+    else {
+        BuildMD5_CertVerify(ssl, hashes->md5);
+        BuildSHA_CertVerify(ssl, hashes->sha);
+    }
+
+    /* restore */
+#endif
+    if (IsAtLeastTLSv1_2(ssl)) {
+        #ifdef WOLFSSL_SHA384
+            ssl->hsHashes->hashSha384 = sha384;
+        #endif
+        #ifdef WOLFSSL_SHA512
+            ssl->hsHashes->hashSha512 = sha512;
+        #endif
+    }
+
+    return 0;
+}
+
+#endif /* WOLFSSL_LEANPSK */
+
+/* Build SSL Message, encrypted */
+static int BuildMessage(WOLFSSL* ssl, byte* output, int outSz,
+                        const byte* input, int inSz, int type)
+{
+#ifdef HAVE_TRUNCATED_HMAC
+    word32 digestSz = min(ssl->specs.hash_size,
+                ssl->truncated_hmac ? TRUNCATED_HMAC_SZ : ssl->specs.hash_size);
+#else
+    word32 digestSz = ssl->specs.hash_size;
+#endif
+    word32 sz = RECORD_HEADER_SZ + inSz + digestSz;
+    word32 pad  = 0, i;
+    word32 idx  = RECORD_HEADER_SZ;
+    word32 ivSz = 0;      /* TLSv1.1  IV */
+    word32 headerSz = RECORD_HEADER_SZ;
+    word16 size;
+    byte               iv[AES_BLOCK_SIZE];                  /* max size */
+    int ret        = 0;
+    int atomicUser = 0;
+
+#ifdef WOLFSSL_DTLS
+    if (ssl->options.dtls) {
+        sz       += DTLS_RECORD_EXTRA;
+        idx      += DTLS_RECORD_EXTRA;
+        headerSz += DTLS_RECORD_EXTRA;
+    }
+#endif
+
+#ifdef ATOMIC_USER
+    if (ssl->ctx->MacEncryptCb)
+        atomicUser = 1;
+#endif
+
+    if (ssl->specs.cipher_type == block) {
+        word32 blockSz = ssl->specs.block_size;
+        if (ssl->options.tls1_1) {
+            ivSz = blockSz;
+            sz  += ivSz;
+
+            if (ivSz > (word32)sizeof(iv))
+                return BUFFER_E;
+
+            ret = wc_RNG_GenerateBlock(ssl->rng, iv, ivSz);
+            if (ret != 0)
+                return ret;
+
+        }
+        sz += 1;       /* pad byte */
+        pad = (sz - headerSz) % blockSz;
+        pad = blockSz - pad;
+        sz += pad;
+    }
+
+#ifdef HAVE_AEAD
+    if (ssl->specs.cipher_type == aead) {
+        if (ssl->specs.bulk_cipher_algorithm != wolfssl_chacha)
+            ivSz = AEAD_EXP_IV_SZ;
+
+        sz += (ivSz + ssl->specs.aead_mac_size - digestSz);
+        XMEMCPY(iv, ssl->keys.aead_exp_IV, AEAD_EXP_IV_SZ);
+    }
+#endif
+    if (sz > (word32)outSz) {
+        WOLFSSL_MSG("Oops, want to write past output buffer size");
+        return BUFFER_E;
+    }
+    size = (word16)(sz - headerSz);    /* include mac and digest */
+    AddRecordHeader(output, size, (byte)type, ssl);
+
+    /* write to output */
+    if (ivSz) {
+        XMEMCPY(output + idx, iv, min(ivSz, sizeof(iv)));
+        idx += ivSz;
+    }
+    XMEMCPY(output + idx, input, inSz);
+    idx += inSz;
+
+    if (type == handshake) {
+        ret = HashOutput(ssl, output, headerSz + inSz, ivSz);
+        if (ret != 0)
+            return ret;
+    }
+
+    if (ssl->specs.cipher_type == block) {
+        word32 tmpIdx = idx + digestSz;
+
+        for (i = 0; i <= pad; i++)
+            output[tmpIdx++] = (byte)pad; /* pad byte gets pad value too */
+    }
+
+    if (atomicUser) {   /* User Record Layer Callback handling */
+#ifdef ATOMIC_USER
+        if ( (ret = ssl->ctx->MacEncryptCb(ssl, output + idx,
+                        output + headerSz + ivSz, inSz, type, 0,
+                        output + headerSz, output + headerSz, size,
+                        ssl->MacEncryptCtx)) != 0)
+            return ret;
+#endif
+    }
+    else {
+        if (ssl->specs.cipher_type != aead) {
+#ifdef HAVE_TRUNCATED_HMAC
+            if (ssl->truncated_hmac && ssl->specs.hash_size > digestSz) {
+            #ifdef WOLFSSL_SMALL_STACK
+                byte* hmac = NULL;
+            #else
+                byte  hmac[MAX_DIGEST_SIZE];
+            #endif
+
+            #ifdef WOLFSSL_SMALL_STACK
+                hmac = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                if (hmac == NULL)
+                    return MEMORY_E;
+            #endif
+
+                ret = ssl->hmac(ssl, hmac, output + headerSz + ivSz, inSz,
+                                                                       type, 0);
+                XMEMCPY(output + idx, hmac, digestSz);
+
+            #ifdef WOLFSSL_SMALL_STACK
+                XFREE(hmac, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            #endif
+            } else
+#endif
+                ret = ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz,
+                                                                       type, 0);
+        }
+        if (ret != 0)
+            return ret;
+
+        if ( (ret = Encrypt(ssl, output + headerSz, output+headerSz,size)) != 0)
+            return ret;
+    }
+
+    return sz;
+}
+
+
+int SendFinished(WOLFSSL* ssl)
+{
+    int              sendSz,
+                     finishedSz = ssl->options.tls ? TLS_FINISHED_SZ :
+                                                     FINISHED_SZ;
+    byte             input[FINISHED_SZ + DTLS_HANDSHAKE_HEADER_SZ];  /* max */
+    byte            *output;
+    Hashes*          hashes;
+    int              ret;
+    int              headerSz = HANDSHAKE_HEADER_SZ;
+    int              outputSz;
+
+    #ifdef WOLFSSL_DTLS
+        word32 sequence_number = ssl->keys.dtls_sequence_number;
+        word16 epoch           = ssl->keys.dtls_epoch;
+    #endif
+
+    /* setup encrypt keys */
+    if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0)
+        return ret;
+
+    /* check for available size */
+    outputSz = sizeof(input) + MAX_MSG_EXTRA;
+    if ((ret = CheckAvailableSize(ssl, outputSz)) != 0)
+        return ret;
+
+    #ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls) {
+            /* Send Finished message with the next epoch, but don't commit that
+             * change until the other end confirms its reception. */
+            headerSz += DTLS_HANDSHAKE_EXTRA;
+            ssl->keys.dtls_epoch++;
+            ssl->keys.dtls_sequence_number = 0;  /* reset after epoch change */
+        }
+    #endif
+
+    /* get ouput buffer */
+    output = ssl->buffers.outputBuffer.buffer +
+             ssl->buffers.outputBuffer.length;
+
+    AddHandShakeHeader(input, finishedSz, finished, ssl);
+
+    /* make finished hashes */
+    hashes = (Hashes*)&input[headerSz];
+    ret = BuildFinished(ssl, hashes,
+                     ssl->options.side == WOLFSSL_CLIENT_END ? client : server);
+    if (ret != 0) return ret;
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+    if (ssl->secure_renegotiation) {
+        if (ssl->options.side == WOLFSSL_CLIENT_END)
+            XMEMCPY(ssl->secure_renegotiation->client_verify_data, hashes,
+                    TLS_FINISHED_SZ);
+        else
+            XMEMCPY(ssl->secure_renegotiation->server_verify_data, hashes,
+                    TLS_FINISHED_SZ);
+    }
+#endif
+
+    sendSz = BuildMessage(ssl, output, outputSz, input, headerSz + finishedSz,
+                          handshake);
+    if (sendSz < 0)
+        return BUILD_MSG_ERROR;
+
+    #ifdef WOLFSSL_DTLS
+    if (ssl->options.dtls) {
+        ssl->keys.dtls_epoch = epoch;
+        ssl->keys.dtls_sequence_number = sequence_number;
+    }
+    #endif
+
+    if (!ssl->options.resuming) {
+#ifndef NO_SESSION_CACHE
+        AddSession(ssl);    /* just try */
+#endif
+        if (ssl->options.side == WOLFSSL_SERVER_END) {
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+            ssl->options.handShakeDone  = 1;
+            #ifdef WOLFSSL_DTLS
+                if (ssl->options.dtls) {
+                    /* Other side will soon receive our Finished, go to next
+                     * epoch. */
+                    ssl->keys.dtls_epoch++;
+                    ssl->keys.dtls_sequence_number = 1;
+                }
+            #endif
+        }
+    }
+    else {
+        if (ssl->options.side == WOLFSSL_CLIENT_END) {
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+            ssl->options.handShakeDone  = 1;
+            #ifdef WOLFSSL_DTLS
+                if (ssl->options.dtls) {
+                    /* Other side will soon receive our Finished, go to next
+                     * epoch. */
+                    ssl->keys.dtls_epoch++;
+                    ssl->keys.dtls_sequence_number = 1;
+                }
+            #endif
+        }
+    }
+    #ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls) {
+            if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                return ret;
+        }
+    #endif
+
+    #ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("Finished", &ssl->timeoutInfo, output, sendSz,
+                          ssl->heap);
+    #endif
+
+    ssl->buffers.outputBuffer.length += sendSz;
+
+    return SendBuffered(ssl);
+}
+
+#ifndef NO_CERTS
+int SendCertificate(WOLFSSL* ssl)
+{
+    int    sendSz, length, ret = 0;
+    word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+    word32 certSz, listSz;
+    byte*  output = 0;
+
+    if (ssl->options.usingPSK_cipher || ssl->options.usingAnon_cipher)
+        return 0;  /* not needed */
+
+    if (ssl->options.sendVerify == SEND_BLANK_CERT) {
+        certSz = 0;
+        length = CERT_HEADER_SZ;
+        listSz = 0;
+    }
+    else {
+        certSz = ssl->buffers.certificate.length;
+        /* list + cert size */
+        length = certSz + 2 * CERT_HEADER_SZ;
+        listSz = certSz + CERT_HEADER_SZ;
+
+        /* may need to send rest of chain, already has leading size(s) */
+        if (ssl->buffers.certChain.buffer) {
+            length += ssl->buffers.certChain.length;
+            listSz += ssl->buffers.certChain.length;
+        }
+    }
+    sendSz = length + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+
+    #ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls) {
+            sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+            i      += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+        }
+    #endif
+
+    if (ssl->keys.encryptionOn)
+        sendSz += MAX_MSG_EXTRA;
+
+    /* check for available size */
+    if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
+        return ret;
+
+    /* get ouput buffer */
+    output = ssl->buffers.outputBuffer.buffer +
+             ssl->buffers.outputBuffer.length;
+
+    AddHeaders(output, length, certificate, ssl);
+
+    /* list total */
+    c32to24(listSz, output + i);
+    i += CERT_HEADER_SZ;
+
+    /* member */
+    if (certSz) {
+        c32to24(certSz, output + i);
+        i += CERT_HEADER_SZ;
+        XMEMCPY(output + i, ssl->buffers.certificate.buffer, certSz);
+        i += certSz;
+
+        /* send rest of chain? */
+        if (ssl->buffers.certChain.buffer) {
+            XMEMCPY(output + i, ssl->buffers.certChain.buffer,
+                                ssl->buffers.certChain.length);
+            i += ssl->buffers.certChain.length;
+        }
+    }
+
+    if (ssl->keys.encryptionOn) {
+        byte* input;
+        int   inputSz = i - RECORD_HEADER_SZ; /* build msg adds rec hdr */
+
+        input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+        if (input == NULL)
+            return MEMORY_E;
+
+        XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
+        sendSz = BuildMessage(ssl, output, sendSz, input,inputSz,handshake);
+        XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+
+        if (sendSz < 0)
+            return sendSz;
+    } else {
+        ret = HashOutput(ssl, output, sendSz, 0);
+        if (ret != 0)
+            return ret;
+    }
+
+    #ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls) {
+            if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                return ret;
+        }
+    #endif
+
+    #ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz,
+                           ssl->heap);
+    #endif
+
+    if (ssl->options.side == WOLFSSL_SERVER_END)
+        ssl->options.serverState = SERVER_CERT_COMPLETE;
+
+    ssl->buffers.outputBuffer.length += sendSz;
+    if (ssl->options.groupMessages)
+        return 0;
+    else
+        return SendBuffered(ssl);
+}
+
+
+int SendCertificateRequest(WOLFSSL* ssl)
+{
+    byte   *output;
+    int    ret;
+    int    sendSz;
+    word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+
+    int  typeTotal = 1;  /* only 1 for now */
+    int  reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ;  /* add auth later */
+
+    if (IsAtLeastTLSv1_2(ssl))
+        reqSz += LENGTH_SZ + ssl->suites->hashSigAlgoSz;
+
+    if (ssl->options.usingPSK_cipher || ssl->options.usingAnon_cipher)
+        return 0;  /* not needed */
+
+    sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz;
+
+    #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)
+        return ret;
+
+    /* get ouput buffer */
+    output = ssl->buffers.outputBuffer.buffer +
+             ssl->buffers.outputBuffer.length;
+
+    AddHeaders(output, reqSz, certificate_request, ssl);
+
+    /* write to output */
+    output[i++] = (byte)typeTotal;  /* # of types */
+#ifdef HAVE_ECC
+    if (ssl->options.cipherSuite0 == ECC_BYTE &&
+                     ssl->specs.sig_algo == ecc_dsa_sa_algo) {
+        output[i++] = ecdsa_sign;
+    } else
+#endif /* HAVE_ECC */
+    {
+        output[i++] = rsa_sign;
+    }
+
+    /* supported hash/sig */
+    if (IsAtLeastTLSv1_2(ssl)) {
+        c16toa(ssl->suites->hashSigAlgoSz, &output[i]);
+        i += LENGTH_SZ;
+
+        XMEMCPY(&output[i],
+                         ssl->suites->hashSigAlgo, ssl->suites->hashSigAlgoSz);
+        i += ssl->suites->hashSigAlgoSz;
+    }
+
+    c16toa(0, &output[i]);  /* auth's */
+    /* if add more to output, adjust i
+    i += REQ_HEADER_SZ; */
+
+    #ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls) {
+            if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                return ret;
+        }
+    #endif
+
+    ret = HashOutput(ssl, output, sendSz, 0);
+    if (ret != 0)
+        return ret;
+
+    #ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("CertificateRequest", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("CertificateRequest", &ssl->timeoutInfo, output,
+                          sendSz, ssl->heap);
+    #endif
+    ssl->buffers.outputBuffer.length += sendSz;
+    if (ssl->options.groupMessages)
+        return 0;
+    else
+        return SendBuffered(ssl);
+}
+#endif /* !NO_CERTS */
+
+
+int SendData(WOLFSSL* ssl, const void* data, int sz)
+{
+    int sent = 0,  /* plainText size */
+        sendSz,
+        ret,
+        dtlsExtra = 0;
+
+    if (ssl->error == WANT_WRITE)
+        ssl->error = 0;
+
+    if (ssl->options.handShakeState != HANDSHAKE_DONE) {
+        int err;
+        WOLFSSL_MSG("handshake not complete, trying to finish");
+        if ( (err = wolfSSL_negotiate(ssl)) != SSL_SUCCESS)
+            return  err;
+    }
+
+    /* last time system socket output buffer was full, try again to send */
+    if (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 */
+            return ssl->error;
+        }
+        else {
+            /* advance sent to previous sent + plain size just sent */
+            sent = ssl->buffers.prevSent + ssl->buffers.plainSz;
+            WOLFSSL_MSG("sent write buffered data");
+
+            if (sent > sz) {
+                WOLFSSL_MSG("error: write() after WANT_WRITE with short size");
+                return ssl->error = BAD_FUNC_ARG;
+            }
+        }
+    }
+
+#ifdef WOLFSSL_DTLS
+    if (ssl->options.dtls) {
+        dtlsExtra = DTLS_RECORD_EXTRA;
+    }
+#endif
+
+    for (;;) {
+#ifdef HAVE_MAX_FRAGMENT
+        int   len = min(sz - sent, min(ssl->max_fragment, OUTPUT_RECORD_SIZE));
+#else
+        int   len = min(sz - sent, OUTPUT_RECORD_SIZE);
+#endif
+        byte* out;
+        byte* sendBuffer = (byte*)data + sent;  /* may switch on comp */
+        int   buffSz = len;                     /* may switch on comp */
+        int   outputSz;
+#ifdef HAVE_LIBZ
+        byte  comp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
+#endif
+
+        if (sent == sz) break;
+
+#ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls) {
+            len    = min(len, MAX_UDP_SIZE);
+            buffSz = len;
+        }
+#endif
+
+        /* check for available size */
+        outputSz = len + COMP_EXTRA + dtlsExtra + MAX_MSG_EXTRA;
+        if ((ret = CheckAvailableSize(ssl, outputSz)) != 0)
+            return ssl->error = ret;
+
+        /* get ouput buffer */
+        out = ssl->buffers.outputBuffer.buffer +
+              ssl->buffers.outputBuffer.length;
+
+#ifdef HAVE_LIBZ
+        if (ssl->options.usingCompression) {
+            buffSz = myCompress(ssl, sendBuffer, buffSz, comp, sizeof(comp));
+            if (buffSz < 0) {
+                return buffSz;
+            }
+            sendBuffer = comp;
+        }
+#endif
+        sendSz = BuildMessage(ssl, out, outputSz, sendBuffer, buffSz,
+                              application_data);
+        if (sendSz < 0)
+            return BUILD_MSG_ERROR;
+
+        ssl->buffers.outputBuffer.length += sendSz;
+
+        if ( (ret = SendBuffered(ssl)) < 0) {
+            WOLFSSL_ERROR(ret);
+            /* 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;
+        }
+
+        sent += len;
+
+        /* only one message per attempt */
+        if (ssl->options.partialWrite == 1) {
+            WOLFSSL_MSG("Paritial Write on, only sending one record");
+            break;
+        }
+    }
+
+    return sent;
+}
+
+/* process input data */
+int ReceiveData(WOLFSSL* ssl, byte* output, int sz, int peek)
+{
+    int size;
+
+    WOLFSSL_ENTER("ReceiveData()");
+
+    if (ssl->error == WANT_READ)
+        ssl->error = 0;
+
+    if (ssl->error != 0 && ssl->error != WANT_WRITE) {
+        WOLFSSL_MSG("User calling wolfSSL_read in error state, not allowed");
+        return ssl->error;
+    }
+
+    if (ssl->options.handShakeState != HANDSHAKE_DONE) {
+        int err;
+        WOLFSSL_MSG("Handshake not complete, trying to finish");
+        if ( (err = wolfSSL_negotiate(ssl)) != SSL_SUCCESS)
+            return  err;
+    }
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+startScr:
+    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)) != SSL_SUCCESS)
+            return  err;
+    }
+#endif
+
+    while (ssl->buffers.clearOutputBuffer.length == 0) {
+        if ( (ssl->error = ProcessReply(ssl)) < 0) {
+            WOLFSSL_ERROR(ssl->error);
+            if (ssl->error == ZERO_RETURN) {
+                WOLFSSL_MSG("Zero return, no more data coming");
+                return 0;         /* no more data coming */
+            }
+            if (ssl->error == SOCKET_ERROR_E) {
+                if (ssl->options.connReset || ssl->options.isClosed) {
+                    WOLFSSL_MSG("Peer reset or closed, connection done");
+                    ssl->error = SOCKET_PEER_CLOSED_E;
+                    WOLFSSL_ERROR(ssl->error);
+                    return 0;     /* peer reset or closed */
+                }
+            }
+            return ssl->error;
+        }
+        #ifdef HAVE_SECURE_RENEGOTIATION
+            if (ssl->secure_renegotiation &&
+                ssl->secure_renegotiation->startScr) {
+                goto startScr;
+            }
+        #endif
+    }
+
+    if (sz < (int)ssl->buffers.clearOutputBuffer.length)
+        size = sz;
+    else
+        size = ssl->buffers.clearOutputBuffer.length;
+
+    XMEMCPY(output, ssl->buffers.clearOutputBuffer.buffer, size);
+
+    if (peek == 0) {
+        ssl->buffers.clearOutputBuffer.length -= size;
+        ssl->buffers.clearOutputBuffer.buffer += size;
+    }
+
+    if (ssl->buffers.clearOutputBuffer.length == 0 &&
+                                           ssl->buffers.inputBuffer.dynamicFlag)
+       ShrinkInputBuffer(ssl, NO_FORCED_FREE);
+
+    WOLFSSL_LEAVE("ReceiveData()", size);
+    return size;
+}
+
+
+/* send alert message */
+int SendAlert(WOLFSSL* ssl, int severity, int type)
+{
+    byte input[ALERT_SIZE];
+    byte *output;
+    int  sendSz;
+    int  ret;
+    int  outputSz;
+    int  dtlsExtra = 0;
+
+    /* if sendalert is called again for nonbloking */
+    if (ssl->options.sendAlertState != 0) {
+        ret = SendBuffered(ssl);
+        if (ret == 0)
+            ssl->options.sendAlertState = 0;
+        return ret;
+    }
+
+   #ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls)
+           dtlsExtra = DTLS_RECORD_EXTRA;
+   #endif
+
+    /* check for available size */
+    outputSz = ALERT_SIZE + MAX_MSG_EXTRA + dtlsExtra;
+    if ((ret = CheckAvailableSize(ssl, outputSz)) != 0)
+        return ret;
+
+    /* get ouput buffer */
+    output = ssl->buffers.outputBuffer.buffer +
+             ssl->buffers.outputBuffer.length;
+
+    input[0] = (byte)severity;
+    input[1] = (byte)type;
+    ssl->alert_history.last_tx.code = type;
+    ssl->alert_history.last_tx.level = severity;
+    if (severity == alert_fatal) {
+        ssl->options.isClosed = 1;  /* Don't send close_notify */
+    }
+
+    /* only send encrypted alert if handshake actually complete, otherwise
+       other side may not be able to handle it */
+    if (ssl->keys.encryptionOn && ssl->options.handShakeDone)
+        sendSz = BuildMessage(ssl, output, outputSz, input, ALERT_SIZE, alert);
+    else {
+
+        AddRecordHeader(output, ALERT_SIZE, alert, ssl);
+        output += RECORD_HEADER_SZ;
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls)
+                output += DTLS_RECORD_EXTRA;
+        #endif
+        XMEMCPY(output, input, ALERT_SIZE);
+
+        sendSz = RECORD_HEADER_SZ + ALERT_SIZE;
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls)
+                sendSz += DTLS_RECORD_EXTRA;
+        #endif
+    }
+    if (sendSz < 0)
+        return BUILD_MSG_ERROR;
+
+    #ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("Alert", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("Alert", &ssl->timeoutInfo, output, sendSz,ssl->heap);
+    #endif
+
+    ssl->buffers.outputBuffer.length += sendSz;
+    ssl->options.sendAlertState = 1;
+
+    return SendBuffered(ssl);
+}
+
+const char* wolfSSL_ERR_reason_error_string(unsigned long e)
+{
+#ifdef NO_ERROR_STRINGS
+
+    (void)e;
+    return "no support for error strings built in";
+
+#else
+
+    int error = (int)e;
+
+    /* pass to wolfCrypt */
+    if (error < MAX_CODE_E && error > MIN_CODE_E) {
+        return wc_GetErrorString(error);
+    }
+
+    switch (error) {
+
+    case UNSUPPORTED_SUITE :
+        return "unsupported cipher suite";
+
+    case INPUT_CASE_ERROR :
+        return "input state error";
+
+    case PREFIX_ERROR :
+        return "bad index to key rounds";
+
+    case MEMORY_ERROR :
+        return "out of memory";
+
+    case VERIFY_FINISHED_ERROR :
+        return "verify problem on finished";
+
+    case VERIFY_MAC_ERROR :
+        return "verify mac problem";
+
+    case PARSE_ERROR :
+        return "parse error on header";
+
+    case SIDE_ERROR :
+        return "wrong client/server type";
+
+    case NO_PEER_CERT :
+        return "peer didn't send cert";
+
+    case UNKNOWN_HANDSHAKE_TYPE :
+        return "weird handshake type";
+
+    case SOCKET_ERROR_E :
+        return "error state on socket";
+
+    case SOCKET_NODATA :
+        return "expected data, not there";
+
+    case INCOMPLETE_DATA :
+        return "don't have enough data to complete task";
+
+    case UNKNOWN_RECORD_TYPE :
+        return "unknown type in record hdr";
+
+    case DECRYPT_ERROR :
+        return "error during decryption";
+
+    case FATAL_ERROR :
+        return "revcd alert fatal error";
+
+    case ENCRYPT_ERROR :
+        return "error during encryption";
+
+    case FREAD_ERROR :
+        return "fread problem";
+
+    case NO_PEER_KEY :
+        return "need peer's key";
+
+    case NO_PRIVATE_KEY :
+        return "need the private key";
+
+    case NO_DH_PARAMS :
+        return "server missing DH params";
+
+    case RSA_PRIVATE_ERROR :
+        return "error during rsa priv op";
+
+    case MATCH_SUITE_ERROR :
+        return "can't match cipher suite";
+
+    case BUILD_MSG_ERROR :
+        return "build message failure";
+
+    case BAD_HELLO :
+        return "client hello malformed";
+
+    case DOMAIN_NAME_MISMATCH :
+        return "peer subject name mismatch";
+
+    case WANT_READ :
+    case SSL_ERROR_WANT_READ :
+        return "non-blocking socket wants data to be read";
+
+    case NOT_READY_ERROR :
+        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";
+
+    case WANT_WRITE :
+    case SSL_ERROR_WANT_WRITE :
+        return "non-blocking socket write buffer full";
+
+    case BUFFER_ERROR :
+        return "malformed buffer input error";
+
+    case VERIFY_CERT_ERROR :
+        return "verify problem on certificate";
+
+    case VERIFY_SIGN_ERROR :
+        return "verify problem based on signature";
+
+    case CLIENT_ID_ERROR :
+        return "psk client identity error";
+
+    case SERVER_HINT_ERROR:
+        return "psk server hint error";
+
+    case PSK_KEY_ERROR:
+        return "psk key callback error";
+
+    case NTRU_KEY_ERROR:
+        return "NTRU key error";
+
+    case NTRU_DRBG_ERROR:
+        return "NTRU drbg error";
+
+    case NTRU_ENCRYPT_ERROR:
+        return "NTRU encrypt error";
+
+    case NTRU_DECRYPT_ERROR:
+        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";
+
+    case GETITIMER_ERROR:
+        return "getitimer() error";
+
+    case SIGACT_ERROR:
+        return "sigaction() error";
+
+    case SETITIMER_ERROR:
+        return "setitimer() error";
+
+    case LENGTH_ERROR:
+        return "record layer length error";
+
+    case PEER_KEY_ERROR:
+        return "cant decode peer key";
+
+    case ZERO_RETURN:
+    case SSL_ERROR_ZERO_RETURN:
+        return "peer sent close notify alert";
+
+    case ECC_CURVETYPE_ERROR:
+        return "Bad ECC Curve Type or unsupported";
+
+    case ECC_CURVE_ERROR:
+        return "Bad ECC Curve or unsupported";
+
+    case ECC_PEERKEY_ERROR:
+        return "Bad ECC Peer Key";
+
+    case ECC_MAKEKEY_ERROR:
+        return "ECC Make Key failure";
+
+    case ECC_EXPORT_ERROR:
+        return "ECC Export Key failure";
+
+    case ECC_SHARED_ERROR:
+        return "ECC DHE shared failure";
+
+    case NOT_CA_ERROR:
+        return "Not a CA by basic constraint error";
+
+    case BAD_PATH_ERROR:
+        return "Bad path for opendir error";
+
+    case BAD_CERT_MANAGER_ERROR:
+        return "Bad Cert Manager error";
+
+    case OCSP_CERT_REVOKED:
+        return "OCSP Cert revoked";
+
+    case CRL_CERT_REVOKED:
+        return "CRL Cert revoked";
+
+    case CRL_MISSING:
+        return "CRL missing, not loaded";
+
+    case MONITOR_RUNNING_E:
+        return "CRL monitor already running";
+
+    case THREAD_CREATE_E:
+        return "Thread creation problem";
+
+    case OCSP_NEED_URL:
+        return "OCSP need URL";
+
+    case OCSP_CERT_UNKNOWN:
+        return "OCSP Cert unknown";
+
+    case OCSP_LOOKUP_FAIL:
+        return "OCSP Responder lookup fail";
+
+    case MAX_CHAIN_ERROR:
+        return "Maximum Chain Depth Exceeded";
+
+    case COOKIE_ERROR:
+        return "DTLS Cookie Error";
+
+    case SEQUENCE_ERROR:
+        return "DTLS Sequence Error";
+
+    case SUITES_ERROR:
+        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";
+
+    case BAD_KEA_TYPE_E:
+        return "Bad KEA type found";
+
+    case SANITY_CIPHER_E:
+        return "Sanity check on ciphertext failed";
+
+    case RECV_OVERFLOW_E:
+        return "Receive callback returned more than requested";
+
+    case GEN_COOKIE_E:
+        return "Generate Cookie Error";
+
+    case NO_PEER_VERIFY:
+        return "Need peer certificate verify Error";
+
+    case FWRITE_ERROR:
+        return "fwrite Error";
+
+    case CACHE_MATCH_ERROR:
+        return "Cache restore header match Error";
+
+    case UNKNOWN_SNI_HOST_NAME_E:
+        return "Unrecognized host name Error";
+
+    case KEYUSE_SIGNATURE_E:
+        return "Key Use digitalSignature not set Error";
+
+    case KEYUSE_ENCIPHER_E:
+        return "Key Use keyEncipherment not set Error";
+
+    case EXTKEYUSE_AUTH_E:
+        return "Ext Key Use server/client auth not set Error";
+
+    case SEND_OOB_READ_E:
+        return "Send Callback Out of Bounds Read Error";
+
+    case SECURE_RENEGOTIATION_E:
+        return "Invalid Renegotiation Error";
+
+    case SESSION_TICKET_LEN_E:
+        return "Session Ticket Too Long Error";
+
+    case SESSION_TICKET_EXPECT_E:
+        return "Session Ticket Error";
+
+    case SCR_DIFFERENT_CERT_E:
+        return "Peer sent different cert during SCR";
+
+    case SESSION_SECRET_CB_E:
+        return "Session Secret Callback Error";
+
+    case NO_CHANGE_CIPHER_E:
+        return "Finished received from peer before Change Cipher Error";
+
+    case SANITY_MSG_E:
+        return "Sanity Check on message order Error";
+
+    case DUPLICATE_MSG_E:
+        return "Duplicate HandShake message Error";
+
+    case SNI_UNSUPPORTED:
+        return "Protocol version does not support SNI Error";
+
+    case SOCKET_PEER_CLOSED_E:
+        return "Peer closed underlying transport Error";
+
+    case BAD_TICKET_KEY_CB_SZ:
+        return "Bad user session ticket key callback Size Error";
+
+    case BAD_TICKET_MSG_SZ:
+        return "Bad session ticket message Size Error";
+
+    case BAD_TICKET_ENCRYPT:
+        return "Bad user ticket callback encrypt Error";
+
+    case DH_KEY_SIZE_E:
+        return "DH key too small Error";
+
+    default :
+        return "unknown error number";
+    }
+
+#endif /* NO_ERROR_STRINGS */
+}
+
+void SetErrorString(int error, char* str)
+{
+    XSTRNCPY(str, wolfSSL_ERR_reason_error_string(error), WOLFSSL_MAX_ERROR_SZ);
+}
+
+
+/* be sure to add to cipher_name_idx too !!!! */
+static const char* const cipher_names[] =
+{
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
+    "RC4-SHA",
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
+    "RC4-MD5",
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+    "DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+    "AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
+    "AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_NULL_SHA
+    "NULL-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256
+    "NULL-SHA256",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+    "DHE-RSA-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+    "DHE-RSA-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
+    "DHE-PSK-AES256-GCM-SHA384",
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
+    "DHE-PSK-AES128-GCM-SHA256",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_GCM_SHA384
+    "PSK-AES256-GCM-SHA384",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256
+    "PSK-AES128-GCM-SHA256",
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
+    "DHE-PSK-AES256-CBC-SHA384",
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
+    "DHE-PSK-AES128-CBC-SHA256",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA384
+    "PSK-AES256-CBC-SHA384",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256
+    "PSK-AES128-CBC-SHA256",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
+    "PSK-AES128-CBC-SHA",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
+    "PSK-AES256-CBC-SHA",
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CCM
+    "DHE-PSK-AES128-CCM",
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CCM
+    "DHE-PSK-AES256-CCM",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM
+    "PSK-AES128-CCM",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM
+    "PSK-AES256-CCM",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8
+    "PSK-AES128-CCM-8",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8
+    "PSK-AES256-CCM-8",
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA384
+    "DHE-PSK-NULL-SHA384",
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA256
+    "DHE-PSK-NULL-SHA256",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_NULL_SHA384
+    "PSK-NULL-SHA384",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256
+    "PSK-NULL-SHA256",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_NULL_SHA
+    "PSK-NULL-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5
+    "HC128-MD5",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA
+    "HC128-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256
+    "HC128-B2B256",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
+    "AES128-B2B256",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
+    "AES256-B2B256",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA
+    "RABBIT-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+    "NTRU-RC4-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    "NTRU-DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+    "NTRU-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    "NTRU-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8
+    "AES128-CCM-8",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8
+    "AES256-CCM-8",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+    "ECDHE-ECDSA-AES128-CCM-8",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
+    "ECDHE-ECDSA-AES256-CCM-8",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+    "ECDHE-RSA-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+    "ECDHE-RSA-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+    "ECDHE-ECDSA-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+    "ECDHE-ECDSA-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
+    "ECDHE-RSA-RC4-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+    "ECDHE-RSA-DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+    "ECDHE-ECDSA-RC4-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+    "ECDHE-ECDSA-DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256
+    "AES128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256
+    "AES256-SHA256",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
+    "DHE-RSA-AES128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
+    "DHE-RSA-AES256-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
+    "ECDH-RSA-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
+    "ECDH-RSA-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
+    "ECDH-ECDSA-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
+    "ECDH-ECDSA-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA
+    "ECDH-RSA-RC4-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+    "ECDH-RSA-DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
+    "ECDH-ECDSA-RC4-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
+    "ECDH-ECDSA-DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256
+    "AES128-GCM-SHA256",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384
+    "AES256-GCM-SHA384",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+    "DHE-RSA-AES128-GCM-SHA256",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+    "DHE-RSA-AES256-GCM-SHA384",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+    "ECDHE-RSA-AES128-GCM-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+    "ECDHE-RSA-AES256-GCM-SHA384",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+    "ECDHE-ECDSA-AES128-GCM-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+    "ECDHE-ECDSA-AES256-GCM-SHA384",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+    "ECDH-RSA-AES128-GCM-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+    "ECDH-RSA-AES256-GCM-SHA384",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+    "ECDH-ECDSA-AES128-GCM-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+    "ECDH-ECDSA-AES256-GCM-SHA384",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+    "CAMELLIA128-SHA",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+    "DHE-RSA-CAMELLIA128-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
+    "CAMELLIA256-SHA",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+    "DHE-RSA-CAMELLIA256-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
+    "CAMELLIA128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+    "DHE-RSA-CAMELLIA128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
+    "CAMELLIA256-SHA256",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
+    "DHE-RSA-CAMELLIA256-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+    "ECDHE-RSA-AES128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+    "ECDHE-ECDSA-AES128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
+    "ECDH-RSA-AES128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
+    "ECDH-ECDSA-AES128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+    "ECDHE-RSA-AES256-SHA384",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+    "ECDHE-ECDSA-AES256-SHA384",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
+    "ECDH-RSA-AES256-SHA384",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
+    "ECDH-ECDSA-AES256-SHA384",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+    "ECDHE-RSA-CHACHA20-POLY1305",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
+    "ECDHE-ECDSA-CHACHA20-POLY1305",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+    "DHE-RSA-CHACHA20-POLY1305",
+#endif
+
+#ifdef BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA
+    "ADH-AES128-SHA",
+#endif
+
+#ifdef HAVE_RENEGOTIATION_INDICATION
+    "RENEGOTIATION-INFO",
+#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_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_DH_anon_WITH_AES_128_CBC_SHA
+    TLS_DH_anon_WITH_AES_128_CBC_SHA,
+#endif
+
+#ifdef HAVE_RENEGOTIATION_INDICATION
+    TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
+#endif
+};
+
+
+/* returns the cipher_names array */
+const char* const* GetCipherNames(void)
+{
+    return cipher_names;
+}
+
+
+/* returns the size of the cipher_names array */
+int GetCipherNamesSize(void)
+{
+    return (int)(sizeof(cipher_names) / sizeof(char*));
+}
+
+
+/**
+Set the enabled cipher suites.
+
+@param [out] suites Suites structure.
+@param [in]  list   List of cipher suites, only supports full name from
+                    cipher_name[] delimited by ':'.
+
+@return true on success, else false.
+*/
+int SetCipherList(Suites* suites, const char* list)
+{
+    int       ret          = 0;
+    int       idx          = 0;
+    int       haveRSAsig   = 0;
+    int       haveECDSAsig = 0;
+    int       haveAnon     = 0;
+    const int suiteSz      = GetCipherNamesSize();
+    char*     next         = (char*)list;
+
+    if (suites == NULL || list == NULL) {
+        WOLFSSL_MSG("SetCipherList parameter error");
+        return 0;
+    }
+
+    if (next[0] == 0 || XSTRNCMP(next, "ALL", 3) == 0)
+        return 1; /* wolfSSL defualt */
+
+    do {
+        char*  current = next;
+        char   name[MAX_SUITE_NAME + 1];
+        int    i;
+        word32 length;
+
+        next   = XSTRSTR(next, ":");
+        length = min(sizeof(name), !next ? (word32)XSTRLEN(current) /* last */
+                                         : (word32)(next - current));
+
+        XSTRNCPY(name, current, length);
+        name[(length == sizeof(name)) ? length - 1 : length] = 0;
+
+        for (i = 0; i < suiteSz; i++) {
+            if (XSTRNCMP(name, cipher_names[i], sizeof(name)) == 0) {
+                suites->suites[idx++] = (XSTRSTR(name, "CHACHA")) ? CHACHA_BYTE
+                                      : (XSTRSTR(name, "EC"))     ? ECC_BYTE
+                                      : (XSTRSTR(name, "CCM"))    ? ECC_BYTE
+                                      : 0x00; /* normal */
+
+                suites->suites[idx++] = (byte)cipher_name_idx[i];
+
+                /* The suites are either ECDSA, RSA, PSK, or Anon. The RSA
+                 * suites don't necessarily have RSA in the name. */
+                if ((haveECDSAsig == 0) && XSTRSTR(name, "ECDSA"))
+                    haveECDSAsig = 1;
+                else if (XSTRSTR(name, "ADH"))
+                    haveAnon = 1;
+                else if ((haveRSAsig == 0) && (XSTRSTR(name, "PSK") == NULL))
+                    haveRSAsig = 1;
+
+                ret = 1; /* found at least one */
+                break;
+            }
+        }
+    }
+    while (next++); /* ++ needed to skip ':' */
+
+    if (ret) {
+        suites->setSuites = 1;
+        suites->suiteSz   = (word16)idx;
+        InitSuitesHashSigAlgo(suites, haveECDSAsig, haveRSAsig, haveAnon);
+    }
+
+    return ret;
+}
+
+
+static void PickHashSigAlgo(WOLFSSL* ssl,
+                             const byte* hashSigAlgo, word32 hashSigAlgoSz)
+{
+    word32 i;
+
+    ssl->suites->sigAlgo = ssl->specs.sig_algo;
+    ssl->suites->hashAlgo = sha_mac;
+
+    /* i+1 since peek a byte ahead for type */
+    for (i = 0; (i+1) < hashSigAlgoSz; i += 2) {
+        if (hashSigAlgo[i+1] == ssl->specs.sig_algo) {
+            if (hashSigAlgo[i] == sha_mac) {
+                break;
+            }
+            #ifndef NO_SHA256
+            else if (hashSigAlgo[i] == sha256_mac) {
+                ssl->suites->hashAlgo = sha256_mac;
+                break;
+            }
+            #endif
+            #ifdef WOLFSSL_SHA384
+            else if (hashSigAlgo[i] == sha384_mac) {
+                ssl->suites->hashAlgo = sha384_mac;
+                break;
+            }
+            #endif
+            #ifdef WOLFSSL_SHA512
+            else if (hashSigAlgo[i] == sha512_mac) {
+                ssl->suites->hashAlgo = sha512_mac;
+                break;
+            }
+            #endif
+        }
+    }
+}
+
+
+#ifdef WOLFSSL_CALLBACKS
+
+    /* Initialisze HandShakeInfo */
+    void InitHandShakeInfo(HandShakeInfo* info)
+    {
+        int i;
+
+        info->cipherName[0] = 0;
+        for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++)
+            info->packetNames[i][0] = 0;
+        info->numberPackets = 0;
+        info->negotiationError = 0;
+    }
+
+    /* Set Final HandShakeInfo parameters */
+    void FinishHandShakeInfo(HandShakeInfo* info, const WOLFSSL* ssl)
+    {
+        int i;
+        int sz = sizeof(cipher_name_idx)/sizeof(int);
+
+        for (i = 0; i < sz; i++)
+            if (ssl->options.cipherSuite == (byte)cipher_name_idx[i]) {
+                if (ssl->options.cipherSuite0 == ECC_BYTE)
+                    continue;   /* ECC suites at end */
+                XSTRNCPY(info->cipherName, cipher_names[i], MAX_CIPHERNAME_SZ);
+                break;
+            }
+
+        /* error max and min are negative numbers */
+        if (ssl->error <= MIN_PARAM_ERR && ssl->error >= MAX_PARAM_ERR)
+            info->negotiationError = ssl->error;
+    }
+
+
+    /* Add name to info packet names, increase packet name count */
+    void AddPacketName(const char* name, HandShakeInfo* info)
+    {
+        if (info->numberPackets < MAX_PACKETS_HANDSHAKE) {
+            XSTRNCPY(info->packetNames[info->numberPackets++], name,
+                    MAX_PACKETNAME_SZ);
+        }
+    }
+
+
+    /* Initialisze TimeoutInfo */
+    void InitTimeoutInfo(TimeoutInfo* info)
+    {
+        int i;
+
+        info->timeoutName[0] = 0;
+        info->flags          = 0;
+
+        for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) {
+            info->packets[i].packetName[0]     = 0;
+            info->packets[i].timestamp.tv_sec  = 0;
+            info->packets[i].timestamp.tv_usec = 0;
+            info->packets[i].bufferValue       = 0;
+            info->packets[i].valueSz           = 0;
+        }
+        info->numberPackets        = 0;
+        info->timeoutValue.tv_sec  = 0;
+        info->timeoutValue.tv_usec = 0;
+    }
+
+
+    /* Free TimeoutInfo */
+    void FreeTimeoutInfo(TimeoutInfo* info, void* heap)
+    {
+        int i;
+        (void)heap;
+        for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++)
+            if (info->packets[i].bufferValue) {
+                XFREE(info->packets[i].bufferValue, heap, DYNAMIC_TYPE_INFO);
+                info->packets[i].bufferValue = 0;
+            }
+
+    }
+
+
+    /* Add PacketInfo to TimeoutInfo */
+    void AddPacketInfo(const char* name, TimeoutInfo* info, const byte* data,
+                       int sz, void* heap)
+    {
+        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);
+
+            /* add data, put in buffer if bigger than static buffer */
+            info->packets[info->numberPackets].valueSz = sz;
+            if (sz < MAX_VALUE_SZ)
+                XMEMCPY(info->packets[info->numberPackets].value, data, sz);
+            else {
+                info->packets[info->numberPackets].bufferValue =
+                           XMALLOC(sz, heap, DYNAMIC_TYPE_INFO);
+                if (!info->packets[info->numberPackets].bufferValue)
+                    /* let next alloc catch, just don't fill, not fatal here  */
+                    info->packets[info->numberPackets].valueSz = 0;
+                else
+                    XMEMCPY(info->packets[info->numberPackets].bufferValue,
+                           data, sz);
+            }
+            gettimeofday(&currTime, 0);
+            info->packets[info->numberPackets].timestamp.tv_sec  =
+                                                             currTime.tv_sec;
+            info->packets[info->numberPackets].timestamp.tv_usec =
+                                                             currTime.tv_usec;
+            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 */
+
+
+
+/* client only parts */
+#ifndef NO_WOLFSSL_CLIENT
+
+    int SendClientHello(WOLFSSL* ssl)
+    {
+        byte              *output;
+        word32             length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        int                sendSz;
+        int                idSz = ssl->options.resuming
+                                ? ssl->session.sessionIDSz
+                                : 0;
+        int                ret;
+
+        if (ssl->suites == NULL) {
+            WOLFSSL_MSG("Bad suites pointer in SendClientHello");
+            return SUITES_ERROR;
+        }
+
+#ifdef HAVE_SESSION_TICKET
+        if (ssl->options.resuming && ssl->session.ticketLen > 0) {
+            SessionTicket* ticket;
+
+            ticket = TLSX_SessionTicket_Create(0,
+                                   ssl->session.ticket, ssl->session.ticketLen);
+            if (ticket == NULL) return MEMORY_E;
+
+            ret = TLSX_UseSessionTicket(&ssl->extensions, ticket);
+            if (ret != SSL_SUCCESS) return ret;
+
+            idSz = 0;
+        }
+#endif
+
+        length = VERSION_SZ + RAN_LEN
+               + idSz + ENUM_LEN
+               + ssl->suites->suiteSz + SUITE_LEN
+               + COMP_LEN + ENUM_LEN;
+
+#ifdef HAVE_TLS_EXTENSIONS
+        length += TLSX_GetRequestSize(ssl);
+#else
+        if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) {
+            length += ssl->suites->hashSigAlgoSz + HELLO_EXT_SZ;
+        }
+#endif
+        sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+#ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls) {
+            length += ENUM_LEN;   /* cookie */
+            if (ssl->arrays->cookieSz != 0) length += ssl->arrays->cookieSz;
+            sendSz  = length + DTLS_HANDSHAKE_HEADER_SZ + DTLS_RECORD_HEADER_SZ;
+            idx    += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA;
+        }
+#endif
+
+        if (ssl->keys.encryptionOn)
+            sendSz += MAX_MSG_EXTRA;
+
+        /* check for available size */
+        if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.length;
+
+        AddHeaders(output, length, client_hello, ssl);
+
+            /* client hello, first version */
+        output[idx++] = ssl->version.major;
+        output[idx++] = ssl->version.minor;
+        ssl->chVersion = ssl->version;  /* store in case changed */
+
+            /* then random */
+        if (ssl->options.connectState == CONNECT_BEGIN) {
+            ret = wc_RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN);
+            if (ret != 0)
+                return ret;
+
+                /* store random */
+            XMEMCPY(ssl->arrays->clientRandom, output + idx, RAN_LEN);
+        } else {
+#ifdef WOLFSSL_DTLS
+                /* send same random on hello again */
+            XMEMCPY(output + idx, ssl->arrays->clientRandom, RAN_LEN);
+#endif
+        }
+        idx += RAN_LEN;
+
+            /* then session id */
+        output[idx++] = (byte)idSz;
+        if (idSz) {
+            XMEMCPY(output + idx, ssl->session.sessionID,
+                                                      ssl->session.sessionIDSz);
+            idx += ssl->session.sessionIDSz;
+        }
+
+            /* then DTLS cookie */
+#ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls) {
+            byte cookieSz = ssl->arrays->cookieSz;
+
+            output[idx++] = cookieSz;
+            if (cookieSz) {
+                XMEMCPY(&output[idx], ssl->arrays->cookie, cookieSz);
+                idx += cookieSz;
+            }
+        }
+#endif
+            /* then cipher suites */
+        c16toa(ssl->suites->suiteSz, output + idx);
+        idx += 2;
+        XMEMCPY(output + idx, &ssl->suites->suites, ssl->suites->suiteSz);
+        idx += ssl->suites->suiteSz;
+
+            /* last, compression */
+        output[idx++] = COMP_LEN;
+        if (ssl->options.usingCompression)
+            output[idx++] = ZLIB_COMPRESSION;
+        else
+            output[idx++] = NO_COMPRESSION;
+
+#ifdef HAVE_TLS_EXTENSIONS
+        idx += TLSX_WriteRequest(ssl, output + idx);
+
+        (void)idx; /* suppress analyzer warning, keep idx current */
+#else
+        if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz)
+        {
+            int i;
+            /* add in the extensions length */
+            c16toa(HELLO_EXT_LEN + ssl->suites->hashSigAlgoSz, output + idx);
+            idx += 2;
+
+            c16toa(HELLO_EXT_SIG_ALGO, output + idx);
+            idx += 2;
+            c16toa(HELLO_EXT_SIGALGO_SZ+ssl->suites->hashSigAlgoSz, output+idx);
+            idx += 2;
+            c16toa(ssl->suites->hashSigAlgoSz, output + idx);
+            idx += 2;
+            for (i = 0; i < ssl->suites->hashSigAlgoSz; i++, idx++) {
+                output[idx] = ssl->suites->hashSigAlgo[i];
+            }
+        }
+#endif
+
+        if (ssl->keys.encryptionOn) {
+            byte* input;
+            int   inputSz = idx - RECORD_HEADER_SZ; /* build msg adds rec hdr */
+
+            input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+            if (input == NULL)
+                return MEMORY_E;
+
+            XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
+            sendSz = BuildMessage(ssl, output, sendSz, input,inputSz,handshake);
+            XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+
+            if (sendSz < 0)
+                return sendSz;
+        } else {
+            ret = HashOutput(ssl, output, sendSz, 0);
+            if (ret != 0)
+                return ret;
+        }
+
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls) {
+                if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                    return ret;
+            }
+        #endif
+
+        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;
+
+        return SendBuffered(ssl);
+    }
+
+
+    static int DoHelloVerifyRequest(WOLFSSL* ssl, const byte* input,
+                                    word32* inOutIdx, word32 size)
+    {
+        ProtocolVersion pv;
+        byte            cookieSz;
+        word32          begin = *inOutIdx;
+
+#ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("HelloVerifyRequest",
+                                         &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("HelloVerifyRequest", &ssl->timeoutInfo);
+#endif
+
+#ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls) {
+            DtlsPoolReset(ssl);
+        }
+#endif
+
+        if ((*inOutIdx - begin) + OPAQUE16_LEN + OPAQUE8_LEN > size)
+            return BUFFER_ERROR;
+
+        XMEMCPY(&pv, input + *inOutIdx, OPAQUE16_LEN);
+        *inOutIdx += OPAQUE16_LEN;
+
+        cookieSz = input[(*inOutIdx)++];
+
+        if (cookieSz) {
+            if ((*inOutIdx - begin) + cookieSz > size)
+                return BUFFER_ERROR;
+
+#ifdef WOLFSSL_DTLS
+            if (cookieSz <= MAX_COOKIE_LEN) {
+                XMEMCPY(ssl->arrays->cookie, input + *inOutIdx, cookieSz);
+                ssl->arrays->cookieSz = cookieSz;
+            }
+#endif
+            *inOutIdx += cookieSz;
+        }
+
+        ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE;
+        return 0;
+    }
+
+
+    static INLINE int DSH_CheckSessionId(WOLFSSL* ssl)
+    {
+        int ret = 0;
+
+#ifdef HAVE_SECRET_CALLBACK
+        /* If a session secret callback exists, we are using that
+         * key instead of the saved session key. */
+        ret = ret || (ssl->sessionSecretCb != NULL);
+#endif
+
+#ifdef HAVE_SESSION_TICKET
+        /* server may send blank ticket which may not be expected to indicate
+         * exisiting one ok but will also be sending a new one */
+        ret = ret || (ssl->session.ticketLen > 0);
+#endif
+
+        ret = ret ||
+              (ssl->options.haveSessionId && XMEMCMP(ssl->arrays->sessionID,
+                                          ssl->session.sessionID, ID_LEN) == 0);
+
+        return ret;
+    }
+
+    static int DoServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
+                             word32 helloSz)
+    {
+        byte            cs0;   /* cipher suite bytes 0, 1 */
+        byte            cs1;
+        ProtocolVersion pv;
+        byte            compression;
+        word32          i = *inOutIdx;
+        word32          begin = i;
+
+#ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo);
+#endif
+
+        /* protocol version, random and session id length check */
+        if (OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz)
+            return BUFFER_ERROR;
+
+        /* protocol version */
+        XMEMCPY(&pv, input + i, OPAQUE16_LEN);
+        i += OPAQUE16_LEN;
+
+        if (pv.minor > ssl->version.minor) {
+            WOLFSSL_MSG("Server using higher version, fatal error");
+            return VERSION_ERROR;
+        }
+        else if (pv.minor < ssl->version.minor) {
+            WOLFSSL_MSG("server using lower version");
+
+            if (!ssl->options.downgrade) {
+                WOLFSSL_MSG("    no downgrade allowed, fatal error");
+                return VERSION_ERROR;
+            }
+            if (pv.minor < ssl->options.minDowngrade) {
+                WOLFSSL_MSG("    version below minimum allowed, fatal error");
+                return VERSION_ERROR;
+            }
+
+            #ifdef HAVE_SECURE_RENEGOTIATION
+                if (ssl->secure_renegotiation &&
+                                         ssl->secure_renegotiation->enabled &&
+                                         ssl->options.handShakeDone) {
+                    WOLFSSL_MSG("Server changed version during scr");
+                    return VERSION_ERROR;
+                }
+            #endif
+
+            if (pv.minor == SSLv3_MINOR) {
+                /* turn off tls */
+                WOLFSSL_MSG("    downgrading to SSLv3");
+                ssl->options.tls    = 0;
+                ssl->options.tls1_1 = 0;
+                ssl->version.minor  = SSLv3_MINOR;
+            }
+            else if (pv.minor == TLSv1_MINOR) {
+                /* turn off tls 1.1+ */
+                WOLFSSL_MSG("    downgrading to TLSv1");
+                ssl->options.tls1_1 = 0;
+                ssl->version.minor  = TLSv1_MINOR;
+            }
+            else if (pv.minor == TLSv1_1_MINOR) {
+                WOLFSSL_MSG("    downgrading to TLSv1.1");
+                ssl->version.minor  = TLSv1_1_MINOR;
+            }
+        }
+
+        /* random */
+        XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN);
+        i += RAN_LEN;
+
+        /* session id */
+        ssl->arrays->sessionIDSz = input[i++];
+
+        if (ssl->arrays->sessionIDSz > ID_LEN) {
+            WOLFSSL_MSG("Invalid session ID size");
+            ssl->arrays->sessionIDSz = 0;
+            return BUFFER_ERROR;
+        }
+        else if (ssl->arrays->sessionIDSz) {
+            if ((i - begin) + ssl->arrays->sessionIDSz > helloSz)
+                return BUFFER_ERROR;
+
+            XMEMCPY(ssl->arrays->sessionID, input + i,
+                                                      ssl->arrays->sessionIDSz);
+            i += ssl->arrays->sessionIDSz;
+            ssl->options.haveSessionId = 1;
+        }
+
+
+        /* suite and compression */
+        if ((i - begin) + OPAQUE16_LEN + OPAQUE8_LEN > helloSz)
+            return BUFFER_ERROR;
+
+        cs0 = input[i++];
+        cs1 = input[i++];
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+        if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled &&
+                                         ssl->options.handShakeDone) {
+            if (ssl->options.cipherSuite0 != cs0 ||
+                ssl->options.cipherSuite  != cs1) {
+                WOLFSSL_MSG("Server changed cipher suite during scr");
+                return MATCH_SUITE_ERROR;
+            }
+        }
+#endif
+
+        ssl->options.cipherSuite0 = cs0;
+        ssl->options.cipherSuite  = cs1;
+        compression = input[i++];
+
+        if (compression != ZLIB_COMPRESSION && ssl->options.usingCompression) {
+            WOLFSSL_MSG("Server refused compression, turning off");
+            ssl->options.usingCompression = 0;  /* turn off if server refused */
+        }
+
+        *inOutIdx = i;
+
+        /* tls extensions */
+        if ( (i - begin) < helloSz) {
+#ifdef HAVE_TLS_EXTENSIONS
+            if (TLSX_SupportExtensions(ssl)) {
+                int    ret = 0;
+                word16 totalExtSz;
+
+                if ((i - begin) + OPAQUE16_LEN > helloSz)
+                    return BUFFER_ERROR;
+
+                ato16(&input[i], &totalExtSz);
+                i += OPAQUE16_LEN;
+
+                if ((i - begin) + totalExtSz > helloSz)
+                    return BUFFER_ERROR;
+
+                if ((ret = TLSX_Parse(ssl, (byte *) input + i,
+                                                          totalExtSz, 0, NULL)))
+                    return ret;
+
+                i += totalExtSz;
+                *inOutIdx = i;
+            }
+            else
+#endif
+                *inOutIdx = begin + helloSz; /* skip extensions */
+        }
+
+        ssl->options.serverState = SERVER_HELLO_COMPLETE;
+
+        if (ssl->keys.encryptionOn) {
+            *inOutIdx += ssl->keys.padSz;
+        }
+
+#ifdef HAVE_SECRET_CALLBACK
+        if (ssl->sessionSecretCb != NULL) {
+            int secretSz = SECRET_LEN, ret;
+            ret = ssl->sessionSecretCb(ssl, ssl->session.masterSecret,
+                                              &secretSz, ssl->sessionSecretCtx);
+            if (ret != 0 || secretSz != SECRET_LEN)
+                return SESSION_SECRET_CB_E;
+        }
+#endif /* HAVE_SECRET_CALLBACK */
+
+        if (ssl->options.resuming) {
+            if (DSH_CheckSessionId(ssl)) {
+                if (SetCipherSpecs(ssl) == 0) {
+                    int ret = -1;
+
+                    XMEMCPY(ssl->arrays->masterSecret,
+                            ssl->session.masterSecret, SECRET_LEN);
+                    #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.serverState = SERVER_HELLODONE_COMPLETE;
+
+                    return ret;
+                }
+                else {
+                    WOLFSSL_MSG("Unsupported cipher suite, DoServerHello");
+                    return UNSUPPORTED_SUITE;
+                }
+            }
+            else {
+                WOLFSSL_MSG("Server denied resumption attempt");
+                ssl->options.resuming = 0; /* server denied resumption try */
+            }
+        }
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls) {
+                DtlsPoolReset(ssl);
+            }
+        #endif
+
+        return SetCipherSpecs(ssl);
+    }
+
+
+    /* Make sure client setup is valid for this suite, true on success */
+    int VerifyClientSuite(WOLFSSL* ssl)
+    {
+        int  havePSK = 0;
+        byte first   = ssl->options.cipherSuite0;
+        byte second  = ssl->options.cipherSuite;
+
+        WOLFSSL_ENTER("VerifyClientSuite");
+
+        #ifndef NO_PSK
+            havePSK = ssl->options.havePSK;
+        #endif
+
+        if (CipherRequires(first, second, REQUIRES_PSK)) {
+            WOLFSSL_MSG("Requires PSK");
+            if (havePSK == 0) {
+                WOLFSSL_MSG("Don't have PSK");
+                return 0;
+            }
+        }
+
+        return 1;  /* success */
+    }
+
+
+#ifndef NO_CERTS
+    /* just read in and ignore for now TODO: */
+    static int DoCertificateRequest(WOLFSSL* ssl, const byte* input, word32*
+                                    inOutIdx, word32 size)
+    {
+        word16 len;
+        word32 begin = *inOutIdx;
+
+        #ifdef WOLFSSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("CertificateRequest", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("CertificateRequest", &ssl->timeoutInfo);
+        #endif
+
+        if ((*inOutIdx - begin) + OPAQUE8_LEN > size)
+            return BUFFER_ERROR;
+
+        len = input[(*inOutIdx)++];
+
+        if ((*inOutIdx - begin) + len > size)
+            return BUFFER_ERROR;
+
+        /* types, read in here */
+        *inOutIdx += len;
+
+        /* signature and hash signature algorithm */
+        if (IsAtLeastTLSv1_2(ssl)) {
+            if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                return BUFFER_ERROR;
+
+            ato16(input + *inOutIdx, &len);
+            *inOutIdx += OPAQUE16_LEN;
+
+            if ((*inOutIdx - begin) + len > size)
+                return BUFFER_ERROR;
+
+            PickHashSigAlgo(ssl, input + *inOutIdx, len);
+            *inOutIdx += len;
+        }
+
+        /* authorities */
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &len);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + len > size)
+            return BUFFER_ERROR;
+
+        while (len) {
+            word16 dnSz;
+
+            if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                return BUFFER_ERROR;
+
+            ato16(input + *inOutIdx, &dnSz);
+            *inOutIdx += OPAQUE16_LEN;
+
+            if ((*inOutIdx - begin) + dnSz > size)
+                return BUFFER_ERROR;
+
+            *inOutIdx += dnSz;
+            len -= OPAQUE16_LEN + dnSz;
+        }
+
+        /* don't send client cert or cert verify if user hasn't provided
+           cert and private key */
+        if (ssl->buffers.certificate.buffer && ssl->buffers.key.buffer)
+            ssl->options.sendVerify = SEND_CERT;
+        else if (IsTLS(ssl))
+            ssl->options.sendVerify = SEND_BLANK_CERT;
+
+        if (ssl->keys.encryptionOn)
+            *inOutIdx += ssl->keys.padSz;
+
+        return 0;
+    }
+#endif /* !NO_CERTS */
+
+
+#ifdef HAVE_ECC
+
+    static int CheckCurveId(int oid)
+    {
+        int ret = 0;
+
+        switch (oid) {
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC160)
+            case WOLFSSL_ECC_SECP160R1:
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC192)
+            case WOLFSSL_ECC_SECP192R1:
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC224)
+            case WOLFSSL_ECC_SECP224R1:
+#endif
+#if defined(HAVE_ALL_CURVES) || !defined(NO_ECC256)
+            case WOLFSSL_ECC_SECP256R1:
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC384)
+            case WOLFSSL_ECC_SECP384R1:
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC521)
+            case WOLFSSL_ECC_SECP521R1:
+#endif
+                break;
+
+            default:
+                ret = -1;
+        }
+
+        return ret;
+    }
+
+#endif /* HAVE_ECC */
+
+    static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input,
+                                   word32* inOutIdx, word32 size)
+    {
+        word16 length = 0;
+        word32 begin  = *inOutIdx;
+        int    ret    = 0;
+        #define ERROR_OUT(err, eLabel) do { ret = err; goto eLabel; } while(0)
+
+        (void)length; /* shut up compiler warnings */
+        (void)begin;
+        (void)ssl;
+        (void)input;
+        (void)size;
+        (void)ret;
+
+    #ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddLateName("ServerKeyExchange", &ssl->timeoutInfo);
+    #endif
+
+    #ifndef NO_PSK
+        if (ssl->specs.kea == psk_kea) {
+
+            if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                return BUFFER_ERROR;
+
+            ato16(input + *inOutIdx, &length);
+            *inOutIdx += OPAQUE16_LEN;
+
+            if ((*inOutIdx - begin) + length > size)
+                return BUFFER_ERROR;
+
+            XMEMCPY(ssl->arrays->server_hint, input + *inOutIdx,
+                   min(length, MAX_PSK_ID_LEN));
+
+            ssl->arrays->server_hint[min(length, MAX_PSK_ID_LEN - 1)] = 0;
+            *inOutIdx += length;
+
+            return 0;
+        }
+    #endif
+    #ifndef NO_DH
+        if (ssl->specs.kea == diffie_hellman_kea)
+        {
+        /* p */
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &length);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + length > size)
+            return BUFFER_ERROR;
+
+        if (length < ssl->options.minDhKeySz) {
+            WOLFSSL_MSG("Server using a DH key that is too small");
+            SendAlert(ssl, alert_fatal, handshake_failure);
+            return DH_KEY_SIZE_E;
+        }
+
+        ssl->buffers.serverDH_P.buffer = (byte*) XMALLOC(length, ssl->heap,
+                                                         DYNAMIC_TYPE_DH);
+
+        if (ssl->buffers.serverDH_P.buffer)
+            ssl->buffers.serverDH_P.length = length;
+        else
+            return MEMORY_ERROR;
+
+        XMEMCPY(ssl->buffers.serverDH_P.buffer, input + *inOutIdx, length);
+        *inOutIdx += length;
+
+        ssl->options.dhKeySz = length;
+
+        /* g */
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &length);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + length > size)
+            return BUFFER_ERROR;
+
+        ssl->buffers.serverDH_G.buffer = (byte*) XMALLOC(length, ssl->heap,
+                                                         DYNAMIC_TYPE_DH);
+
+        if (ssl->buffers.serverDH_G.buffer)
+            ssl->buffers.serverDH_G.length = length;
+        else
+            return MEMORY_ERROR;
+
+        XMEMCPY(ssl->buffers.serverDH_G.buffer, input + *inOutIdx, length);
+        *inOutIdx += length;
+
+        /* pub */
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &length);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + length > size)
+            return BUFFER_ERROR;
+
+        ssl->buffers.serverDH_Pub.buffer = (byte*) XMALLOC(length, ssl->heap,
+                                                           DYNAMIC_TYPE_DH);
+
+        if (ssl->buffers.serverDH_Pub.buffer)
+            ssl->buffers.serverDH_Pub.length = length;
+        else
+            return MEMORY_ERROR;
+
+        XMEMCPY(ssl->buffers.serverDH_Pub.buffer, input + *inOutIdx, length);
+        *inOutIdx += length;
+        }  /* dh_kea */
+    #endif /* NO_DH */
+
+    #ifdef HAVE_ECC
+        if (ssl->specs.kea == ecc_diffie_hellman_kea)
+        {
+        byte b;
+
+        if ((*inOutIdx - begin) + ENUM_LEN + OPAQUE16_LEN + OPAQUE8_LEN > size)
+            return BUFFER_ERROR;
+
+        b = input[(*inOutIdx)++];
+
+        if (b != named_curve)
+            return ECC_CURVETYPE_ERROR;
+
+        *inOutIdx += 1;   /* curve type, eat leading 0 */
+        b = input[(*inOutIdx)++];
+
+        if (CheckCurveId(b) != 0) {
+            return ECC_CURVE_ERROR;
+        }
+
+        length = input[(*inOutIdx)++];
+
+        if ((*inOutIdx - begin) + length > size)
+            return BUFFER_ERROR;
+
+        if (ssl->peerEccKey == NULL) {
+            /* alloc/init on demand */
+            ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key),
+                                              ssl->ctx->heap, DYNAMIC_TYPE_ECC);
+            if (ssl->peerEccKey == NULL) {
+                WOLFSSL_MSG("PeerEccKey Memory error");
+                return MEMORY_E;
+            }
+            wc_ecc_init(ssl->peerEccKey);
+        } else if (ssl->peerEccKeyPresent) {  /* don't leak on reuse */
+            wc_ecc_free(ssl->peerEccKey);
+            ssl->peerEccKeyPresent = 0;
+            wc_ecc_init(ssl->peerEccKey);
+        }
+
+        if (wc_ecc_import_x963(input + *inOutIdx, length, ssl->peerEccKey) != 0)
+            return ECC_PEERKEY_ERROR;
+
+        *inOutIdx += length;
+        ssl->peerEccKeyPresent = 1;
+        }
+    #endif /* HAVE_ECC */
+
+    #if !defined(NO_DH) && !defined(NO_PSK)
+    if (ssl->specs.kea == dhe_psk_kea) {
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &length);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + length > size)
+            return BUFFER_ERROR;
+
+        XMEMCPY(ssl->arrays->server_hint, input + *inOutIdx,
+               min(length, MAX_PSK_ID_LEN));
+
+        ssl->arrays->server_hint[min(length, MAX_PSK_ID_LEN - 1)] = 0;
+        *inOutIdx += length;
+
+        /* p */
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &length);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + length > size)
+            return BUFFER_ERROR;
+
+        if (length < ssl->options.minDhKeySz) {
+            WOLFSSL_MSG("Server using a DH key that is too small");
+            SendAlert(ssl, alert_fatal, handshake_failure);
+            return DH_KEY_SIZE_E;
+        }
+
+        ssl->buffers.serverDH_P.buffer = (byte*) XMALLOC(length, ssl->heap,
+                                                         DYNAMIC_TYPE_DH);
+
+        if (ssl->buffers.serverDH_P.buffer)
+            ssl->buffers.serverDH_P.length = length;
+        else
+            return MEMORY_ERROR;
+
+        XMEMCPY(ssl->buffers.serverDH_P.buffer, input + *inOutIdx, length);
+        *inOutIdx += length;
+
+        ssl->options.dhKeySz = length;
+
+        /* g */
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &length);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + length > size)
+            return BUFFER_ERROR;
+
+        ssl->buffers.serverDH_G.buffer = (byte*) XMALLOC(length, ssl->heap,
+                                                         DYNAMIC_TYPE_DH);
+
+        if (ssl->buffers.serverDH_G.buffer)
+            ssl->buffers.serverDH_G.length = length;
+        else
+            return MEMORY_ERROR;
+
+        XMEMCPY(ssl->buffers.serverDH_G.buffer, input + *inOutIdx, length);
+        *inOutIdx += length;
+
+        /* pub */
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &length);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + length > size)
+            return BUFFER_ERROR;
+
+        ssl->buffers.serverDH_Pub.buffer = (byte*) XMALLOC(length, ssl->heap,
+                                                           DYNAMIC_TYPE_DH);
+
+        if (ssl->buffers.serverDH_Pub.buffer)
+            ssl->buffers.serverDH_Pub.length = length;
+        else
+            return MEMORY_ERROR;
+
+        XMEMCPY(ssl->buffers.serverDH_Pub.buffer, input + *inOutIdx, length);
+        *inOutIdx += length;
+    }
+    #endif /* !NO_DH || !NO_PSK */
+
+    #if !defined(NO_DH) || defined(HAVE_ECC)
+    if (!ssl->options.usingAnon_cipher &&
+        (ssl->specs.kea == ecc_diffie_hellman_kea ||
+         ssl->specs.kea == diffie_hellman_kea))
+    {
+#ifndef NO_OLD_TLS
+#ifdef WOLFSSL_SMALL_STACK
+        Md5*    md5 = NULL;
+        Sha*    sha = NULL;
+#else
+        Md5     md5[1];
+        Sha     sha[1];
+#endif
+#endif
+#ifndef NO_SHA256
+#ifdef WOLFSSL_SMALL_STACK
+        Sha256* sha256  = NULL;
+        byte*   hash256 = NULL;
+#else
+        Sha256  sha256[1];
+        byte    hash256[SHA256_DIGEST_SIZE];
+#endif
+#endif
+#ifdef WOLFSSL_SHA384
+#ifdef WOLFSSL_SMALL_STACK
+        Sha384* sha384  = NULL;
+        byte*   hash384 = NULL;
+#else
+        Sha384  sha384[1];
+        byte    hash384[SHA384_DIGEST_SIZE];
+#endif
+#endif
+#ifdef WOLFSSL_SHA512
+#ifdef WOLFSSL_SMALL_STACK
+        Sha512* sha512  = NULL;
+        byte*   hash512 = NULL;
+#else
+        Sha512  sha512[1];
+        byte    hash512[SHA512_DIGEST_SIZE];
+#endif
+#endif
+#ifdef WOLFSSL_SMALL_STACK
+        byte*   hash          = NULL;
+        byte*   messageVerify = NULL;
+#else
+        byte    hash[FINISHED_SZ];
+        byte    messageVerify[MAX_DH_SZ];
+#endif
+        byte    hashAlgo = sha_mac;
+        byte    sigAlgo  = ssl->specs.sig_algo;
+        word16  verifySz = (word16) (*inOutIdx - begin);
+
+#ifndef NO_OLD_TLS
+        byte doMd5 = 0;
+        byte doSha = 0;
+#endif
+#ifndef NO_SHA256
+        byte doSha256 = 0;
+#endif
+#ifdef WOLFSSL_SHA384
+        byte doSha384 = 0;
+#endif
+#ifdef WOLFSSL_SHA512
+        byte doSha512 = 0;
+#endif
+
+        (void)hash;
+        (void)sigAlgo;
+        (void)hashAlgo;
+
+        /* save message for hash verify */
+        if (verifySz > MAX_DH_SZ)
+            ERROR_OUT(BUFFER_ERROR, done);
+
+    #ifdef WOLFSSL_SMALL_STACK
+        messageVerify = (byte*)XMALLOC(MAX_DH_SZ, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        if (messageVerify == NULL)
+            ERROR_OUT(MEMORY_E, done);
+    #endif
+
+        XMEMCPY(messageVerify, input + begin, verifySz);
+
+        if (IsAtLeastTLSv1_2(ssl)) {
+            byte setHash = 0;
+            if ((*inOutIdx - begin) + ENUM_LEN + ENUM_LEN > size)
+                ERROR_OUT(BUFFER_ERROR, done);
+
+            hashAlgo = input[(*inOutIdx)++];
+            sigAlgo  = input[(*inOutIdx)++];
+
+            switch (hashAlgo) {
+                case sha512_mac:
+                    #ifdef WOLFSSL_SHA512
+                        doSha512 = 1;
+                        setHash  = 1;
+                    #endif
+                    break;
+
+                case sha384_mac:
+                    #ifdef WOLFSSL_SHA384
+                        doSha384 = 1;
+                        setHash  = 1;
+                    #endif
+                    break;
+
+                case sha256_mac:
+                    #ifndef NO_SHA256
+                        doSha256 = 1;
+                        setHash  = 1;
+                    #endif
+                    break;
+
+                case sha_mac:
+                    #ifndef NO_OLD_TLS
+                        doSha = 1;
+                        setHash  = 1;
+                    #endif
+                    break;
+
+                default:
+                    ERROR_OUT(ALGO_ID_E, done);
+            }
+
+            if (setHash == 0) {
+                ERROR_OUT(ALGO_ID_E, done);
+            }
+
+        } else {
+            /* only using sha and md5 for rsa */
+            #ifndef NO_OLD_TLS
+                doSha = 1;
+                if (sigAlgo == rsa_sa_algo) {
+                    doMd5 = 1;
+                }
+            #else
+                ERROR_OUT(ALGO_ID_E, done);
+            #endif
+        }
+
+        /* signature */
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            ERROR_OUT(BUFFER_ERROR, done);
+
+        ato16(input + *inOutIdx, &length);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + length > size)
+            ERROR_OUT(BUFFER_ERROR, done);
+
+        /* inOutIdx updated at the end of the function */
+
+        /* verify signature */
+    #ifdef WOLFSSL_SMALL_STACK
+        hash = (byte*)XMALLOC(FINISHED_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (hash == NULL)
+            ERROR_OUT(MEMORY_E, done);
+    #endif
+
+#ifndef NO_OLD_TLS
+        /* md5 */
+    #ifdef WOLFSSL_SMALL_STACK
+        if (doMd5) {
+            md5 = (Md5*)XMALLOC(sizeof(Md5), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            if (md5 == NULL)
+                ERROR_OUT(MEMORY_E, done);
+        }
+    #endif
+        if (doMd5) {
+            wc_InitMd5(md5);
+            wc_Md5Update(md5, ssl->arrays->clientRandom, RAN_LEN);
+            wc_Md5Update(md5, ssl->arrays->serverRandom, RAN_LEN);
+            wc_Md5Update(md5, messageVerify, verifySz);
+            wc_Md5Final(md5, hash);
+        }
+        /* sha */
+    #ifdef WOLFSSL_SMALL_STACK
+        if (doSha) {
+            sha = (Sha*)XMALLOC(sizeof(Sha), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            if (sha == NULL)
+                ERROR_OUT(MEMORY_E, done);
+        }
+    #endif
+        if (doSha) {
+            ret = wc_InitSha(sha);
+            if (ret != 0) goto done;
+            wc_ShaUpdate(sha, ssl->arrays->clientRandom, RAN_LEN);
+            wc_ShaUpdate(sha, ssl->arrays->serverRandom, RAN_LEN);
+            wc_ShaUpdate(sha, messageVerify, verifySz);
+            wc_ShaFinal(sha, hash + MD5_DIGEST_SIZE);
+        }
+#endif
+
+#ifndef NO_SHA256
+    #ifdef WOLFSSL_SMALL_STACK
+        if (doSha256) {
+            sha256 = (Sha256*)XMALLOC(sizeof(Sha256), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            hash256 = (byte*)XMALLOC(SHA256_DIGEST_SIZE, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            if (sha256 == NULL || hash256 == NULL)
+                ERROR_OUT(MEMORY_E, done);
+        }
+    #endif
+        if (doSha256) {
+            if (!(ret = wc_InitSha256(sha256))
+            &&  !(ret = wc_Sha256Update(sha256, ssl->arrays->clientRandom,
+                                        RAN_LEN))
+            &&  !(ret = wc_Sha256Update(sha256, ssl->arrays->serverRandom,
+                                        RAN_LEN))
+            &&  !(ret = wc_Sha256Update(sha256, messageVerify, verifySz)))
+                  ret = wc_Sha256Final(sha256, hash256);
+            if (ret != 0) goto done;
+        }
+#endif
+
+#ifdef WOLFSSL_SHA384
+    #ifdef WOLFSSL_SMALL_STACK
+        if (doSha384) {
+            sha384 = (Sha384*)XMALLOC(sizeof(Sha384), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            hash384 = (byte*)XMALLOC(SHA384_DIGEST_SIZE, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            if (sha384 == NULL || hash384 == NULL)
+                ERROR_OUT(MEMORY_E, done);
+        }
+    #endif
+        if (doSha384) {
+            if (!(ret = wc_InitSha384(sha384))
+            &&  !(ret = wc_Sha384Update(sha384, ssl->arrays->clientRandom,
+                                        RAN_LEN))
+            &&  !(ret = wc_Sha384Update(sha384, ssl->arrays->serverRandom,
+                                        RAN_LEN))
+            &&  !(ret = wc_Sha384Update(sha384, messageVerify, verifySz)))
+                  ret = wc_Sha384Final(sha384, hash384);
+            if (ret != 0) goto done;
+        }
+#endif
+
+#ifdef WOLFSSL_SHA512
+    #ifdef WOLFSSL_SMALL_STACK
+        if (doSha512) {
+            sha512 = (Sha512*)XMALLOC(sizeof(Sha512), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            hash512 = (byte*)XMALLOC(SHA512_DIGEST_SIZE, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            if (sha512 == NULL || hash512 == NULL)
+                ERROR_OUT(MEMORY_E, done);
+        }
+    #endif
+        if (doSha512) {
+            if (!(ret = wc_InitSha512(sha512))
+            &&  !(ret = wc_Sha512Update(sha512, ssl->arrays->clientRandom,
+                                        RAN_LEN))
+            &&  !(ret = wc_Sha512Update(sha512, ssl->arrays->serverRandom,
+                                        RAN_LEN))
+            &&  !(ret = wc_Sha512Update(sha512, messageVerify, verifySz)))
+                  ret = wc_Sha512Final(sha512, hash512);
+            if (ret != 0) goto done;
+        }
+#endif
+
+#ifndef NO_RSA
+        /* rsa */
+        if (sigAlgo == rsa_sa_algo)
+        {
+            byte*  out        = NULL;
+            byte   doUserRsa  = 0;
+            word32 verifiedSz = 0;
+
+            #ifdef HAVE_PK_CALLBACKS
+                if (ssl->ctx->RsaVerifyCb)
+                    doUserRsa = 1;
+            #endif /*HAVE_PK_CALLBACKS */
+
+            if (ssl->peerRsaKey == NULL || !ssl->peerRsaKeyPresent)
+                ERROR_OUT(NO_PEER_KEY, done);
+
+            if (doUserRsa) {
+            #ifdef HAVE_PK_CALLBACKS
+                verifiedSz = ssl->ctx->RsaVerifyCb(ssl,
+                                                 (byte *)input + *inOutIdx,
+                                                 length, &out,
+                                                 ssl->buffers.peerRsaKey.buffer,
+                                                 ssl->buffers.peerRsaKey.length,
+                                                 ssl->RsaVerifyCtx);
+            #endif /*HAVE_PK_CALLBACKS */
+            }
+            else
+                verifiedSz = wc_RsaSSL_VerifyInline((byte *)input + *inOutIdx,
+                                                 length, &out, ssl->peerRsaKey);
+
+            if (IsAtLeastTLSv1_2(ssl)) {
+                word32 encSigSz;
+#ifndef NO_OLD_TLS
+                byte*  digest = &hash[MD5_DIGEST_SIZE];
+                int    typeH = SHAh;
+                int    digestSz = SHA_DIGEST_SIZE;
+#else
+                byte*  digest = hash256;
+                int    typeH =  SHA256h;
+                int    digestSz = SHA256_DIGEST_SIZE;
+#endif
+#ifdef WOLFSSL_SMALL_STACK
+                byte*  encodedSig = NULL;
+#else
+                byte   encodedSig[MAX_ENCODED_SIG_SZ];
+#endif
+
+                if (hashAlgo == sha_mac) {
+                    #ifndef NO_SHA
+                        digest   = &hash[MD5_DIGEST_SIZE];
+                        typeH    = SHAh;
+                        digestSz = SHA_DIGEST_SIZE;
+                    #endif
+                }
+                else if (hashAlgo == sha256_mac) {
+                    #ifndef NO_SHA256
+                        digest   = hash256;
+                        typeH    = SHA256h;
+                        digestSz = SHA256_DIGEST_SIZE;
+                    #endif
+                }
+                else if (hashAlgo == sha384_mac) {
+                    #ifdef WOLFSSL_SHA384
+                        digest   = hash384;
+                        typeH    = SHA384h;
+                        digestSz = SHA384_DIGEST_SIZE;
+                    #endif
+                }
+                else if (hashAlgo == sha512_mac) {
+                    #ifdef WOLFSSL_SHA512
+                        digest   = hash512;
+                        typeH    = SHA512h;
+                        digestSz = SHA512_DIGEST_SIZE;
+                    #endif
+                }
+
+            #ifdef WOLFSSL_SMALL_STACK
+                encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                if (encodedSig == NULL)
+                    ERROR_OUT(MEMORY_E, done);
+            #endif
+
+                if (digest == NULL)
+                    ERROR_OUT(ALGO_ID_E, done);
+                encSigSz = wc_EncodeSignature(encodedSig, digest, digestSz,
+                                              typeH);
+                if (encSigSz != verifiedSz || !out || XMEMCMP(out, encodedSig,
+                                        min(encSigSz, MAX_ENCODED_SIG_SZ)) != 0)
+                    ret = VERIFY_SIGN_ERROR;
+
+            #ifdef WOLFSSL_SMALL_STACK
+                XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            #endif
+                if (ret != 0)
+                    goto done;
+            }
+            else if (verifiedSz != FINISHED_SZ || !out || XMEMCMP(out,
+                                                        hash, FINISHED_SZ) != 0)
+                ERROR_OUT(VERIFY_SIGN_ERROR, done);
+        } else
+#endif
+#ifdef HAVE_ECC
+        /* ecdsa */
+        if (sigAlgo == ecc_dsa_sa_algo) {
+            int verify = 0;
+#ifndef NO_OLD_TLS
+            byte* digest = &hash[MD5_DIGEST_SIZE];
+            word32 digestSz = SHA_DIGEST_SIZE;
+#else
+            byte* digest = hash256;
+            word32 digestSz = SHA256_DIGEST_SIZE;
+#endif
+            byte doUserEcc = 0;
+
+            #ifdef HAVE_PK_CALLBACKS
+                if (ssl->ctx->EccVerifyCb)
+                    doUserEcc = 1;
+            #endif
+
+            if (!ssl->peerEccDsaKeyPresent)
+                ERROR_OUT(NO_PEER_KEY, done);
+
+            if (IsAtLeastTLSv1_2(ssl)) {
+                if (hashAlgo == sha_mac) {
+                    #ifndef NO_SHA
+                        digest   = &hash[MD5_DIGEST_SIZE];
+                        digestSz = SHA_DIGEST_SIZE;
+                    #endif
+                }
+                else if (hashAlgo == sha256_mac) {
+                    #ifndef NO_SHA256
+                        digest   = hash256;
+                        digestSz = SHA256_DIGEST_SIZE;
+                    #endif
+                }
+                else if (hashAlgo == sha384_mac) {
+                    #ifdef WOLFSSL_SHA384
+                        digest   = hash384;
+                        digestSz = SHA384_DIGEST_SIZE;
+                    #endif
+                }
+                else if (hashAlgo == sha512_mac) {
+                    #ifdef WOLFSSL_SHA512
+                        digest   = hash512;
+                        digestSz = SHA512_DIGEST_SIZE;
+                    #endif
+                }
+            }
+            if (doUserEcc) {
+            #ifdef HAVE_PK_CALLBACKS
+                ret = ssl->ctx->EccVerifyCb(ssl, input + *inOutIdx, length,
+                                            digest, digestSz,
+                                            ssl->buffers.peerEccDsaKey.buffer,
+                                            ssl->buffers.peerEccDsaKey.length,
+                                            &verify, ssl->EccVerifyCtx);
+            #endif
+            }
+            else {
+                ret = wc_ecc_verify_hash(input + *inOutIdx, length,
+                                 digest, digestSz, &verify, ssl->peerEccDsaKey);
+            }
+            if (ret != 0 || verify == 0)
+                ERROR_OUT(VERIFY_SIGN_ERROR, done);
+        }
+        else
+#endif /* HAVE_ECC */
+            ERROR_OUT(ALGO_ID_E, done);
+
+        /* signature length */
+        *inOutIdx += length;
+
+        ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
+
+    done:
+#ifdef WOLFSSL_SMALL_STACK
+    #ifndef NO_OLD_TLS
+        XFREE(md5,           NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(sha,           NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+    #ifndef NO_SHA256
+        XFREE(sha256,        NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(hash256,       NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+    #ifdef WOLFSSL_SHA384
+        XFREE(sha384,        NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(hash384,       NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+    #ifdef WOLFSSL_SHA512
+        XFREE(sha512,        NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(hash512,       NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+        XFREE(hash,          NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(messageVerify, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        if (ret != 0)
+            return ret;
+    }
+
+    if (ssl->keys.encryptionOn) {
+        *inOutIdx += ssl->keys.padSz;
+    }
+
+    return 0;
+#else  /* !NO_DH or HAVE_ECC */
+        return NOT_COMPILED_IN;  /* not supported by build */
+#endif /* !NO_DH or HAVE_ECC */
+
+        #undef ERROR_OUT
+    }
+
+
+    int SendClientKeyExchange(WOLFSSL* ssl)
+    {
+#ifdef WOLFSSL_SMALL_STACK
+        byte*  encSecret = NULL;
+#else
+        byte   encSecret[MAX_ENCRYPT_SZ];
+#endif
+        word32 encSz = 0;
+        word32 idx = 0;
+        int    ret = 0;
+        byte   doUserRsa = 0;
+
+        (void)doUserRsa;
+
+#ifdef HAVE_PK_CALLBACKS
+    #ifndef NO_RSA
+        if (ssl->ctx->RsaEncCb)
+            doUserRsa = 1;
+    #endif /* NO_RSA */
+#endif /*HAVE_PK_CALLBACKS */
+
+    #ifdef WOLFSSL_SMALL_STACK
+        encSecret = (byte*)XMALLOC(MAX_ENCRYPT_SZ, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        if (encSecret == NULL)
+            return MEMORY_E;
+    #endif
+
+        switch (ssl->specs.kea) {
+        #ifndef NO_RSA
+            case rsa_kea:
+                ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->preMasterSecret,
+                                                                    SECRET_LEN);
+                if (ret != 0) {
+                #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                #endif
+                    return ret;
+                }
+
+                ssl->arrays->preMasterSecret[0] = ssl->chVersion.major;
+                ssl->arrays->preMasterSecret[1] = ssl->chVersion.minor;
+                ssl->arrays->preMasterSz = SECRET_LEN;
+
+                if (ssl->peerRsaKey == NULL || ssl->peerRsaKeyPresent == 0) {
+                #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                #endif
+                    return NO_PEER_KEY;
+                }
+
+                if (doUserRsa) {
+                #ifdef HAVE_PK_CALLBACKS
+                    #ifndef NO_RSA
+                        encSz = MAX_ENCRYPT_SZ;
+                        ret = ssl->ctx->RsaEncCb(ssl,
+                                            ssl->arrays->preMasterSecret,
+                                            SECRET_LEN,
+                                            encSecret, &encSz,
+                                            ssl->buffers.peerRsaKey.buffer,
+                                            ssl->buffers.peerRsaKey.length,
+                                            ssl->RsaEncCtx);
+                    #endif /* NO_RSA */
+                #endif /*HAVE_PK_CALLBACKS */
+                }
+                else {
+                    ret = wc_RsaPublicEncrypt(ssl->arrays->preMasterSecret,
+                                 SECRET_LEN, encSecret, MAX_ENCRYPT_SZ,
+                                 ssl->peerRsaKey, ssl->rng);
+                    if (ret > 0) {
+                        encSz = ret;
+                        ret = 0;   /* set success to 0 */
+                    }
+                }
+                break;
+        #endif
+        #ifndef NO_DH
+            case diffie_hellman_kea:
+                {
+                    buffer  serverP   = ssl->buffers.serverDH_P;
+                    buffer  serverG   = ssl->buffers.serverDH_G;
+                    buffer  serverPub = ssl->buffers.serverDH_Pub;
+                #ifdef WOLFSSL_SMALL_STACK
+                    byte*   priv = NULL;
+                #else
+                    byte    priv[ENCRYPT_LEN];
+                #endif
+                    word32  privSz = 0;
+                    DhKey   key;
+
+                    if (serverP.buffer == 0 || serverG.buffer == 0 ||
+                                               serverPub.buffer == 0) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return NO_PEER_KEY;
+                    }
+
+                #ifdef WOLFSSL_SMALL_STACK
+                    priv = (byte*)XMALLOC(ENCRYPT_LEN, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                    if (priv == NULL) {
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                        return MEMORY_E;
+                    }
+                #endif
+
+                    wc_InitDhKey(&key);
+                    ret = wc_DhSetKey(&key, serverP.buffer, serverP.length,
+                                   serverG.buffer, serverG.length);
+                    if (ret == 0)
+                        /* for DH, encSecret is Yc, agree is pre-master */
+                        ret = wc_DhGenerateKeyPair(&key, ssl->rng, priv, &privSz,
+                                                encSecret, &encSz);
+                    if (ret == 0)
+                        ret = wc_DhAgree(&key, ssl->arrays->preMasterSecret,
+                                      &ssl->arrays->preMasterSz, priv, privSz,
+                                      serverPub.buffer, serverPub.length);
+                #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                #endif
+                    wc_FreeDhKey(&key);
+                }
+                break;
+        #endif /* NO_DH */
+        #ifndef NO_PSK
+            case psk_kea:
+                {
+                    byte* pms = ssl->arrays->preMasterSecret;
+
+                    ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl,
+                        ssl->arrays->server_hint, 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) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return PSK_KEY_ERROR;
+                    }
+                    encSz = (word32)XSTRLEN(ssl->arrays->client_identity);
+                    if (encSz > MAX_PSK_ID_LEN) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return CLIENT_ID_ERROR;
+                    }
+                    XMEMCPY(encSecret, ssl->arrays->client_identity, encSz);
+
+                    /* make psk pre master secret */
+                    /* length of key + length 0s + length of key + key */
+                    c16toa((word16)ssl->arrays->psk_keySz, pms);
+                    pms += 2;
+                    XMEMSET(pms, 0, ssl->arrays->psk_keySz);
+                    pms += ssl->arrays->psk_keySz;
+                    c16toa((word16)ssl->arrays->psk_keySz, pms);
+                    pms += 2;
+                    XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz);
+                    ssl->arrays->preMasterSz = ssl->arrays->psk_keySz * 2 + 4;
+                    ForceZero(ssl->arrays->psk_key, ssl->arrays->psk_keySz);
+                    ssl->arrays->psk_keySz = 0; /* No further need */
+                }
+                break;
+        #endif /* NO_PSK */
+        #if !defined(NO_DH) && !defined(NO_PSK)
+            case dhe_psk_kea:
+                {
+                    byte* pms = ssl->arrays->preMasterSecret;
+                    byte* es  = encSecret;
+                    buffer  serverP   = ssl->buffers.serverDH_P;
+                    buffer  serverG   = ssl->buffers.serverDH_G;
+                    buffer  serverPub = ssl->buffers.serverDH_Pub;
+                #ifdef WOLFSSL_SMALL_STACK
+                    byte*   priv = NULL;
+                #else
+                    byte    priv[ENCRYPT_LEN];
+                #endif
+                    word32  privSz = 0;
+                    word32  pubSz = 0;
+                    word32  esSz = 0;
+                    DhKey   key;
+
+                    if (serverP.buffer == 0 || serverG.buffer == 0 ||
+                                               serverPub.buffer == 0) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return NO_PEER_KEY;
+                    }
+
+                    ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl,
+                         ssl->arrays->server_hint, 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) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return PSK_KEY_ERROR;
+                    }
+                    esSz = (word32)XSTRLEN(ssl->arrays->client_identity);
+
+                    if (esSz > MAX_PSK_ID_LEN) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return CLIENT_ID_ERROR;
+                    }
+
+                #ifdef WOLFSSL_SMALL_STACK
+                    priv = (byte*)XMALLOC(ENCRYPT_LEN, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                    if (priv == NULL) {
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                        return MEMORY_E;
+                    }
+                #endif
+                    c16toa((word16)esSz, es);
+                    es += OPAQUE16_LEN;
+                    XMEMCPY(es, ssl->arrays->client_identity, esSz);
+                    es += esSz;
+                    encSz = esSz + OPAQUE16_LEN;
+
+                    wc_InitDhKey(&key);
+                    ret = wc_DhSetKey(&key, serverP.buffer, serverP.length,
+                                   serverG.buffer, serverG.length);
+                    if (ret == 0)
+                        /* for DH, encSecret is Yc, agree is pre-master */
+                        ret = wc_DhGenerateKeyPair(&key, ssl->rng, priv, &privSz,
+                                                es + OPAQUE16_LEN, &pubSz);
+                    if (ret == 0)
+                        ret = wc_DhAgree(&key, pms + OPAQUE16_LEN,
+                                      &ssl->arrays->preMasterSz, priv, privSz,
+                                      serverPub.buffer, serverPub.length);
+                    wc_FreeDhKey(&key);
+                #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                #endif
+                    if (ret != 0) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return ret;
+                    }
+
+                    c16toa((word16)pubSz, es);
+                    encSz += pubSz + OPAQUE16_LEN;
+                    c16toa((word16)ssl->arrays->preMasterSz, pms);
+                    ssl->arrays->preMasterSz += OPAQUE16_LEN;
+                    pms += ssl->arrays->preMasterSz;
+
+                    /* make psk pre master secret */
+                    /* length of key + length 0s + length of key + key */
+                    c16toa((word16)ssl->arrays->psk_keySz, pms);
+                    pms += OPAQUE16_LEN;
+                    XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz);
+                    ssl->arrays->preMasterSz +=
+                                          ssl->arrays->psk_keySz + OPAQUE16_LEN;
+                    ForceZero(ssl->arrays->psk_key, ssl->arrays->psk_keySz);
+                    ssl->arrays->psk_keySz = 0; /* No further need */
+                }
+                break;
+        #endif /* !NO_DH && !NO_PSK */
+        #ifdef HAVE_NTRU
+            case ntru_kea:
+                {
+                    word32 rc;
+                    word16 cipherLen = MAX_ENCRYPT_SZ;
+                    DRBG_HANDLE drbg;
+                    static uint8_t const wolfsslStr[] = {
+                        'C', 'y', 'a', 'S', 'S', 'L', ' ', 'N', 'T', 'R', 'U'
+                    };
+
+                    ret = wc_RNG_GenerateBlock(ssl->rng,
+                                      ssl->arrays->preMasterSecret, SECRET_LEN);
+                    if (ret != 0) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return ret;
+                    }
+
+                    ssl->arrays->preMasterSz = SECRET_LEN;
+
+                    if (ssl->peerNtruKeyPresent == 0) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return NO_PEER_KEY;
+                    }
+
+                    rc = ntru_crypto_drbg_instantiate(MAX_NTRU_BITS, wolfsslStr,
+                                                 sizeof(wolfsslStr), GetEntropy,
+                                                 &drbg);
+                    if (rc != DRBG_OK) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return NTRU_DRBG_ERROR;
+                    }
+
+                    rc = ntru_crypto_ntru_encrypt(drbg, ssl->peerNtruKeyLen,
+                                                  ssl->peerNtruKey,
+                                                  ssl->arrays->preMasterSz,
+                                                  ssl->arrays->preMasterSecret,
+                                                  &cipherLen, encSecret);
+                    ntru_crypto_drbg_uninstantiate(drbg);
+                    if (rc != NTRU_OK) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return NTRU_ENCRYPT_ERROR;
+                    }
+
+                    encSz = cipherLen;
+                    ret = 0;
+                }
+                break;
+        #endif /* HAVE_NTRU */
+        #ifdef HAVE_ECC
+            case ecc_diffie_hellman_kea:
+                {
+                    ecc_key  myKey;
+                    ecc_key* peerKey = NULL;
+                    word32   size = MAX_ENCRYPT_SZ;
+
+                    if (ssl->specs.static_ecdh) {
+                        /* TODO: EccDsa is really fixed Ecc change naming */
+                        if (!ssl->peerEccDsaKey || !ssl->peerEccDsaKeyPresent ||
+                                                   !ssl->peerEccDsaKey->dp) {
+                        #ifdef WOLFSSL_SMALL_STACK
+                            XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                        #endif
+                            return NO_PEER_KEY;
+                        }
+                        peerKey = ssl->peerEccDsaKey;
+                    }
+                    else {
+                        if (!ssl->peerEccKey || !ssl->peerEccKeyPresent ||
+                                                !ssl->peerEccKey->dp) {
+                        #ifdef WOLFSSL_SMALL_STACK
+                            XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                        #endif
+                            return NO_PEER_KEY;
+                        }
+                        peerKey = ssl->peerEccKey;
+                    }
+
+                    if (peerKey == NULL) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return NO_PEER_KEY;
+                    }
+
+                    wc_ecc_init(&myKey);
+                    ret = wc_ecc_make_key(ssl->rng, peerKey->dp->size, &myKey);
+                    if (ret != 0) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return ECC_MAKEKEY_ERROR;
+                    }
+
+                    /* precede export with 1 byte length */
+                    ret = wc_ecc_export_x963(&myKey, encSecret + 1, &size);
+                    encSecret[0] = (byte)size;
+                    encSz = size + 1;
+
+                    if (ret != 0)
+                        ret = ECC_EXPORT_ERROR;
+                    else {
+                        size = sizeof(ssl->arrays->preMasterSecret);
+                        ret  = wc_ecc_shared_secret(&myKey, peerKey,
+                                                 ssl->arrays->preMasterSecret, &size);
+                        if (ret != 0)
+                            ret = ECC_SHARED_ERROR;
+                    }
+
+                    ssl->arrays->preMasterSz = size;
+                    wc_ecc_free(&myKey);
+                }
+                break;
+        #endif /* HAVE_ECC */
+            default:
+            #ifdef WOLFSSL_SMALL_STACK
+                XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            #endif
+                return ALGO_ID_E; /* unsupported kea */
+        }
+
+        if (ret == 0) {
+            byte              *output;
+            int                sendSz;
+            word32             tlsSz = 0;
+
+            if (ssl->options.tls || ssl->specs.kea == diffie_hellman_kea)
+                tlsSz = 2;
+
+            if (ssl->specs.kea == ecc_diffie_hellman_kea ||
+                ssl->specs.kea == dhe_psk_kea)  /* always off */
+                tlsSz = 0;
+
+            sendSz = encSz + tlsSz + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+            idx    = HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+            #ifdef WOLFSSL_DTLS
+                if (ssl->options.dtls) {
+                    sendSz += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA;
+                    idx    += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA;
+                }
+            #endif
+
+            if (ssl->keys.encryptionOn)
+                sendSz += MAX_MSG_EXTRA;
+
+            /* check for available size */
+            if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) {
+            #ifdef WOLFSSL_SMALL_STACK
+                XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            #endif
+                return ret;
+            }
+
+            /* get ouput buffer */
+            output = ssl->buffers.outputBuffer.buffer +
+                     ssl->buffers.outputBuffer.length;
+
+            AddHeaders(output, encSz + tlsSz, client_key_exchange, ssl);
+
+            if (tlsSz) {
+                c16toa((word16)encSz, &output[idx]);
+                idx += 2;
+            }
+            XMEMCPY(output + idx, encSecret, encSz);
+            idx += encSz;
+
+            if (ssl->keys.encryptionOn) {
+                byte* input;
+                int   inputSz = idx-RECORD_HEADER_SZ; /* buildmsg adds rechdr */
+
+                input = (byte*)XMALLOC(inputSz, ssl->heap,
+                                       DYNAMIC_TYPE_TMP_BUFFER);
+                if (input == NULL) {
+                #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                #endif
+                    return MEMORY_E;
+                }
+
+                XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
+                sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
+                                      handshake);
+                XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+                if (sendSz < 0) {
+                #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                #endif
+                    return sendSz;
+                }
+            } else {
+                ret = HashOutput(ssl, output, sendSz, 0);
+                if (ret != 0) {
+                #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                #endif
+                    return ret;
+                }
+            }
+
+            #ifdef WOLFSSL_DTLS
+                if (ssl->options.dtls) {
+                    if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) {
+                    #ifdef WOLFSSL_SMALL_STACK
+                        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                    #endif
+                        return ret;
+                    }
+                }
+            #endif
+
+            #ifdef WOLFSSL_CALLBACKS
+                if (ssl->hsInfoOn)
+                    AddPacketName("ClientKeyExchange", &ssl->handShakeInfo);
+                if (ssl->toInfoOn)
+                    AddPacketInfo("ClientKeyExchange", &ssl->timeoutInfo,
+                                  output, sendSz, ssl->heap);
+            #endif
+
+            ssl->buffers.outputBuffer.length += sendSz;
+
+            if (ssl->options.groupMessages)
+                ret = 0;
+            else
+                ret = SendBuffered(ssl);
+        }
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+
+        if (ret == 0 || ret == WANT_WRITE) {
+            int tmpRet = MakeMasterSecret(ssl);
+            if (tmpRet != 0)
+                ret = tmpRet;   /* save WANT_WRITE unless more serious */
+            ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+        }
+        /* No further need for PMS */
+        ForceZero(ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz);
+        ssl->arrays->preMasterSz = 0;
+
+        return ret;
+    }
+
+#ifndef NO_CERTS
+    int SendCertificateVerify(WOLFSSL* ssl)
+    {
+        byte              *output;
+        int                sendSz = MAX_CERT_VERIFY_SZ, length, ret;
+        word32             idx = 0;
+        word32             sigOutSz = 0;
+#ifndef NO_RSA
+        RsaKey             key;
+        int                initRsaKey = 0;
+#endif
+        int                usingEcc = 0;
+#ifdef HAVE_ECC
+        ecc_key            eccKey;
+#endif
+
+        (void)idx;
+
+        if (ssl->options.sendVerify == SEND_BLANK_CERT)
+            return 0;  /* sent blank cert, can't verify */
+
+        if (ssl->keys.encryptionOn)
+            sendSz += MAX_MSG_EXTRA;
+
+        /* check for available size */
+        if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.length;
+
+        ret = BuildCertHashes(ssl, &ssl->hsHashes->certHashes);
+        if (ret != 0)
+            return ret;
+
+#ifdef HAVE_ECC
+        wc_ecc_init(&eccKey);
+#endif
+#ifndef NO_RSA
+        ret = wc_InitRsaKey(&key, ssl->heap);
+        if (ret == 0) initRsaKey = 1;
+        if (ret == 0)
+            ret = wc_RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &key,
+                                      ssl->buffers.key.length);
+        if (ret == 0)
+            sigOutSz = wc_RsaEncryptSize(&key);
+        else
+#endif
+        {
+    #ifdef HAVE_ECC
+            WOLFSSL_MSG("Trying ECC client cert, RSA didn't work");
+
+            idx = 0;
+            ret = wc_EccPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &eccKey,
+                                      ssl->buffers.key.length);
+            if (ret == 0) {
+                WOLFSSL_MSG("Using ECC client cert");
+                usingEcc = 1;
+                sigOutSz = MAX_ENCODED_SIG_SZ;
+            }
+            else {
+                WOLFSSL_MSG("Bad client cert type");
+            }
+    #endif
+        }
+        if (ret == 0) {
+            byte*  verify = (byte*)&output[RECORD_HEADER_SZ +
+                                           HANDSHAKE_HEADER_SZ];
+#ifndef NO_OLD_TLS
+            byte*  signBuffer = ssl->hsHashes->certHashes.md5;
+#else
+            byte*  signBuffer = NULL;
+#endif
+            word32 signSz = FINISHED_SZ;
+            word32 extraSz = 0;  /* tls 1.2 hash/sig */
+#ifdef WOLFSSL_SMALL_STACK
+            byte*  encodedSig = NULL;
+#else
+            byte   encodedSig[MAX_ENCODED_SIG_SZ];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+            encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            if (encodedSig == NULL) {
+            #ifndef NO_RSA
+                if (initRsaKey)
+                    wc_FreeRsaKey(&key);
+            #endif
+            #ifdef HAVE_ECC
+                wc_ecc_free(&eccKey);
+            #endif
+                return MEMORY_E;
+            }
+#endif
+
+            (void)encodedSig;
+            (void)signSz;
+            (void)signBuffer;
+
+            #ifdef WOLFSSL_DTLS
+                if (ssl->options.dtls)
+                    verify += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+            #endif
+            length = sigOutSz;
+            if (IsAtLeastTLSv1_2(ssl)) {
+                verify[0] = ssl->suites->hashAlgo;
+                verify[1] = usingEcc ? ecc_dsa_sa_algo : rsa_sa_algo;
+                extraSz = HASH_SIG_SIZE;
+            }
+
+            if (usingEcc) {
+#ifdef HAVE_ECC
+                word32 localSz = MAX_ENCODED_SIG_SZ;
+                word32 digestSz;
+                byte*  digest;
+                byte   doUserEcc = 0;
+#ifndef NO_OLD_TLS
+                /* old tls default */
+                digestSz = SHA_DIGEST_SIZE;
+                digest   = ssl->hsHashes->certHashes.sha;
+#else
+                /* new tls default */
+                digestSz = SHA256_DIGEST_SIZE;
+                digest   = ssl->hsHashes->certHashes.sha256;
+#endif
+
+                #ifdef HAVE_PK_CALLBACKS
+                    #ifdef HAVE_ECC
+                        if (ssl->ctx->EccSignCb)
+                            doUserEcc = 1;
+                    #endif /* HAVE_ECC */
+                #endif /*HAVE_PK_CALLBACKS */
+
+                if (IsAtLeastTLSv1_2(ssl)) {
+                    if (ssl->suites->hashAlgo == sha_mac) {
+                        #ifndef NO_SHA
+                            digest = ssl->hsHashes->certHashes.sha;
+                            digestSz = SHA_DIGEST_SIZE;
+                        #endif
+                    }
+                    else if (ssl->suites->hashAlgo == sha256_mac) {
+                        #ifndef NO_SHA256
+                            digest = ssl->hsHashes->certHashes.sha256;
+                            digestSz = SHA256_DIGEST_SIZE;
+                        #endif
+                    }
+                    else if (ssl->suites->hashAlgo == sha384_mac) {
+                        #ifdef WOLFSSL_SHA384
+                            digest = ssl->hsHashes->certHashes.sha384;
+                            digestSz = SHA384_DIGEST_SIZE;
+                        #endif
+                    }
+                    else if (ssl->suites->hashAlgo == sha512_mac) {
+                        #ifdef WOLFSSL_SHA512
+                            digest = ssl->hsHashes->certHashes.sha512;
+                            digestSz = SHA512_DIGEST_SIZE;
+                        #endif
+                    }
+                }
+
+                if (doUserEcc) {
+                #ifdef HAVE_PK_CALLBACKS
+                    #ifdef HAVE_ECC
+                        ret = ssl->ctx->EccSignCb(ssl, digest, digestSz,
+                                        encodedSig, &localSz,
+                                        ssl->buffers.key.buffer,
+                                        ssl->buffers.key.length,
+                                        ssl->EccSignCtx);
+                    #endif /* HAVE_ECC */
+                #endif /*HAVE_PK_CALLBACKS */
+                }
+                else {
+                    ret = wc_ecc_sign_hash(digest, digestSz, encodedSig,
+                                        &localSz, ssl->rng, &eccKey);
+                }
+                if (ret == 0) {
+                    length = localSz;
+                    c16toa((word16)length, verify + extraSz); /* prepend hdr */
+                    XMEMCPY(verify + extraSz + VERIFY_HEADER,encodedSig,length);
+                }
+#endif
+            }
+#ifndef NO_RSA
+            else {
+                byte doUserRsa = 0;
+
+                #ifdef HAVE_PK_CALLBACKS
+                    if (ssl->ctx->RsaSignCb)
+                        doUserRsa = 1;
+                #endif /*HAVE_PK_CALLBACKS */
+
+                if (IsAtLeastTLSv1_2(ssl)) {
+                    /*
+                     * MSVC Compiler complains because it can not
+                     * guarantee any of the conditionals will succeed in
+                     * assigning a value before wc_EncodeSignature executes.
+                     */
+                    byte* digest    = NULL;
+                    int   digestSz  = 0;
+                    int   typeH     = 0;
+                    int   didSet    = 0;
+
+                    if (ssl->suites->hashAlgo == sha_mac) {
+                        #ifndef NO_SHA
+                            digest   = ssl->hsHashes->certHashes.sha;
+                            typeH    = SHAh;
+                            digestSz = SHA_DIGEST_SIZE;
+                            didSet   = 1;
+                        #endif
+                    }
+                    else if (ssl->suites->hashAlgo == sha256_mac) {
+                        #ifndef NO_SHA256
+                            digest   = ssl->hsHashes->certHashes.sha256;
+                            typeH    = SHA256h;
+                            digestSz = SHA256_DIGEST_SIZE;
+                            didSet   = 1;
+                        #endif
+                    }
+                    else if (ssl->suites->hashAlgo == sha384_mac) {
+                        #ifdef WOLFSSL_SHA384
+                            digest   = ssl->hsHashes->certHashes.sha384;
+                            typeH    = SHA384h;
+                            digestSz = SHA384_DIGEST_SIZE;
+                            didSet   = 1;
+                        #endif
+                    }
+                    else if (ssl->suites->hashAlgo == sha512_mac) {
+                        #ifdef WOLFSSL_SHA512
+                            digest   = ssl->hsHashes->certHashes.sha512;
+                            typeH    = SHA512h;
+                            digestSz = SHA512_DIGEST_SIZE;
+                            didSet   = 1;
+                        #endif
+                    }
+
+                    if (didSet == 0) {
+                        /* defaults */
+                        #ifndef NO_OLD_TLS
+                            digest = ssl->hsHashes->certHashes.sha;
+                            digestSz = SHA_DIGEST_SIZE;
+                            typeH = SHAh;
+                        #else
+                            digest = ssl->hsHashes->certHashes.sha256;
+                            digestSz = SHA256_DIGEST_SIZE;
+                            typeH = SHA256h;
+                        #endif
+                    }
+
+                    signSz = wc_EncodeSignature(encodedSig, digest,digestSz,typeH);
+                    signBuffer = encodedSig;
+                }
+
+                c16toa((word16)length, verify + extraSz); /* prepend hdr */
+                if (doUserRsa) {
+                #ifdef HAVE_PK_CALLBACKS
+                    #ifndef NO_RSA
+                        word32 ioLen = ENCRYPT_LEN;
+                        ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz,
+                                            verify + extraSz + VERIFY_HEADER,
+                                            &ioLen,
+                                            ssl->buffers.key.buffer,
+                                            ssl->buffers.key.length,
+                                            ssl->RsaSignCtx);
+                    #endif /* NO_RSA */
+                #endif /*HAVE_PK_CALLBACKS */
+                }
+                else {
+                    ret = wc_RsaSSL_Sign(signBuffer, signSz, verify + extraSz +
+                                  VERIFY_HEADER, ENCRYPT_LEN, &key, ssl->rng);
+                }
+
+                if (ret > 0)
+                    ret = 0;  /* RSA reset */
+            }
+#endif
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+            if (ret == 0) {
+                AddHeaders(output, length + extraSz + VERIFY_HEADER,
+                           certificate_verify, ssl);
+
+                sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + length +
+                         extraSz + VERIFY_HEADER;
+
+                #ifdef WOLFSSL_DTLS
+                    if (ssl->options.dtls) {
+                        sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                    }
+                #endif
+
+                if (ssl->keys.encryptionOn) {
+                    byte* input;
+                    int   inputSz = sendSz - RECORD_HEADER_SZ;
+                                    /* build msg adds rec hdr */
+                    input = (byte*)XMALLOC(inputSz, ssl->heap,
+                                           DYNAMIC_TYPE_TMP_BUFFER);
+                    if (input == NULL)
+                        ret = MEMORY_E;
+                    else {
+                        XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
+                        sendSz = BuildMessage(ssl, output,
+                                              MAX_CERT_VERIFY_SZ +MAX_MSG_EXTRA,
+                                              input, inputSz, handshake);
+                        XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+
+                        if (sendSz < 0)
+                            ret = sendSz;
+                    }
+                } else {
+                    ret = HashOutput(ssl, output, sendSz, 0);
+                }
+
+                #ifdef WOLFSSL_DTLS
+                    if (ssl->options.dtls) {
+                        if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                            return ret;
+                    }
+                #endif
+            }
+        }
+#ifndef NO_RSA
+        if (initRsaKey)
+            wc_FreeRsaKey(&key);
+#endif
+#ifdef HAVE_ECC
+        wc_ecc_free(&eccKey);
+#endif
+
+        if (ret == 0) {
+            #ifdef WOLFSSL_CALLBACKS
+                if (ssl->hsInfoOn)
+                    AddPacketName("CertificateVerify", &ssl->handShakeInfo);
+                if (ssl->toInfoOn)
+                    AddPacketInfo("CertificateVerify", &ssl->timeoutInfo,
+                                  output, sendSz, ssl->heap);
+            #endif
+            ssl->buffers.outputBuffer.length += sendSz;
+            if (ssl->options.groupMessages)
+                return 0;
+            else
+                return SendBuffered(ssl);
+        }
+        else
+            return ret;
+    }
+#endif /* NO_CERTS */
+
+#ifdef HAVE_SESSION_TICKET
+int DoSessionTicket(WOLFSSL* ssl,
+                               const byte* input, word32* inOutIdx, word32 size)
+{
+    word32 begin = *inOutIdx;
+    word32 lifetime;
+    word16 length;
+
+    if (ssl->expect_session_ticket == 0) {
+        WOLFSSL_MSG("Unexpected session ticket");
+        return SESSION_TICKET_EXPECT_E;
+    }
+
+    if ((*inOutIdx - begin) + OPAQUE32_LEN > size)
+        return BUFFER_ERROR;
+
+    ato32(input + *inOutIdx, &lifetime);
+    *inOutIdx += OPAQUE32_LEN;
+
+    if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+        return BUFFER_ERROR;
+
+    ato16(input + *inOutIdx, &length);
+    *inOutIdx += OPAQUE16_LEN;
+
+    if (length > sizeof(ssl->session.ticket))
+        return SESSION_TICKET_LEN_E;
+
+    if ((*inOutIdx - begin) + length > size)
+        return BUFFER_ERROR;
+
+    /* If the received ticket including its length is greater than
+     * a length value, the save it. Otherwise, don't save it. */
+    if (length > 0) {
+        XMEMCPY(ssl->session.ticket, input + *inOutIdx, length);
+        *inOutIdx += length;
+        ssl->session.ticketLen = length;
+        ssl->timeout = lifetime;
+        if (ssl->session_ticket_cb != NULL) {
+            ssl->session_ticket_cb(ssl,
+                                   ssl->session.ticket, ssl->session.ticketLen,
+                                   ssl->session_ticket_ctx);
+        }
+        /* Create a fake sessionID based on the ticket, this will
+         * supercede the existing session cache info. */
+        ssl->options.haveSessionId = 1;
+        XMEMCPY(ssl->arrays->sessionID,
+                                 ssl->session.ticket + length - ID_LEN, ID_LEN);
+#ifndef NO_SESSION_CACHE
+        AddSession(ssl);
+#endif
+
+    }
+    else {
+        ssl->session.ticketLen = 0;
+    }
+
+    if (ssl->keys.encryptionOn) {
+        *inOutIdx += ssl->keys.padSz;
+    }
+
+    ssl->expect_session_ticket = 0;
+
+    return 0;
+}
+#endif /* HAVE_SESSION_TICKET */
+
+#endif /* NO_WOLFSSL_CLIENT */
+
+
+#ifndef NO_WOLFSSL_SERVER
+
+    int SendServerHello(WOLFSSL* ssl)
+    {
+        byte              *output;
+        word32             length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        int                sendSz;
+        int                ret;
+        byte               sessIdSz = ID_LEN;
+
+        length = VERSION_SZ + RAN_LEN
+               + ID_LEN + ENUM_LEN
+               + SUITE_LEN
+               + ENUM_LEN;
+
+#ifdef HAVE_TLS_EXTENSIONS
+        length += TLSX_GetResponseSize(ssl);
+
+    #ifdef HAVE_SESSION_TICKET
+        if (ssl->options.useTicket && ssl->arrays->sessionIDSz == 0) {
+            /* no session id */
+            length  -= ID_LEN;
+            sessIdSz = 0;
+        }
+    #endif /* HAVE_SESSION_TICKET */
+#endif
+
+        /* check for avalaible size */
+        if ((ret = CheckAvailableSize(ssl, MAX_HELLO_SZ)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.length;
+
+        sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+        AddHeaders(output, length, server_hello, ssl);
+
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls) {
+                idx    += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+            }
+        #endif
+        /* now write to output */
+            /* first version */
+        output[idx++] = ssl->version.major;
+        output[idx++] = ssl->version.minor;
+
+            /* then random */
+        if (!ssl->options.resuming) {
+            ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom,
+                                                                       RAN_LEN);
+            if (ret != 0)
+                return ret;
+        }
+
+        XMEMCPY(output + idx, ssl->arrays->serverRandom, RAN_LEN);
+        idx += RAN_LEN;
+
+#ifdef SHOW_SECRETS
+        {
+            int j;
+            printf("server random: ");
+            for (j = 0; j < RAN_LEN; j++)
+                printf("%02x", ssl->arrays->serverRandom[j]);
+            printf("\n");
+        }
+#endif
+            /* then session id */
+        output[idx++] = sessIdSz;
+        if (sessIdSz) {
+
+            if (!ssl->options.resuming) {
+                ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->sessionID,
+                                           sessIdSz);
+                if (ret != 0) return ret;
+            }
+
+            XMEMCPY(output + idx, ssl->arrays->sessionID, sessIdSz);
+            idx += sessIdSz;
+        }
+
+            /* then cipher suite */
+        output[idx++] = ssl->options.cipherSuite0;
+        output[idx++] = ssl->options.cipherSuite;
+
+            /* then compression */
+        if (ssl->options.usingCompression)
+            output[idx++] = ZLIB_COMPRESSION;
+        else
+            output[idx++] = NO_COMPRESSION;
+
+            /* last, extensions */
+#ifdef HAVE_TLS_EXTENSIONS
+        TLSX_WriteResponse(ssl, output + idx);
+#endif
+
+        ssl->buffers.outputBuffer.length += sendSz;
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls) {
+                if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                    return ret;
+            }
+        #endif
+
+        ret = HashOutput(ssl, output, sendSz, 0);
+        if (ret != 0)
+            return ret;
+
+        #ifdef WOLFSSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("ServerHello", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddPacketInfo("ServerHello", &ssl->timeoutInfo, output, sendSz,
+                              ssl->heap);
+        #endif
+
+        ssl->options.serverState = SERVER_HELLO_COMPLETE;
+
+        if (ssl->options.groupMessages)
+            return 0;
+        else
+            return SendBuffered(ssl);
+    }
+
+
+#ifdef HAVE_ECC
+
+    static byte SetCurveId(int size)
+    {
+        switch(size) {
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC160)
+            case 20:
+                return WOLFSSL_ECC_SECP160R1;
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC192)
+            case 24:
+                return WOLFSSL_ECC_SECP192R1;
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC224)
+            case 28:
+                return WOLFSSL_ECC_SECP224R1;
+#endif
+#if defined(HAVE_ALL_CURVES) || !defined(NO_ECC256)
+            case 32:
+                return WOLFSSL_ECC_SECP256R1;
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC384)
+            case 48:
+                return WOLFSSL_ECC_SECP384R1;
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC521)
+            case 66:
+                return WOLFSSL_ECC_SECP521R1;
+#endif
+            default:
+                return 0;
+        }
+    }
+
+#endif /* HAVE_ECC */
+
+
+    int SendServerKeyExchange(WOLFSSL* ssl)
+    {
+        int ret = 0;
+        (void)ssl;
+        #define ERROR_OUT(err, eLabel) do { ret = err; goto eLabel; } while(0)
+
+    #ifndef NO_PSK
+        if (ssl->specs.kea == psk_kea)
+        {
+            byte    *output;
+            word32   length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+            int      sendSz;
+            if (ssl->arrays->server_hint[0] == 0) return 0; /* don't send */
+
+            /* include size part */
+            length = (word32)XSTRLEN(ssl->arrays->server_hint);
+            if (length > MAX_PSK_ID_LEN)
+                return SERVER_HINT_ERROR;
+
+            length += HINT_LEN_SZ;
+            sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+        #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)
+               return ret;
+
+            /* get ouput buffer */
+            output = ssl->buffers.outputBuffer.buffer +
+                     ssl->buffers.outputBuffer.length;
+
+            AddHeaders(output, length, server_key_exchange, ssl);
+
+            /* key data */
+            c16toa((word16)(length - HINT_LEN_SZ), output + idx);
+            idx += HINT_LEN_SZ;
+            XMEMCPY(output + idx, ssl->arrays->server_hint,length -HINT_LEN_SZ);
+
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls)
+                if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                    return ret;
+        #endif
+
+            ret = HashOutput(ssl, output, sendSz, 0);
+            if (ret != 0)
+                return ret;
+
+        #ifdef WOLFSSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, output,
+                                                             sendSz, ssl->heap);
+        #endif
+
+            ssl->buffers.outputBuffer.length += sendSz;
+            if (ssl->options.groupMessages)
+                ret = 0;
+            else
+                ret = SendBuffered(ssl);
+            ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
+        }
+    #endif /*NO_PSK */
+
+    #if !defined(NO_DH) && !defined(NO_PSK)
+        if (ssl->specs.kea == dhe_psk_kea) {
+            byte    *output;
+            word32   length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+            word32   hintLen;
+            int      sendSz;
+            DhKey    dhKey;
+
+            if (ssl->buffers.serverDH_P.buffer == NULL ||
+                ssl->buffers.serverDH_G.buffer == NULL)
+                return NO_DH_PARAMS;
+
+            if (ssl->buffers.serverDH_Pub.buffer == NULL) {
+                ssl->buffers.serverDH_Pub.buffer = (byte*)XMALLOC(
+                        ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap,
+                        DYNAMIC_TYPE_DH);
+                if (ssl->buffers.serverDH_Pub.buffer == NULL)
+                    return MEMORY_E;
+            }
+
+            if (ssl->buffers.serverDH_Priv.buffer == NULL) {
+                ssl->buffers.serverDH_Priv.buffer = (byte*)XMALLOC(
+                        ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap,
+                        DYNAMIC_TYPE_DH);
+                if (ssl->buffers.serverDH_Priv.buffer == NULL)
+                    return MEMORY_E;
+            }
+
+            wc_InitDhKey(&dhKey);
+            ret = wc_DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer,
+                                   ssl->buffers.serverDH_P.length,
+                                   ssl->buffers.serverDH_G.buffer,
+                                   ssl->buffers.serverDH_G.length);
+            if (ret == 0)
+                ret = wc_DhGenerateKeyPair(&dhKey, ssl->rng,
+                                         ssl->buffers.serverDH_Priv.buffer,
+                                        &ssl->buffers.serverDH_Priv.length,
+                                         ssl->buffers.serverDH_Pub.buffer,
+                                        &ssl->buffers.serverDH_Pub.length);
+            wc_FreeDhKey(&dhKey);
+            if (ret != 0)
+                return ret;
+
+            length = LENGTH_SZ * 3 + /* p, g, pub */
+                     ssl->buffers.serverDH_P.length +
+                     ssl->buffers.serverDH_G.length +
+                     ssl->buffers.serverDH_Pub.length;
+
+            /* include size part */
+            hintLen = (word32)XSTRLEN(ssl->arrays->server_hint);
+            if (hintLen > MAX_PSK_ID_LEN)
+                return SERVER_HINT_ERROR;
+            length += hintLen + HINT_LEN_SZ;
+            sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+        #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)
+               return ret;
+
+            /* get ouput buffer */
+            output = ssl->buffers.outputBuffer.buffer +
+                     ssl->buffers.outputBuffer.length;
+
+            AddHeaders(output, length, server_key_exchange, ssl);
+
+            /* key data */
+            c16toa((word16)hintLen, output + idx);
+            idx += HINT_LEN_SZ;
+            XMEMCPY(output + idx, ssl->arrays->server_hint, hintLen);
+            idx += hintLen;
+
+            /* add p, g, pub */
+            c16toa((word16)ssl->buffers.serverDH_P.length, output + idx);
+            idx += LENGTH_SZ;
+            XMEMCPY(output + idx, ssl->buffers.serverDH_P.buffer,
+                                  ssl->buffers.serverDH_P.length);
+            idx += ssl->buffers.serverDH_P.length;
+
+            /*  g */
+            c16toa((word16)ssl->buffers.serverDH_G.length, output + idx);
+            idx += LENGTH_SZ;
+            XMEMCPY(output + idx, ssl->buffers.serverDH_G.buffer,
+                                  ssl->buffers.serverDH_G.length);
+            idx += ssl->buffers.serverDH_G.length;
+
+            /*  pub */
+            c16toa((word16)ssl->buffers.serverDH_Pub.length, output + idx);
+            idx += LENGTH_SZ;
+            XMEMCPY(output + idx, ssl->buffers.serverDH_Pub.buffer,
+                                  ssl->buffers.serverDH_Pub.length);
+            idx += ssl->buffers.serverDH_Pub.length;
+            (void)idx; /* suppress analyzer warning, and keep idx current */
+
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls)
+                if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                    return ret;
+        #endif
+
+            ret = HashOutput(ssl, output, sendSz, 0);
+
+            if (ret != 0)
+                return ret;
+
+        #ifdef WOLFSSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, output,
+                                                             sendSz, ssl->heap);
+        #endif
+
+            ssl->buffers.outputBuffer.length += sendSz;
+            if (ssl->options.groupMessages)
+                ret = 0;
+            else
+                ret = SendBuffered(ssl);
+            ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
+        }
+    #endif /* !NO_DH && !NO_PSK */
+
+    #ifdef HAVE_ECC
+        if (ssl->specs.kea == ecc_diffie_hellman_kea)
+        {
+            byte    *output;
+            word32   length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+            int      sendSz;
+            word32   sigSz;
+            word32   preSigSz, preSigIdx;
+        #ifndef NO_RSA
+            RsaKey   rsaKey;
+        #endif
+            ecc_key  dsaKey;
+        #ifdef WOLFSSL_SMALL_STACK
+            byte*    exportBuf = NULL;
+        #else
+            byte     exportBuf[MAX_EXPORT_ECC_SZ];
+        #endif
+            word32   expSz = MAX_EXPORT_ECC_SZ;
+
+        #ifndef NO_OLD_TLS
+            byte doMd5 = 0;
+            byte doSha = 0;
+        #endif
+        #ifndef NO_SHA256
+            byte doSha256 = 0;
+        #endif
+        #ifdef WOLFSSL_SHA384
+            byte doSha384 = 0;
+        #endif
+        #ifdef WOLFSSL_SHA512
+            byte doSha512 = 0;
+        #endif
+
+            if (ssl->specs.static_ecdh) {
+                WOLFSSL_MSG("Using Static ECDH, not sending ServerKeyExchagne");
+                return 0;
+            }
+
+            /* curve type, named curve, length(1) */
+            length = ENUM_LEN + CURVE_LEN + ENUM_LEN;
+            /* pub key size */
+            WOLFSSL_MSG("Using ephemeral ECDH");
+
+            /* need ephemeral key now, create it if missing */
+            if (ssl->eccTempKey == NULL) {
+                /* alloc/init on demand */
+                ssl->eccTempKey = (ecc_key*)XMALLOC(sizeof(ecc_key),
+                                              ssl->ctx->heap, DYNAMIC_TYPE_ECC);
+                if (ssl->eccTempKey == NULL) {
+                    WOLFSSL_MSG("EccTempKey Memory error");
+                    return MEMORY_E;
+                }
+                wc_ecc_init(ssl->eccTempKey);
+            }
+            if (ssl->eccTempKeyPresent == 0) {
+                if (wc_ecc_make_key(ssl->rng, ssl->eccTempKeySz,
+                                 ssl->eccTempKey) != 0) {
+                    return ECC_MAKEKEY_ERROR;
+                }
+                ssl->eccTempKeyPresent = 1;
+            }
+
+        #ifdef WOLFSSL_SMALL_STACK
+            exportBuf = (byte*)XMALLOC(MAX_EXPORT_ECC_SZ, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            if (exportBuf == NULL)
+                return MEMORY_E;
+        #endif
+
+            if (wc_ecc_export_x963(ssl->eccTempKey, exportBuf, &expSz) != 0)
+                ERROR_OUT(ECC_EXPORT_ERROR, done_a);
+            length += expSz;
+
+            preSigSz  = length;
+            preSigIdx = idx;
+
+        #ifndef NO_RSA
+            ret = wc_InitRsaKey(&rsaKey, ssl->heap);
+            if (ret != 0)
+                goto done_a;
+        #endif
+
+            wc_ecc_init(&dsaKey);
+
+            /* sig length */
+            length += LENGTH_SZ;
+
+            if (!ssl->buffers.key.buffer) {
+            #ifndef NO_RSA
+                wc_FreeRsaKey(&rsaKey);
+            #endif
+                wc_ecc_free(&dsaKey);
+                ERROR_OUT(NO_PRIVATE_KEY, done_a);
+            }
+
+        #ifndef NO_RSA
+            if (ssl->specs.sig_algo == rsa_sa_algo) {
+                /* rsa sig size */
+                word32 i = 0;
+                ret = wc_RsaPrivateKeyDecode(ssl->buffers.key.buffer, &i,
+                                          &rsaKey, ssl->buffers.key.length);
+                if (ret != 0)
+                    goto done_a;
+                sigSz = wc_RsaEncryptSize(&rsaKey);
+            } else
+        #endif
+
+            if (ssl->specs.sig_algo == ecc_dsa_sa_algo) {
+                /* ecdsa sig size */
+                word32 i = 0;
+                ret = wc_EccPrivateKeyDecode(ssl->buffers.key.buffer, &i,
+                                          &dsaKey, ssl->buffers.key.length);
+                if (ret != 0)
+                    goto done_a;
+                sigSz = wc_ecc_sig_size(&dsaKey);  /* worst case estimate */
+            }
+            else {
+            #ifndef NO_RSA
+                wc_FreeRsaKey(&rsaKey);
+            #endif
+                wc_ecc_free(&dsaKey);
+                ERROR_OUT(ALGO_ID_E, done_a);  /* unsupported type */
+            }
+            length += sigSz;
+
+            if (IsAtLeastTLSv1_2(ssl))
+                length += HASH_SIG_SIZE;
+
+            sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls) {
+                sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                idx    += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                preSigIdx = idx;
+            }
+        #endif
+            /* check for available size */
+            if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) {
+            #ifndef NO_RSA
+                wc_FreeRsaKey(&rsaKey);
+            #endif
+                wc_ecc_free(&dsaKey);
+                goto done_a;
+            }
+
+            /* get ouput buffer */
+            output = ssl->buffers.outputBuffer.buffer +
+                     ssl->buffers.outputBuffer.length;
+
+            /* record and message headers will be added below, when we're sure
+               of the sig length */
+
+            /* key exchange data */
+            output[idx++] = named_curve;
+            output[idx++] = 0x00;          /* leading zero */
+            output[idx++] = SetCurveId(wc_ecc_size(ssl->eccTempKey));
+            output[idx++] = (byte)expSz;
+            XMEMCPY(output + idx, exportBuf, expSz);
+            idx += expSz;
+            if (IsAtLeastTLSv1_2(ssl)) {
+                byte setHash = 0;
+
+                output[idx++] = ssl->suites->hashAlgo;
+                output[idx++] = ssl->suites->sigAlgo;
+
+                switch (ssl->suites->hashAlgo) {
+                    case sha512_mac:
+                        #ifdef WOLFSSL_SHA512
+                            doSha512 = 1;
+                            setHash  = 1;
+                        #endif
+                        break;
+
+                    case sha384_mac:
+                        #ifdef WOLFSSL_SHA384
+                            doSha384 = 1;
+                            setHash  = 1;
+                        #endif
+                        break;
+
+                    case sha256_mac:
+                        #ifndef NO_SHA256
+                            doSha256 = 1;
+                            setHash  = 1;
+                        #endif
+                        break;
+
+                    case sha_mac:
+                        #ifndef NO_OLD_TLS
+                            doSha = 1;
+                            setHash  = 1;
+                        #endif
+                        break;
+
+                    default:
+                        WOLFSSL_MSG("Bad hash sig algo");
+                        break;
+                }
+
+                if (setHash == 0) {
+                    #ifndef NO_RSA
+                        wc_FreeRsaKey(&rsaKey);
+                    #endif
+                    wc_ecc_free(&dsaKey);
+                    ERROR_OUT(ALGO_ID_E, done_a);
+                }
+            } else {
+                /* only using sha and md5 for rsa */
+                #ifndef NO_OLD_TLS
+                    doSha = 1;
+                    if (ssl->suites->sigAlgo == rsa_sa_algo) {
+                        doMd5 = 1;
+                    }
+                #else
+                    #ifndef NO_RSA
+                        wc_FreeRsaKey(&rsaKey);
+                    #endif
+                    wc_ecc_free(&dsaKey);
+                    ERROR_OUT(ALGO_ID_E, done_a);
+                #endif
+            }
+
+            /* Signtaure length will be written later, when we're sure what it
+               is */
+
+        #ifdef HAVE_FUZZER
+            if (ssl->fuzzerCb)
+                ssl->fuzzerCb(ssl, output + preSigIdx, preSigSz, FUZZ_SIGNATURE,
+                              ssl->fuzzerCtx);
+        #endif
+
+            /* do signature */
+            {
+        #ifndef NO_OLD_TLS
+            #ifdef WOLFSSL_SMALL_STACK
+                Md5*   md5  = NULL;
+                Sha*   sha  = NULL;
+            #else
+                Md5    md5[1];
+                Sha    sha[1];
+            #endif
+        #endif
+            #ifdef WOLFSSL_SMALL_STACK
+                byte*  hash = NULL;
+            #else
+                byte   hash[FINISHED_SZ];
+            #endif
+        #ifndef NO_SHA256
+            #ifdef WOLFSSL_SMALL_STACK
+                Sha256* sha256  = NULL;
+                byte*   hash256 = NULL;
+            #else
+                Sha256  sha256[1];
+                byte    hash256[SHA256_DIGEST_SIZE];
+            #endif
+        #endif
+        #ifdef WOLFSSL_SHA384
+            #ifdef WOLFSSL_SMALL_STACK
+                Sha384* sha384  = NULL;
+                byte*   hash384 = NULL;
+            #else
+                Sha384  sha384[1];
+                byte    hash384[SHA384_DIGEST_SIZE];
+            #endif
+        #endif
+        #ifdef WOLFSSL_SHA512
+            #ifdef WOLFSSL_SMALL_STACK
+                Sha512* sha512  = NULL;
+                byte*   hash512 = NULL;
+            #else
+                Sha512  sha512[1];
+                byte    hash512[SHA512_DIGEST_SIZE];
+            #endif
+        #endif
+
+            #ifdef WOLFSSL_SMALL_STACK
+                hash = (byte*)XMALLOC(FINISHED_SZ, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                if (hash == NULL)
+                    ERROR_OUT(MEMORY_E, done_a);
+            #endif
+
+        #ifndef NO_OLD_TLS
+                /* md5 */
+            #ifdef WOLFSSL_SMALL_STACK
+                if (doMd5) {
+                    md5 = (Md5*)XMALLOC(sizeof(Md5), NULL,
+                                        DYNAMIC_TYPE_TMP_BUFFER);
+                    if (md5 == NULL)
+                        ERROR_OUT(MEMORY_E, done_a2);
+                }
+            #endif
+                if (doMd5) {
+                    wc_InitMd5(md5);
+                    wc_Md5Update(md5, ssl->arrays->clientRandom, RAN_LEN);
+                    wc_Md5Update(md5, ssl->arrays->serverRandom, RAN_LEN);
+                    wc_Md5Update(md5, output + preSigIdx, preSigSz);
+                    wc_Md5Final(md5, hash);
+                }
+                /* sha */
+            #ifdef WOLFSSL_SMALL_STACK
+                if (doSha) {
+                    sha = (Sha*)XMALLOC(sizeof(Sha), NULL,
+                                        DYNAMIC_TYPE_TMP_BUFFER);
+                    if (sha == NULL)
+                        ERROR_OUT(MEMORY_E, done_a2);
+                }
+            #endif
+                if (doSha) {
+                    ret = wc_InitSha(sha);
+                    if (ret != 0) goto done_a2;
+                    wc_ShaUpdate(sha, ssl->arrays->clientRandom, RAN_LEN);
+                    wc_ShaUpdate(sha, ssl->arrays->serverRandom, RAN_LEN);
+                    wc_ShaUpdate(sha, output + preSigIdx, preSigSz);
+                    wc_ShaFinal(sha, &hash[MD5_DIGEST_SIZE]);
+                }
+        #endif
+
+        #ifndef NO_SHA256
+            #ifdef WOLFSSL_SMALL_STACK
+                if (doSha256) {
+                    sha256 = (Sha256*)XMALLOC(sizeof(Sha256), NULL,
+                                              DYNAMIC_TYPE_TMP_BUFFER);
+                    hash256 = (byte*)XMALLOC(SHA256_DIGEST_SIZE, NULL,
+                                             DYNAMIC_TYPE_TMP_BUFFER);
+                    if (sha256 == NULL || hash256 == NULL)
+                        ERROR_OUT(MEMORY_E, done_a2);
+                }
+            #endif
+
+                if (doSha256) {
+                    if (!(ret = wc_InitSha256(sha256))
+                    &&  !(ret = wc_Sha256Update(sha256,
+                                            ssl->arrays->clientRandom, RAN_LEN))
+                    &&  !(ret = wc_Sha256Update(sha256,
+                                            ssl->arrays->serverRandom, RAN_LEN))
+                    &&  !(ret = wc_Sha256Update(sha256,
+                                            output + preSigIdx, preSigSz)))
+                        ret = wc_Sha256Final(sha256, hash256);
+
+                    if (ret != 0) goto done_a2;
+                }
+        #endif
+
+        #ifdef WOLFSSL_SHA384
+            #ifdef WOLFSSL_SMALL_STACK
+                if (doSha384) {
+                    sha384 = (Sha384*)XMALLOC(sizeof(Sha384), NULL,
+                                              DYNAMIC_TYPE_TMP_BUFFER);
+                    hash384 = (byte*)XMALLOC(SHA384_DIGEST_SIZE, NULL,
+                                             DYNAMIC_TYPE_TMP_BUFFER);
+                    if (sha384 == NULL || hash384 == NULL)
+                        ERROR_OUT(MEMORY_E, done_a2);
+                }
+            #endif
+
+                if (doSha384) {
+                    if (!(ret = wc_InitSha384(sha384))
+                    &&  !(ret = wc_Sha384Update(sha384,
+                                            ssl->arrays->clientRandom, RAN_LEN))
+                    &&  !(ret = wc_Sha384Update(sha384,
+                                            ssl->arrays->serverRandom, RAN_LEN))
+                    &&  !(ret = wc_Sha384Update(sha384,
+                                            output + preSigIdx, preSigSz)))
+                        ret = wc_Sha384Final(sha384, hash384);
+
+                    if (ret != 0) goto done_a2;
+                }
+        #endif
+
+        #ifdef WOLFSSL_SHA512
+            #ifdef WOLFSSL_SMALL_STACK
+                if (doSha512) {
+                    sha512 = (Sha512*)XMALLOC(sizeof(Sha512), NULL,
+                                              DYNAMIC_TYPE_TMP_BUFFER);
+                    hash512 = (byte*)XMALLOC(SHA512_DIGEST_SIZE, NULL,
+                                             DYNAMIC_TYPE_TMP_BUFFER);
+                    if (sha512 == NULL || hash512 == NULL)
+                        ERROR_OUT(MEMORY_E, done_a2);
+                }
+            #endif
+
+                if (doSha512) {
+                    if (!(ret = wc_InitSha512(sha512))
+                    &&  !(ret = wc_Sha512Update(sha512,
+                                            ssl->arrays->clientRandom, RAN_LEN))
+                    &&  !(ret = wc_Sha512Update(sha512,
+                                            ssl->arrays->serverRandom, RAN_LEN))
+                    &&  !(ret = wc_Sha512Update(sha512,
+                                            output + preSigIdx, preSigSz)))
+                        ret = wc_Sha512Final(sha512, hash512);
+
+                    if (ret != 0) goto done_a2;
+                }
+        #endif
+
+            #ifndef NO_RSA
+                if (ssl->suites->sigAlgo == rsa_sa_algo) {
+                    byte*  signBuffer = hash;
+                    word32 signSz     = FINISHED_SZ;
+                    byte   doUserRsa = 0;
+                #ifdef WOLFSSL_SMALL_STACK
+                    byte*  encodedSig = NULL;
+                #else
+                    byte   encodedSig[MAX_ENCODED_SIG_SZ];
+                #endif
+
+                #ifdef HAVE_PK_CALLBACKS
+                    if (ssl->ctx->RsaSignCb)
+                        doUserRsa = 1;
+                #endif
+
+                #ifdef WOLFSSL_SMALL_STACK
+                    encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                    if (encodedSig == NULL)
+                        ERROR_OUT(MEMORY_E, done_a2);
+                #endif
+
+                    if (IsAtLeastTLSv1_2(ssl)) {
+                        byte* digest   = &hash[MD5_DIGEST_SIZE];
+                        int   typeH    = SHAh;
+                        int   digestSz = SHA_DIGEST_SIZE;
+
+                        if (ssl->suites->hashAlgo == sha256_mac) {
+                        #ifndef NO_SHA256
+                            digest   = hash256;
+                            typeH    = SHA256h;
+                            digestSz = SHA256_DIGEST_SIZE;
+                        #endif
+                        }
+                        else if (ssl->suites->hashAlgo == sha384_mac) {
+                        #ifdef WOLFSSL_SHA384
+                            digest   = hash384;
+                            typeH    = SHA384h;
+                            digestSz = SHA384_DIGEST_SIZE;
+                        #endif
+                        }
+                        else if (ssl->suites->hashAlgo == sha512_mac) {
+                        #ifdef WOLFSSL_SHA512
+                            digest   = hash512;
+                            typeH    = SHA512h;
+                            digestSz = SHA512_DIGEST_SIZE;
+                        #endif
+                        }
+
+                        if (digest == NULL) {
+                            #ifndef NO_RSA
+                                wc_FreeRsaKey(&rsaKey);
+                            #endif
+                            wc_ecc_free(&dsaKey);
+                            ERROR_OUT(ALGO_ID_E, done_a2);
+                        }
+                        signSz = wc_EncodeSignature(encodedSig, digest,
+                                                    digestSz, typeH);
+                        signBuffer = encodedSig;
+                    }
+                    /* write sig size here */
+                    c16toa((word16)sigSz, output + idx);
+                    idx += LENGTH_SZ;
+
+                    if (doUserRsa) {
+                    #ifdef HAVE_PK_CALLBACKS
+                        word32 ioLen = sigSz;
+                        ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz,
+                                            output + idx, &ioLen,
+                                            ssl->buffers.key.buffer,
+                                            ssl->buffers.key.length,
+                                            ssl->RsaSignCtx);
+                    #endif /*HAVE_PK_CALLBACKS */
+                    }
+                    else
+                        ret = wc_RsaSSL_Sign(signBuffer, signSz, output + idx,
+                                          sigSz, &rsaKey, ssl->rng);
+
+                    wc_FreeRsaKey(&rsaKey);
+                    wc_ecc_free(&dsaKey);
+
+                #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                #endif
+
+                    if (ret < 0)
+                        goto done_a2;
+                } else
+            #endif
+
+                if (ssl->suites->sigAlgo == ecc_dsa_sa_algo) {
+                #ifndef NO_OLD_TLS
+                    byte* digest = &hash[MD5_DIGEST_SIZE];
+                    word32 digestSz = SHA_DIGEST_SIZE;
+                #else
+                    byte* digest = hash256;
+                    word32 digestSz = SHA256_DIGEST_SIZE;
+                #endif
+                    word32 sz = sigSz;
+                    byte   doUserEcc = 0;
+
+                #if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC)
+                    if (ssl->ctx->EccSignCb)
+                        doUserEcc = 1;
+                #endif
+
+                    if (IsAtLeastTLSv1_2(ssl)) {
+                        if (ssl->suites->hashAlgo == sha_mac) {
+                        #ifndef NO_SHA
+                            digest   = &hash[MD5_DIGEST_SIZE];
+                            digestSz = SHA_DIGEST_SIZE;
+                        #endif
+                        }
+                        else if (ssl->suites->hashAlgo == sha256_mac) {
+                        #ifndef NO_SHA256
+                            digest   = hash256;
+                            digestSz = SHA256_DIGEST_SIZE;
+                        #endif
+                        }
+                        else if (ssl->suites->hashAlgo == sha384_mac) {
+                        #ifdef WOLFSSL_SHA384
+                            digest   = hash384;
+                            digestSz = SHA384_DIGEST_SIZE;
+                        #endif
+                        }
+                        else if (ssl->suites->hashAlgo == sha512_mac) {
+                        #ifdef WOLFSSL_SHA512
+                            digest   = hash512;
+                            digestSz = SHA512_DIGEST_SIZE;
+                        #endif
+                        }
+                    }
+
+                    if (doUserEcc) {
+                    #if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC)
+                        ret = ssl->ctx->EccSignCb(ssl, digest, digestSz,
+                                                  output + LENGTH_SZ + idx, &sz,
+                                                  ssl->buffers.key.buffer,
+                                                  ssl->buffers.key.length,
+                                                  ssl->EccSignCtx);
+                    #endif
+                    }
+                    else {
+                        ret = wc_ecc_sign_hash(digest, digestSz,
+                              output + LENGTH_SZ + idx, &sz, ssl->rng, &dsaKey);
+                    }
+                #ifndef NO_RSA
+                    wc_FreeRsaKey(&rsaKey);
+                #endif
+                    wc_ecc_free(&dsaKey);
+
+                    if (ret < 0)
+                        goto done_a2;
+
+                    /* Now that we know the real sig size, write it. */
+                    c16toa((word16)sz, output + idx);
+
+                    /* And adjust length and sendSz from estimates */
+                    length += sz - sigSz;
+                    sendSz += sz - sigSz;
+                }
+
+            done_a2:
+        #ifdef WOLFSSL_SMALL_STACK
+            #ifndef NO_OLD_TLS
+                XFREE(md5,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(sha,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            #endif
+                XFREE(hash,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            #ifndef NO_SHA256
+                XFREE(sha256,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(hash256, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            #endif
+            #ifdef WOLFSSL_SHA384
+                XFREE(sha384,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(hash384, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            #endif
+            #ifdef WOLFSSL_SHA512
+                XFREE(sha512,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(hash512, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            #endif
+        #endif
+
+                if (ret < 0)
+                    goto done_a;
+            }
+
+            AddHeaders(output, length, server_key_exchange, ssl);
+
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls)
+                if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                    goto done_a;
+        #endif
+
+            if ((ret = HashOutput(ssl, output, sendSz, 0)) != 0)
+                goto done_a;
+
+        #ifdef WOLFSSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo,
+                              output, sendSz, ssl->heap);
+        #endif
+
+            ssl->buffers.outputBuffer.length += sendSz;
+            if (ssl->options.groupMessages)
+                ret = 0;
+            else
+                ret = SendBuffered(ssl);
+            ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
+
+        done_a:
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(exportBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+
+            return ret;
+        }
+    #endif /* HAVE_ECC */
+
+    #if !defined(NO_DH) && !defined(NO_RSA)
+        if (ssl->specs.kea == diffie_hellman_kea) {
+            byte    *output;
+            word32   length = 0, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+            int      sendSz;
+            word32   sigSz = 0, i = 0;
+            word32   preSigSz = 0, preSigIdx = 0;
+            RsaKey   rsaKey;
+            DhKey    dhKey;
+
+            if (ssl->buffers.serverDH_P.buffer == NULL ||
+                ssl->buffers.serverDH_G.buffer == NULL)
+                return NO_DH_PARAMS;
+
+            if (ssl->buffers.serverDH_Pub.buffer == NULL) {
+                ssl->buffers.serverDH_Pub.buffer = (byte*)XMALLOC(
+                        ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap,
+                        DYNAMIC_TYPE_DH);
+                if (ssl->buffers.serverDH_Pub.buffer == NULL)
+                    return MEMORY_E;
+            }
+
+            if (ssl->buffers.serverDH_Priv.buffer == NULL) {
+                ssl->buffers.serverDH_Priv.buffer = (byte*)XMALLOC(
+                        ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap,
+                        DYNAMIC_TYPE_DH);
+                if (ssl->buffers.serverDH_Priv.buffer == NULL)
+                    return MEMORY_E;
+            }
+
+            wc_InitDhKey(&dhKey);
+            ret = wc_DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer,
+                                   ssl->buffers.serverDH_P.length,
+                                   ssl->buffers.serverDH_G.buffer,
+                                   ssl->buffers.serverDH_G.length);
+            if (ret == 0)
+                ret = wc_DhGenerateKeyPair(&dhKey, ssl->rng,
+                                         ssl->buffers.serverDH_Priv.buffer,
+                                        &ssl->buffers.serverDH_Priv.length,
+                                         ssl->buffers.serverDH_Pub.buffer,
+                                        &ssl->buffers.serverDH_Pub.length);
+            wc_FreeDhKey(&dhKey);
+
+            if (ret != 0) return ret;
+
+            length = LENGTH_SZ * 3;  /* p, g, pub */
+            length += ssl->buffers.serverDH_P.length +
+                      ssl->buffers.serverDH_G.length +
+                      ssl->buffers.serverDH_Pub.length;
+
+            preSigIdx = idx;
+            preSigSz  = length;
+
+            if (!ssl->options.usingAnon_cipher) {
+                ret = wc_InitRsaKey(&rsaKey, ssl->heap);
+                if (ret != 0) return ret;
+
+                /* sig length */
+                length += LENGTH_SZ;
+
+                if (!ssl->buffers.key.buffer)
+                    return NO_PRIVATE_KEY;
+
+                ret = wc_RsaPrivateKeyDecode(ssl->buffers.key.buffer, &i, &rsaKey,
+                                          ssl->buffers.key.length);
+                if (ret == 0) {
+                    sigSz = wc_RsaEncryptSize(&rsaKey);
+                    length += sigSz;
+                }
+                else {
+                    wc_FreeRsaKey(&rsaKey);
+                    return ret;
+                }
+
+                if (IsAtLeastTLSv1_2(ssl))
+                    length += HASH_SIG_SIZE;
+            }
+
+            sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls) {
+                sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                idx    += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                preSigIdx = idx;
+            }
+        #endif
+
+            /* check for available size */
+            if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) {
+                if (!ssl->options.usingAnon_cipher)
+                    wc_FreeRsaKey(&rsaKey);
+                return ret;
+            }
+
+            /* get ouput buffer */
+            output = ssl->buffers.outputBuffer.buffer +
+                     ssl->buffers.outputBuffer.length;
+
+            AddHeaders(output, length, server_key_exchange, ssl);
+
+            /* add p, g, pub */
+            c16toa((word16)ssl->buffers.serverDH_P.length, output + idx);
+            idx += LENGTH_SZ;
+            XMEMCPY(output + idx, ssl->buffers.serverDH_P.buffer,
+                                  ssl->buffers.serverDH_P.length);
+            idx += ssl->buffers.serverDH_P.length;
+
+            /*  g */
+            c16toa((word16)ssl->buffers.serverDH_G.length, output + idx);
+            idx += LENGTH_SZ;
+            XMEMCPY(output + idx, ssl->buffers.serverDH_G.buffer,
+                                  ssl->buffers.serverDH_G.length);
+            idx += ssl->buffers.serverDH_G.length;
+
+            /*  pub */
+            c16toa((word16)ssl->buffers.serverDH_Pub.length, output + idx);
+            idx += LENGTH_SZ;
+            XMEMCPY(output + idx, ssl->buffers.serverDH_Pub.buffer,
+                                  ssl->buffers.serverDH_Pub.length);
+            idx += ssl->buffers.serverDH_Pub.length;
+
+        #ifdef HAVE_FUZZER
+            if (ssl->fuzzerCb)
+                ssl->fuzzerCb(ssl, output + preSigIdx, preSigSz, FUZZ_SIGNATURE,
+                        ssl->fuzzerCtx);
+        #endif
+
+            /* Add signature */
+            if (!ssl->options.usingAnon_cipher) {
+        #ifndef NO_OLD_TLS
+            #ifdef WOLFSSL_SMALL_STACK
+                Md5*   md5  = NULL;
+                Sha*   sha  = NULL;
+            #else
+                Md5    md5[1];
+                Sha    sha[1];
+            #endif
+        #endif
+            #ifdef WOLFSSL_SMALL_STACK
+                byte*  hash = NULL;
+            #else
+                byte   hash[FINISHED_SZ];
+            #endif
+        #ifndef NO_SHA256
+            #ifdef WOLFSSL_SMALL_STACK
+                Sha256* sha256  = NULL;
+                byte*   hash256 = NULL;
+            #else
+                Sha256  sha256[1];
+                byte    hash256[SHA256_DIGEST_SIZE];
+            #endif
+        #endif
+        #ifdef WOLFSSL_SHA384
+            #ifdef WOLFSSL_SMALL_STACK
+                Sha384* sha384  = NULL;
+                byte*   hash384 = NULL;
+            #else
+                Sha384  sha384[1];
+                byte    hash384[SHA384_DIGEST_SIZE];
+            #endif
+        #endif
+        #ifdef WOLFSSL_SHA512
+            #ifdef WOLFSSL_SMALL_STACK
+                Sha512* sha512  = NULL;
+                byte*   hash512 = NULL;
+            #else
+                Sha512  sha512[1];
+                byte    hash512[SHA512_DIGEST_SIZE];
+            #endif
+        #endif
+
+        #ifndef NO_OLD_TLS
+            byte doMd5 = 0;
+            byte doSha = 0;
+        #endif
+        #ifndef NO_SHA256
+            byte doSha256 = 0;
+        #endif
+        #ifdef WOLFSSL_SHA384
+            byte doSha384 = 0;
+        #endif
+        #ifdef WOLFSSL_SHA512
+            byte doSha512 = 0;
+        #endif
+
+            /* Add hash/signature algo ID */
+            if (IsAtLeastTLSv1_2(ssl)) {
+                byte setHash = 0;
+
+                output[idx++] = ssl->suites->hashAlgo;
+                output[idx++] = ssl->suites->sigAlgo;
+
+                switch (ssl->suites->hashAlgo) {
+                    case sha512_mac:
+                        #ifdef WOLFSSL_SHA512
+                            doSha512 = 1;
+                            setHash  = 1;
+                        #endif
+                        break;
+
+                    case sha384_mac:
+                        #ifdef WOLFSSL_SHA384
+                            doSha384 = 1;
+                            setHash  = 1;
+                        #endif
+                        break;
+
+                    case sha256_mac:
+                        #ifndef NO_SHA256
+                            doSha256 = 1;
+                            setHash  = 1;
+                        #endif
+                        break;
+
+                    case sha_mac:
+                        #ifndef NO_OLD_TLS
+                            doSha = 1;
+                            setHash  = 1;
+                        #endif
+                        break;
+
+                    default:
+                        WOLFSSL_MSG("Bad hash sig algo");
+                        break;
+                }
+
+                if (setHash == 0) {
+                    wc_FreeRsaKey(&rsaKey);
+                    return ALGO_ID_E;
+                }
+            } else {
+                /* only using sha and md5 for rsa */
+                #ifndef NO_OLD_TLS
+                    doSha = 1;
+                    if (ssl->suites->sigAlgo == rsa_sa_algo) {
+                        doMd5 = 1;
+                    }
+                #else
+                    wc_FreeRsaKey(&rsaKey);
+                    return ALGO_ID_E;
+                #endif
+            }
+
+            /* signature size */
+            c16toa((word16)sigSz, output + idx);
+            idx += LENGTH_SZ;
+
+            /* do signature */
+            #ifdef WOLFSSL_SMALL_STACK
+                hash = (byte*)XMALLOC(FINISHED_SZ, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                if (hash == NULL)
+                    return MEMORY_E; /* No heap commitment before this point,
+                                        from now on, the resources are freed
+                                        at done_b. */
+            #endif
+
+        #ifndef NO_OLD_TLS
+                /* md5 */
+            #ifdef WOLFSSL_SMALL_STACK
+                if (doMd5) {
+                    md5 = (Md5*)XMALLOC(sizeof(Md5), NULL,
+                                        DYNAMIC_TYPE_TMP_BUFFER);
+                    if (md5 == NULL)
+                        ERROR_OUT(MEMORY_E, done_b);
+                }
+            #endif
+                if (doMd5) {
+                    wc_InitMd5(md5);
+                    wc_Md5Update(md5, ssl->arrays->clientRandom, RAN_LEN);
+                    wc_Md5Update(md5, ssl->arrays->serverRandom, RAN_LEN);
+                    wc_Md5Update(md5, output + preSigIdx, preSigSz);
+                    wc_Md5Final(md5, hash);
+                }
+
+                /* sha */
+            #ifdef WOLFSSL_SMALL_STACK
+                if (doSha) {
+                    sha = (Sha*)XMALLOC(sizeof(Sha), NULL,
+                                        DYNAMIC_TYPE_TMP_BUFFER);
+                    if (sha == NULL)
+                        ERROR_OUT(MEMORY_E, done_b);
+                }
+            #endif
+
+                if (doSha) {
+                    if ((ret = wc_InitSha(sha)) != 0)
+                        goto done_b;
+                    wc_ShaUpdate(sha, ssl->arrays->clientRandom, RAN_LEN);
+                    wc_ShaUpdate(sha, ssl->arrays->serverRandom, RAN_LEN);
+                    wc_ShaUpdate(sha, output + preSigIdx, preSigSz);
+                    wc_ShaFinal(sha, &hash[MD5_DIGEST_SIZE]);
+                }
+        #endif
+
+        #ifndef NO_SHA256
+            #ifdef WOLFSSL_SMALL_STACK
+                if (doSha256) {
+                    sha256 = (Sha256*)XMALLOC(sizeof(Sha256), NULL,
+                                              DYNAMIC_TYPE_TMP_BUFFER);
+                    hash256 = (byte*)XMALLOC(SHA256_DIGEST_SIZE, NULL,
+                                             DYNAMIC_TYPE_TMP_BUFFER);
+                    if (sha256 == NULL || hash256 == NULL)
+                        ERROR_OUT(MEMORY_E, done_b);
+                }
+            #endif
+
+                if (doSha256) {
+                    if (!(ret = wc_InitSha256(sha256))
+                    &&  !(ret = wc_Sha256Update(sha256,
+                                            ssl->arrays->clientRandom, RAN_LEN))
+                    &&  !(ret = wc_Sha256Update(sha256,
+                                            ssl->arrays->serverRandom, RAN_LEN))
+                    &&  !(ret = wc_Sha256Update(sha256,
+                                            output + preSigIdx, preSigSz)))
+                        ret = wc_Sha256Final(sha256, hash256);
+
+                    if (ret != 0) goto done_b;
+                }
+            #endif
+
+        #ifdef WOLFSSL_SHA384
+            #ifdef WOLFSSL_SMALL_STACK
+                if (doSha384) {
+                    sha384 = (Sha384*)XMALLOC(sizeof(Sha384), NULL,
+                                              DYNAMIC_TYPE_TMP_BUFFER);
+                    hash384 = (byte*)XMALLOC(SHA384_DIGEST_SIZE, NULL,
+                                             DYNAMIC_TYPE_TMP_BUFFER);
+                    if (sha384 == NULL || hash384 == NULL)
+                        ERROR_OUT(MEMORY_E, done_b);
+                }
+            #endif
+
+                if (doSha384) {
+                    if (!(ret = wc_InitSha384(sha384))
+                    &&  !(ret = wc_Sha384Update(sha384,
+                                            ssl->arrays->clientRandom, RAN_LEN))
+                    &&  !(ret = wc_Sha384Update(sha384,
+                                            ssl->arrays->serverRandom, RAN_LEN))
+                    &&  !(ret = wc_Sha384Update(sha384,
+                                            output + preSigIdx, preSigSz)))
+                        ret = wc_Sha384Final(sha384, hash384);
+
+                    if (ret != 0) goto done_b;
+                }
+        #endif
+
+        #ifdef WOLFSSL_SHA512
+            #ifdef WOLFSSL_SMALL_STACK
+                if (doSha512) {
+                    sha512 = (Sha512*)XMALLOC(sizeof(Sha512), NULL,
+                                              DYNAMIC_TYPE_TMP_BUFFER);
+                    hash512 = (byte*)XMALLOC(SHA512_DIGEST_SIZE, NULL,
+                                             DYNAMIC_TYPE_TMP_BUFFER);
+                    if (sha512 == NULL || hash512 == NULL)
+                        ERROR_OUT(MEMORY_E, done_b);
+                }
+            #endif
+
+                if (doSha512) {
+                    if (!(ret = wc_InitSha512(sha512))
+                    &&  !(ret = wc_Sha512Update(sha512,
+                                            ssl->arrays->clientRandom, RAN_LEN))
+                    &&  !(ret = wc_Sha512Update(sha512,
+                                            ssl->arrays->serverRandom, RAN_LEN))
+                    &&  !(ret = wc_Sha512Update(sha512,
+                                            output + preSigIdx, preSigSz)))
+                        ret = wc_Sha512Final(sha512, hash512);
+
+                    if (ret != 0) goto done_b;
+                }
+        #endif
+
+            #ifndef NO_RSA
+                if (ssl->suites->sigAlgo == rsa_sa_algo) {
+                    byte*  signBuffer = hash;
+                    word32 signSz     = FINISHED_SZ;
+                #ifdef WOLFSSL_SMALL_STACK
+                    byte*  encodedSig = NULL;
+                #else
+                    byte   encodedSig[MAX_ENCODED_SIG_SZ];
+                #endif
+                    byte   doUserRsa = 0;
+
+                #ifdef HAVE_PK_CALLBACKS
+                    if (ssl->ctx->RsaSignCb)
+                        doUserRsa = 1;
+                #endif
+
+                #ifdef WOLFSSL_SMALL_STACK
+                    encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                    if (encodedSig == NULL)
+                        ERROR_OUT(MEMORY_E, done_b);
+                #endif
+
+                    if (IsAtLeastTLSv1_2(ssl)) {
+                        byte* digest   = &hash[MD5_DIGEST_SIZE];
+                        int   typeH    = SHAh;
+                        int   digestSz = SHA_DIGEST_SIZE;
+
+                        if (ssl->suites->hashAlgo == sha256_mac) {
+                        #ifndef NO_SHA256
+                            digest   = hash256;
+                            typeH    = SHA256h;
+                            digestSz = SHA256_DIGEST_SIZE;
+                        #endif
+                        }
+                        else if (ssl->suites->hashAlgo == sha384_mac) {
+                        #ifdef WOLFSSL_SHA384
+                            digest   = hash384;
+                            typeH    = SHA384h;
+                            digestSz = SHA384_DIGEST_SIZE;
+                        #endif
+                        }
+                        else if (ssl->suites->hashAlgo == sha512_mac) {
+                        #ifdef WOLFSSL_SHA512
+                            digest   = hash512;
+                            typeH    = SHA512h;
+                            digestSz = SHA512_DIGEST_SIZE;
+                        #endif
+                        }
+
+                        if (digest == NULL) {
+                            ret = ALGO_ID_E;
+                        } else {
+                            signSz = wc_EncodeSignature(encodedSig, digest,
+                                                        digestSz, typeH);
+                            signBuffer = encodedSig;
+                        }
+                    }
+                    if (doUserRsa && ret == 0) {
+                    #ifdef HAVE_PK_CALLBACKS
+                        word32 ioLen = sigSz;
+                        ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz,
+                                                  output + idx, &ioLen,
+                                                  ssl->buffers.key.buffer,
+                                                  ssl->buffers.key.length,
+                                                  ssl->RsaSignCtx);
+                    #endif
+                    } else if (ret == 0) {
+                        ret = wc_RsaSSL_Sign(signBuffer, signSz, output + idx,
+                                          sigSz, &rsaKey, ssl->rng);
+                    }
+
+                    wc_FreeRsaKey(&rsaKey);
+
+                #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                #endif
+                }
+            #endif
+
+            done_b:
+        #ifdef WOLFSSL_SMALL_STACK
+            #ifndef NO_OLD_TLS
+                XFREE(md5,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(sha,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            #endif
+                XFREE(hash,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            #ifndef NO_SHA256
+                XFREE(sha256,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(hash256, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            #endif
+            #ifdef WOLFSSL_SHA384
+                XFREE(sha384,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(hash384, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            #endif
+            #ifdef WOLFSSL_SHA512
+                XFREE(sha512,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(hash512, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            #endif
+        #endif
+
+                if (ret < 0) return ret;
+            }
+
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls)
+                if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                    return ret;
+        #endif
+
+            if ((ret = HashOutput(ssl, output, sendSz, 0)) != 0)
+                return ret;
+
+        #ifdef WOLFSSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo,
+                              output, sendSz, ssl->heap);
+        #endif
+
+            ssl->buffers.outputBuffer.length += sendSz;
+            if (ssl->options.groupMessages)
+                ret = 0;
+            else
+                ret = SendBuffered(ssl);
+            ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
+        }
+    #endif /* NO_DH */
+
+        return ret;
+        #undef ERROR_OUT
+    }
+
+
+    /* Make sure server cert/key are valid for this suite, true on success */
+    static int VerifyServerSuite(WOLFSSL* ssl, word16 idx)
+    {
+        int  haveRSA = !ssl->options.haveStaticECC;
+        int  havePSK = 0;
+        byte first;
+        byte second;
+
+        WOLFSSL_ENTER("VerifyServerSuite");
+
+        if (ssl->suites == NULL) {
+            WOLFSSL_MSG("Suites pointer error");
+            return 0;
+        }
+
+        first   = ssl->suites->suites[idx];
+        second  = ssl->suites->suites[idx+1];
+
+        #ifndef NO_PSK
+            havePSK = ssl->options.havePSK;
+        #endif
+
+        if (ssl->options.haveNTRU)
+            haveRSA = 0;
+
+        if (CipherRequires(first, second, REQUIRES_RSA)) {
+            WOLFSSL_MSG("Requires RSA");
+            if (haveRSA == 0) {
+                WOLFSSL_MSG("Don't have RSA");
+                return 0;
+            }
+        }
+
+        if (CipherRequires(first, second, REQUIRES_DHE)) {
+            WOLFSSL_MSG("Requires DHE");
+            if (ssl->options.haveDH == 0) {
+                WOLFSSL_MSG("Don't have DHE");
+                return 0;
+            }
+        }
+
+        if (CipherRequires(first, second, REQUIRES_ECC_DSA)) {
+            WOLFSSL_MSG("Requires ECCDSA");
+            if (ssl->options.haveECDSAsig == 0) {
+                WOLFSSL_MSG("Don't have ECCDSA");
+                return 0;
+            }
+        }
+
+        if (CipherRequires(first, second, REQUIRES_ECC_STATIC)) {
+            WOLFSSL_MSG("Requires static ECC");
+            if (ssl->options.haveStaticECC == 0) {
+                WOLFSSL_MSG("Don't have static ECC");
+                return 0;
+            }
+        }
+
+        if (CipherRequires(first, second, REQUIRES_PSK)) {
+            WOLFSSL_MSG("Requires PSK");
+            if (havePSK == 0) {
+                WOLFSSL_MSG("Don't have PSK");
+                return 0;
+            }
+        }
+
+        if (CipherRequires(first, second, REQUIRES_NTRU)) {
+            WOLFSSL_MSG("Requires NTRU");
+            if (ssl->options.haveNTRU == 0) {
+                WOLFSSL_MSG("Don't have NTRU");
+                return 0;
+            }
+        }
+
+        if (CipherRequires(first, second, REQUIRES_RSA_SIG)) {
+            WOLFSSL_MSG("Requires RSA Signature");
+            if (ssl->options.side == WOLFSSL_SERVER_END &&
+                                           ssl->options.haveECDSAsig == 1) {
+                WOLFSSL_MSG("Don't have RSA Signature");
+                return 0;
+            }
+        }
+
+#ifdef HAVE_SUPPORTED_CURVES
+        if (!TLSX_ValidateEllipticCurves(ssl, first, second)) {
+            WOLFSSL_MSG("Don't have matching curves");
+                return 0;
+        }
+#endif
+
+        /* ECCDHE is always supported if ECC on */
+
+        return 1;
+    }
+
+
+    static int MatchSuite(WOLFSSL* ssl, Suites* peerSuites)
+    {
+        word16 i, j;
+
+        WOLFSSL_ENTER("MatchSuite");
+
+        /* & 0x1 equivalent % 2 */
+        if (peerSuites->suiteSz == 0 || peerSuites->suiteSz & 0x1)
+            return MATCH_SUITE_ERROR;
+
+        if (ssl->suites == NULL)
+            return SUITES_ERROR;
+        /* start with best, if a match we are good */
+        for (i = 0; i < ssl->suites->suiteSz; i += 2)
+            for (j = 0; j < peerSuites->suiteSz; j += 2)
+                if (ssl->suites->suites[i]   == peerSuites->suites[j] &&
+                    ssl->suites->suites[i+1] == peerSuites->suites[j+1] ) {
+
+                    if (VerifyServerSuite(ssl, i)) {
+                        int result;
+                        WOLFSSL_MSG("Verified suite validity");
+                        ssl->options.cipherSuite0 = ssl->suites->suites[i];
+                        ssl->options.cipherSuite  = ssl->suites->suites[i+1];
+                        result = SetCipherSpecs(ssl);
+                        if (result == 0)
+                            PickHashSigAlgo(ssl, peerSuites->hashSigAlgo,
+                                                 peerSuites->hashSigAlgoSz);
+                        return result;
+                    }
+                    else {
+                        WOLFSSL_MSG("Could not verify suite validity, continue");
+                    }
+                }
+
+        return MATCH_SUITE_ERROR;
+    }
+
+
+#ifdef OLD_HELLO_ALLOWED
+
+    /* process old style client hello, deprecate? */
+    int ProcessOldClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
+                              word32 inSz, word16 sz)
+    {
+        word32          idx = *inOutIdx;
+        word16          sessionSz;
+        word16          randomSz;
+        word16          i, j;
+        ProtocolVersion pv;
+        Suites          clSuites;
+
+        (void)inSz;
+        WOLFSSL_MSG("Got old format client hello");
+#ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("ClientHello", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddLateName("ClientHello", &ssl->timeoutInfo);
+#endif
+
+        /* manually hash input since different format */
+#ifndef NO_OLD_TLS
+#ifndef NO_MD5
+        wc_Md5Update(&ssl->hsHashes->hashMd5, input + idx, sz);
+#endif
+#ifndef NO_SHA
+        wc_ShaUpdate(&ssl->hsHashes->hashSha, input + idx, sz);
+#endif
+#endif
+#ifndef NO_SHA256
+        if (IsAtLeastTLSv1_2(ssl)) {
+            int shaRet = wc_Sha256Update(&ssl->hsHashes->hashSha256,
+                                         input + idx, sz);
+            if (shaRet != 0)
+                return shaRet;
+        }
+#endif
+
+        /* does this value mean client_hello? */
+        idx++;
+
+        /* version */
+        pv.major = input[idx++];
+        pv.minor = input[idx++];
+        ssl->chVersion = pv;  /* store */
+
+        if (ssl->version.minor > pv.minor) {
+            byte haveRSA = 0;
+            byte havePSK = 0;
+            if (!ssl->options.downgrade) {
+                WOLFSSL_MSG("Client trying to connect with lesser version");
+                return VERSION_ERROR;
+            }
+            if (pv.minor < ssl->options.minDowngrade) {
+                WOLFSSL_MSG("    version below minimum allowed, fatal error");
+                return VERSION_ERROR;
+            }
+            if (pv.minor == SSLv3_MINOR) {
+                /* turn off tls */
+                WOLFSSL_MSG("    downgrading to SSLv3");
+                ssl->options.tls    = 0;
+                ssl->options.tls1_1 = 0;
+                ssl->version.minor  = SSLv3_MINOR;
+            }
+            else if (pv.minor == TLSv1_MINOR) {
+                WOLFSSL_MSG("    downgrading to TLSv1");
+                /* turn off tls 1.1+ */
+                ssl->options.tls1_1 = 0;
+                ssl->version.minor  = TLSv1_MINOR;
+            }
+            else if (pv.minor == TLSv1_1_MINOR) {
+                WOLFSSL_MSG("    downgrading to TLSv1.1");
+                ssl->version.minor  = TLSv1_1_MINOR;
+            }
+#ifndef NO_RSA
+            haveRSA = 1;
+#endif
+#ifndef NO_PSK
+            havePSK = ssl->options.havePSK;
+#endif
+
+            InitSuites(ssl->suites, ssl->version, haveRSA, havePSK,
+                       ssl->options.haveDH, ssl->options.haveNTRU,
+                       ssl->options.haveECDSAsig, ssl->options.haveStaticECC,
+                       ssl->options.side);
+        }
+
+        /* suite size */
+        ato16(&input[idx], &clSuites.suiteSz);
+        idx += 2;
+
+        if (clSuites.suiteSz > MAX_SUITE_SZ)
+            return BUFFER_ERROR;
+        clSuites.hashSigAlgoSz = 0;
+
+        /* session size */
+        ato16(&input[idx], &sessionSz);
+        idx += 2;
+
+        if (sessionSz > ID_LEN)
+            return BUFFER_ERROR;
+
+        /* random size */
+        ato16(&input[idx], &randomSz);
+        idx += 2;
+
+        if (randomSz > RAN_LEN)
+            return BUFFER_ERROR;
+
+        /* suites */
+        for (i = 0, j = 0; i < clSuites.suiteSz; i += 3) {
+            byte first = input[idx++];
+            if (!first) { /* implicit: skip sslv2 type */
+                XMEMCPY(&clSuites.suites[j], &input[idx], 2);
+                j += 2;
+            }
+            idx += 2;
+        }
+        clSuites.suiteSz = j;
+
+        /* session id */
+        if (sessionSz) {
+            XMEMCPY(ssl->arrays->sessionID, input + idx, sessionSz);
+            ssl->arrays->sessionIDSz = (byte)sessionSz;
+            idx += sessionSz;
+            ssl->options.resuming = 1;
+        }
+
+        /* random */
+        if (randomSz < RAN_LEN)
+            XMEMSET(ssl->arrays->clientRandom, 0, RAN_LEN - randomSz);
+        XMEMCPY(&ssl->arrays->clientRandom[RAN_LEN - randomSz], input + idx,
+               randomSz);
+        idx += randomSz;
+
+        if (ssl->options.usingCompression)
+            ssl->options.usingCompression = 0;  /* turn off */
+
+        ssl->options.clientState = CLIENT_HELLO_COMPLETE;
+        *inOutIdx = idx;
+
+        ssl->options.haveSessionId = 1;
+        /* DoClientHello uses same resume code */
+        if (ssl->options.resuming) {  /* let's try */
+            int ret = -1;
+            WOLFSSL_SESSION* session = GetSession(ssl,
+                                                  ssl->arrays->masterSecret);
+            #ifdef HAVE_SESSION_TICKET
+                if (ssl->options.useTicket == 1) {
+                    session = &ssl->session;
+                }
+            #endif
+
+            if (!session) {
+                WOLFSSL_MSG("Session lookup for resume failed");
+                ssl->options.resuming = 0;
+            } else {
+                if (MatchSuite(ssl, &clSuites) < 0) {
+                    WOLFSSL_MSG("Unsupported cipher suite, OldClientHello");
+                    return UNSUPPORTED_SUITE;
+                }
+                #ifdef SESSION_CERTS
+                    ssl->session = *session; /* restore session certs. */
+                #endif
+
+                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;
+            }
+        }
+
+        return MatchSuite(ssl, &clSuites);
+    }
+
+#endif /* OLD_HELLO_ALLOWED */
+
+
+    static int DoClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
+                             word32 helloSz)
+    {
+        byte            b;
+        ProtocolVersion pv;
+        Suites          clSuites;
+        word32          i = *inOutIdx;
+        word32          begin = i;
+
+#ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo);
+        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)
+            return BUFFER_ERROR;
+
+        /* protocol version */
+        XMEMCPY(&pv, input + i, OPAQUE16_LEN);
+        ssl->chVersion = pv;   /* store */
+        i += OPAQUE16_LEN;
+
+        if (ssl->version.minor > pv.minor) {
+            byte haveRSA = 0;
+            byte havePSK = 0;
+
+            if (!ssl->options.downgrade) {
+                WOLFSSL_MSG("Client trying to connect with lesser version");
+                return VERSION_ERROR;
+            }
+            if (pv.minor < ssl->options.minDowngrade) {
+                WOLFSSL_MSG("    version below minimum allowed, fatal error");
+                return VERSION_ERROR;
+            }
+
+            if (pv.minor == SSLv3_MINOR) {
+                /* turn off tls */
+                WOLFSSL_MSG("    downgrading to SSLv3");
+                ssl->options.tls    = 0;
+                ssl->options.tls1_1 = 0;
+                ssl->version.minor  = SSLv3_MINOR;
+            }
+            else if (pv.minor == TLSv1_MINOR) {
+                /* turn off tls 1.1+ */
+                WOLFSSL_MSG("    downgrading to TLSv1");
+                ssl->options.tls1_1 = 0;
+                ssl->version.minor  = TLSv1_MINOR;
+            }
+            else if (pv.minor == TLSv1_1_MINOR) {
+                WOLFSSL_MSG("    downgrading to TLSv1.1");
+                ssl->version.minor  = TLSv1_1_MINOR;
+            }
+#ifndef NO_RSA
+            haveRSA = 1;
+#endif
+#ifndef NO_PSK
+            havePSK = ssl->options.havePSK;
+#endif
+            InitSuites(ssl->suites, ssl->version, haveRSA, havePSK,
+                       ssl->options.haveDH, ssl->options.haveNTRU,
+                       ssl->options.haveECDSAsig, ssl->options.haveStaticECC,
+                       ssl->options.side);
+        }
+
+        /* random */
+        XMEMCPY(ssl->arrays->clientRandom, input + i, RAN_LEN);
+        i += RAN_LEN;
+
+#ifdef SHOW_SECRETS
+        {
+            int j;
+            printf("client random: ");
+            for (j = 0; j < RAN_LEN; j++)
+                printf("%02x", ssl->arrays->clientRandom[j]);
+            printf("\n");
+        }
+#endif
+
+        /* session id */
+        b = input[i++];
+
+        if (b == ID_LEN) {
+            if ((i - begin) + ID_LEN > helloSz)
+                return BUFFER_ERROR;
+
+            XMEMCPY(ssl->arrays->sessionID, input + i, ID_LEN);
+            ssl->arrays->sessionIDSz = ID_LEN;
+            i += ID_LEN;
+            ssl->options.resuming = 1; /* client wants to resume */
+            WOLFSSL_MSG("Client wants to resume session");
+        }
+        else if (b) {
+            WOLFSSL_MSG("Invalid session ID size");
+            return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */
+        }
+
+        #ifdef WOLFSSL_DTLS
+            /* cookie */
+            if (ssl->options.dtls) {
+
+                if ((i - begin) + OPAQUE8_LEN > helloSz)
+                    return BUFFER_ERROR;
+
+                b = input[i++];
+
+                if (b) {
+                    byte cookie[MAX_COOKIE_LEN];
+
+                    if (b > MAX_COOKIE_LEN)
+                        return BUFFER_ERROR;
+
+                    if ((i - begin) + b > helloSz)
+                        return BUFFER_ERROR;
+
+                    if (ssl->ctx->CBIOCookie == NULL) {
+                        WOLFSSL_MSG("Your Cookie callback is null, please set");
+                        return COOKIE_ERROR;
+                    }
+
+                    if ((ssl->ctx->CBIOCookie(ssl, cookie, COOKIE_SZ,
+                                              ssl->IOCB_CookieCtx) != COOKIE_SZ)
+                            || (b != COOKIE_SZ)
+                            || (XMEMCMP(cookie, input + i, b) != 0)) {
+                        return COOKIE_ERROR;
+                    }
+
+                    i += b;
+                }
+            }
+        #endif
+
+        /* suites */
+        if ((i - begin) + OPAQUE16_LEN > helloSz)
+            return BUFFER_ERROR;
+
+        ato16(&input[i], &clSuites.suiteSz);
+        i += OPAQUE16_LEN;
+
+        /* suites and compression length check */
+        if ((i - begin) + clSuites.suiteSz + OPAQUE8_LEN > helloSz)
+            return BUFFER_ERROR;
+
+        if (clSuites.suiteSz > MAX_SUITE_SZ)
+            return BUFFER_ERROR;
+
+        XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz);
+        i += clSuites.suiteSz;
+        clSuites.hashSigAlgoSz = 0;
+
+        /* compression length */
+        b = input[i++];
+
+        if ((i - begin) + b > helloSz)
+            return BUFFER_ERROR;
+
+        if (ssl->options.usingCompression) {
+            int match = 0;
+
+            while (b--) {
+                byte comp = input[i++];
+
+                if (comp == ZLIB_COMPRESSION)
+                    match = 1;
+            }
+
+            if (!match) {
+                WOLFSSL_MSG("Not matching compression, turning off");
+                ssl->options.usingCompression = 0;  /* turn off */
+            }
+        }
+        else
+            i += b; /* ignore, since we're not on */
+
+        *inOutIdx = i;
+
+        /* tls extensions */
+        if ((i - begin) < helloSz) {
+#ifdef HAVE_TLS_EXTENSIONS
+            if (TLSX_SupportExtensions(ssl)) {
+                int ret = 0;
+#else
+            if (IsAtLeastTLSv1_2(ssl)) {
+#endif
+                /* Process the hello extension. Skip unsupported. */
+                word16 totalExtSz;
+
+                if ((i - begin) + OPAQUE16_LEN > helloSz)
+                    return BUFFER_ERROR;
+
+                ato16(&input[i], &totalExtSz);
+                i += OPAQUE16_LEN;
+
+                if ((i - begin) + totalExtSz > helloSz)
+                    return BUFFER_ERROR;
+
+#ifdef HAVE_TLS_EXTENSIONS
+                if ((ret = TLSX_Parse(ssl, (byte *) input + i,
+                                                     totalExtSz, 1, &clSuites)))
+                    return ret;
+
+                i += totalExtSz;
+#else
+                while (totalExtSz) {
+                    word16 extId, extSz;
+
+                    if (OPAQUE16_LEN + OPAQUE16_LEN > totalExtSz)
+                        return BUFFER_ERROR;
+
+                    ato16(&input[i], &extId);
+                    i += OPAQUE16_LEN;
+                    ato16(&input[i], &extSz);
+                    i += OPAQUE16_LEN;
+
+                    if (OPAQUE16_LEN + OPAQUE16_LEN + extSz > totalExtSz)
+                        return BUFFER_ERROR;
+
+                    if (extId == HELLO_EXT_SIG_ALGO) {
+                        ato16(&input[i], &clSuites.hashSigAlgoSz);
+                        i += OPAQUE16_LEN;
+
+                        if (OPAQUE16_LEN + clSuites.hashSigAlgoSz > extSz)
+                            return BUFFER_ERROR;
+
+                        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;
+                    }
+                    else
+                        i += extSz;
+
+                    totalExtSz -= OPAQUE16_LEN + OPAQUE16_LEN + extSz;
+                }
+#endif
+                *inOutIdx = i;
+            }
+            else
+                *inOutIdx = begin + helloSz; /* skip extensions */
+        }
+
+        ssl->options.clientState   = CLIENT_HELLO_COMPLETE;
+        ssl->options.haveSessionId = 1;
+
+        /* ProcessOld uses same resume code */
+        if (ssl->options.resuming && (!ssl->options.dtls ||
+               ssl->options.acceptState == HELLO_VERIFY_SENT)) { /* let's try */
+            int ret = -1;
+            WOLFSSL_SESSION* session = GetSession(ssl,
+                                                  ssl->arrays->masterSecret);
+            #ifdef HAVE_SESSION_TICKET
+                if (ssl->options.useTicket == 1) {
+                    session = &ssl->session;
+                }
+            #endif
+
+            if (!session) {
+                WOLFSSL_MSG("Session lookup for resume failed");
+                ssl->options.resuming = 0;
+            }
+            else {
+                if (MatchSuite(ssl, &clSuites) < 0) {
+                    WOLFSSL_MSG("Unsupported cipher suite, ClientHello");
+                    return UNSUPPORTED_SUITE;
+                }
+                #ifdef SESSION_CERTS
+                    ssl->session = *session; /* restore session certs. */
+                #endif
+
+                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;
+            }
+        }
+        return MatchSuite(ssl, &clSuites);
+    }
+
+#if !defined(NO_RSA) || defined(HAVE_ECC)
+    static int DoCertificateVerify(WOLFSSL* ssl, byte* input, word32* inOutIdx,
+                                   word32 size)
+    {
+        word16      sz = 0;
+        int         ret = VERIFY_CERT_ERROR;   /* start in error state */
+        byte        hashAlgo = sha_mac;
+        byte        sigAlgo = anonymous_sa_algo;
+        word32      begin = *inOutIdx;
+
+        #ifdef WOLFSSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("CertificateVerify", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("CertificateVerify", &ssl->timeoutInfo);
+        #endif
+
+
+        if (IsAtLeastTLSv1_2(ssl)) {
+            if ((*inOutIdx - begin) + ENUM_LEN + ENUM_LEN > size)
+                return BUFFER_ERROR;
+
+            hashAlgo = input[(*inOutIdx)++];
+            sigAlgo  = input[(*inOutIdx)++];
+        }
+
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &sz);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + sz > size || sz > ENCRYPT_LEN)
+            return BUFFER_ERROR;
+
+        /* RSA */
+#ifndef NO_RSA
+        if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) {
+            byte* out       = NULL;
+            int   outLen    = 0;
+            byte  doUserRsa = 0;
+
+            #ifdef HAVE_PK_CALLBACKS
+                if (ssl->ctx->RsaVerifyCb)
+                    doUserRsa = 1;
+            #endif /*HAVE_PK_CALLBACKS */
+
+            WOLFSSL_MSG("Doing RSA peer cert verify");
+
+            if (doUserRsa) {
+            #ifdef HAVE_PK_CALLBACKS
+                outLen = ssl->ctx->RsaVerifyCb(ssl, input + *inOutIdx, sz,
+                                            &out,
+                                            ssl->buffers.peerRsaKey.buffer,
+                                            ssl->buffers.peerRsaKey.length,
+                                            ssl->RsaVerifyCtx);
+            #endif /*HAVE_PK_CALLBACKS */
+            }
+            else {
+                outLen = wc_RsaSSL_VerifyInline(input + *inOutIdx, sz, &out,
+                                                               ssl->peerRsaKey);
+            }
+
+            if (IsAtLeastTLSv1_2(ssl)) {
+#ifdef WOLFSSL_SMALL_STACK
+                byte*  encodedSig = NULL;
+#else
+                byte   encodedSig[MAX_ENCODED_SIG_SZ];
+#endif
+                word32 sigSz;
+                byte*  digest = ssl->hsHashes->certHashes.sha;
+                int    typeH = SHAh;
+                int    digestSz = SHA_DIGEST_SIZE;
+
+#ifdef WOLFSSL_SMALL_STACK
+                encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                if (encodedSig == NULL)
+                    return MEMORY_E;
+#endif
+
+                if (sigAlgo != rsa_sa_algo) {
+                    WOLFSSL_MSG("Oops, peer sent RSA key but not in verify");
+                }
+
+                if (hashAlgo == sha256_mac) {
+                    #ifndef NO_SHA256
+                        digest = ssl->hsHashes->certHashes.sha256;
+                        typeH    = SHA256h;
+                        digestSz = SHA256_DIGEST_SIZE;
+                    #endif
+                }
+                else if (hashAlgo == sha384_mac) {
+                    #ifdef WOLFSSL_SHA384
+                        digest = ssl->hsHashes->certHashes.sha384;
+                        typeH    = SHA384h;
+                        digestSz = SHA384_DIGEST_SIZE;
+                    #endif
+                }
+                else if (hashAlgo == sha512_mac) {
+                    #ifdef WOLFSSL_SHA512
+                        digest = ssl->hsHashes->certHashes.sha512;
+                        typeH    = SHA512h;
+                        digestSz = SHA512_DIGEST_SIZE;
+                    #endif
+                }
+
+                sigSz = wc_EncodeSignature(encodedSig, digest, digestSz, typeH);
+
+                if (outLen == (int)sigSz && out && XMEMCMP(out, encodedSig,
+                                           min(sigSz, MAX_ENCODED_SIG_SZ)) == 0)
+                    ret = 0; /* verified */
+
+#ifdef WOLFSSL_SMALL_STACK
+                XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            }
+            else {
+                if (outLen == FINISHED_SZ && out && XMEMCMP(out,
+                                            &ssl->hsHashes->certHashes,
+                                            FINISHED_SZ) == 0) {
+                    ret = 0; /* verified */
+                }
+            }
+        }
+#endif
+#ifdef HAVE_ECC
+        if (ssl->peerEccDsaKeyPresent) {
+            int verify =  0;
+            int err    = -1;
+            byte* digest = ssl->hsHashes->certHashes.sha;
+            word32 digestSz = SHA_DIGEST_SIZE;
+            byte doUserEcc = 0;
+
+            #ifdef HAVE_PK_CALLBACKS
+                if (ssl->ctx->EccVerifyCb)
+                    doUserEcc = 1;
+            #endif
+
+            WOLFSSL_MSG("Doing ECC peer cert verify");
+
+            if (IsAtLeastTLSv1_2(ssl)) {
+                if (sigAlgo != ecc_dsa_sa_algo) {
+                    WOLFSSL_MSG("Oops, peer sent ECC key but not in verify");
+                }
+
+                if (hashAlgo == sha256_mac) {
+                    #ifndef NO_SHA256
+                        digest = ssl->hsHashes->certHashes.sha256;
+                        digestSz = SHA256_DIGEST_SIZE;
+                    #endif
+                }
+                else if (hashAlgo == sha384_mac) {
+                    #ifdef WOLFSSL_SHA384
+                        digest = ssl->hsHashes->certHashes.sha384;
+                        digestSz = SHA384_DIGEST_SIZE;
+                    #endif
+                }
+                else if (hashAlgo == sha512_mac) {
+                    #ifdef WOLFSSL_SHA512
+                        digest = ssl->hsHashes->certHashes.sha512;
+                        digestSz = SHA512_DIGEST_SIZE;
+                    #endif
+                }
+            }
+
+            if (doUserEcc) {
+            #ifdef HAVE_PK_CALLBACKS
+                ret = ssl->ctx->EccVerifyCb(ssl, input + *inOutIdx, sz, digest,
+                                            digestSz,
+                                            ssl->buffers.peerEccDsaKey.buffer,
+                                            ssl->buffers.peerEccDsaKey.length,
+                                            &verify, ssl->EccVerifyCtx);
+            #endif
+            }
+            else {
+                err = wc_ecc_verify_hash(input + *inOutIdx, sz, digest,
+                                         digestSz, &verify, ssl->peerEccDsaKey);
+            }
+
+            if (err == 0 && verify == 1)
+               ret = 0; /* verified */
+        }
+#endif
+        *inOutIdx += sz;
+
+        if (ret == 0)
+            ssl->options.havePeerVerify = 1;
+
+        return ret;
+    }
+#endif /* !NO_RSA || HAVE_ECC */
+
+    int SendServerHelloDone(WOLFSSL* ssl)
+    {
+        byte              *output;
+        int                sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        int                ret;
+
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls)
+                sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+        #endif
+        /* check for available size */
+        if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.length;
+
+        AddHeaders(output, 0, server_hello_done, ssl);
+
+        #ifdef WOLFSSL_DTLS
+            if (ssl->options.dtls) {
+                if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                    return 0;
+            }
+        #endif
+
+        ret = HashOutput(ssl, output, sendSz, 0);
+            if (ret != 0)
+                return ret;
+
+#ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("ServerHelloDone", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("ServerHelloDone", &ssl->timeoutInfo, output, sendSz,
+                          ssl->heap);
+#endif
+        ssl->options.serverState = SERVER_HELLODONE_COMPLETE;
+
+        ssl->buffers.outputBuffer.length += sendSz;
+
+        return SendBuffered(ssl);
+    }
+
+
+#ifdef HAVE_SESSION_TICKET
+
+#define WOLFSSL_TICKET_FIXED_SZ (WOLFSSL_TICKET_NAME_SZ + \
+                WOLFSSL_TICKET_IV_SZ + WOLFSSL_TICKET_MAC_SZ + LENGTH_SZ)
+#define WOLFSSL_TICKET_ENC_SZ (SESSION_TICKET_LEN - WOLFSSL_TICKET_FIXED_SZ)
+
+    /* our ticket format */
+    typedef struct InternalTicket {
+        ProtocolVersion pv;                    /* version when ticket created */
+        byte            suite[SUITE_LEN];      /* cipher suite when created */
+        byte            msecret[SECRET_LEN];   /* master secret */
+        word32          timestamp;             /* born on */
+    } InternalTicket;
+
+    /* fit within SESSION_TICKET_LEN */
+    typedef struct ExternalTicket {
+        byte key_name[WOLFSSL_TICKET_NAME_SZ];  /* key context name */
+        byte iv[WOLFSSL_TICKET_IV_SZ];          /* this ticket's iv */
+        byte enc_len[LENGTH_SZ];                /* encrypted length */
+        byte enc_ticket[WOLFSSL_TICKET_ENC_SZ]; /* encrypted internal ticket */
+        byte mac[WOLFSSL_TICKET_MAC_SZ];        /* total mac */
+        /* !! if add to structure, add to TICKET_FIXED_SZ !! */
+    } ExternalTicket;
+
+    /* create a new session ticket, 0 on success */
+    static int CreateTicket(WOLFSSL* ssl)
+    {
+        InternalTicket  it;
+        ExternalTicket* et = (ExternalTicket*)ssl->session.ticket;
+        int encLen;
+        int ret;
+        byte zeros[WOLFSSL_TICKET_MAC_SZ];   /* biggest cmp size */
+
+        /* build internal */
+        it.pv.major = ssl->version.major;
+        it.pv.minor = ssl->version.minor;
+
+        it.suite[0] = ssl->options.cipherSuite0;
+        it.suite[1] = ssl->options.cipherSuite;
+
+        XMEMCPY(it.msecret, ssl->arrays->masterSecret, SECRET_LEN);
+        c32toa(LowResTimer(), (byte*)&it.timestamp);
+
+        /* build external */
+        XMEMCPY(et->enc_ticket, &it, sizeof(InternalTicket));
+
+        /* encrypt */
+        encLen = WOLFSSL_TICKET_ENC_SZ;  /* max size user can use */
+        ret = ssl->ctx->ticketEncCb(ssl, et->key_name, et->iv, et->mac, 1,
+                                    et->enc_ticket, sizeof(InternalTicket),
+                                    &encLen, ssl->ctx->ticketEncCtx);
+        if (ret == WOLFSSL_TICKET_RET_OK) {
+            if (encLen < (int)sizeof(InternalTicket) ||
+                encLen > WOLFSSL_TICKET_ENC_SZ) {
+                WOLFSSL_MSG("Bad user ticket encrypt size");
+                return BAD_TICKET_KEY_CB_SZ;
+            }
+
+            /* sanity checks on encrypt callback */
+
+            /* internal ticket can't be the same if encrypted */
+            if (XMEMCMP(et->enc_ticket, &it, sizeof(InternalTicket)) == 0) {
+                WOLFSSL_MSG("User ticket encrypt didn't encrypt");
+                return BAD_TICKET_ENCRYPT;
+            }
+
+            XMEMSET(zeros, 0, sizeof(zeros));
+
+            /* name */
+            if (XMEMCMP(et->key_name, zeros, WOLFSSL_TICKET_NAME_SZ) == 0) {
+                WOLFSSL_MSG("User ticket encrypt didn't set name");
+                return BAD_TICKET_ENCRYPT;
+            }
+
+            /* iv */
+            if (XMEMCMP(et->iv, zeros, WOLFSSL_TICKET_IV_SZ) == 0) {
+                WOLFSSL_MSG("User ticket encrypt didn't set iv");
+                return BAD_TICKET_ENCRYPT;
+            }
+
+            /* mac */
+            if (XMEMCMP(et->mac, zeros, WOLFSSL_TICKET_MAC_SZ) == 0) {
+                WOLFSSL_MSG("User ticket encrypt didn't set mac");
+                return BAD_TICKET_ENCRYPT;
+            }
+
+            /* set size */
+            c16toa((word16)encLen, et->enc_len);
+            ssl->session.ticketLen = (word16)(encLen + WOLFSSL_TICKET_FIXED_SZ);
+            if (encLen < WOLFSSL_TICKET_ENC_SZ) {
+                /* move mac up since whole enc buffer not used */
+                XMEMMOVE(et->enc_ticket +encLen, et->mac,WOLFSSL_TICKET_MAC_SZ);
+            }
+        }
+
+        return ret;
+    }
+
+
+    /* Parse ticket sent by client, returns callback return value */
+    int DoClientTicket(WOLFSSL* ssl, const byte* input, word32 len)
+    {
+        ExternalTicket* et;
+        InternalTicket* it;
+        int             ret;
+        int             outLen;
+        word16          inLen;
+
+        if (len > SESSION_TICKET_LEN ||
+             len < (word32)(sizeof(InternalTicket) + WOLFSSL_TICKET_FIXED_SZ)) {
+            return BAD_TICKET_MSG_SZ;
+        }
+
+        et = (ExternalTicket*)input;
+        it = (InternalTicket*)et->enc_ticket;
+
+        /* decrypt */
+        ato16(et->enc_len, &inLen);
+        if (inLen > (word16)(len - WOLFSSL_TICKET_FIXED_SZ)) {
+            return BAD_TICKET_MSG_SZ;
+        }
+        outLen = inLen;   /* may be reduced by user padding */
+        ret = ssl->ctx->ticketEncCb(ssl, et->key_name, et->iv,
+                                    et->enc_ticket + inLen, 0,
+                                    et->enc_ticket, inLen, &outLen,
+                                    ssl->ctx->ticketEncCtx);
+        if (ret == WOLFSSL_TICKET_RET_FATAL || ret < 0) return ret;
+        if (outLen > inLen || outLen < (int)sizeof(InternalTicket)) {
+            WOLFSSL_MSG("Bad user ticket decrypt len");
+            return BAD_TICKET_KEY_CB_SZ;
+        }
+
+        /* get master secret */
+        if (ret == WOLFSSL_TICKET_RET_OK || ret == WOLFSSL_TICKET_RET_CREATE)
+            XMEMCPY(ssl->arrays->masterSecret, it->msecret, SECRET_LEN);
+
+        return ret;
+    }
+
+
+    /* send Session Ticket */
+    int SendTicket(WOLFSSL* ssl)
+    {
+        byte*              output;
+        int                ret;
+        int                sendSz;
+        word32             length = SESSION_HINT_SZ + LENGTH_SZ;
+        word32             idx    = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+
+    #ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls) {
+            length += DTLS_RECORD_EXTRA;
+            idx    += DTLS_RECORD_EXTRA;
+        }
+    #endif
+
+        if (ssl->options.createTicket) {
+            ret = CreateTicket(ssl);
+            if (ret != 0) return ret;
+        }
+
+        length += ssl->session.ticketLen;
+        sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+        /* check for available size */
+        if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.length;
+
+        AddHeaders(output, length, session_ticket, ssl);
+
+        /* hint */
+        c32toa(ssl->ctx->ticketHint, output + idx);
+        idx += SESSION_HINT_SZ;
+
+        /* length */
+        c16toa(ssl->session.ticketLen, output + idx);
+        idx += LENGTH_SZ;
+
+        /* ticket */
+        XMEMCPY(output + idx, ssl->session.ticket, ssl->session.ticketLen);
+        /* idx += ssl->session.ticketLen; */
+
+        ret = HashOutput(ssl, output, sendSz, 0);
+        if (ret != 0) return ret;
+        ssl->buffers.outputBuffer.length += sendSz;
+
+        return SendBuffered(ssl);
+    }
+
+#endif /* HAVE_SESSION_TICKET */
+
+
+#ifdef WOLFSSL_DTLS
+    int SendHelloVerifyRequest(WOLFSSL* ssl)
+    {
+        byte* output;
+        byte  cookieSz = COOKIE_SZ;
+        int   length = VERSION_SZ + ENUM_LEN + cookieSz;
+        int   idx    = DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ;
+        int   sendSz = length + idx;
+        int   ret;
+
+        /* check for available size */
+        if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.length;
+
+        AddHeaders(output, length, hello_verify_request, ssl);
+
+        output[idx++] =  ssl->chVersion.major;
+        output[idx++] =  ssl->chVersion.minor;
+
+        output[idx++] = cookieSz;
+        if (ssl->ctx->CBIOCookie == NULL) {
+            WOLFSSL_MSG("Your Cookie callback is null, please set");
+            return COOKIE_ERROR;
+        }
+        if ((ret = ssl->ctx->CBIOCookie(ssl, output + idx, cookieSz,
+                                        ssl->IOCB_CookieCtx)) < 0)
+            return ret;
+
+        ret = HashOutput(ssl, output, sendSz, 0);
+        if (ret != 0)
+            return ret;
+
+#ifdef WOLFSSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("HelloVerifyRequest", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("HelloVerifyRequest", &ssl->timeoutInfo, output,
+                          sendSz, ssl->heap);
+#endif
+        ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE;
+
+        ssl->buffers.outputBuffer.length += sendSz;
+
+        return SendBuffered(ssl);
+    }
+#endif
+
+    static int DoClientKeyExchange(WOLFSSL* ssl, byte* input, word32* inOutIdx,
+                                                                    word32 size)
+    {
+        int    ret = 0;
+        word32 length = 0;
+        byte*  out = NULL;
+        word32 begin = *inOutIdx;
+
+        (void)length; /* shut up compiler warnings */
+        (void)out;
+        (void)input;
+        (void)size;
+        (void)begin;
+
+        if (ssl->options.side != WOLFSSL_SERVER_END) {
+            WOLFSSL_MSG("Client received client keyexchange, attack?");
+            WOLFSSL_ERROR(ssl->error = SIDE_ERROR);
+            return SSL_FATAL_ERROR;
+        }
+
+        if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) {
+            WOLFSSL_MSG("Client sending keyexchange at wrong time");
+            SendAlert(ssl, alert_fatal, unexpected_message);
+            return OUT_OF_ORDER_E;
+        }
+
+        #ifndef NO_CERTS
+            if (ssl->options.verifyPeer && ssl->options.failNoCert)
+                if (!ssl->options.havePeerCert) {
+                    WOLFSSL_MSG("client didn't present peer cert");
+                    return NO_PEER_CERT;
+                }
+        #endif
+
+        #ifdef WOLFSSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("ClientKeyExchange", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("ClientKeyExchange", &ssl->timeoutInfo);
+        #endif
+
+        switch (ssl->specs.kea) {
+        #ifndef NO_RSA
+            case rsa_kea:
+            {
+                word32 idx = 0;
+                RsaKey key;
+                byte   doUserRsa = 0;
+
+                #ifdef HAVE_PK_CALLBACKS
+                    if (ssl->ctx->RsaDecCb)
+                        doUserRsa = 1;
+                #endif
+
+                ret = wc_InitRsaKey(&key, ssl->heap);
+                if (ret != 0) return ret;
+
+                if (ssl->buffers.key.buffer)
+                    ret = wc_RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx,
+                                             &key, ssl->buffers.key.length);
+                else
+                    return NO_PRIVATE_KEY;
+
+                if (ret == 0) {
+                    length = wc_RsaEncryptSize(&key);
+                    ssl->arrays->preMasterSz = SECRET_LEN;
+
+                    if (ssl->options.tls) {
+                        word16 check;
+
+                        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                            return BUFFER_ERROR;
+
+                        ato16(input + *inOutIdx, &check);
+                        *inOutIdx += OPAQUE16_LEN;
+
+                        if ((word32) check != length) {
+                            WOLFSSL_MSG("RSA explicit size doesn't match");
+                            wc_FreeRsaKey(&key);
+                            return RSA_PRIVATE_ERROR;
+                        }
+                    }
+
+                    if ((*inOutIdx - begin) + length > size) {
+                        WOLFSSL_MSG("RSA message too big");
+                        wc_FreeRsaKey(&key);
+                        return BUFFER_ERROR;
+                    }
+
+                    if (doUserRsa) {
+                        #ifdef HAVE_PK_CALLBACKS
+                            ret = ssl->ctx->RsaDecCb(ssl,
+                                        input + *inOutIdx, length, &out,
+                                        ssl->buffers.key.buffer,
+                                        ssl->buffers.key.length,
+                                        ssl->RsaDecCtx);
+                        #endif
+                    }
+                    else {
+                        ret = wc_RsaPrivateDecryptInline(input + *inOutIdx, length,
+                                                                    &out, &key);
+                    }
+
+                    *inOutIdx += length;
+
+                    if (ret == SECRET_LEN) {
+                        XMEMCPY(ssl->arrays->preMasterSecret, out, SECRET_LEN);
+                        if (ssl->arrays->preMasterSecret[0] !=
+                                                           ssl->chVersion.major
+                            || ssl->arrays->preMasterSecret[1] !=
+                                                           ssl->chVersion.minor)
+                            ret = PMS_VERSION_ERROR;
+                        else
+                            ret = MakeMasterSecret(ssl);
+                    }
+                    else {
+                        ret = RSA_PRIVATE_ERROR;
+                    }
+                }
+
+                wc_FreeRsaKey(&key);
+            }
+            break;
+        #endif
+        #ifndef NO_PSK
+            case psk_kea:
+            {
+                byte* pms = ssl->arrays->preMasterSecret;
+                word16 ci_sz;
+
+                if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                    return BUFFER_ERROR;
+
+                ato16(input + *inOutIdx, &ci_sz);
+                *inOutIdx += OPAQUE16_LEN;
+
+                if (ci_sz > MAX_PSK_ID_LEN)
+                    return CLIENT_ID_ERROR;
+
+                if ((*inOutIdx - begin) + ci_sz > size)
+                    return BUFFER_ERROR;
+
+                XMEMCPY(ssl->arrays->client_identity, input + *inOutIdx, ci_sz);
+                *inOutIdx += ci_sz;
+
+                ssl->arrays->client_identity[min(ci_sz, MAX_PSK_ID_LEN-1)] = 0;
+                ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl,
+                    ssl->arrays->client_identity, 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;
+
+                /* make psk pre master secret */
+                /* length of key + length 0s + length of key + key */
+                c16toa((word16) ssl->arrays->psk_keySz, pms);
+                pms += OPAQUE16_LEN;
+
+                XMEMSET(pms, 0, ssl->arrays->psk_keySz);
+                pms += ssl->arrays->psk_keySz;
+
+                c16toa((word16) ssl->arrays->psk_keySz, pms);
+                pms += OPAQUE16_LEN;
+
+                XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz);
+                ssl->arrays->preMasterSz = ssl->arrays->psk_keySz * 2 + 4;
+
+                ret = MakeMasterSecret(ssl);
+
+                /* No further need for PSK */
+                ForceZero(ssl->arrays->psk_key, ssl->arrays->psk_keySz);
+                ssl->arrays->psk_keySz = 0;
+            }
+            break;
+        #endif /* NO_PSK */
+        #ifdef HAVE_NTRU
+            case ntru_kea:
+            {
+                word16 cipherLen;
+                word16 plainLen = sizeof(ssl->arrays->preMasterSecret);
+
+                if (!ssl->buffers.key.buffer)
+                    return NO_PRIVATE_KEY;
+
+                if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                    return BUFFER_ERROR;
+
+                ato16(input + *inOutIdx, &cipherLen);
+                *inOutIdx += OPAQUE16_LEN;
+
+                if (cipherLen > MAX_NTRU_ENCRYPT_SZ)
+                    return NTRU_KEY_ERROR;
+
+                if ((*inOutIdx - begin) + cipherLen > size)
+                    return BUFFER_ERROR;
+
+                if (NTRU_OK != ntru_crypto_ntru_decrypt(
+                            (word16) ssl->buffers.key.length,
+                            ssl->buffers.key.buffer, cipherLen,
+                            input + *inOutIdx, &plainLen,
+                            ssl->arrays->preMasterSecret))
+                    return NTRU_DECRYPT_ERROR;
+
+                if (plainLen != SECRET_LEN)
+                    return NTRU_DECRYPT_ERROR;
+
+                *inOutIdx += cipherLen;
+
+                ssl->arrays->preMasterSz = plainLen;
+                ret = MakeMasterSecret(ssl);
+            }
+            break;
+        #endif /* HAVE_NTRU */
+        #ifdef HAVE_ECC
+            case ecc_diffie_hellman_kea:
+            {
+                if ((*inOutIdx - begin) + OPAQUE8_LEN > size)
+                    return BUFFER_ERROR;
+
+                length = input[(*inOutIdx)++];
+
+                if ((*inOutIdx - begin) + length > size)
+                    return BUFFER_ERROR;
+
+                if (ssl->peerEccKey == NULL) {
+                    /* alloc/init on demand */
+                    ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key),
+                                              ssl->ctx->heap, DYNAMIC_TYPE_ECC);
+                    if (ssl->peerEccKey == NULL) {
+                        WOLFSSL_MSG("PeerEccKey Memory error");
+                        return MEMORY_E;
+                    }
+                    wc_ecc_init(ssl->peerEccKey);
+                } else if (ssl->peerEccKeyPresent) {  /* don't leak on reuse */
+                    wc_ecc_free(ssl->peerEccKey);
+                    ssl->peerEccKeyPresent = 0;
+                    wc_ecc_init(ssl->peerEccKey);
+                }
+
+                if (wc_ecc_import_x963(input + *inOutIdx, length, ssl->peerEccKey))
+                    return ECC_PEERKEY_ERROR;
+
+                *inOutIdx += length;
+                ssl->peerEccKeyPresent = 1;
+
+                length = sizeof(ssl->arrays->preMasterSecret);
+
+                if (ssl->specs.static_ecdh) {
+                    ecc_key staticKey;
+                    word32 i = 0;
+
+                    wc_ecc_init(&staticKey);
+                    ret = wc_EccPrivateKeyDecode(ssl->buffers.key.buffer, &i,
+                                           &staticKey, ssl->buffers.key.length);
+
+                    if (ret == 0)
+                        ret = wc_ecc_shared_secret(&staticKey, ssl->peerEccKey,
+                                         ssl->arrays->preMasterSecret, &length);
+
+                    wc_ecc_free(&staticKey);
+                }
+                else {
+                    if (ssl->eccTempKeyPresent == 0) {
+                        WOLFSSL_MSG("Ecc ephemeral key not made correctly");
+                        ret = ECC_MAKEKEY_ERROR;
+                    } else {
+                        ret = wc_ecc_shared_secret(ssl->eccTempKey,ssl->peerEccKey,
+                                         ssl->arrays->preMasterSecret, &length);
+                    }
+                }
+
+                if (ret != 0)
+                    return ECC_SHARED_ERROR;
+
+                ssl->arrays->preMasterSz = length;
+                ret = MakeMasterSecret(ssl);
+            }
+            break;
+        #endif /* HAVE_ECC */
+        #ifndef NO_DH
+            case diffie_hellman_kea:
+            {
+                word16 clientPubSz;
+                DhKey  dhKey;
+
+                if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                    return BUFFER_ERROR;
+
+                ato16(input + *inOutIdx, &clientPubSz);
+                *inOutIdx += OPAQUE16_LEN;
+
+                if ((*inOutIdx - begin) + clientPubSz > size)
+                    return BUFFER_ERROR;
+
+                wc_InitDhKey(&dhKey);
+                ret = wc_DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer,
+                                       ssl->buffers.serverDH_P.length,
+                                       ssl->buffers.serverDH_G.buffer,
+                                       ssl->buffers.serverDH_G.length);
+                if (ret == 0)
+                    ret = wc_DhAgree(&dhKey, ssl->arrays->preMasterSecret,
+                                         &ssl->arrays->preMasterSz,
+                                          ssl->buffers.serverDH_Priv.buffer,
+                                          ssl->buffers.serverDH_Priv.length,
+                                          input + *inOutIdx, clientPubSz);
+                wc_FreeDhKey(&dhKey);
+
+                *inOutIdx += clientPubSz;
+
+                if (ret == 0)
+                    ret = MakeMasterSecret(ssl);
+            }
+            break;
+        #endif /* NO_DH */
+        #if !defined(NO_DH) && !defined(NO_PSK)
+            case dhe_psk_kea:
+            {
+                byte* pms = ssl->arrays->preMasterSecret;
+                word16 clientSz;
+                DhKey  dhKey;
+
+                /* Read in the PSK hint */
+                if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                    return BUFFER_ERROR;
+
+                ato16(input + *inOutIdx, &clientSz);
+                *inOutIdx += OPAQUE16_LEN;
+                if (clientSz > MAX_PSK_ID_LEN)
+                    return CLIENT_ID_ERROR;
+
+                if ((*inOutIdx - begin) + clientSz > size)
+                    return BUFFER_ERROR;
+
+                XMEMCPY(ssl->arrays->client_identity,
+                                                   input + *inOutIdx, clientSz);
+                *inOutIdx += clientSz;
+                ssl->arrays->client_identity[min(clientSz, MAX_PSK_ID_LEN-1)] =
+                                                                              0;
+
+                /* Read in the DHE business */
+                if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                    return BUFFER_ERROR;
+
+                ato16(input + *inOutIdx, &clientSz);
+                *inOutIdx += OPAQUE16_LEN;
+
+                if ((*inOutIdx - begin) + clientSz > size)
+                    return BUFFER_ERROR;
+
+                wc_InitDhKey(&dhKey);
+                ret = wc_DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer,
+                                       ssl->buffers.serverDH_P.length,
+                                       ssl->buffers.serverDH_G.buffer,
+                                       ssl->buffers.serverDH_G.length);
+                if (ret == 0)
+                    ret = wc_DhAgree(&dhKey, pms + OPAQUE16_LEN,
+                                          &ssl->arrays->preMasterSz,
+                                          ssl->buffers.serverDH_Priv.buffer,
+                                          ssl->buffers.serverDH_Priv.length,
+                                          input + *inOutIdx, clientSz);
+                wc_FreeDhKey(&dhKey);
+
+                *inOutIdx += clientSz;
+                c16toa((word16)ssl->arrays->preMasterSz, pms);
+                ssl->arrays->preMasterSz += OPAQUE16_LEN;
+                pms += ssl->arrays->preMasterSz;
+
+                /* Use the PSK hint to look up the PSK and add it to the
+                 * preMasterSecret here. */
+                ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl,
+                    ssl->arrays->client_identity, 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;
+
+                c16toa((word16) ssl->arrays->psk_keySz, pms);
+                pms += OPAQUE16_LEN;
+
+                XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz);
+                ssl->arrays->preMasterSz +=
+                                          ssl->arrays->psk_keySz + OPAQUE16_LEN;
+                if (ret == 0)
+                    ret = MakeMasterSecret(ssl);
+
+                /* No further need for PSK */
+                ForceZero(ssl->arrays->psk_key, ssl->arrays->psk_keySz);
+                ssl->arrays->psk_keySz = 0;
+            }
+            break;
+        #endif /* !NO_DH && !NO_PSK */
+            default:
+            {
+                WOLFSSL_MSG("Bad kea type");
+                ret = BAD_KEA_TYPE_E;
+            }
+            break;
+        }
+
+        /* No further need for PMS */
+        ForceZero(ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz);
+        ssl->arrays->preMasterSz = 0;
+
+        if (ret == 0) {
+            ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+            #ifndef NO_CERTS
+                if (ssl->options.verifyPeer)
+                    ret = BuildCertHashes(ssl, &ssl->hsHashes->certHashes);
+            #endif
+        }
+
+        return ret;
+    }
+
+#endif /* NO_WOLFSSL_SERVER */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/io.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,1142 @@
+/* io.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef _WIN32_WCE
+    /* On WinCE winsock2.h must be included before windows.h for socket stuff */
+    #include <winsock2.h>
+#endif
+
+#include <wolfssl/internal.h>
+#include <wolfssl/error-ssl.h>
+
+
+/* if user writes own I/O callbacks they can define WOLFSSL_USER_IO to remove
+   automatic setting of default I/O functions EmbedSend() and EmbedReceive()
+   but they'll still need SetCallback xxx() at end of file 
+*/
+#ifndef WOLFSSL_USER_IO
+
+#ifdef HAVE_LIBZ
+    #include "zlib.h"
+#endif
+
+#ifndef USE_WINDOWS_API
+    #ifdef WOLFSSL_LWIP
+        /* 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
+            #define LWIP_PROVIDE_ERRNO 1
+        #endif
+    #elif defined(FREESCALE_MQX)
+        #include <posix.h>
+        #include <rtcs.h>
+    #elif defined(WOLFSSL_MDK_ARM)
+        #if defined(WOLFSSL_MDK5)
+            #include "cmsis_os.h"
+            #include "rl_fs.h" 
+            #include "rl_net.h" 
+        #else
+            #include <rtl.h>
+        #endif
+        #undef RNG
+        #include "WOLFSSL_MDK_ARM.h"
+        #undef RNG
+        #define RNG wolfSSL_RNG 
+        /* for avoiding name conflict in "stm32f2xx.h" */
+        static int errno;
+    #elif defined(WOLFSSL_TIRTOS)
+        #include <sys/socket.h>
+    #elif defined(WOLFSSL_IAR_ARM)
+        /* nothing */
+    #else
+        #include <sys/types.h>
+        #include <errno.h>
+        #ifndef EBSNET
+            #include <unistd.h>
+        #endif
+        #include <fcntl.h>
+        #if !(defined(DEVKITPRO) || defined(HAVE_RTP_SYS) || defined(EBSNET)) \
+            && !(defined(WOLFSSL_PICOTCP))
+            #include <sys/socket.h>
+            #include <arpa/inet.h>
+            #include <netinet/in.h>
+            #include <netdb.h>
+            #ifdef __PPU
+                #include <netex/errno.h>
+            #else
+                #include <sys/ioctl.h>
+            #endif
+        #endif
+        #ifdef HAVE_RTP_SYS
+            #include <socket.h>
+        #endif
+        #ifdef EBSNET
+            #include "rtipapi.h"  /* errno */
+            #include "socket.h"
+        #endif
+    #endif
+#endif /* USE_WINDOWS_API */
+
+#ifdef __sun
+    #include <sys/filio.h>
+#endif
+
+#ifdef USE_WINDOWS_API 
+    /* no epipe yet */
+    #ifndef WSAEPIPE
+        #define WSAEPIPE       -12345
+    #endif
+    #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
+    #define SOCKET_EAGAIN      WSAETIMEDOUT
+    #define SOCKET_ECONNRESET  WSAECONNRESET
+    #define SOCKET_EINTR       WSAEINTR
+    #define SOCKET_EPIPE       WSAEPIPE
+    #define SOCKET_ECONNREFUSED WSAENOTCONN
+    #define SOCKET_ECONNABORTED WSAECONNABORTED
+    #define close(s) closesocket(s)
+#elif defined(__PPU)
+    #define SOCKET_EWOULDBLOCK SYS_NET_EWOULDBLOCK
+    #define SOCKET_EAGAIN      SYS_NET_EAGAIN
+    #define SOCKET_ECONNRESET  SYS_NET_ECONNRESET
+    #define SOCKET_EINTR       SYS_NET_EINTR
+    #define SOCKET_EPIPE       SYS_NET_EPIPE
+    #define SOCKET_ECONNREFUSED SYS_NET_ECONNREFUSED
+    #define SOCKET_ECONNABORTED SYS_NET_ECONNABORTED
+#elif defined(FREESCALE_MQX)
+    /* RTCS doesn't have an EWOULDBLOCK error */
+    #define SOCKET_EWOULDBLOCK EAGAIN
+    #define SOCKET_EAGAIN      EAGAIN
+    #define SOCKET_ECONNRESET  RTCSERR_TCP_CONN_RESET
+    #define SOCKET_EINTR       EINTR
+    #define SOCKET_EPIPE       EPIPE
+    #define SOCKET_ECONNREFUSED RTCSERR_TCP_CONN_REFUSED
+    #define SOCKET_ECONNABORTED RTCSERR_TCP_CONN_ABORTED
+#elif defined(WOLFSSL_MDK_ARM)
+    #if defined(WOLFSSL_MDK5)
+        #define SOCKET_EWOULDBLOCK BSD_ERROR_WOULDBLOCK
+        #define SOCKET_EAGAIN      BSD_ERROR_LOCKED
+        #define SOCKET_ECONNRESET  BSD_ERROR_CLOSED
+        #define SOCKET_EINTR       BSD_ERROR
+        #define SOCKET_EPIPE       BSD_ERROR
+        #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
+    #define SOCKET_EAGAIN       PICO_ERR_EAGAIN
+    #define SOCKET_ECONNRESET   PICO_ERR_ECONNRESET
+    #define SOCKET_EINTR        PICO_ERR_EINTR
+    #define SOCKET_EPIPE        PICO_ERR_EIO
+    #define SOCKET_ECONNREFUSED PICO_ERR_ECONNREFUSED
+    #define SOCKET_ECONNABORTED PICO_ERR_ESHUTDOWN
+#else
+    #define SOCKET_EWOULDBLOCK EWOULDBLOCK
+    #define SOCKET_EAGAIN      EAGAIN
+    #define SOCKET_ECONNRESET  ECONNRESET
+    #define SOCKET_EINTR       EINTR
+    #define SOCKET_EPIPE       EPIPE
+    #define SOCKET_ECONNREFUSED ECONNREFUSED
+    #define SOCKET_ECONNABORTED ECONNABORTED
+#endif /* USE_WINDOWS_API */
+
+
+#ifdef DEVKITPRO
+    /* from network.h */
+    int net_send(int, const void*, int, unsigned int);
+    int net_recv(int, void*, int, unsigned int);
+    #define SEND_FUNCTION net_send
+    #define RECV_FUNCTION net_recv
+#elif defined(WOLFSSL_LWIP)
+    #define SEND_FUNCTION lwip_send
+    #define RECV_FUNCTION lwip_recv
+#elif defined(WOLFSSL_PICOTCP)
+    #define SEND_FUNCTION pico_send
+    #define RECV_FUNCTION pico_recv
+#else
+    #define SEND_FUNCTION send
+    #define RECV_FUNCTION recv
+#endif
+
+
+/* Translates return codes returned from 
+ * send() and recv() if need be. 
+ */
+static INLINE int TranslateReturnCode(int old, int sd)
+{
+    (void)sd;
+
+#ifdef FREESCALE_MQX
+    if (old == 0) {
+        errno = SOCKET_EWOULDBLOCK;
+        return -1;  /* convert to BSD style wouldblock as error */
+    }
+
+    if (old < 0) {
+        errno = RTCS_geterror(sd);
+        if (errno == RTCSERR_TCP_CONN_CLOSING)
+            return 0;   /* convert to BSD style closing */
+    }
+#endif
+
+    return old;
+}
+
+static INLINE int LastError(void)
+{
+#ifdef USE_WINDOWS_API 
+    return WSAGetLastError();
+#elif defined(EBSNET)
+    return xn_getlasterror();
+#else
+    return errno;
+#endif
+}
+
+/* The receive embedded callback
+ *  return : nb bytes read, or error
+ */
+int EmbedReceive(WOLFSSL *ssl, char *buf, int sz, void *ctx)
+{
+    int recvd;
+    int err;
+    int sd = *(int*)ctx;
+
+#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 = (int)RECV_FUNCTION(sd, buf, sz, ssl->rflags);
+
+    recvd = TranslateReturnCode(recvd, sd);
+
+    if (recvd < 0) {
+        err = LastError();
+        WOLFSSL_MSG("Embed Receive error");
+
+        if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
+            if (!wolfSSL_dtls(ssl) || wolfSSL_get_using_nonblock(ssl)) {
+                WOLFSSL_MSG("    Would block");
+                return WOLFSSL_CBIO_ERR_WANT_READ;
+            }
+            else {
+                WOLFSSL_MSG("    Socket timeout");
+                return WOLFSSL_CBIO_ERR_TIMEOUT;
+            }
+        }
+        else if (err == SOCKET_ECONNRESET) {
+            WOLFSSL_MSG("    Connection reset");
+            return WOLFSSL_CBIO_ERR_CONN_RST;
+        }
+        else if (err == SOCKET_EINTR) {
+            WOLFSSL_MSG("    Socket interrupted");
+            return WOLFSSL_CBIO_ERR_ISR;
+        }
+        else if (err == SOCKET_ECONNREFUSED) {
+            WOLFSSL_MSG("    Connection refused");
+            return WOLFSSL_CBIO_ERR_WANT_READ;
+        }
+        else if (err == SOCKET_ECONNABORTED) {
+            WOLFSSL_MSG("    Connection aborted");
+            return WOLFSSL_CBIO_ERR_CONN_CLOSE;
+        }
+        else {
+            WOLFSSL_MSG("    General error");
+            return WOLFSSL_CBIO_ERR_GENERAL;
+        }
+    }
+    else if (recvd == 0) {
+        WOLFSSL_MSG("Embed receive connection closed");
+        return WOLFSSL_CBIO_ERR_CONN_CLOSE;
+    }
+
+    return recvd;
+}
+
+/* The send embedded callback
+ *  return : nb bytes sent, or error
+ */
+int EmbedSend(WOLFSSL* ssl, char *buf, int sz, void *ctx)
+{
+    int sd = *(int*)ctx;
+    int sent;
+    int len = sz;
+    int err;
+
+    sent = (int)SEND_FUNCTION(sd, &buf[sz - len], len, ssl->wflags);
+
+    if (sent < 0) {
+        err = LastError();
+        WOLFSSL_MSG("Embed Send error");
+
+        if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
+            WOLFSSL_MSG("    Would Block");
+            return WOLFSSL_CBIO_ERR_WANT_WRITE;
+        }
+        else if (err == SOCKET_ECONNRESET) {
+            WOLFSSL_MSG("    Connection reset");
+            return WOLFSSL_CBIO_ERR_CONN_RST;
+        }
+        else if (err == SOCKET_EINTR) {
+            WOLFSSL_MSG("    Socket interrupted");
+            return WOLFSSL_CBIO_ERR_ISR;
+        }
+        else if (err == SOCKET_EPIPE) {
+            WOLFSSL_MSG("    Socket EPIPE");
+            return WOLFSSL_CBIO_ERR_CONN_CLOSE;
+        }
+        else {
+            WOLFSSL_MSG("    General error");
+            return WOLFSSL_CBIO_ERR_GENERAL;
+        }
+    }
+ 
+    return sent;
+}
+
+
+#ifdef WOLFSSL_DTLS
+
+#include <wolfssl/wolfcrypt/sha.h>
+
+#ifdef USE_WINDOWS_API
+   #define XSOCKLENT int
+#else
+   #define XSOCKLENT socklen_t
+#endif
+
+#define SENDTO_FUNCTION sendto
+#define RECVFROM_FUNCTION recvfrom
+
+
+/* The receive embedded callback
+ *  return : nb bytes read, or error
+ */
+int EmbedReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx)
+{
+    WOLFSSL_DTLS_CTX* dtlsCtx = (WOLFSSL_DTLS_CTX*)ctx;
+    int recvd;
+    int err;
+    int sd = dtlsCtx->fd;
+    int dtls_timeout = wolfSSL_dtls_get_current_timeout(ssl);
+    struct sockaddr_storage peer;
+    XSOCKLENT peerSz = sizeof(peer);
+
+    WOLFSSL_ENTER("EmbedReceiveFrom()");
+
+    if (!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");
+        }
+    }
+
+    recvd = (int)RECVFROM_FUNCTION(sd, buf, sz, ssl->rflags,
+                                  (struct sockaddr*)&peer, &peerSz);
+
+    recvd = TranslateReturnCode(recvd, sd);
+
+    if (recvd < 0) {
+        err = LastError();
+        WOLFSSL_MSG("Embed Receive From error");
+
+        if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
+            if (wolfSSL_get_using_nonblock(ssl)) {
+                WOLFSSL_MSG("    Would block");
+                return WOLFSSL_CBIO_ERR_WANT_READ;
+            }
+            else {
+                WOLFSSL_MSG("    Socket timeout");
+                return WOLFSSL_CBIO_ERR_TIMEOUT;
+            }
+        }
+        else if (err == SOCKET_ECONNRESET) {
+            WOLFSSL_MSG("    Connection reset");
+            return WOLFSSL_CBIO_ERR_CONN_RST;
+        }
+        else if (err == SOCKET_EINTR) {
+            WOLFSSL_MSG("    Socket interrupted");
+            return WOLFSSL_CBIO_ERR_ISR;
+        }
+        else if (err == SOCKET_ECONNREFUSED) {
+            WOLFSSL_MSG("    Connection refused");
+            return WOLFSSL_CBIO_ERR_WANT_READ;
+        }
+        else {
+            WOLFSSL_MSG("    General error");
+            return WOLFSSL_CBIO_ERR_GENERAL;
+        }
+    }
+    else {
+        if (dtlsCtx->peer.sz > 0
+                && peerSz != (XSOCKLENT)dtlsCtx->peer.sz
+                && memcmp(&peer, dtlsCtx->peer.sa, peerSz) != 0) {
+            WOLFSSL_MSG("    Ignored packet from invalid peer");
+            return WOLFSSL_CBIO_ERR_WANT_READ;
+        }
+    }
+
+    return recvd;
+}
+
+
+/* The send embedded callback
+ *  return : nb bytes sent, or error
+ */
+int EmbedSendTo(WOLFSSL* ssl, char *buf, int sz, void *ctx)
+{
+    WOLFSSL_DTLS_CTX* dtlsCtx = (WOLFSSL_DTLS_CTX*)ctx;
+    int sd = dtlsCtx->fd;
+    int sent;
+    int len = sz;
+    int err;
+
+    WOLFSSL_ENTER("EmbedSendTo()");
+
+    sent = (int)SENDTO_FUNCTION(sd, &buf[sz - len], len, ssl->wflags,
+                                (const struct sockaddr*)dtlsCtx->peer.sa,
+                                dtlsCtx->peer.sz);
+    if (sent < 0) {
+        err = LastError();
+        WOLFSSL_MSG("Embed Send To error");
+
+        if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
+            WOLFSSL_MSG("    Would Block");
+            return WOLFSSL_CBIO_ERR_WANT_WRITE;
+        }
+        else if (err == SOCKET_ECONNRESET) {
+            WOLFSSL_MSG("    Connection reset");
+            return WOLFSSL_CBIO_ERR_CONN_RST;
+        }
+        else if (err == SOCKET_EINTR) {
+            WOLFSSL_MSG("    Socket interrupted");
+            return WOLFSSL_CBIO_ERR_ISR;
+        }
+        else if (err == SOCKET_EPIPE) {
+            WOLFSSL_MSG("    Socket EPIPE");
+            return WOLFSSL_CBIO_ERR_CONN_CLOSE;
+        }
+        else {
+            WOLFSSL_MSG("    General error");
+            return WOLFSSL_CBIO_ERR_GENERAL;
+        }
+    }
+ 
+    return sent;
+}
+
+
+/* The DTLS Generate Cookie callback
+ *  return : number of bytes copied into buf, or error
+ */
+int EmbedGenerateCookie(WOLFSSL* ssl, byte *buf, int sz, void *ctx)
+{
+    int sd = ssl->wfd;
+    struct sockaddr_storage peer;
+    XSOCKLENT peerSz = sizeof(peer);
+    byte digest[SHA_DIGEST_SIZE];
+    int  ret = 0;
+
+    (void)ctx;
+
+    XMEMSET(&peer, 0, sizeof(peer));
+    if (getpeername(sd, (struct sockaddr*)&peer, &peerSz) != 0) {
+        WOLFSSL_MSG("getpeername failed in EmbedGenerateCookie");
+        return GEN_COOKIE_E;
+    }
+
+    ret = wc_ShaHash((byte*)&peer, peerSz, digest);
+    if (ret != 0)
+        return ret;
+
+    if (sz > SHA_DIGEST_SIZE)
+        sz = SHA_DIGEST_SIZE;
+    XMEMCPY(buf, digest, sz);
+
+    return sz;
+}
+
+#endif /* WOLFSSL_DTLS */
+
+#ifdef HAVE_OCSP
+
+
+static int Word16ToString(char* d, word16 number)
+{
+    int i = 0;
+
+    if (d != NULL) {
+        word16 order = 10000;
+        word16 digit;
+
+        if (number == 0) {
+            d[i++] = '0';
+        }
+        else {
+            while (order) {
+                digit = number / order;
+                if (i > 0 || digit != 0) {
+                    d[i++] = (char)digit + '0';
+                }
+                if (digit != 0)
+                    number %= digit * order;
+                if (order > 1)
+                    order /= 10;
+                else
+                    order = 0;
+            }
+        }
+        d[i] = 0;
+    }
+
+    return i;
+}
+
+
+static int tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port)
+{
+    struct sockaddr_storage addr;
+    int sockaddr_len = sizeof(struct sockaddr_in);
+    XMEMSET(&addr, 0, sizeof(addr));
+
+    #ifdef HAVE_GETADDRINFO
+    {
+        struct addrinfo hints;
+        struct addrinfo* answer = NULL;
+        char strPort[6];
+
+        XMEMSET(&hints, 0, sizeof(hints));
+        hints.ai_family = AF_UNSPEC;
+        hints.ai_socktype = SOCK_STREAM;
+        hints.ai_protocol = IPPROTO_TCP;
+
+        if (Word16ToString(strPort, port) == 0) {
+            WOLFSSL_MSG("invalid port number for OCSP responder");
+            return -1;
+        }
+
+        if (getaddrinfo(ip, strPort, &hints, &answer) < 0 || answer == NULL) {
+            WOLFSSL_MSG("no addr info for OCSP responder");
+            return -1;
+        }
+
+        sockaddr_len = answer->ai_addrlen;
+        XMEMCPY(&addr, answer->ai_addr, sockaddr_len);
+        freeaddrinfo(answer);
+
+    }
+    #else /* HAVE_GETADDRINFO */
+    {
+        struct hostent* entry = gethostbyname(ip);
+        struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
+
+        if (entry) {
+            sin->sin_family = AF_INET;
+            sin->sin_port = htons(port);
+            XMEMCPY(&sin->sin_addr.s_addr, entry->h_addr_list[0],
+                                                               entry->h_length);
+        }
+        else {
+            WOLFSSL_MSG("no addr info for OCSP responder");
+            return -1;
+        }
+    }
+    #endif /* HAVE_GETADDRINFO */
+
+    *sockfd = socket(addr.ss_family, SOCK_STREAM, 0);
+
+#ifdef USE_WINDOWS_API
+    if (*sockfd == INVALID_SOCKET) {
+        WOLFSSL_MSG("bad socket fd, out of fds?");
+        return -1;
+    }
+#else
+     if (*sockfd < 0) {
+         WOLFSSL_MSG("bad socket fd, out of fds?");
+         return -1;
+     }
+#endif
+
+    if (connect(*sockfd, (struct sockaddr *)&addr, sockaddr_len) != 0) {
+        WOLFSSL_MSG("OCSP responder tcp connect failed");
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static int build_http_request(const char* domainName, const char* path,
+                                    int ocspReqSz, byte* buf, int bufSize)
+{
+    word32 domainNameLen, pathLen, ocspReqSzStrLen, completeLen;
+    char ocspReqSzStr[6];
+
+    domainNameLen = (word32)XSTRLEN(domainName);
+    pathLen = (word32)XSTRLEN(path);
+    ocspReqSzStrLen = Word16ToString(ocspReqSzStr, (word16)ocspReqSz);
+
+    completeLen = domainNameLen + pathLen + ocspReqSzStrLen + 84;
+    if (completeLen > (word32)bufSize)
+        return 0;
+
+    XSTRNCPY((char*)buf, "POST ", 5);
+    buf += 5;
+    XSTRNCPY((char*)buf, path, pathLen);
+    buf += pathLen;
+    XSTRNCPY((char*)buf, " HTTP/1.1\r\nHost: ", 17);
+    buf += 17;
+    XSTRNCPY((char*)buf, domainName, domainNameLen);
+    buf += domainNameLen;
+    XSTRNCPY((char*)buf, "\r\nContent-Length: ", 18);
+    buf += 18;
+    XSTRNCPY((char*)buf, ocspReqSzStr, ocspReqSzStrLen);
+    buf += ocspReqSzStrLen;
+    XSTRNCPY((char*)buf,
+                      "\r\nContent-Type: application/ocsp-request\r\n\r\n", 44);
+
+    return completeLen;
+}
+
+
+static int decode_url(const char* url, int urlSz,
+    char* outName, char* outPath, word16* outPort)
+{
+    int result = -1;
+
+    if (outName != NULL && outPath != NULL && outPort != NULL)
+    {
+        if (url == NULL || urlSz == 0)
+        {
+            *outName = 0;
+            *outPath = 0;
+            *outPort = 0;
+        }
+        else
+        {
+            int i, cur;
+    
+            /* need to break the url down into scheme, address, and port */
+            /*     "http://example.com:8080/" */
+            /*     "http://[::1]:443/"        */
+            if (XSTRNCMP(url, "http://", 7) == 0) {
+                cur = 7;
+            } else cur = 0;
+    
+            i = 0;
+            if (url[cur] == '[') {
+                cur++;
+                /* copy until ']' */
+                while (url[cur] != 0 && url[cur] != ']' && cur < urlSz) {
+                    outName[i++] = url[cur++];
+                }
+                cur++; /* skip ']' */
+            }
+            else {
+                while (url[cur] != 0 && url[cur] != ':' &&
+                                               url[cur] != '/' && cur < urlSz) {
+                    outName[i++] = url[cur++];
+                }
+            }
+            outName[i] = 0;
+            /* Need to pick out the path after the domain name */
+    
+            if (cur < urlSz && url[cur] == ':') {
+                char port[6];
+                int j;
+                word32 bigPort = 0;
+                i = 0;
+                cur++;
+                while (cur < urlSz && url[cur] != 0 && url[cur] != '/' &&
+                        i < 6) {
+                    port[i++] = url[cur++];
+                }
+    
+                for (j = 0; j < i; j++) {
+                    if (port[j] < '0' || port[j] > '9') return -1;
+                    bigPort = (bigPort * 10) + (port[j] - '0');
+                }
+                *outPort = (word16)bigPort;
+            }
+            else
+                *outPort = 80;
+    
+            if (cur < urlSz && url[cur] == '/') {
+                i = 0;
+                while (cur < urlSz && url[cur] != 0 && i < 80) {
+                    outPath[i++] = url[cur++];
+                }
+                outPath[i] = 0;
+            }
+            else {
+                outPath[0] = '/';
+                outPath[1] = 0;
+            }
+            result = 0;
+        }
+    }
+
+    return result;
+}
+
+
+/* return: >0 OCSP Response Size
+ *         -1 error */
+static int process_http_response(int sfd, byte** respBuf,
+                                                  byte* httpBuf, int httpBufSz)
+{
+    int result;
+    int len = 0;
+    char *start, *end;
+    byte *recvBuf = NULL;
+    int recvBufSz = 0;
+    enum phr_state { phr_init, phr_http_start, phr_have_length,
+                     phr_have_type, phr_wait_end, phr_http_end
+    } state = phr_init;
+
+    start = end = NULL;
+    do {
+        if (end == NULL) {
+            result = (int)recv(sfd, (char*)httpBuf+len, httpBufSz-len-1, 0);
+            if (result > 0) {
+                len += result;
+                start = (char*)httpBuf;
+                start[len] = 0;
+            }
+            else {
+                WOLFSSL_MSG("process_http_response recv http from peer failed");
+                return -1;
+            }
+        }
+        end = XSTRSTR(start, "\r\n");
+
+        if (end == NULL) {
+            if (len != 0)
+                XMEMMOVE(httpBuf, start, len);
+            start = end = NULL;
+        }
+        else if (end == start) {
+            if (state == phr_wait_end) {
+                state = phr_http_end;
+                len -= 2;
+                start += 2;
+             }
+             else {
+                WOLFSSL_MSG("process_http_response header ended early");
+                return -1;
+             }
+        }
+        else {
+            *end = 0;
+            len -= (int)(end - start) + 2;
+                /* adjust len to remove the first line including the /r/n */
+
+            if (XSTRNCASECMP(start, "HTTP/1", 6) == 0) {
+                start += 9;
+                if (XSTRNCASECMP(start, "200 OK", 6) != 0 ||
+                                                           state != phr_init) {
+                    WOLFSSL_MSG("process_http_response not OK");
+                    return -1;
+                }
+                state = phr_http_start;
+            }
+            else if (XSTRNCASECMP(start, "Content-Type:", 13) == 0) {
+                start += 13;
+                while (*start == ' ' && *start != '\0') start++;
+                if (XSTRNCASECMP(start, "application/ocsp-response", 25) != 0) {
+                    WOLFSSL_MSG("process_http_response not ocsp-response");
+                    return -1;
+                }
+                
+                if (state == phr_http_start) state = phr_have_type;
+                else if (state == phr_have_length) state = phr_wait_end;
+                else {
+                    WOLFSSL_MSG("process_http_response type invalid state");
+                    return -1;
+                }
+            }
+            else if (XSTRNCASECMP(start, "Content-Length:", 15) == 0) {
+                start += 15;
+                while (*start == ' ' && *start != '\0') start++;
+                recvBufSz = atoi(start);
+
+                if (state == phr_http_start) state = phr_have_length;
+                else if (state == phr_have_type) state = phr_wait_end;
+                else {
+                    WOLFSSL_MSG("process_http_response length invalid state");
+                    return -1;
+                }
+            }
+            
+            start = end + 2;
+        }
+    } while (state != phr_http_end);
+
+    recvBuf = (byte*)XMALLOC(recvBufSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
+    if (recvBuf == NULL) {
+        WOLFSSL_MSG("process_http_response couldn't create response buffer");
+        return -1;
+    }
+
+    /* copy the remainder of the httpBuf into the respBuf */
+    if (len != 0)
+        XMEMCPY(recvBuf, start, len);
+
+    /* receive the OCSP response data */
+    do {
+        result = (int)recv(sfd, (char*)recvBuf+len, recvBufSz-len, 0);
+        if (result > 0)
+            len += result;
+        else {
+            WOLFSSL_MSG("process_http_response recv ocsp from peer failed");
+            return -1;
+        }
+    } while (len != recvBufSz);
+
+    *respBuf = recvBuf;
+    return recvBufSz;
+}
+
+
+#define SCRATCH_BUFFER_SIZE 512
+
+int EmbedOcspLookup(void* ctx, const char* url, int urlSz,
+                        byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf)
+{
+    SOCKET_T sfd = 0;
+    word16   port;
+    int      ret = -1;
+#ifdef WOLFSSL_SMALL_STACK
+    char*    path;
+    char*    domainName;
+#else
+    char     path[80];
+    char     domainName[80];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    path = (char*)XMALLOC(80, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (path == NULL)
+        return -1;
+    
+    domainName = (char*)XMALLOC(80, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (domainName == NULL) {
+        XFREE(path, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return -1;
+    }
+#endif
+
+    (void)ctx;
+
+    if (ocspReqBuf == NULL || ocspReqSz == 0) {
+        WOLFSSL_MSG("OCSP request is required for lookup");
+    }
+    else if (ocspRespBuf == NULL) {
+        WOLFSSL_MSG("Cannot save OCSP response");
+    }
+    else if (decode_url(url, urlSz, domainName, path, &port) < 0) {
+        WOLFSSL_MSG("Unable to decode OCSP URL");
+    }
+    else {
+        /* Note, the library uses the EmbedOcspRespFree() callback to
+         * free this buffer. */
+        int   httpBufSz = SCRATCH_BUFFER_SIZE;
+        byte* httpBuf   = (byte*)XMALLOC(httpBufSz, NULL, 
+                                                        DYNAMIC_TYPE_IN_BUFFER);
+
+        if (httpBuf == NULL) {
+            WOLFSSL_MSG("Unable to create OCSP response buffer");
+        }
+        else {
+            httpBufSz = build_http_request(domainName, path, ocspReqSz,
+                                                            httpBuf, httpBufSz);
+
+            if ((tcp_connect(&sfd, domainName, port) != 0) || (sfd <= 0)) {
+                WOLFSSL_MSG("OCSP Responder connection failed");
+            }
+            else if ((int)send(sfd, (char*)httpBuf, httpBufSz, 0) !=
+                                                                    httpBufSz) {
+                WOLFSSL_MSG("OCSP http request failed");
+            }
+            else if ((int)send(sfd, (char*)ocspReqBuf, ocspReqSz, 0) !=
+                                                                    ocspReqSz) {
+                WOLFSSL_MSG("OCSP ocsp request failed");
+            }
+            else {
+                ret = process_http_response(sfd, ocspRespBuf, httpBuf,
+                                                           SCRATCH_BUFFER_SIZE);
+            }
+
+            close(sfd);
+            XFREE(httpBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
+        }
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(path,       NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(domainName, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+void EmbedOcspRespFree(void* ctx, byte *resp)
+{
+    (void)ctx;
+
+    if (resp)
+        XFREE(resp, NULL, DYNAMIC_TYPE_IN_BUFFER);
+}
+
+
+#endif
+
+#endif /* WOLFSSL_USER_IO */
+
+WOLFSSL_API void wolfSSL_SetIORecv(WOLFSSL_CTX *ctx, CallbackIORecv CBIORecv)
+{
+    ctx->CBIORecv = CBIORecv;
+}
+
+
+WOLFSSL_API void wolfSSL_SetIOSend(WOLFSSL_CTX *ctx, CallbackIOSend CBIOSend)
+{
+    ctx->CBIOSend = CBIOSend;
+}
+
+
+WOLFSSL_API void wolfSSL_SetIOReadCtx(WOLFSSL* ssl, void *rctx)
+{
+	ssl->IOCB_ReadCtx = rctx;
+}
+
+
+WOLFSSL_API void wolfSSL_SetIOWriteCtx(WOLFSSL* ssl, void *wctx)
+{
+	ssl->IOCB_WriteCtx = wctx;
+}
+
+
+WOLFSSL_API void* wolfSSL_GetIOReadCtx(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->IOCB_ReadCtx;
+
+    return NULL;
+}
+
+
+WOLFSSL_API void* wolfSSL_GetIOWriteCtx(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->IOCB_WriteCtx;
+
+    return NULL;
+}
+
+
+WOLFSSL_API void wolfSSL_SetIOReadFlags(WOLFSSL* ssl, int flags)
+{
+    ssl->rflags = flags; 
+}
+
+
+WOLFSSL_API void wolfSSL_SetIOWriteFlags(WOLFSSL* ssl, int flags)
+{
+    ssl->wflags = flags;
+}
+
+
+#ifdef WOLFSSL_DTLS
+
+WOLFSSL_API void wolfSSL_CTX_SetGenCookie(WOLFSSL_CTX* ctx, CallbackGenCookie cb)
+{
+    ctx->CBIOCookie = cb;
+}
+
+
+WOLFSSL_API void wolfSSL_SetCookieCtx(WOLFSSL* ssl, void *ctx)
+{
+	ssl->IOCB_CookieCtx = ctx;
+}
+
+
+WOLFSSL_API void* wolfSSL_GetCookieCtx(WOLFSSL* ssl)
+{
+    if (ssl)
+	    return ssl->IOCB_CookieCtx;
+
+    return NULL;
+}
+
+#endif /* WOLFSSL_DTLS */
+
+
+#ifdef HAVE_NETX
+
+/* The NetX receive callback
+ *  return :  bytes read, or error
+ */
+int NetX_Receive(WOLFSSL *ssl, char *buf, int sz, void *ctx)
+{
+    NetX_Ctx* nxCtx = (NetX_Ctx*)ctx;
+    ULONG left;
+    ULONG total;
+    ULONG copied = 0;
+    UINT  status;
+
+    if (nxCtx == NULL || nxCtx->nxSocket == NULL) {
+        WOLFSSL_MSG("NetX Recv NULL parameters");
+        return WOLFSSL_CBIO_ERR_GENERAL;
+    }
+
+    if (nxCtx->nxPacket == NULL) {
+        status = nx_tcp_socket_receive(nxCtx->nxSocket, &nxCtx->nxPacket,
+                                       nxCtx->nxWait);
+        if (status != NX_SUCCESS) {
+            WOLFSSL_MSG("NetX Recv receive error");
+            return WOLFSSL_CBIO_ERR_GENERAL;
+        }
+    }
+
+    if (nxCtx->nxPacket) {
+        status = nx_packet_length_get(nxCtx->nxPacket, &total);
+        if (status != NX_SUCCESS) {
+            WOLFSSL_MSG("NetX Recv length get error");
+            return WOLFSSL_CBIO_ERR_GENERAL;
+        }
+
+        left = total - nxCtx->nxOffset;
+        status = nx_packet_data_extract_offset(nxCtx->nxPacket, nxCtx->nxOffset,
+                                               buf, sz, &copied);
+        if (status != NX_SUCCESS) {
+            WOLFSSL_MSG("NetX Recv data extract offset error");
+            return WOLFSSL_CBIO_ERR_GENERAL;
+        }
+
+        nxCtx->nxOffset += copied;
+
+        if (copied == left) {
+            WOLFSSL_MSG("NetX Recv Drained packet");
+            nx_packet_release(nxCtx->nxPacket);
+            nxCtx->nxPacket = NULL;
+            nxCtx->nxOffset = 0;
+        }
+    }
+
+    return copied;
+}
+
+
+/* The NetX send callback
+ *  return : bytes sent, or error
+ */
+int NetX_Send(WOLFSSL* ssl, char *buf, int sz, void *ctx)
+{
+    NetX_Ctx*       nxCtx = (NetX_Ctx*)ctx;
+    NX_PACKET*      packet;
+    NX_PACKET_POOL* pool;   /* shorthand */
+    UINT            status;
+
+    if (nxCtx == NULL || nxCtx->nxSocket == NULL) {
+        WOLFSSL_MSG("NetX Send NULL parameters");
+        return WOLFSSL_CBIO_ERR_GENERAL;
+    }
+
+    pool = nxCtx->nxSocket->nx_tcp_socket_ip_ptr->nx_ip_default_packet_pool;
+    status = nx_packet_allocate(pool, &packet, NX_TCP_PACKET,
+                                nxCtx->nxWait);
+    if (status != NX_SUCCESS) {
+        WOLFSSL_MSG("NetX Send packet alloc error");
+        return WOLFSSL_CBIO_ERR_GENERAL;
+    }
+
+    status = nx_packet_data_append(packet, buf, sz, pool, nxCtx->nxWait);
+    if (status != NX_SUCCESS) {
+        nx_packet_release(packet);
+        WOLFSSL_MSG("NetX Send data append error");
+        return WOLFSSL_CBIO_ERR_GENERAL;
+    }
+
+    status = nx_tcp_socket_send(nxCtx->nxSocket, packet, nxCtx->nxWait);
+    if (status != NX_SUCCESS) {
+        nx_packet_release(packet);
+        WOLFSSL_MSG("NetX Send socket send error");
+        return WOLFSSL_CBIO_ERR_GENERAL;
+    }
+
+    return sz;
+}
+
+
+/* like set_fd, but for default NetX context */
+void wolfSSL_SetIO_NetX(WOLFSSL* ssl, NX_TCP_SOCKET* nxSocket, ULONG waitOption)
+{
+    if (ssl) {
+        ssl->nxCtx.nxSocket = nxSocket;
+        ssl->nxCtx.nxWait   = waitOption;
+    }
+}
+
+#endif /* HAVE_NETX */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/keys.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,2736 @@
+/* keys.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+/* Name change compatibility layer no longer needs to be included here */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#include <wolfssl/internal.h>
+#include <wolfssl/error-ssl.h>
+#if defined(SHOW_SECRETS) || defined(CHACHA_AEAD_TEST)
+    #ifdef FREESCALE_MQX
+        #include <fio.h>
+    #else
+        #include <stdio.h>
+    #endif
+#endif
+
+
+int SetCipherSpecs(WOLFSSL* ssl)
+{
+#ifndef NO_WOLFSSL_CLIENT
+    if (ssl->options.side == WOLFSSL_CLIENT_END) {
+        /* server side verified before SetCipherSpecs call */
+        if (VerifyClientSuite(ssl) != 1) {
+            WOLFSSL_MSG("SetCipherSpecs() client has an unusuable suite");
+            return UNSUPPORTED_SUITE;
+        }
+    }
+#endif /* NO_WOLFSSL_CLIENT */
+
+    /* Chacha extensions, 0xcc */
+    if (ssl->options.cipherSuite0 == CHACHA_BYTE) {
+    
+    switch (ssl->options.cipherSuite) {
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+    case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+        ssl->specs.bulk_cipher_algorithm = wolfssl_chacha;
+        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             = SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = CHACHA20_256_KEY_SIZE;
+        ssl->specs.block_size            = CHACHA20_BLOCK_SIZE;
+        ssl->specs.iv_size               = CHACHA20_IV_SIZE;
+        ssl->specs.aead_mac_size         = POLY1305_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
+    case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+        ssl->specs.bulk_cipher_algorithm = wolfssl_chacha;
+        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             = SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = CHACHA20_256_KEY_SIZE;
+        ssl->specs.block_size            = CHACHA20_BLOCK_SIZE;
+        ssl->specs.iv_size               = CHACHA20_IV_SIZE;
+        ssl->specs.aead_mac_size         = POLY1305_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+    case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+        ssl->specs.bulk_cipher_algorithm = wolfssl_chacha;
+        ssl->specs.cipher_type           = aead;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = CHACHA20_256_KEY_SIZE;
+        ssl->specs.block_size            = CHACHA20_BLOCK_SIZE;
+        ssl->specs.iv_size               = CHACHA20_IV_SIZE;
+        ssl->specs.aead_mac_size         = POLY1305_AUTH_SZ;
+
+        break;
+#endif
+    default:
+        WOLFSSL_MSG("Unsupported cipher suite, SetCipherSpecs ChaCha");
+        return UNSUPPORTED_SUITE;
+    }
+    }
+
+    /* ECC extensions, or AES-CCM */
+    if (ssl->options.cipherSuite0 == ECC_BYTE) {
+    
+    switch (ssl->options.cipherSuite) {
+
+#ifdef HAVE_ECC
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+    case TLS_ECDHE_RSA_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                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_128_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_128_CBC_SHA256
+    case TLS_ECDHE_ECDSA_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                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+    break;
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
+    case TLS_ECDH_RSA_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                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+    break;
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
+    case TLS_ECDH_ECDSA_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                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        ssl->specs.key_size              = AES_128_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_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             = 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             = 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_ECDH_RSA_WITH_AES_256_CBC_SHA384
+    case TLS_ECDH_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             = SHA384_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        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_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
+    case TLS_ECDH_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             = SHA384_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        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             = 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_RSA_WITH_AES_128_CBC_SHA
+    case TLS_ECDH_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             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        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             = 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_RSA_WITH_3DES_EDE_CBC_SHA
+    case TLS_ECDH_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             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        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             = 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 :
+        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             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        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_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             = 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 :
+        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             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        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             = 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 :
+        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             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        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             = 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 :
+        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             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        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_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             = 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 :
+        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             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        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             = 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 :
+        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             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        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             = 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               = AEAD_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             = 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               = AEAD_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             = 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               = AEAD_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             = 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               = AEAD_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 :
+        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             = SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+    case TLS_ECDH_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             = SHA384_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+    case TLS_ECDH_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             = SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+    case TLS_ECDH_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             = SHA384_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 1;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_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             = 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               = AEAD_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             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_CCM_8_AUTH_SZ;
+
+        break;
+#endif
+#endif /* HAVE_ECC */
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8
+    case TLS_RSA_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                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_CCM_8_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8
+    case TLS_RSA_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                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_CCM_8_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM_8
+    case TLS_PSK_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                   = psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_CCM_8_AUTH_SZ;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM_8
+    case TLS_PSK_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                   = psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_CCM_8_AUTH_SZ;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CCM
+    case TLS_PSK_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                   = psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_CCM_16_AUTH_SZ;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CCM
+    case TLS_PSK_WITH_AES_256_CCM :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm;
+        ssl->specs.cipher_type           = aead;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_CCM_16_AUTH_SZ;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CCM
+    case TLS_DHE_PSK_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                   = dhe_psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_CCM_16_AUTH_SZ;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CCM
+    case TLS_DHE_PSK_WITH_AES_256_CCM :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes_ccm;
+        ssl->specs.cipher_type           = aead;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = dhe_psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_CCM_16_AUTH_SZ;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+    default:
+        WOLFSSL_MSG("Unsupported cipher suite, SetCipherSpecs ECC");
+        return UNSUPPORTED_SUITE;
+    }   /* switch */
+    }   /* if     */
+    if (ssl->options.cipherSuite0 != ECC_BYTE && 
+            ssl->options.cipherSuite0 != CHACHA_BYTE) {   /* normal suites */
+    switch (ssl->options.cipherSuite) {
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
+    case SSL_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                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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_NTRU_RSA_WITH_RC4_128_SHA
+    case TLS_NTRU_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                   = ntru_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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_SSL_RSA_WITH_RC4_128_MD5
+    case SSL_RSA_WITH_RC4_128_MD5 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_rc4;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = md5_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = MD5_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_MD5;
+        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_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+    case SSL_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                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    case TLS_NTRU_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                   = ntru_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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_RSA_WITH_AES_128_CBC_SHA
+    case TLS_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                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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_RSA_WITH_AES_128_CBC_SHA256
+    case TLS_RSA_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                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_NULL_SHA
+    case TLS_RSA_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                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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_RSA_WITH_NULL_SHA256
+    case TLS_RSA_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                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+    case TLS_NTRU_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                   = ntru_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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_RSA_WITH_AES_256_CBC_SHA
+    case TLS_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                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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_RSA_WITH_AES_256_CBC_SHA256
+    case TLS_RSA_WITH_AES_256_CBC_SHA256 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    case TLS_NTRU_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                   = ntru_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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_PSK_WITH_AES_128_GCM_SHA256
+    case TLS_PSK_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                   = psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_GCM_SHA384
+    case TLS_PSK_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                   = psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
+    case TLS_DHE_PSK_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                   = dhe_psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
+    case TLS_DHE_PSK_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                   = dhe_psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256
+    case TLS_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                   = psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA384
+    case TLS_PSK_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                   = psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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               = AES_IV_SIZE;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
+    case TLS_DHE_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                   = dhe_psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
+    case TLS_DHE_PSK_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                   = dhe_psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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               = AES_IV_SIZE;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
+    case TLS_PSK_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                   = psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
+    case TLS_PSK_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                   = psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_NULL_SHA256
+    case TLS_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                   = psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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_PSK_WITH_NULL_SHA384
+    case TLS_PSK_WITH_NULL_SHA384 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = sha384_mac;
+        ssl->specs.kea                   = psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = SHA384_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_PSK_WITH_NULL_SHA
+    case TLS_PSK_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                   = psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_PSK_WITH_NULL_SHA256
+    case TLS_DHE_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                   = dhe_psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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_DHE_PSK_WITH_NULL_SHA384
+    case TLS_DHE_PSK_WITH_NULL_SHA384 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = sha384_mac;
+        ssl->specs.kea                   = dhe_psk_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = SHA384_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_DHE_RSA_WITH_AES_128_CBC_SHA256
+    case TLS_DHE_RSA_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                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
+    case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+    case TLS_DHE_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                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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_DHE_RSA_WITH_AES_256_CBC_SHA
+    case TLS_DHE_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                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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_RSA_WITH_HC_128_MD5
+    case TLS_RSA_WITH_HC_128_MD5 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_hc128;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = md5_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = MD5_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_MD5;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = HC_128_KEY_SIZE;
+        ssl->specs.block_size            = 0;
+        ssl->specs.iv_size               = HC_128_IV_SIZE;
+
+        break;
+#endif
+            
+#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA
+        case TLS_RSA_WITH_HC_128_SHA :
+            ssl->specs.bulk_cipher_algorithm = wolfssl_hc128;
+            ssl->specs.cipher_type           = stream;
+            ssl->specs.mac_algorithm         = sha_mac;
+            ssl->specs.kea                   = rsa_kea;
+            ssl->specs.sig_algo              = rsa_sa_algo;
+            ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+            ssl->specs.pad_size              = PAD_SHA;
+            ssl->specs.static_ecdh           = 0;
+            ssl->specs.key_size              = HC_128_KEY_SIZE;
+            ssl->specs.block_size            = 0;
+            ssl->specs.iv_size               = HC_128_IV_SIZE;
+            
+            break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256
+        case TLS_RSA_WITH_HC_128_B2B256:
+            ssl->specs.bulk_cipher_algorithm = wolfssl_hc128;
+            ssl->specs.cipher_type           = stream;
+            ssl->specs.mac_algorithm         = blake2b_mac;
+            ssl->specs.kea                   = rsa_kea;
+            ssl->specs.sig_algo              = rsa_sa_algo;
+            ssl->specs.hash_size             = BLAKE2B_256;
+            ssl->specs.pad_size              = PAD_SHA;
+            ssl->specs.static_ecdh           = 0;
+            ssl->specs.key_size              = HC_128_KEY_SIZE;
+            ssl->specs.block_size            = 0;
+            ssl->specs.iv_size               = HC_128_IV_SIZE;
+            
+            break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
+        case TLS_RSA_WITH_AES_128_CBC_B2B256:
+            ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
+            ssl->specs.cipher_type           = block;
+            ssl->specs.mac_algorithm         = blake2b_mac;
+            ssl->specs.kea                   = rsa_kea;
+            ssl->specs.sig_algo              = rsa_sa_algo;
+            ssl->specs.hash_size             = BLAKE2B_256;
+            ssl->specs.pad_size              = PAD_SHA;
+            ssl->specs.static_ecdh           = 0;
+            ssl->specs.key_size              = AES_128_KEY_SIZE;
+            ssl->specs.iv_size               = AES_IV_SIZE;
+            ssl->specs.block_size            = AES_BLOCK_SIZE;
+            
+            break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
+        case TLS_RSA_WITH_AES_256_CBC_B2B256:
+            ssl->specs.bulk_cipher_algorithm = wolfssl_aes;
+            ssl->specs.cipher_type           = block;
+            ssl->specs.mac_algorithm         = blake2b_mac;
+            ssl->specs.kea                   = rsa_kea;
+            ssl->specs.sig_algo              = rsa_sa_algo;
+            ssl->specs.hash_size             = BLAKE2B_256;
+            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_RSA_WITH_RABBIT_SHA
+    case TLS_RSA_WITH_RABBIT_SHA :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_rabbit;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = RABBIT_KEY_SIZE;
+        ssl->specs.block_size            = 0;
+        ssl->specs.iv_size               = RABBIT_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256
+    case TLS_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                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384
+    case TLS_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                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+    case TLS_DHE_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                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+    case TLS_DHE_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                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = 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               = AEAD_IMP_IV_SZ;
+        ssl->specs.aead_mac_size         = AES_GCM_AUTH_SZ;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+    case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_camellia;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = CAMELLIA_128_KEY_SIZE;
+        ssl->specs.block_size            = CAMELLIA_BLOCK_SIZE;
+        ssl->specs.iv_size               = CAMELLIA_IV_SIZE;
+
+        break;
+#endif
+    
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
+    case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_camellia;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = CAMELLIA_256_KEY_SIZE;
+        ssl->specs.block_size            = CAMELLIA_BLOCK_SIZE;
+        ssl->specs.iv_size               = CAMELLIA_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
+    case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_camellia;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = CAMELLIA_128_KEY_SIZE;
+        ssl->specs.block_size            = CAMELLIA_BLOCK_SIZE;
+        ssl->specs.iv_size               = CAMELLIA_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
+    case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_camellia;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = CAMELLIA_256_KEY_SIZE;
+        ssl->specs.block_size            = CAMELLIA_BLOCK_SIZE;
+        ssl->specs.iv_size               = CAMELLIA_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+    case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_camellia;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = CAMELLIA_128_KEY_SIZE;
+        ssl->specs.block_size            = CAMELLIA_BLOCK_SIZE;
+        ssl->specs.iv_size               = CAMELLIA_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+    case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_camellia;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = CAMELLIA_256_KEY_SIZE;
+        ssl->specs.block_size            = CAMELLIA_BLOCK_SIZE;
+        ssl->specs.iv_size               = CAMELLIA_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+    case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_camellia;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = CAMELLIA_128_KEY_SIZE;
+        ssl->specs.block_size            = CAMELLIA_BLOCK_SIZE;
+        ssl->specs.iv_size               = CAMELLIA_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
+    case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 :
+        ssl->specs.bulk_cipher_algorithm = wolfssl_camellia;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha256_mac;
+        ssl->specs.kea                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA256_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = CAMELLIA_256_KEY_SIZE;
+        ssl->specs.block_size            = CAMELLIA_BLOCK_SIZE;
+        ssl->specs.iv_size               = CAMELLIA_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA
+    case TLS_DH_anon_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                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = anonymous_sa_algo;
+        ssl->specs.hash_size             = 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;
+
+        ssl->options.usingAnon_cipher    = 1;
+        break;
+#endif
+
+    default:
+        WOLFSSL_MSG("Unsupported cipher suite, SetCipherSpecs");
+        return UNSUPPORTED_SUITE;
+    }  /* switch */
+    }  /* if ECC / Normal suites else */
+
+    /* set TLS if it hasn't been turned off */
+    if (ssl->version.major == 3 && ssl->version.minor >= 1) {
+#ifndef NO_TLS
+        ssl->options.tls = 1;
+        ssl->hmac = TLS_hmac;
+        if (ssl->version.minor >= 2)
+            ssl->options.tls1_1 = 1;
+#endif
+    }
+
+#ifdef WOLFSSL_DTLS
+    if (ssl->options.dtls)
+        ssl->hmac = TLS_hmac;
+#endif
+
+    return 0;
+}
+
+
+enum KeyStuff {
+    MASTER_ROUNDS = 3,
+    PREFIX        = 3,     /* up to three letters for master prefix */
+    KEY_PREFIX    = 7      /* up to 7 prefix letters for key rounds */
+
+
+};
+
+#ifndef NO_OLD_TLS
+/* true or false, zero for error */
+static int SetPrefix(byte* sha_input, int idx)
+{
+    switch (idx) {
+    case 0:
+        XMEMCPY(sha_input, "A", 1);
+        break;
+    case 1:
+        XMEMCPY(sha_input, "BB", 2);
+        break;
+    case 2:
+        XMEMCPY(sha_input, "CCC", 3);
+        break;
+    case 3:
+        XMEMCPY(sha_input, "DDDD", 4);
+        break;
+    case 4:
+        XMEMCPY(sha_input, "EEEEE", 5);
+        break;
+    case 5:
+        XMEMCPY(sha_input, "FFFFFF", 6);
+        break;
+    case 6:
+        XMEMCPY(sha_input, "GGGGGGG", 7);
+        break;
+    default:
+        WOLFSSL_MSG("Set Prefix error, bad input");
+        return 0; 
+    }
+    return 1;
+}
+#endif
+
+
+static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs,
+                   int side, void* heap, int devId)
+{
+#ifdef BUILD_ARC4
+    word32 sz = specs->key_size;
+    if (specs->bulk_cipher_algorithm == wolfssl_rc4) {
+        if (enc && enc->arc4 == NULL)
+            enc->arc4 = (Arc4*)XMALLOC(sizeof(Arc4), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc && enc->arc4 == NULL)
+            return MEMORY_E;
+        if (dec && dec->arc4 == NULL)
+            dec->arc4 = (Arc4*)XMALLOC(sizeof(Arc4), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec && dec->arc4 == NULL)
+            return MEMORY_E;
+#ifdef HAVE_CAVIUM
+        if (devId != NO_CAVIUM_DEVICE) {
+            if (enc) {
+                if (Arc4InitCavium(enc->arc4, devId) != 0) {
+                    WOLFSSL_MSG("Arc4InitCavium failed in SetKeys");
+                    return CAVIUM_INIT_E;
+                }
+            }
+            if (dec) {
+                if (Arc4InitCavium(dec->arc4, devId) != 0) {
+                    WOLFSSL_MSG("Arc4InitCavium failed in SetKeys");
+                    return CAVIUM_INIT_E;
+                }
+            }
+        }
+#endif
+        if (side == WOLFSSL_CLIENT_END) {
+            if (enc)
+                wc_Arc4SetKey(enc->arc4, keys->client_write_key, sz);
+            if (dec)
+                wc_Arc4SetKey(dec->arc4, keys->server_write_key, sz);
+        }
+        else {
+            if (enc)
+                wc_Arc4SetKey(enc->arc4, keys->server_write_key, sz);
+            if (dec)
+                wc_Arc4SetKey(dec->arc4, keys->client_write_key, sz);
+        }
+        if (enc)
+            enc->setup = 1;
+        if (dec)
+            dec->setup = 1;
+    }
+#endif
+
+    
+#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
+    if (specs->bulk_cipher_algorithm == wolfssl_chacha) {
+        int chachaRet;
+        if (enc && enc->chacha == NULL)
+            enc->chacha =
+                    (ChaCha*)XMALLOC(sizeof(ChaCha), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc && enc->chacha == NULL)
+            return MEMORY_E;
+        if (dec && dec->chacha == NULL)
+            dec->chacha =
+                    (ChaCha*)XMALLOC(sizeof(ChaCha), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec && dec->chacha == NULL)
+            return MEMORY_E;
+        if (side == WOLFSSL_CLIENT_END) {
+            if (enc) {
+                chachaRet = wc_Chacha_SetKey(enc->chacha, keys->client_write_key,
+                                          specs->key_size);
+                XMEMCPY(keys->aead_enc_imp_IV, keys->client_write_IV,
+                        AEAD_IMP_IV_SZ);
+                if (chachaRet != 0) return chachaRet;
+            }
+            if (dec) {
+                chachaRet = wc_Chacha_SetKey(dec->chacha, keys->server_write_key,
+                                          specs->key_size);
+                XMEMCPY(keys->aead_dec_imp_IV, keys->server_write_IV,
+                        AEAD_IMP_IV_SZ);
+                if (chachaRet != 0) return chachaRet;
+            }
+        }
+        else {
+            if (enc) {
+                chachaRet = wc_Chacha_SetKey(enc->chacha, keys->server_write_key,
+                                          specs->key_size);
+                XMEMCPY(keys->aead_enc_imp_IV, keys->server_write_IV,
+                        AEAD_IMP_IV_SZ);
+                if (chachaRet != 0) return chachaRet;
+            }
+            if (dec) {
+                chachaRet = wc_Chacha_SetKey(dec->chacha, keys->client_write_key,
+                                          specs->key_size);
+                XMEMCPY(keys->aead_dec_imp_IV, keys->client_write_IV,
+                        AEAD_IMP_IV_SZ);
+                if (chachaRet != 0) return chachaRet;
+            }
+        }
+
+        if (enc)
+            enc->setup = 1;
+        if (dec)
+            dec->setup = 1;
+    }
+#endif
+
+#ifdef HAVE_HC128
+    if (specs->bulk_cipher_algorithm == wolfssl_hc128) {
+        int hcRet;
+        if (enc && enc->hc128 == NULL)
+            enc->hc128 =
+                      (HC128*)XMALLOC(sizeof(HC128), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc && enc->hc128 == NULL)
+            return MEMORY_E;
+        if (dec && dec->hc128 == NULL)
+            dec->hc128 =
+                      (HC128*)XMALLOC(sizeof(HC128), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec && dec->hc128 == NULL)
+            return MEMORY_E;
+        if (side == WOLFSSL_CLIENT_END) {
+            if (enc) {
+                hcRet = wc_Hc128_SetKey(enc->hc128, keys->client_write_key,
+                                     keys->client_write_IV);
+                if (hcRet != 0) return hcRet;
+            }
+            if (dec) {
+                hcRet = wc_Hc128_SetKey(dec->hc128, keys->server_write_key,
+                                     keys->server_write_IV);
+                if (hcRet != 0) return hcRet;
+            }
+        }
+        else {
+            if (enc) {
+                hcRet = wc_Hc128_SetKey(enc->hc128, keys->server_write_key,
+                                     keys->server_write_IV);
+                if (hcRet != 0) return hcRet;
+            }
+            if (dec) {
+                hcRet = wc_Hc128_SetKey(dec->hc128, keys->client_write_key,
+                                     keys->client_write_IV);
+                if (hcRet != 0) return hcRet;
+            }
+        }
+        if (enc)
+            enc->setup = 1;
+        if (dec)
+            dec->setup = 1;
+    }
+#endif
+    
+#ifdef BUILD_RABBIT
+    if (specs->bulk_cipher_algorithm == wolfssl_rabbit) {
+        int rabRet;
+        if (enc && enc->rabbit == NULL)
+            enc->rabbit =
+                    (Rabbit*)XMALLOC(sizeof(Rabbit), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc && enc->rabbit == NULL)
+            return MEMORY_E;
+        if (dec && dec->rabbit == NULL)
+            dec->rabbit =
+                    (Rabbit*)XMALLOC(sizeof(Rabbit), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec && dec->rabbit == NULL)
+            return MEMORY_E;
+        if (side == WOLFSSL_CLIENT_END) {
+            if (enc) {
+                rabRet = wc_RabbitSetKey(enc->rabbit, keys->client_write_key,
+                                      keys->client_write_IV);
+                if (rabRet != 0) return rabRet;
+            }
+            if (dec) {
+                rabRet = wc_RabbitSetKey(dec->rabbit, keys->server_write_key,
+                                      keys->server_write_IV);
+                if (rabRet != 0) return rabRet;
+            }
+        }
+        else {
+            if (enc) {
+                rabRet = wc_RabbitSetKey(enc->rabbit, keys->server_write_key,
+                                      keys->server_write_IV);
+                if (rabRet != 0) return rabRet;
+            }
+            if (dec) {
+                rabRet = wc_RabbitSetKey(dec->rabbit, keys->client_write_key,
+                                      keys->client_write_IV);
+                if (rabRet != 0) return rabRet;
+            }
+        }
+        if (enc)
+            enc->setup = 1;
+        if (dec)
+            dec->setup = 1;
+    }
+#endif
+    
+#ifdef BUILD_DES3
+    if (specs->bulk_cipher_algorithm == wolfssl_triple_des) {
+        int desRet = 0;
+
+        if (enc && enc->des3 == NULL)
+            enc->des3 = (Des3*)XMALLOC(sizeof(Des3), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc && enc->des3 == NULL)
+            return MEMORY_E;
+        if (dec && dec->des3 == NULL)
+            dec->des3 = (Des3*)XMALLOC(sizeof(Des3), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec && dec->des3 == NULL)
+            return MEMORY_E;
+#ifdef HAVE_CAVIUM
+        if (devId != NO_CAVIUM_DEVICE) {
+            if (enc) {
+                if (Des3_InitCavium(enc->des3, devId) != 0) {
+                    WOLFSSL_MSG("Des3_InitCavium failed in SetKeys");
+                    return CAVIUM_INIT_E;
+                }
+            }
+            if (dec) {
+                if (Des3_InitCavium(dec->des3, devId) != 0) {
+                    WOLFSSL_MSG("Des3_InitCavium failed in SetKeys");
+                    return CAVIUM_INIT_E;
+                }
+            }
+        }
+#endif
+        if (side == WOLFSSL_CLIENT_END) {
+            if (enc) {
+                desRet = wc_Des3_SetKey(enc->des3, keys->client_write_key,
+                                     keys->client_write_IV, DES_ENCRYPTION);
+                if (desRet != 0) return desRet;
+            }
+            if (dec) {
+                desRet = wc_Des3_SetKey(dec->des3, keys->server_write_key,
+                                     keys->server_write_IV, DES_DECRYPTION);
+                if (desRet != 0) return desRet;
+            }
+        }
+        else {
+            if (enc) {
+                desRet = wc_Des3_SetKey(enc->des3, keys->server_write_key,
+                                     keys->server_write_IV, DES_ENCRYPTION);
+                if (desRet != 0) return desRet;
+            }
+            if (dec) {
+                desRet = wc_Des3_SetKey(dec->des3, keys->client_write_key,
+                                     keys->client_write_IV, DES_DECRYPTION);
+                if (desRet != 0) return desRet;
+            }
+        }
+        if (enc)
+            enc->setup = 1;
+        if (dec)
+            dec->setup = 1;
+    }
+#endif
+
+#ifdef BUILD_AES
+    if (specs->bulk_cipher_algorithm == wolfssl_aes) {
+        int aesRet = 0;
+
+        if (enc && enc->aes == NULL)
+            enc->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc && enc->aes == NULL)
+            return MEMORY_E;
+        if (dec && dec->aes == NULL)
+            dec->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec && dec->aes == NULL)
+            return MEMORY_E;
+#ifdef HAVE_CAVIUM
+        if (devId != NO_CAVIUM_DEVICE) {
+            if (enc) {
+                if (wc_AesInitCavium(enc->aes, devId) != 0) {
+                    WOLFSSL_MSG("AesInitCavium failed in SetKeys");
+                    return CAVIUM_INIT_E;
+                }
+            }
+            if (dec) {
+                if (wc_AesInitCavium(dec->aes, devId) != 0) {
+                    WOLFSSL_MSG("AesInitCavium failed in SetKeys");
+                    return CAVIUM_INIT_E;
+                }
+            }
+        }
+#endif
+        if (side == WOLFSSL_CLIENT_END) {
+            if (enc) {
+                aesRet = wc_AesSetKey(enc->aes, keys->client_write_key,
+                                   specs->key_size, keys->client_write_IV,
+                                   AES_ENCRYPTION);
+                if (aesRet != 0) return aesRet;
+            }
+            if (dec) {
+                aesRet = wc_AesSetKey(dec->aes, keys->server_write_key,
+                                   specs->key_size, keys->server_write_IV,
+                                   AES_DECRYPTION);
+                if (aesRet != 0) return aesRet;
+            }
+        }
+        else {
+            if (enc) {
+                aesRet = wc_AesSetKey(enc->aes, keys->server_write_key,
+                                   specs->key_size, keys->server_write_IV,
+                                   AES_ENCRYPTION);
+                if (aesRet != 0) return aesRet;
+            }
+            if (dec) {
+                aesRet = wc_AesSetKey(dec->aes, keys->client_write_key,
+                                   specs->key_size, keys->client_write_IV,
+                                   AES_DECRYPTION);
+                if (aesRet != 0) return aesRet;
+            }
+        }
+        if (enc)
+            enc->setup = 1;
+        if (dec)
+            dec->setup = 1;
+    }
+#endif
+
+#ifdef BUILD_AESGCM
+    if (specs->bulk_cipher_algorithm == wolfssl_aes_gcm) {
+        int gcmRet;
+
+        if (enc && enc->aes == NULL)
+            enc->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc && enc->aes == NULL)
+            return MEMORY_E;
+        if (dec && dec->aes == NULL)
+            dec->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec && dec->aes == NULL)
+            return MEMORY_E;
+
+        if (side == WOLFSSL_CLIENT_END) {
+            if (enc) {
+                gcmRet = wc_AesGcmSetKey(enc->aes, keys->client_write_key,
+                                      specs->key_size);
+                if (gcmRet != 0) return gcmRet;
+                XMEMCPY(keys->aead_enc_imp_IV, keys->client_write_IV,
+                        AEAD_IMP_IV_SZ);
+            }
+            if (dec) {
+                gcmRet = wc_AesGcmSetKey(dec->aes, keys->server_write_key,
+                                      specs->key_size);
+                if (gcmRet != 0) return gcmRet;
+                XMEMCPY(keys->aead_dec_imp_IV, keys->server_write_IV,
+                        AEAD_IMP_IV_SZ);
+            }
+        }
+        else {
+            if (enc) {
+                gcmRet = wc_AesGcmSetKey(enc->aes, keys->server_write_key,
+                                      specs->key_size);
+                if (gcmRet != 0) return gcmRet;
+                XMEMCPY(keys->aead_enc_imp_IV, keys->server_write_IV,
+                        AEAD_IMP_IV_SZ);
+            }
+            if (dec) {
+                gcmRet = wc_AesGcmSetKey(dec->aes, keys->client_write_key,
+                                      specs->key_size);
+                if (gcmRet != 0) return gcmRet;
+                XMEMCPY(keys->aead_dec_imp_IV, keys->client_write_IV,
+                        AEAD_IMP_IV_SZ);
+            }
+        }
+        if (enc)
+            enc->setup = 1;
+        if (dec)
+            dec->setup = 1;
+    }
+#endif
+
+#ifdef HAVE_AESCCM
+    if (specs->bulk_cipher_algorithm == wolfssl_aes_ccm) {
+        if (enc && enc->aes == NULL)
+            enc->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc && enc->aes == NULL)
+            return MEMORY_E;
+        if (dec && dec->aes == NULL)
+            dec->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec && dec->aes == NULL)
+            return MEMORY_E;
+
+        if (side == WOLFSSL_CLIENT_END) {
+            if (enc) {
+                wc_AesCcmSetKey(enc->aes, keys->client_write_key, specs->key_size);
+                XMEMCPY(keys->aead_enc_imp_IV, keys->client_write_IV,
+                        AEAD_IMP_IV_SZ);
+            }
+            if (dec) {
+                wc_AesCcmSetKey(dec->aes, keys->server_write_key, specs->key_size);
+                XMEMCPY(keys->aead_dec_imp_IV, keys->server_write_IV,
+                        AEAD_IMP_IV_SZ);
+            }
+        }
+        else {
+            if (enc) {
+                wc_AesCcmSetKey(enc->aes, keys->server_write_key, specs->key_size);
+                XMEMCPY(keys->aead_enc_imp_IV, keys->server_write_IV,
+                        AEAD_IMP_IV_SZ);
+            }
+            if (dec) {
+                wc_AesCcmSetKey(dec->aes, keys->client_write_key, specs->key_size);
+                XMEMCPY(keys->aead_dec_imp_IV, keys->client_write_IV,
+                        AEAD_IMP_IV_SZ);
+            }
+        }
+        if (enc)
+            enc->setup = 1;
+        if (dec)
+            dec->setup = 1;
+    }
+#endif
+
+#ifdef HAVE_CAMELLIA
+    if (specs->bulk_cipher_algorithm == wolfssl_camellia) {
+        int camRet;
+
+        if (enc && enc->cam == NULL)
+            enc->cam =
+                (Camellia*)XMALLOC(sizeof(Camellia), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc && enc->cam == NULL)
+            return MEMORY_E;
+
+        if (dec && dec->cam == NULL)
+            dec->cam =
+                (Camellia*)XMALLOC(sizeof(Camellia), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec && dec->cam == NULL)
+            return MEMORY_E;
+
+        if (side == WOLFSSL_CLIENT_END) {
+            if (enc) {
+                camRet = wc_CamelliaSetKey(enc->cam, keys->client_write_key,
+                                        specs->key_size, keys->client_write_IV);
+                if (camRet != 0) return camRet;
+            }
+            if (dec) {
+                camRet = wc_CamelliaSetKey(dec->cam, keys->server_write_key,
+                                        specs->key_size, keys->server_write_IV);
+                if (camRet != 0) return camRet;
+            }
+        }
+        else {
+            if (enc) {
+                camRet = wc_CamelliaSetKey(enc->cam, keys->server_write_key,
+                                        specs->key_size, keys->server_write_IV);
+                if (camRet != 0) return camRet;
+            }
+            if (dec) {
+                camRet = wc_CamelliaSetKey(dec->cam, keys->client_write_key,
+                                        specs->key_size, keys->client_write_IV);
+                if (camRet != 0) return camRet;
+            }
+        }
+        if (enc)
+            enc->setup = 1;
+        if (dec)
+            dec->setup = 1;
+    }
+#endif
+
+#ifdef HAVE_NULL_CIPHER
+    if (specs->bulk_cipher_algorithm == wolfssl_cipher_null) {
+        if (enc)
+            enc->setup = 1;
+        if (dec)
+            dec->setup = 1;
+    }
+#endif
+
+    if (enc)
+        keys->sequence_number      = 0;
+    if (dec)
+        keys->peer_sequence_number = 0;
+    (void)side;
+    (void)heap;
+    (void)enc;
+    (void)dec;
+    (void)specs;
+    (void)devId;
+
+    return 0;
+}
+
+
+#ifdef HAVE_ONE_TIME_AUTH
+/* set one time authentication keys */
+static int SetAuthKeys(OneTimeAuth* authentication, Keys* keys,
+                       CipherSpecs* specs, void* heap, int devId)
+{
+
+#ifdef HAVE_POLY1305
+        /* set up memory space for poly1305 */
+        if (authentication && authentication->poly1305 == NULL)
+            authentication->poly1305 =
+                (Poly1305*)XMALLOC(sizeof(Poly1305), heap, DYNAMIC_TYPE_CIPHER);
+        if (authentication && authentication->poly1305 == NULL)
+            return MEMORY_E;
+        if (authentication)
+            authentication->setup = 1;
+#endif
+        (void)heap;
+        (void)keys;
+        (void)specs;
+        (void)devId;
+
+        return 0;
+}
+#endif /* HAVE_ONE_TIME_AUTH */
+
+
+/* Set wc_encrypt/wc_decrypt or both sides of key setup
+ * note: use wc_encrypt to avoid shadowing global encrypt
+ * declared in unistd.h
+ */
+int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side)
+{
+    int devId = NO_CAVIUM_DEVICE, ret, copy = 0;
+    Ciphers* wc_encrypt = NULL;
+    Ciphers* wc_decrypt = NULL;
+    Keys*    keys    = &ssl->keys;
+
+    (void)copy;
+
+#ifdef HAVE_CAVIUM
+    devId = ssl->devId;
+#endif
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+    if (ssl->secure_renegotiation && ssl->secure_renegotiation->cache_status) {
+        keys = &ssl->secure_renegotiation->tmp_keys;
+        copy = 1;
+    }
+#endif /* HAVE_SECURE_RENEGOTIATION */
+
+    switch (side) {
+        case ENCRYPT_SIDE_ONLY:
+            wc_encrypt = &ssl->encrypt;
+            break;
+
+        case DECRYPT_SIDE_ONLY:
+            wc_decrypt = &ssl->decrypt;
+            break;
+
+        case ENCRYPT_AND_DECRYPT_SIDE:
+            wc_encrypt = &ssl->encrypt;
+            wc_decrypt = &ssl->decrypt;
+            break;
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+#ifdef HAVE_ONE_TIME_AUTH
+    if (!ssl->auth.setup && ssl->specs.bulk_cipher_algorithm == wolfssl_chacha){
+        ret = SetAuthKeys(&ssl->auth, keys, &ssl->specs, ssl->heap, devId);
+        if (ret != 0)
+           return ret;
+    }
+#endif
+
+    ret = SetKeys(wc_encrypt, wc_decrypt, keys, &ssl->specs, ssl->options.side,
+                  ssl->heap, devId);
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+    if (copy) {
+        int clientCopy = 0;
+
+        if (ssl->options.side == WOLFSSL_CLIENT_END && wc_encrypt)
+            clientCopy = 1;
+        else if (ssl->options.side == WOLFSSL_SERVER_END && wc_decrypt)
+            clientCopy = 1;
+
+        if (clientCopy) {
+            XMEMCPY(ssl->keys.client_write_MAC_secret,
+                    keys->client_write_MAC_secret, MAX_DIGEST_SIZE);
+            XMEMCPY(ssl->keys.client_write_key,
+                    keys->client_write_key, AES_256_KEY_SIZE);
+            XMEMCPY(ssl->keys.client_write_IV,
+                    keys->client_write_IV, AES_IV_SIZE);
+        } else {
+            XMEMCPY(ssl->keys.server_write_MAC_secret,
+                    keys->server_write_MAC_secret, MAX_DIGEST_SIZE);
+            XMEMCPY(ssl->keys.server_write_key,
+                    keys->server_write_key, AES_256_KEY_SIZE);
+            XMEMCPY(ssl->keys.server_write_IV,
+                    keys->server_write_IV, AES_IV_SIZE);
+        }
+        if (wc_encrypt) {
+            ssl->keys.sequence_number = keys->sequence_number;
+            #ifdef HAVE_AEAD
+                if (ssl->specs.cipher_type == aead) {
+                    /* Initialize the AES-GCM/CCM explicit IV to a zero. */
+                    XMEMCPY(ssl->keys.aead_exp_IV, keys->aead_exp_IV,
+                            AEAD_EXP_IV_SZ);
+
+                    /* Initialize encrypt implicit IV by encrypt side */
+                    if (ssl->options.side == WOLFSSL_CLIENT_END) {
+                        XMEMCPY(ssl->keys.aead_enc_imp_IV,
+                                keys->client_write_IV, AEAD_IMP_IV_SZ);
+                    } else {
+                        XMEMCPY(ssl->keys.aead_enc_imp_IV,
+                                keys->server_write_IV, AEAD_IMP_IV_SZ);
+                    }
+                }
+            #endif
+        }
+        if (wc_decrypt) {
+            ssl->keys.peer_sequence_number = keys->peer_sequence_number;
+            #ifdef HAVE_AEAD
+                if (ssl->specs.cipher_type == aead) {
+                    /* Initialize decrypt implicit IV by decrypt side */
+                    if (ssl->options.side == WOLFSSL_SERVER_END) {
+                        XMEMCPY(ssl->keys.aead_dec_imp_IV,
+                                keys->client_write_IV, AEAD_IMP_IV_SZ);
+                    } else {
+                        XMEMCPY(ssl->keys.aead_dec_imp_IV,
+                                keys->server_write_IV, AEAD_IMP_IV_SZ);
+                    }
+                }
+            #endif
+        }
+        ssl->secure_renegotiation->cache_status++;
+    }
+#endif /* HAVE_SECURE_RENEGOTIATION */
+
+    return ret;
+}
+
+
+/* TLS can call too */
+int StoreKeys(WOLFSSL* ssl, const byte* keyData)
+{
+    int sz, i = 0;
+    Keys* keys = &ssl->keys;
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+    if (ssl->secure_renegotiation && ssl->secure_renegotiation->cache_status ==
+                                                            SCR_CACHE_NEEDED) {
+        keys = &ssl->secure_renegotiation->tmp_keys;
+        ssl->secure_renegotiation->cache_status++;
+    }
+#endif /* HAVE_SECURE_RENEGOTIATION */
+
+    if (ssl->specs.cipher_type != aead) {
+        sz = ssl->specs.hash_size;
+        XMEMCPY(keys->client_write_MAC_secret,&keyData[i], sz);
+        i += sz;
+        XMEMCPY(keys->server_write_MAC_secret,&keyData[i], sz);
+        i += sz;
+    }
+    sz = ssl->specs.key_size;
+    XMEMCPY(keys->client_write_key, &keyData[i], sz);
+    i += sz;
+    XMEMCPY(keys->server_write_key, &keyData[i], sz);
+    i += sz;
+
+    sz = ssl->specs.iv_size;
+    XMEMCPY(keys->client_write_IV, &keyData[i], sz);
+    i += sz;
+    XMEMCPY(keys->server_write_IV, &keyData[i], sz);
+
+#ifdef HAVE_AEAD
+    if (ssl->specs.cipher_type == aead) {
+        /* Initialize the AES-GCM/CCM explicit IV to a zero. */
+        XMEMSET(keys->aead_exp_IV, 0, AEAD_EXP_IV_SZ);
+    }
+#endif
+
+    return 0;
+}
+
+#ifndef NO_OLD_TLS
+int DeriveKeys(WOLFSSL* ssl)
+{
+    int    length = 2 * ssl->specs.hash_size + 
+                    2 * ssl->specs.key_size  +
+                    2 * ssl->specs.iv_size;
+    int    rounds = (length + MD5_DIGEST_SIZE - 1 ) / MD5_DIGEST_SIZE, i;
+    int    ret = 0;
+    
+#ifdef WOLFSSL_SMALL_STACK
+    byte*  shaOutput;
+    byte*  md5Input;
+    byte*  shaInput;
+    byte*  keyData;
+    Md5*   md5;
+    Sha*   sha;
+#else
+    byte   shaOutput[SHA_DIGEST_SIZE];
+    byte   md5Input[SECRET_LEN + SHA_DIGEST_SIZE];
+    byte   shaInput[KEY_PREFIX + SECRET_LEN + 2 * RAN_LEN];
+    byte   keyData[KEY_PREFIX * MD5_DIGEST_SIZE];
+    Md5    md5[1];
+    Sha    sha[1];
+#endif
+    
+#ifdef WOLFSSL_SMALL_STACK
+    shaOutput = (byte*)XMALLOC(SHA_DIGEST_SIZE, 
+                                            NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    md5Input  = (byte*)XMALLOC(SECRET_LEN + SHA_DIGEST_SIZE,
+                                            NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    shaInput  = (byte*)XMALLOC(KEY_PREFIX + SECRET_LEN + 2 * RAN_LEN,
+                                            NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    keyData   = (byte*)XMALLOC(KEY_PREFIX * MD5_DIGEST_SIZE,
+                                            NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    md5       =  (Md5*)XMALLOC(sizeof(Md5), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    sha       =  (Sha*)XMALLOC(sizeof(Sha), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    
+    if (shaOutput == NULL || md5Input == NULL || shaInput == NULL ||
+        keyData   == NULL || md5      == NULL || sha      == NULL) {
+        if (shaOutput) XFREE(shaOutput, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (md5Input)  XFREE(md5Input,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (shaInput)  XFREE(shaInput,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (keyData)   XFREE(keyData,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (md5)       XFREE(md5,       NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (sha)       XFREE(sha,       NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        
+        return MEMORY_E;
+    }
+#endif
+
+    wc_InitMd5(md5);
+
+    ret = wc_InitSha(sha);
+
+    if (ret == 0) {
+        XMEMCPY(md5Input, ssl->arrays->masterSecret, SECRET_LEN);
+
+        for (i = 0; i < rounds; ++i) {
+            int j   = i + 1;
+            int idx = j;
+
+            if (!SetPrefix(shaInput, i)) {
+                ret = PREFIX_ERROR;
+                break;
+            }
+
+            XMEMCPY(shaInput + idx, ssl->arrays->masterSecret, SECRET_LEN);
+            idx += SECRET_LEN;
+            XMEMCPY(shaInput + idx, ssl->arrays->serverRandom, RAN_LEN);
+            idx += RAN_LEN;
+            XMEMCPY(shaInput + idx, ssl->arrays->clientRandom, RAN_LEN);
+
+            wc_ShaUpdate(sha, shaInput, (KEY_PREFIX + SECRET_LEN + 2 * RAN_LEN)
+                                                              - KEY_PREFIX + j);
+            wc_ShaFinal(sha, shaOutput);
+
+            XMEMCPY(md5Input + SECRET_LEN, shaOutput, SHA_DIGEST_SIZE);
+            wc_Md5Update(md5, md5Input, SECRET_LEN + SHA_DIGEST_SIZE);
+            wc_Md5Final(md5, keyData + i * MD5_DIGEST_SIZE);
+        }
+
+        if (ret == 0)
+            ret = StoreKeys(ssl, keyData);
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(shaOutput, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(md5Input,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(shaInput,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(keyData,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(md5,       NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(sha,       NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+static int CleanPreMaster(WOLFSSL* ssl)
+{
+    int i, ret, sz = ssl->arrays->preMasterSz;
+
+    for (i = 0; i < sz; i++)
+        ssl->arrays->preMasterSecret[i] = 0;
+
+    ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->preMasterSecret, sz);
+    if (ret != 0)
+        return ret;
+
+    for (i = 0; i < sz; i++)
+        ssl->arrays->preMasterSecret[i] = 0;
+
+    return 0;
+}
+
+
+/* Create and store the master secret see page 32, 6.1 */
+static int MakeSslMasterSecret(WOLFSSL* ssl)
+{
+    int    i, ret;
+    word32 idx;
+    word32 pmsSz = ssl->arrays->preMasterSz;
+
+#ifdef WOLFSSL_SMALL_STACK
+    byte*  shaOutput;
+    byte*  md5Input;
+    byte*  shaInput;
+    Md5*   md5;
+    Sha*   sha;
+#else
+    byte   shaOutput[SHA_DIGEST_SIZE];
+    byte   md5Input[ENCRYPT_LEN + SHA_DIGEST_SIZE];
+    byte   shaInput[PREFIX + ENCRYPT_LEN + 2 * RAN_LEN];
+    Md5    md5[1];
+    Sha    sha[1];
+#endif
+
+#ifdef SHOW_SECRETS
+    {
+        word32 j;
+        printf("pre master secret: ");
+        for (j = 0; j < pmsSz; j++)
+            printf("%02x", ssl->arrays->preMasterSecret[j]);
+        printf("\n");
+    }
+#endif
+    
+#ifdef WOLFSSL_SMALL_STACK
+    shaOutput = (byte*)XMALLOC(SHA_DIGEST_SIZE, 
+                                            NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    md5Input  = (byte*)XMALLOC(ENCRYPT_LEN + SHA_DIGEST_SIZE,
+                                            NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    shaInput  = (byte*)XMALLOC(PREFIX + ENCRYPT_LEN + 2 * RAN_LEN,
+                                            NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    md5       =  (Md5*)XMALLOC(sizeof(Md5), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    sha       =  (Sha*)XMALLOC(sizeof(Sha), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    
+    if (shaOutput == NULL || md5Input == NULL || shaInput == NULL ||
+                             md5      == NULL || sha      == NULL) {
+        if (shaOutput) XFREE(shaOutput, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (md5Input)  XFREE(md5Input,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (shaInput)  XFREE(shaInput,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (md5)       XFREE(md5,       NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (sha)       XFREE(sha,       NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        
+        return MEMORY_E;
+    }
+#endif
+
+    wc_InitMd5(md5);
+    
+    ret = wc_InitSha(sha);
+    
+    if (ret == 0) {
+        XMEMCPY(md5Input, ssl->arrays->preMasterSecret, pmsSz);
+
+        for (i = 0; i < MASTER_ROUNDS; ++i) {
+            byte prefix[KEY_PREFIX];      /* only need PREFIX bytes but static */
+            if (!SetPrefix(prefix, i)) {  /* analysis thinks will overrun      */
+                ret = PREFIX_ERROR;
+                break;
+            }
+
+            idx = 0;
+            XMEMCPY(shaInput, prefix, i + 1);
+            idx += i + 1;
+
+            XMEMCPY(shaInput + idx, ssl->arrays->preMasterSecret, pmsSz);
+            idx += pmsSz;
+            XMEMCPY(shaInput + idx, ssl->arrays->clientRandom, RAN_LEN);
+            idx += RAN_LEN;
+            XMEMCPY(shaInput + idx, ssl->arrays->serverRandom, RAN_LEN);
+            idx += RAN_LEN;
+            wc_ShaUpdate(sha, shaInput, idx);
+            wc_ShaFinal(sha, shaOutput);
+
+            idx = pmsSz;  /* preSz */
+            XMEMCPY(md5Input + idx, shaOutput, SHA_DIGEST_SIZE);
+            idx += SHA_DIGEST_SIZE;
+            wc_Md5Update(md5, md5Input, idx);
+            wc_Md5Final(md5, &ssl->arrays->masterSecret[i * MD5_DIGEST_SIZE]);
+        }
+
+#ifdef SHOW_SECRETS
+        {
+            word32 j;
+            printf("master secret: ");
+            for (j = 0; j < SECRET_LEN; j++)
+                printf("%02x", ssl->arrays->masterSecret[j]);
+            printf("\n");
+        }
+#endif
+
+        if (ret == 0)
+            ret = DeriveKeys(ssl);
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(shaOutput, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(md5Input,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(shaInput,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(md5,       NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(sha,       NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+    
+    if (ret == 0)
+        ret = CleanPreMaster(ssl);
+    else
+        CleanPreMaster(ssl);
+
+    return ret;
+}
+#endif
+
+
+/* Master wrapper, doesn't use SSL stack space in TLS mode */
+int MakeMasterSecret(WOLFSSL* ssl)
+{
+#ifdef NO_OLD_TLS
+    return MakeTlsMasterSecret(ssl);
+#elif !defined(NO_TLS)
+    if (ssl->options.tls) return MakeTlsMasterSecret(ssl);
+#endif
+
+#ifndef NO_OLD_TLS
+    return MakeSslMasterSecret(ssl);
+#endif
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ocsp.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,304 @@
+/* ocsp.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+  /* Name change compatibility layer no longer needs to be included here */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_OCSP
+
+#include <wolfssl/error-ssl.h>
+#include <wolfssl/ocsp.h>
+#include <wolfssl/internal.h>
+
+
+int InitOCSP(WOLFSSL_OCSP* ocsp, WOLFSSL_CERT_MANAGER* cm)
+{
+    WOLFSSL_ENTER("InitOCSP");
+    XMEMSET(ocsp, 0, sizeof(*ocsp));
+    ocsp->cm = cm;
+    if (InitMutex(&ocsp->ocspLock) != 0)
+        return BAD_MUTEX_E;
+
+    return 0;
+}
+
+
+static int InitOCSP_Entry(OCSP_Entry* ocspe, DecodedCert* cert)
+{
+    WOLFSSL_ENTER("InitOCSP_Entry");
+
+    XMEMSET(ocspe, 0, sizeof(*ocspe));
+    XMEMCPY(ocspe->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE);
+    XMEMCPY(ocspe->issuerKeyHash, cert->issuerKeyHash, SHA_DIGEST_SIZE);
+
+    return 0;
+}
+
+
+static void FreeOCSP_Entry(OCSP_Entry* ocspe)
+{
+    CertStatus* tmp = ocspe->status;
+
+    WOLFSSL_ENTER("FreeOCSP_Entry");
+
+    while (tmp) {
+        CertStatus* next = tmp->next;
+        XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_STATUS);
+        tmp = next;
+    }
+}
+
+
+void FreeOCSP(WOLFSSL_OCSP* ocsp, int dynamic)
+{
+    OCSP_Entry* tmp = ocsp->ocspList;
+
+    WOLFSSL_ENTER("FreeOCSP");
+
+    while (tmp) {
+        OCSP_Entry* next = tmp->next;
+        FreeOCSP_Entry(tmp);
+        XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_ENTRY);
+        tmp = next;
+    }
+
+    FreeMutex(&ocsp->ocspLock);
+    if (dynamic)
+        XFREE(ocsp, NULL, DYNAMIC_TYPE_OCSP);
+}
+
+
+static int xstat2err(int stat)
+{
+    switch (stat) {
+        case CERT_GOOD:
+            return 0;
+        case CERT_REVOKED:
+            return OCSP_CERT_REVOKED;
+        default:
+            return OCSP_CERT_UNKNOWN;
+    }
+}
+
+
+int CheckCertOCSP(WOLFSSL_OCSP* ocsp, DecodedCert* cert)
+{
+    byte* ocspReqBuf = NULL;
+    int ocspReqSz = 2048;
+    byte* ocspRespBuf = NULL;
+    int result = -1;
+    OCSP_Entry* ocspe;
+    CertStatus* certStatus = NULL;
+    const char *url;
+    int urlSz;
+#ifdef WOLFSSL_SMALL_STACK
+    CertStatus* newStatus;
+    OcspRequest* ocspRequest;
+    OcspResponse* ocspResponse;
+#else
+    CertStatus newStatus[1];
+    OcspRequest ocspRequest[1];
+    OcspResponse ocspResponse[1];
+#endif
+
+    WOLFSSL_ENTER("CheckCertOCSP");
+
+    if (LockMutex(&ocsp->ocspLock) != 0) {
+        WOLFSSL_LEAVE("CheckCertOCSP", BAD_MUTEX_E);
+        return BAD_MUTEX_E;
+    }
+
+    ocspe = ocsp->ocspList;
+    while (ocspe) {
+        if (XMEMCMP(ocspe->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE) == 0
+            && XMEMCMP(ocspe->issuerKeyHash, cert->issuerKeyHash,
+                                                        SHA_DIGEST_SIZE) == 0)
+            break;
+        else
+            ocspe = ocspe->next;
+    }
+
+    if (ocspe == NULL) {
+        ocspe = (OCSP_Entry*)XMALLOC(sizeof(OCSP_Entry),
+                                                NULL, DYNAMIC_TYPE_OCSP_ENTRY);
+        if (ocspe != NULL) {
+            InitOCSP_Entry(ocspe, cert);
+            ocspe->next = ocsp->ocspList;
+            ocsp->ocspList = ocspe;
+        }
+        else {
+            UnLockMutex(&ocsp->ocspLock);
+            WOLFSSL_LEAVE("CheckCertOCSP", MEMORY_ERROR);
+            return MEMORY_ERROR;
+        }
+    }
+    else {
+        certStatus = ocspe->status;
+        while (certStatus) {
+            if (certStatus->serialSz == cert->serialSz &&
+                 XMEMCMP(certStatus->serial, cert->serial, cert->serialSz) == 0)
+                break;
+            else
+                certStatus = certStatus->next;
+        }
+    }
+
+    if (certStatus != NULL) {
+        if (!ValidateDate(certStatus->thisDate,
+                                        certStatus->thisDateFormat, BEFORE) ||
+            (certStatus->nextDate[0] == 0) ||
+            !ValidateDate(certStatus->nextDate,
+                                        certStatus->nextDateFormat, AFTER)) {
+            WOLFSSL_MSG("\tinvalid status date, looking up cert");
+        }
+        else {
+            result = xstat2err(certStatus->status);
+            UnLockMutex(&ocsp->ocspLock);
+            WOLFSSL_LEAVE("CheckCertOCSP", result);
+            return result;
+        }
+    }
+
+    UnLockMutex(&ocsp->ocspLock);
+
+    if (ocsp->cm->ocspUseOverrideURL) {
+        url = ocsp->cm->ocspOverrideURL;
+        if (url != NULL && url[0] != '\0')
+            urlSz = (int)XSTRLEN(url);
+        else
+            return OCSP_NEED_URL;
+    }
+    else if (cert->extAuthInfoSz != 0 && cert->extAuthInfo != NULL) {
+        url = (const char *)cert->extAuthInfo;
+        urlSz = cert->extAuthInfoSz;
+    }
+    else {
+        /* cert doesn't have extAuthInfo, assuming CERT_GOOD */
+        return 0;
+    }
+
+    ocspReqBuf = (byte*)XMALLOC(ocspReqSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
+    if (ocspReqBuf == NULL) {
+        WOLFSSL_LEAVE("CheckCertOCSP", MEMORY_ERROR);
+        return MEMORY_ERROR;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    newStatus = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    ocspRequest = (OcspRequest*)XMALLOC(sizeof(OcspRequest), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    ocspResponse = (OcspResponse*)XMALLOC(sizeof(OcspResponse), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+
+    if (newStatus == NULL || ocspRequest == NULL || ocspResponse == NULL) {
+        if (newStatus)    XFREE(newStatus,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (ocspRequest)  XFREE(ocspRequest,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (ocspResponse) XFREE(ocspResponse, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+        XFREE(ocspReqBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+        WOLFSSL_LEAVE("CheckCertOCSP", MEMORY_ERROR);
+        return MEMORY_E;
+    }
+#endif
+
+    InitOcspRequest(ocspRequest, cert, ocsp->cm->ocspSendNonce,
+                                                         ocspReqBuf, ocspReqSz);
+    ocspReqSz = EncodeOcspRequest(ocspRequest);
+    
+    if (ocsp->cm->ocspIOCb)
+        result = ocsp->cm->ocspIOCb(ocsp->cm->ocspIOCtx, url, urlSz,
+                                           ocspReqBuf, ocspReqSz, &ocspRespBuf);
+
+    if (result >= 0 && ocspRespBuf) {
+        XMEMSET(newStatus, 0, sizeof(CertStatus));
+
+        InitOcspResponse(ocspResponse, newStatus, ocspRespBuf, result);
+        OcspResponseDecode(ocspResponse);
+    
+        if (ocspResponse->responseStatus != OCSP_SUCCESSFUL)
+            result = OCSP_LOOKUP_FAIL;
+        else {
+            if (CompareOcspReqResp(ocspRequest, ocspResponse) == 0) {
+                result = xstat2err(ocspResponse->status->status);
+
+                if (LockMutex(&ocsp->ocspLock) != 0)
+                    result = BAD_MUTEX_E;
+                else {
+                    if (certStatus != NULL)
+                        /* Replace existing certificate entry with updated */
+                        XMEMCPY(certStatus, newStatus, sizeof(CertStatus));
+                    else {
+                        /* Save new certificate entry */
+                        certStatus = (CertStatus*)XMALLOC(sizeof(CertStatus),
+                                          NULL, DYNAMIC_TYPE_OCSP_STATUS);
+                        if (certStatus != NULL) {
+                            XMEMCPY(certStatus, newStatus, sizeof(CertStatus));
+                            certStatus->next = ocspe->status;
+                            ocspe->status = certStatus;
+                            ocspe->totalStatus++;
+                        }
+                    }
+
+                    UnLockMutex(&ocsp->ocspLock);
+                }
+            }
+            else
+                result = OCSP_LOOKUP_FAIL;
+        }
+    }
+    else
+        result = OCSP_LOOKUP_FAIL;
+
+    XFREE(ocspReqBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(newStatus,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(ocspRequest,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(ocspResponse, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    if (ocspRespBuf != NULL && ocsp->cm->ocspRespFreeCb)
+        ocsp->cm->ocspRespFreeCb(ocsp->cm->ocspIOCtx, ocspRespBuf);
+
+    WOLFSSL_LEAVE("CheckCertOCSP", result);
+    return result;
+}
+
+
+#else /* HAVE_OCSP */
+
+
+#ifdef _MSC_VER
+    /* 4206 warning for blank file */
+    #pragma warning(disable: 4206)
+#endif
+
+
+#endif /* HAVE_OCSP */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sniffer.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,2949 @@
+/* sniffer.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef WOLFSSL_SNIFFER
+
+#include <assert.h>
+#include <time.h>
+
+#ifndef _WIN32
+  #include <arpa/inet.h>
+#endif
+
+#ifdef _WIN32
+    #define SNPRINTF _snprintf
+#else
+    #define SNPRINTF snprintf
+#endif
+
+#include <wolfssl/openssl/ssl.h>
+#include <wolfssl/internal.h>
+#include <wolfssl/error-ssl.h>
+#include <wolfssl/sniffer.h>
+#include <wolfssl/sniffer_error.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+static INLINE word32 min(word32 a, word32 b)
+{
+    return a > b ? b : a;
+}
+
+#endif /* WOLFSSL_HAVE_MIN */
+
+#ifndef WOLFSSL_SNIFFER_TIMEOUT
+    #define WOLFSSL_SNIFFER_TIMEOUT 900
+    /* Cache unclosed Sessions for 15 minutes since last used */
+#endif
+
+/* Misc constants */
+enum {
+    MAX_SERVER_ADDRESS = 128, /* maximum server address length */
+    MAX_SERVER_NAME    = 128, /* maximum server name length */
+    MAX_ERROR_LEN      = 80,  /* maximum error length */
+    ETHER_IF_ADDR_LEN  = 6,   /* ethernet interface address length */
+    LOCAL_IF_ADDR_LEN  = 4,   /* localhost interface address length, !windows */
+    TCP_PROTO          = 6,   /* TCP_PROTOCOL */
+    IP_HDR_SZ          = 20,  /* IP header legnth, min */
+    TCP_HDR_SZ         = 20,  /* TCP header legnth, min */
+    IPV4               = 4,   /* IP version 4 */
+    TCP_PROTOCOL       = 6,   /* TCP Protocol id */
+    TRACE_MSG_SZ       = 80,  /* Trace Message buffer size */
+    HASH_SIZE          = 499, /* Session Hash Table Rows */
+    PSEUDO_HDR_SZ      = 12,  /* TCP Pseudo Header size in bytes */
+    FATAL_ERROR_STATE  =  1,  /* SnifferSession fatal error state */
+    TICKET_HINT_LEN    = 4,   /* Session Ticket Hint length */
+    EXT_TYPE_SZ        = 2,   /* Extension length */
+    MAX_INPUT_SZ       = MAX_RECORD_SIZE + COMP_EXTRA + MAX_MSG_EXTRA +
+                         MTU_EXTRA,  /* Max input sz of reassembly */
+    TICKET_EXT_ID      = 0x23 /* Session Ticket Extension ID */
+};
+
+
+#ifdef _WIN32
+
+static HMODULE dllModule;  /* for error string resources */
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+                       DWORD  ul_reason_for_call,
+                       LPVOID lpReserved
+                     )
+{
+	static int didInit = 0;
+
+    switch (ul_reason_for_call)
+    {
+    case DLL_PROCESS_ATTACH:
+		if (didInit == 0) {
+            dllModule = hModule;
+			ssl_InitSniffer();
+			didInit = 1;
+		}
+        break;
+    case DLL_THREAD_ATTACH:
+        break;
+    case DLL_THREAD_DETACH:
+        break;
+    case DLL_PROCESS_DETACH:
+		if (didInit) {
+			ssl_FreeSniffer();
+			didInit = 0;
+		}
+        break;
+    }
+    return TRUE;
+}
+
+#endif /* _WIN32 */
+
+
+static int TraceOn = 0;         /* Trace is off by default */
+static FILE* TraceFile = 0;
+
+
+/* windows uses .rc table for this */
+#ifndef _WIN32
+
+static const char* const msgTable[] =
+{
+    /* 1 */
+    "Out of Memory",
+    "New SSL Sniffer Server Registered",
+    "Checking IP Header",
+    "SSL Sniffer Server Not Registered",
+    "Checking TCP Header",
+
+    /* 6 */
+    "SSL Sniffer Server Port Not Registered",
+    "RSA Private Decrypt Error",
+    "RSA Private Decode Error",
+    "Set Cipher Spec Error",
+    "Server Hello Input Malformed",
+
+    /* 11 */
+    "Couldn't Resume Session Error",
+    "Server Did Resumption",
+    "Client Hello Input Malformed",
+    "Client Trying to Resume",
+    "Handshake Input Malformed",
+
+    /* 16 */
+    "Got Hello Verify msg",
+    "Got Server Hello msg",
+    "Got Cert Request msg",
+    "Got Server Key Exchange msg",
+    "Got Cert msg",
+
+    /* 21 */
+    "Got Server Hello Done msg",
+    "Got Finished msg",
+    "Got Client Hello msg",
+    "Got Client Key Exchange msg",
+    "Got Cert Verify msg",
+
+    /* 26 */
+    "Got Unknown Handshake msg",
+    "New SSL Sniffer Session created",
+    "Couldn't create new SSL",
+    "Got a Packet to decode",
+    "No data present",
+
+    /* 31 */
+    "Session Not Found",
+    "Got an Old Client Hello msg",
+    "Old Client Hello Input Malformed",
+    "Old Client Hello OK",
+    "Bad Old Client Hello",
+
+    /* 36 */
+    "Bad Record Header",
+    "Record Header Input Malformed",
+    "Got a HandShake msg",
+    "Bad HandShake msg",
+    "Got a Change Cipher Spec msg",
+
+    /* 41 */
+    "Got Application Data msg",
+    "Bad Application Data",
+    "Got an Alert msg",
+    "Another msg to Process",
+    "Removing Session From Table",
+    
+    /* 46 */
+    "Bad Key File",
+    "Wrong IP Version",
+    "Wrong Protocol type",
+    "Packet Short for header processing",
+    "Got Unknown Record Type",
+    
+    /* 51 */
+    "Can't Open Trace File",
+    "Session in Fatal Error State",
+    "Partial SSL record received",
+    "Buffer Error, malformed input",
+    "Added to Partial Input",
+    
+    /* 56 */
+    "Received a Duplicate Packet",
+    "Received an Out of Order Packet",
+    "Received an Overlap Duplicate Packet",
+    "Received an Overlap Reassembly Begin Duplicate Packet",
+    "Received an Overlap Reassembly End Duplicate Packet",
+
+    /* 61 */
+    "Missed the Client Hello Entirely",
+    "Got Hello Request msg",
+    "Got Session Ticket msg",
+    "Bad Input",
+    "Bad Decrypt Type",
+
+    /* 66 */
+    "Bad Finished Message Processing",
+    "Bad Compression Type",
+    "Bad DeriveKeys Error",
+    "Saw ACK for Missing Packet Error",
+    "Bad Decrypt Operation",
+
+    /* 71 */
+    "Decrypt Keys Not Set Up",
+    "Late Key Load Error",
+    "Got Certificate Status msg",
+    "RSA Key Missing Error"
+};
+
+
+/* *nix version uses table above */
+static void GetError(int idx, char* str)
+{
+    XSTRNCPY(str, msgTable[idx - 1], MAX_ERROR_LEN);
+}
+
+
+#else /* _WIN32 */
+
+
+/* Windows version uses .rc table */
+static void GetError(int idx, char* buffer)
+{
+    if (!LoadStringA(dllModule, idx, buffer, MAX_ERROR_LEN))
+        buffer[0] = 0;
+}
+
+
+#endif /* _WIN32 */
+
+
+/* Packet Buffer for reassembly list and ready list */
+typedef struct PacketBuffer {
+    word32  begin;      /* relative sequence begin */
+    word32  end;        /* relative sequence end   */
+    byte*   data;       /* actual data             */
+    struct PacketBuffer* next; /* next on reassembly list or ready list */
+} PacketBuffer;
+
+
+#ifdef HAVE_SNI
+
+/* NamedKey maps a SNI name to a specific private key */
+typedef struct NamedKey {
+    char             name[MAX_SERVER_NAME];      /* server DNS name */
+    word32           nameSz;                     /* size of server DNS name */
+    byte*            key;                        /* DER private key */
+    word32           keySz;                      /* size of DER private key */
+    struct NamedKey* next;                       /* for list */
+} NamedKey;
+
+#endif
+
+
+/* Sniffer Server holds info for each server/port monitored */
+typedef struct SnifferServer {
+    SSL_CTX*       ctx;                          /* SSL context */
+    char           address[MAX_SERVER_ADDRESS];  /* passed in server address */
+    word32         server;                       /* netowrk order address */
+    int            port;                         /* server port */
+#ifdef HAVE_SNI
+    NamedKey*      namedKeys;                    /* mapping of names and keys */
+    wolfSSL_Mutex   namedKeysMutex;               /* mutex for namedKey list */
+#endif
+    struct SnifferServer* next;                  /* for list */
+} SnifferServer;
+
+
+/* Session Flags */
+typedef struct Flags {
+    byte           side;            /* which end is current packet headed */
+    byte           serverCipherOn;  /* indicates whether cipher is active */
+    byte           clientCipherOn;  /* indicates whether cipher is active */
+    byte           resuming;        /* did this session come from resumption */
+    byte           cached;          /* have we cached this session yet */
+    byte           clientHello;     /* processed client hello yet, for SSLv2 */
+    byte           finCount;        /* get both FINs before removing */
+    byte           fatalError;      /* fatal error state */
+} Flags;
+
+
+/* Out of Order FIN caputre */
+typedef struct FinCaputre {
+    word32 cliFinSeq;               /* client relative sequence FIN  0 is no */
+    word32 srvFinSeq;               /* server relative sequence FIN, 0 is no */
+    byte   cliCounted;              /* did we count yet, detects duplicates */
+    byte   srvCounted;              /* did we count yet, detects duplicates */
+} FinCaputre;
+
+
+/* Sniffer Session holds info for each client/server SSL/TLS session */
+typedef struct SnifferSession {
+    SnifferServer* context;         /* server context */
+    SSL*           sslServer;       /* SSL server side decode */
+    SSL*           sslClient;       /* SSL client side decode */
+    word32         server;          /* server address in network byte order */
+    word32         client;          /* client address in network byte order */
+    word16         srvPort;         /* server port */
+    word16         cliPort;         /* client port */
+    word32         cliSeqStart;     /* client start sequence */
+    word32         srvSeqStart;     /* server start sequence */
+    word32         cliExpected;     /* client expected sequence (relative) */
+    word32         srvExpected;     /* server expected sequence (relative) */
+    FinCaputre     finCaputre;      /* retain out of order FIN s */
+    Flags          flags;           /* session flags */
+    time_t         lastUsed;          /* last used ticks */
+    PacketBuffer*  cliReassemblyList; /* client out of order packets */
+    PacketBuffer*  srvReassemblyList; /* server out of order packets */
+    struct SnifferSession* next;      /* for hash table list */
+    byte*          ticketID;          /* mac ID of session ticket */
+} SnifferSession;
+
+
+/* Sniffer Server List and mutex */
+static SnifferServer* ServerList = 0;
+static wolfSSL_Mutex ServerListMutex;
+
+
+/* Session Hash Table, mutex, and count */
+static SnifferSession* SessionTable[HASH_SIZE];
+static wolfSSL_Mutex SessionMutex;
+static int SessionCount = 0;
+
+
+/* Initialize overall Sniffer */
+void ssl_InitSniffer(void)
+{
+    wolfSSL_Init();
+    InitMutex(&ServerListMutex);
+    InitMutex(&SessionMutex);
+}
+
+
+#ifdef HAVE_SNI
+
+/* Free Named Key and the zero out the private key it holds */
+static void FreeNamedKey(NamedKey* in)
+{
+    if (in) {
+        if (in->key) {
+            ForceZero(in->key, in->keySz);
+            free(in->key);
+        }
+        free(in);
+    }
+}
+
+
+static void FreeNamedKeyList(NamedKey* in)
+{
+    NamedKey* next;
+
+    while (in) {
+        next = in->next;
+        FreeNamedKey(in);
+        in = next;
+    }
+}
+
+#endif
+
+
+/* Free Sniffer Server's resources/self */
+static void FreeSnifferServer(SnifferServer* srv)
+{
+    if (srv) {
+#ifdef HAVE_SNI
+        LockMutex(&srv->namedKeysMutex);
+        FreeNamedKeyList(srv->namedKeys);
+        UnLockMutex(&srv->namedKeysMutex);
+        FreeMutex(&srv->namedKeysMutex);
+#endif
+        SSL_CTX_free(srv->ctx);
+    }
+    free(srv);
+}
+
+
+/* free PacketBuffer's resources/self */
+static void FreePacketBuffer(PacketBuffer* del)
+{
+    if (del) {
+        free(del->data);
+        free(del);
+    }
+}
+
+
+/* remove PacketBuffer List */
+static void FreePacketList(PacketBuffer* in)
+{
+    if (in) {
+        PacketBuffer* del;
+        PacketBuffer* packet = in;
+        
+        while (packet) {
+            del = packet;
+            packet = packet->next;
+            FreePacketBuffer(del);
+        }
+    }
+}
+
+
+/* Free Sniffer Session's resources/self */
+static void FreeSnifferSession(SnifferSession* session)
+{
+    if (session) {
+        SSL_free(session->sslClient);
+        SSL_free(session->sslServer);
+        
+        FreePacketList(session->cliReassemblyList);
+        FreePacketList(session->srvReassemblyList);
+
+        free(session->ticketID);
+    }
+    free(session);
+}
+
+
+/* Free overall Sniffer */
+void ssl_FreeSniffer(void)
+{
+    SnifferServer*  srv;
+    SnifferServer*  removeServer;
+    SnifferSession* session;
+    SnifferSession* removeSession;
+    int i;
+
+    LockMutex(&ServerListMutex);
+    LockMutex(&SessionMutex);
+    
+    srv = ServerList;
+    while (srv) {
+        removeServer = srv;
+        srv = srv->next;
+        FreeSnifferServer(removeServer);
+    }
+
+    for (i = 0; i < HASH_SIZE; i++) {
+        session = SessionTable[i];
+        while (session) {
+            removeSession = session;
+            session = session->next;
+            FreeSnifferSession(removeSession);
+        }
+    }
+
+    UnLockMutex(&SessionMutex);
+    UnLockMutex(&ServerListMutex);
+
+    FreeMutex(&SessionMutex);
+    FreeMutex(&ServerListMutex);
+
+    if (TraceFile) {
+        TraceOn = 0;
+        fclose(TraceFile);
+        TraceFile = NULL;
+    }
+
+    wolfSSL_Cleanup();
+}
+
+
+/* Initialize a SnifferServer */
+static void InitSnifferServer(SnifferServer* sniffer)
+{
+    sniffer->ctx = 0;
+    XMEMSET(sniffer->address, 0, MAX_SERVER_ADDRESS);
+    sniffer->server   = 0;
+    sniffer->port     = 0;
+#ifdef HAVE_SNI
+    sniffer->namedKeys = 0;
+    InitMutex(&sniffer->namedKeysMutex);
+#endif
+    sniffer->next     = 0;
+}
+
+
+/* Initialize session flags */
+static void InitFlags(Flags* flags)
+{
+    flags->side           = 0;
+    flags->serverCipherOn = 0;
+    flags->clientCipherOn = 0;
+    flags->resuming       = 0;
+    flags->cached         = 0;
+    flags->clientHello    = 0;
+    flags->finCount       = 0;
+    flags->fatalError     = 0;
+}
+
+
+/* Initialize FIN Capture */
+static void InitFinCapture(FinCaputre* cap)
+{
+    cap->cliFinSeq  = 0;
+    cap->srvFinSeq  = 0;
+    cap->cliCounted = 0;
+    cap->srvCounted = 0;
+}
+
+
+/* Initialize a Sniffer Session */
+static void InitSession(SnifferSession* session)
+{
+    session->context        = 0;
+    session->sslServer      = 0;
+    session->sslClient      = 0;
+    session->server         = 0;
+    session->client         = 0;
+    session->srvPort        = 0;
+    session->cliPort        = 0;
+    session->cliSeqStart    = 0;
+    session->srvSeqStart    = 0;
+    session->cliExpected    = 0;
+    session->srvExpected    = 0;
+    session->lastUsed       = 0;
+    session->cliReassemblyList = 0;
+    session->srvReassemblyList = 0;
+    session->next           = 0;
+    session->ticketID       = 0;
+    
+    InitFlags(&session->flags);
+    InitFinCapture(&session->finCaputre);
+}
+
+
+/* IP Info from IP Header */
+typedef struct IpInfo {
+    int    length;        /* length of this header */
+    int    total;         /* total length of fragment */
+    word32 src;           /* network order source address */
+    word32 dst;           /* network order destination address */
+} IpInfo;
+
+
+/* TCP Info from TCP Header */
+typedef struct TcpInfo {
+    int    srcPort;       /* source port */
+    int    dstPort;       /* source port */
+    int    length;        /* length of this header */
+    word32 sequence;      /* sequence number */
+    word32 ackNumber;     /* ack number */
+    byte   fin;           /* FIN set */
+    byte   rst;           /* RST set */
+    byte   syn;           /* SYN set */
+    byte   ack;           /* ACK set */
+} TcpInfo;
+
+
+/* Tcp Pseudo Header for Checksum calculation */
+typedef struct TcpPseudoHdr {
+    word32  src;        /* source address */
+    word32  dst;        /* destination address */
+    byte    rsv;        /* reserved, always 0 */
+    byte    protocol;   /* IP protocol */
+    word16  legnth;     /* tcp header length + data length (doesn't include */
+                        /* pseudo header length) network order */
+} TcpPseudoHdr;
+
+
+/* Password Setting Callback */
+static int SetPassword(char* passwd, int sz, int rw, void* userdata)
+{
+    (void)rw;
+    XSTRNCPY(passwd, (const char*)userdata, sz);
+    return (int)XSTRLEN((const char*)userdata);
+}
+
+
+/* Ethernet Header */
+typedef struct EthernetHdr {
+    byte   dst[ETHER_IF_ADDR_LEN];    /* destination host address */ 
+    byte   src[ETHER_IF_ADDR_LEN];    /* source  host address */ 
+    word16 type;                      /* IP, ARP, etc */ 
+} EthernetHdr;
+
+
+/* IP Header */
+typedef struct IpHdr {
+    byte    ver_hl;              /* version/header length */
+    byte    tos;                 /* type of service */
+    word16  length;              /* total length */
+    word16  id;                  /* identification */
+    word16  offset;              /* fragment offset field */
+    byte    ttl;                 /* time to live */
+    byte    protocol;            /* protocol */
+    word16  sum;                 /* checksum */
+    word32  src;                 /* source address */
+    word32  dst;                 /* destination address */
+} IpHdr;
+
+
+#define IP_HL(ip)      ( (((ip)->ver_hl) & 0x0f) * 4)
+#define IP_V(ip)       ( ((ip)->ver_hl) >> 4)
+
+/* TCP Header */
+typedef struct TcpHdr {
+    word16  srcPort;            /* source port */
+    word16  dstPort;            /* destination port */
+    word32  sequence;           /* sequence number */ 
+    word32  ack;                /* acknoledgment number */ 
+    byte    offset;             /* data offset, reserved */
+    byte    flags;              /* option flags */
+    word16  window;             /* window */
+    word16  sum;                /* checksum */
+    word16  urgent;             /* urgent pointer */
+} TcpHdr;
+
+#define TCP_LEN(tcp)  ( (((tcp)->offset & 0xf0) >> 4) * 4)
+#define TCP_FIN 0x01
+#define TCP_SYN 0x02
+#define TCP_RST 0x04
+#define TCP_ACK 0x10
+
+
+
+
+
+/* Use platform specific GetError to write to tracfile if tracing */ 
+static void Trace(int idx) 
+{
+    if (TraceOn) {
+        char myBuffer[MAX_ERROR_LEN];
+        GetError(idx, myBuffer);
+        fprintf(TraceFile, "\t%s\n", myBuffer);
+#ifdef DEBUG_SNIFFER
+        fprintf(stderr,    "\t%s\n", myBuffer);
+#endif
+    }
+}
+
+
+/* Show TimeStamp for beginning of packet Trace */
+static void TraceHeader(void)
+{
+    if (TraceOn) {
+        time_t ticks = time(NULL);
+        fprintf(TraceFile, "\n%s", ctime(&ticks));
+    }
+}
+
+
+/* Show Set Server info for Trace */
+static void TraceSetServer(const char* srv, int port, const char* keyFile)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tTrying to install a new Sniffer Server with\n");
+        fprintf(TraceFile, "\tserver: %s, port: %d, keyFile: %s\n", srv, port,
+                                                                    keyFile);
+    }
+}
+
+
+#ifdef HAVE_SNI
+
+/* Show Set Named Server info for Trace */
+static void TraceSetNamedServer(const char* name,
+                                 const char* srv, int port, const char* keyFile)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tTrying to install a new Sniffer Server with\n");
+        fprintf(TraceFile, "\tname: %s, server: %s, port: %d, keyFile: %s\n",
+                                                      name, srv, port, keyFile);
+    }
+}
+
+#endif
+
+
+/* Trace got packet number */
+static void TracePacket(void)
+{
+    if (TraceOn) {
+        static word32 packetNumber = 0;
+        fprintf(TraceFile, "\tGot a Packet to decode, packet %u\n",
+                ++packetNumber);
+    }
+}
+
+
+/* Convert network byte order address into human readable */
+static char* IpToS(word32 addr, char* str)
+{
+    byte* p = (byte*)&addr;
+    
+    SNPRINTF(str, TRACE_MSG_SZ, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+    
+    return str;
+}
+
+
+/* Show destination and source address from Ip Hdr for packet Trace */
+static void TraceIP(IpHdr* iphdr)
+{
+    if (TraceOn) {
+        char src[TRACE_MSG_SZ];
+        char dst[TRACE_MSG_SZ];
+        fprintf(TraceFile, "\tdst:%s src:%s\n", IpToS(iphdr->dst, dst),
+                IpToS(iphdr->src, src));
+    }
+}
+
+
+/* Show destination and source port from Tcp Hdr for packet Trace */
+static void TraceTcp(TcpHdr* tcphdr)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tdstPort:%u srcPort:%u\n", ntohs(tcphdr->dstPort),
+                ntohs(tcphdr->srcPort));
+    }
+}
+
+
+/* Show sequence and payload length for Trace */
+static void TraceSequence(word32 seq, int len)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tSequence:%u, payload length:%d\n", seq, len);
+    }
+}
+
+
+/* Show sequence and payload length for Trace */
+static void TraceAck(word32 ack, word32 expected)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tAck:%u Expected:%u\n", ack, expected);
+    }
+}
+
+
+/* Show relative expected and relative received sequences */
+static void TraceRelativeSequence(word32 expected, word32 got)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tExpected sequence:%u, received sequence:%u\n",
+                expected, got);
+    }
+}
+
+
+/* Show server sequence startup from SYN */
+static void TraceServerSyn(word32 seq)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tServer SYN, Sequence Start:%u\n", seq);
+    }
+}
+
+
+/* Show client sequence startup from SYN */
+static void TraceClientSyn(word32 seq)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tClient SYN, Sequence Start:%u\n", seq);
+    }
+}
+
+
+/* Show client FIN capture */
+static void TraceClientFin(word32 finSeq, word32 relSeq)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tClient FIN capture:%u, current SEQ:%u\n",
+                finSeq, relSeq);
+    }
+}
+
+
+/* Show server FIN capture */
+static void TraceServerFin(word32 finSeq, word32 relSeq)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tServer FIN capture:%u, current SEQ:%u\n",
+                finSeq, relSeq);
+    }
+}
+
+
+/* Show number of SSL data bytes decoded, could be 0 (ok) */
+static void TraceGotData(int bytes)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\t%d bytes of SSL App data processed\n", bytes);
+    }
+}
+
+
+/* Show bytes added to old SSL App data */
+static void TraceAddedData(int newBytes, int existingBytes)
+{
+    if (TraceOn) {
+        fprintf(TraceFile,
+                "\t%d bytes added to %d exisiting bytes in User Buffer\n",
+                newBytes, existingBytes);
+    }
+}
+
+
+/* Show Stale Session */
+static void TraceStaleSession(void)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tFound a stale session\n");
+    }
+}
+
+
+/* Show Finding Stale Sessions */
+static void TraceFindingStale(void)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tTrying to find Stale Sessions\n");
+    }
+}
+
+
+/* Show Removed Session */
+static void TraceRemovedSession(void)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tRemoved it\n");
+    }
+}
+
+
+/* Set user error string */
+static void SetError(int idx, char* error, SnifferSession* session, int fatal)
+{
+    GetError(idx, error);
+    Trace(idx);
+    if (session && fatal == FATAL_ERROR_STATE)
+        session->flags.fatalError = 1;
+}
+
+
+/* See if this IPV4 network order address has been registered */
+/* return 1 is true, 0 is false */
+static int IsServerRegistered(word32 addr)
+{
+    int ret = 0;     /* false */
+    SnifferServer* sniffer;
+
+    LockMutex(&ServerListMutex);
+    
+    sniffer = ServerList;
+    while (sniffer) {
+        if (sniffer->server == addr) {
+            ret = 1;
+            break;
+        }
+        sniffer = sniffer->next;
+    }
+    
+    UnLockMutex(&ServerListMutex);
+
+    return ret;
+}
+
+
+/* See if this port has been registered to watch */
+/* return 1 is true, 0 is false */
+static int IsPortRegistered(word32 port)
+{
+    int ret = 0;    /* false */
+    SnifferServer* sniffer;
+    
+    LockMutex(&ServerListMutex);
+    
+    sniffer = ServerList;
+    while (sniffer) {
+        if (sniffer->port == (int)port) {
+            ret = 1; 
+            break;
+        }
+        sniffer = sniffer->next;
+    }
+    
+    UnLockMutex(&ServerListMutex);
+
+    return ret;
+}
+
+
+/* Get SnifferServer from IP and Port */
+static SnifferServer* GetSnifferServer(IpInfo* ipInfo, TcpInfo* tcpInfo)
+{
+    SnifferServer* sniffer;
+    
+    LockMutex(&ServerListMutex);
+    
+    sniffer = ServerList;
+    while (sniffer) {
+        if (sniffer->port == tcpInfo->srcPort && sniffer->server == ipInfo->src)
+            break;
+        if (sniffer->port == tcpInfo->dstPort && sniffer->server == ipInfo->dst)
+            break;
+        sniffer = sniffer->next;
+    }
+    
+    UnLockMutex(&ServerListMutex);
+    
+    return sniffer;
+}
+
+
+/* Hash the Session Info, return hash row */
+static word32 SessionHash(IpInfo* ipInfo, TcpInfo* tcpInfo)
+{
+    word32 hash = ipInfo->src * ipInfo->dst;
+    hash *= tcpInfo->srcPort * tcpInfo->dstPort;
+    
+    return hash % HASH_SIZE;
+}
+
+
+/* Get Exisiting SnifferSession from IP and Port */
+static SnifferSession* GetSnifferSession(IpInfo* ipInfo, TcpInfo* tcpInfo)
+{
+    SnifferSession* session;
+    time_t          currTime = time(NULL); 
+    word32          row = SessionHash(ipInfo, tcpInfo);
+
+    assert(row <= HASH_SIZE);
+    
+    LockMutex(&SessionMutex);
+    
+    session = SessionTable[row];
+    while (session) {
+        if (session->server == ipInfo->src && session->client == ipInfo->dst &&
+                    session->srvPort == tcpInfo->srcPort &&
+                    session->cliPort == tcpInfo->dstPort)
+            break;
+        if (session->client == ipInfo->src && session->server == ipInfo->dst &&
+                    session->cliPort == tcpInfo->srcPort &&
+                    session->srvPort == tcpInfo->dstPort)
+            break;
+        
+        session = session->next;
+    }
+
+    if (session)
+        session->lastUsed= currTime; /* keep session alive, remove stale will */
+                                     /* leave alone */   
+    UnLockMutex(&SessionMutex);
+    
+    /* determine side */
+    if (session) {
+        if (ipInfo->dst == session->context->server &&
+            tcpInfo->dstPort == session->context->port)
+            session->flags.side = WOLFSSL_SERVER_END;
+        else
+            session->flags.side = WOLFSSL_CLIENT_END;
+    }    
+    
+    return session;
+}
+
+
+#ifdef HAVE_SNI
+
+static int LoadKeyFile(byte** keyBuf, word32* keyBufSz,
+                const char* keyFile, int typeKey,
+                const char* password)
+{
+    byte* loadBuf;
+    byte* saveBuf;
+    long fileSz = 0;
+    int saveBufSz;
+    XFILE file;
+    int ret;
+
+    if (keyBuf == NULL || keyBufSz == NULL || keyFile == NULL) {
+        return -1;
+    }
+
+    file = XFOPEN(keyFile, "rb");
+    if (file == XBADFILE) return -1;
+    XFSEEK(file, 0, XSEEK_END);
+    fileSz = XFTELL(file);
+    XREWIND(file);
+
+    loadBuf = (byte*)malloc(fileSz);
+    if (loadBuf == NULL) {
+        XFCLOSE(file);
+        return -1;
+    }
+
+    ret = (int)XFREAD(loadBuf, fileSz, 1, file);
+    XFCLOSE(file);
+
+    if (typeKey == SSL_FILETYPE_PEM) {
+        saveBuf = (byte*)malloc(fileSz);
+
+        saveBufSz = wolfSSL_KeyPemToDer(loadBuf, (int)fileSz,
+                                                saveBuf, (int)fileSz, password);
+        free(loadBuf);
+
+        *keyBuf = saveBuf;
+        *keyBufSz = (word32)saveBufSz;
+    }
+    else {
+        *keyBuf = loadBuf;
+        *keyBufSz = (word32)fileSz;
+    }
+
+
+    if (ret < 0) {
+        return -1;
+    }
+
+    return ret;
+}
+
+#endif
+
+
+static int SetNamedPrivateKey(const char* name, const char* address, int port,
+            const char* keyFile, int typeKey, const char* password, char* error)
+{
+    SnifferServer* sniffer;
+    int            ret;
+    int            type = (typeKey == FILETYPE_PEM) ? SSL_FILETYPE_PEM :
+                                                      SSL_FILETYPE_ASN1;
+    int            isNew = 0;
+    word32         serverIp;
+
+#ifdef HAVE_SNI
+    NamedKey* namedKey = NULL;
+#endif
+
+    (void)name;
+#ifdef HAVE_SNI
+    if (name != NULL) {
+        namedKey = (NamedKey*)malloc(sizeof(NamedKey));
+        if (namedKey == NULL) {
+            SetError(MEMORY_STR, error, NULL, 0);
+            return -1;
+        }
+        XMEMSET(namedKey, 0, sizeof(NamedKey));
+
+        namedKey->nameSz = (word32)XSTRLEN(name);
+        XSTRNCPY(namedKey->name, name, sizeof(namedKey->name));
+        if (namedKey->nameSz >= sizeof(namedKey->name)) {
+            namedKey->nameSz = sizeof(namedKey->name) - 1;
+            namedKey->name[namedKey->nameSz] = '\0';
+        }
+
+        ret = LoadKeyFile(&namedKey->key, &namedKey->keySz,
+                          keyFile, type, password);
+        if (ret < 0) {
+            SetError(KEY_FILE_STR, error, NULL, 0);
+            FreeNamedKey(namedKey);
+            return -1;
+        }
+    }
+#endif
+
+    serverIp = inet_addr(address);
+    sniffer = ServerList;
+    while (sniffer != NULL &&
+           (sniffer->server != serverIp || sniffer->port != port)) {
+        sniffer = sniffer->next;
+    }
+
+    if (sniffer == NULL) {
+        isNew = 1;
+        sniffer = (SnifferServer*)malloc(sizeof(SnifferServer));
+        if (sniffer == NULL) {
+            SetError(MEMORY_STR, error, NULL, 0);
+#ifdef HAVE_SNI
+            FreeNamedKey(namedKey);
+#endif
+            return -1;
+        }
+        InitSnifferServer(sniffer);
+
+        XSTRNCPY(sniffer->address, address, MAX_SERVER_ADDRESS-1);
+        sniffer->address[MAX_SERVER_ADDRESS-1] = '\0';
+        sniffer->server = serverIp;
+        sniffer->port = port;
+
+        sniffer->ctx = SSL_CTX_new(SSLv3_client_method());
+        if (!sniffer->ctx) {
+            SetError(MEMORY_STR, error, NULL, 0);
+#ifdef HAVE_SNI
+            FreeNamedKey(namedKey);
+#endif
+            FreeSnifferServer(sniffer);
+            return -1;
+        }
+    }
+
+    if (name == NULL) {
+        if (password) {
+            SSL_CTX_set_default_passwd_cb(sniffer->ctx, SetPassword);
+            SSL_CTX_set_default_passwd_cb_userdata(
+                                                 sniffer->ctx, (void*)password);
+        }
+        ret = SSL_CTX_use_PrivateKey_file(sniffer->ctx, keyFile, type);
+        if (ret != SSL_SUCCESS) {
+            SetError(KEY_FILE_STR, error, NULL, 0);
+            if (isNew)
+                FreeSnifferServer(sniffer);
+            return -1;
+        }
+    }
+#ifdef HAVE_SNI
+    else {
+        LockMutex(&sniffer->namedKeysMutex);
+        namedKey->next = sniffer->namedKeys;
+        sniffer->namedKeys = namedKey;
+        UnLockMutex(&sniffer->namedKeysMutex);
+    }
+#endif
+
+    if (isNew) {
+        sniffer->next = ServerList;
+        ServerList = sniffer;
+    }
+
+    return 0;
+}
+
+
+#ifdef HAVE_SNI
+
+/* Sets the private key for a specific name, server and port  */
+/* returns 0 on success, -1 on error */
+int ssl_SetNamedPrivateKey(const char* name,
+                           const char* address, int port,
+                           const char* keyFile, int typeKey,
+                           const char* password, char* error)
+{
+    int ret;
+
+    TraceHeader();
+    TraceSetNamedServer(name, address, port, keyFile);
+
+    LockMutex(&ServerListMutex);
+    ret = SetNamedPrivateKey(name, address, port, keyFile,
+                             typeKey, password, error);
+    UnLockMutex(&ServerListMutex);
+
+    if (ret == 0)
+        Trace(NEW_SERVER_STR);
+
+    return ret;
+}
+
+#endif
+
+
+/* Sets the private key for a specific server and port  */
+/* returns 0 on success, -1 on error */
+int ssl_SetPrivateKey(const char* address, int port, const char* keyFile,
+                      int typeKey, const char* password, char* error)
+{
+    int ret;
+
+    TraceHeader();
+    TraceSetServer(address, port, keyFile);
+
+    LockMutex(&ServerListMutex);
+    ret = SetNamedPrivateKey(NULL, address, port, keyFile,
+                             typeKey, password, error);
+    UnLockMutex(&ServerListMutex);
+
+    if (ret == 0)
+        Trace(NEW_SERVER_STR);
+
+    return ret;
+}
+
+
+/* Check IP Header for IPV4, TCP, and a registered server address */
+/* returns 0 on success, -1 on error */
+static int CheckIpHdr(IpHdr* iphdr, IpInfo* info, int length, char* error)
+{
+    int    version = IP_V(iphdr);
+
+    TraceIP(iphdr);
+    Trace(IP_CHECK_STR);
+
+    if (version != IPV4) {
+        SetError(BAD_IPVER_STR, error, NULL, 0); 
+        return -1;
+    }
+
+    if (iphdr->protocol != TCP_PROTOCOL) { 
+        SetError(BAD_PROTO_STR, error, NULL, 0);
+        return -1;
+    }
+
+    if (!IsServerRegistered(iphdr->src) && !IsServerRegistered(iphdr->dst)) {
+        SetError(SERVER_NOT_REG_STR, error, NULL, 0);
+        return -1;
+    }
+
+    info->length  = IP_HL(iphdr);
+    info->total   = ntohs(iphdr->length);
+    info->src     = iphdr->src;
+    info->dst     = iphdr->dst;
+
+    if (info->total == 0)
+        info->total = length;  /* reassembled may be off */
+
+    return 0;
+}
+
+
+/* Check TCP Header for a registered port */
+/* returns 0 on success, -1 on error */
+static int CheckTcpHdr(TcpHdr* tcphdr, TcpInfo* info, char* error)
+{
+    TraceTcp(tcphdr);
+    Trace(TCP_CHECK_STR);
+    info->srcPort   = ntohs(tcphdr->srcPort);
+    info->dstPort   = ntohs(tcphdr->dstPort);
+    info->length    = TCP_LEN(tcphdr);
+    info->sequence  = ntohl(tcphdr->sequence);
+    info->fin       = tcphdr->flags & TCP_FIN;
+    info->rst       = tcphdr->flags & TCP_RST;
+    info->syn       = tcphdr->flags & TCP_SYN;
+    info->ack       = tcphdr->flags & TCP_ACK;
+    if (info->ack)
+        info->ackNumber = ntohl(tcphdr->ack); 
+
+    if (!IsPortRegistered(info->srcPort) && !IsPortRegistered(info->dstPort)) {
+        SetError(SERVER_PORT_NOT_REG_STR, error, NULL, 0);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/* Decode Record Layer Header */
+static int GetRecordHeader(const byte* input, RecordLayerHeader* rh, int* size)
+{
+    XMEMCPY(rh, input, RECORD_HEADER_SZ);
+    *size = (rh->length[0] << 8) | rh->length[1];
+
+    if (*size > (MAX_RECORD_SIZE + COMP_EXTRA + MAX_MSG_EXTRA))
+        return LENGTH_ERROR;
+
+    return 0;
+}
+
+
+/* Process Client Key Exchange, RSA only */
+static int ProcessClientKeyExchange(const byte* input, int* sslBytes,
+                                    SnifferSession* session, char* error)
+{
+    word32 idx = 0;
+    RsaKey key;
+    int    ret;
+
+    if (session->sslServer->buffers.key.buffer == NULL ||
+        session->sslServer->buffers.key.length == 0) {
+
+        SetError(RSA_KEY_MISSING_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    ret = wc_InitRsaKey(&key, 0);
+    if (ret == 0)
+        ret = wc_RsaPrivateKeyDecode(session->sslServer->buffers.key.buffer,
+                          &idx, &key, session->sslServer->buffers.key.length);
+    if (ret == 0) {
+        int length = wc_RsaEncryptSize(&key);
+
+        if (IsTLS(session->sslServer))
+            input += 2;     /* tls pre length */
+
+        if (length > *sslBytes) {
+            SetError(PARTIAL_INPUT_STR, error, session, FATAL_ERROR_STATE);
+            wc_FreeRsaKey(&key);
+            return -1;
+        }
+        ret = wc_RsaPrivateDecrypt(input, length,
+                  session->sslServer->arrays->preMasterSecret,SECRET_LEN, &key);
+
+        if (ret != SECRET_LEN) {
+            SetError(RSA_DECRYPT_STR, error, session, FATAL_ERROR_STATE);
+            wc_FreeRsaKey(&key);
+            return -1;
+        }
+        ret = 0;  /* not in error state */
+        session->sslServer->arrays->preMasterSz = SECRET_LEN;
+
+        /* store for client side as well */
+        XMEMCPY(session->sslClient->arrays->preMasterSecret,
+               session->sslServer->arrays->preMasterSecret, SECRET_LEN);
+        session->sslClient->arrays->preMasterSz = SECRET_LEN;
+
+        #ifdef SHOW_SECRETS
+        {
+            int i;
+            printf("pre master secret: ");
+            for (i = 0; i < SECRET_LEN; i++)
+                printf("%02x", session->sslServer->arrays->preMasterSecret[i]);
+            printf("\n");
+        }
+        #endif
+    }
+    else {
+        SetError(RSA_DECODE_STR, error, session, FATAL_ERROR_STATE);
+        wc_FreeRsaKey(&key);
+        return -1;
+    }
+
+    if (SetCipherSpecs(session->sslServer) != 0) {
+        SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
+        wc_FreeRsaKey(&key);
+        return -1;
+    }
+
+    if (SetCipherSpecs(session->sslClient) != 0) {
+        SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
+        wc_FreeRsaKey(&key);
+        return -1;
+    }
+
+    ret  = MakeMasterSecret(session->sslServer);
+    ret += MakeMasterSecret(session->sslClient);
+    ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE);
+    ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE);
+
+    if (ret != 0) {
+        SetError(BAD_DERIVE_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+#ifdef SHOW_SECRETS
+    {
+        int i;
+        printf("server master secret: ");
+        for (i = 0; i < SECRET_LEN; i++)
+            printf("%02x", session->sslServer->arrays->masterSecret[i]);
+        printf("\n");
+
+        printf("client master secret: ");
+        for (i = 0; i < SECRET_LEN; i++)
+            printf("%02x", session->sslClient->arrays->masterSecret[i]);
+        printf("\n");
+
+        printf("server suite = %d\n", session->sslServer->options.cipherSuite);
+        printf("client suite = %d\n", session->sslClient->options.cipherSuite);
+    }
+#endif
+
+    wc_FreeRsaKey(&key);
+    return ret;
+}
+
+
+/* Process Session Ticket */
+static int ProcessSessionTicket(const byte* input, int* sslBytes,
+                                SnifferSession* session, char* error)
+{
+    word16 len;
+
+    /* make sure can read through hint and len */
+    if (TICKET_HINT_LEN + LENGTH_SZ > *sslBytes) {
+        SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    input     += TICKET_HINT_LEN;  /* skip over hint */
+    *sslBytes -= TICKET_HINT_LEN;
+
+    len = (word16)((input[0] << 8) | input[1]);
+    input     += LENGTH_SZ;
+    *sslBytes -= LENGTH_SZ;
+
+    /* make sure can read through ticket */
+    if (len > *sslBytes || len < ID_LEN) {
+        SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    /* store session with macID as sessionID */
+    session->sslServer->options.haveSessionId = 1;
+    XMEMCPY(session->sslServer->arrays->sessionID, input + len - ID_LEN,ID_LEN);
+
+    return 0;
+}
+
+
+/* Process Server Hello */
+static int ProcessServerHello(const byte* input, int* sslBytes,
+                              SnifferSession* session, char* error)
+{
+    ProtocolVersion pv;
+    byte            b;
+    int             toRead = VERSION_SZ + RAN_LEN + ENUM_LEN;
+    int             doResume     = 0;
+
+    /* make sure we didn't miss ClientHello */
+    if (session->flags.clientHello == 0) {
+        SetError(MISSED_CLIENT_HELLO_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    /* make sure can read through session len */
+    if (toRead > *sslBytes) {
+        SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    XMEMCPY(&pv, input, VERSION_SZ);
+    input     += VERSION_SZ;
+    *sslBytes -= VERSION_SZ;
+
+    session->sslServer->version = pv;
+    session->sslClient->version = pv;
+
+    XMEMCPY(session->sslServer->arrays->serverRandom, input, RAN_LEN);
+    XMEMCPY(session->sslClient->arrays->serverRandom, input, RAN_LEN);
+    input    += RAN_LEN;
+    *sslBytes -= RAN_LEN;
+
+    b = *input++;
+    *sslBytes -= 1;
+
+    /* make sure can read through compression */
+    if ( (b + SUITE_LEN + ENUM_LEN) > *sslBytes) {
+        SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    if (b) {
+        XMEMCPY(session->sslServer->arrays->sessionID, input, ID_LEN);
+        session->sslServer->options.haveSessionId = 1;
+    }
+    input     += b;
+    *sslBytes -= b;
+
+    /* cipher suite */
+    b = *input++;  /* first byte, ECC or not */
+    session->sslServer->options.cipherSuite0 = b;
+    session->sslClient->options.cipherSuite0 = b;
+    b = *input++;
+    session->sslServer->options.cipherSuite = b;
+    session->sslClient->options.cipherSuite = b;
+    *sslBytes -= SUITE_LEN;
+
+    /* compression */
+    b = *input++;
+    *sslBytes -= ENUM_LEN;
+
+    if (b) {
+        SetError(BAD_COMPRESSION_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    if (session->sslServer->options.haveSessionId &&
+            XMEMCMP(session->sslServer->arrays->sessionID,
+                    session->sslClient->arrays->sessionID, ID_LEN) == 0)
+        doResume = 1;
+    else if (session->sslClient->options.haveSessionId == 0 &&
+             session->sslServer->options.haveSessionId == 0 &&
+             session->ticketID)
+        doResume = 1;
+
+    if (session->ticketID && doResume) {
+        /* use ticketID to retrieve from session, prefer over sessionID */
+        XMEMCPY(session->sslServer->arrays->sessionID,session->ticketID,ID_LEN);
+        session->sslServer->options.haveSessionId = 1;  /* may not have
+                                                           actual sessionID */
+    }
+
+    if (doResume ) {
+        int ret = 0;
+        SSL_SESSION* resume = GetSession(session->sslServer,
+                                      session->sslServer->arrays->masterSecret);
+        if (resume == NULL) {
+            SetError(BAD_SESSION_RESUME_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        /* make sure client has master secret too */
+        XMEMCPY(session->sslClient->arrays->masterSecret,
+               session->sslServer->arrays->masterSecret, SECRET_LEN);
+        session->flags.resuming = 1;
+
+        Trace(SERVER_DID_RESUMPTION_STR);
+        if (SetCipherSpecs(session->sslServer) != 0) {
+            SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+
+        if (SetCipherSpecs(session->sslClient) != 0) {
+            SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+
+        if (session->sslServer->options.tls) {
+            ret =  DeriveTlsKeys(session->sslServer);
+            ret += DeriveTlsKeys(session->sslClient);
+        }
+        else {
+            ret =  DeriveKeys(session->sslServer);
+            ret += DeriveKeys(session->sslClient);
+        }
+        ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE);
+        ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE);
+
+        if (ret != 0) {
+            SetError(BAD_DERIVE_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+    }
+#ifdef SHOW_SECRETS
+    {
+        int i;
+        printf("cipher suite = 0x%02x\n",
+               session->sslServer->options.cipherSuite);
+        printf("server random: ");
+        for (i = 0; i < RAN_LEN; i++)
+            printf("%02x", session->sslServer->arrays->serverRandom[i]);
+        printf("\n");
+    }
+#endif
+    return 0;
+}
+
+
+/* Process normal Client Hello */
+static int ProcessClientHello(const byte* input, int* sslBytes,
+                              SnifferSession* session, char* error)
+{
+    byte   bLen;
+    word16 len;
+    int    toRead = VERSION_SZ + RAN_LEN + ENUM_LEN;
+
+#ifdef HAVE_SNI
+    {
+        byte name[MAX_SERVER_NAME];
+        word32 nameSz = sizeof(name);
+        int ret;
+
+        ret = wolfSSL_SNI_GetFromBuffer(
+                             input - HANDSHAKE_HEADER_SZ - RECORD_HEADER_SZ,
+                             *sslBytes + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ,
+                             WOLFSSL_SNI_HOST_NAME, name, &nameSz);
+
+        if (ret == SSL_SUCCESS) {
+            NamedKey* namedKey;
+
+            if (nameSz >= sizeof(name))
+                nameSz = sizeof(name) - 1;
+            name[nameSz] = 0;
+            LockMutex(&session->context->namedKeysMutex);
+            namedKey = session->context->namedKeys;
+            while (namedKey != NULL) {
+                if (nameSz == namedKey->nameSz &&
+                           XSTRNCMP((char*)name, namedKey->name, nameSz) == 0) {
+                    if (wolfSSL_use_PrivateKey_buffer(session->sslServer,
+                                            namedKey->key, namedKey->keySz,
+                                            SSL_FILETYPE_ASN1) != SSL_SUCCESS) {
+                        UnLockMutex(&session->context->namedKeysMutex);
+                        SetError(CLIENT_HELLO_LATE_KEY_STR, error, session,
+                                                             FATAL_ERROR_STATE);
+                        return -1;
+                    }
+                    break;
+                }
+                else
+                    namedKey = namedKey->next;
+            }
+            UnLockMutex(&session->context->namedKeysMutex);
+        }
+    }
+#endif
+
+    session->flags.clientHello = 1;  /* don't process again */
+
+    /* make sure can read up to session len */
+    if (toRead > *sslBytes) {
+        SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    /* skip, get negotiated one from server hello */
+    input     += VERSION_SZ;
+    *sslBytes -= VERSION_SZ;
+
+    XMEMCPY(session->sslServer->arrays->clientRandom, input, RAN_LEN);
+    XMEMCPY(session->sslClient->arrays->clientRandom, input, RAN_LEN);
+
+    input     += RAN_LEN;
+    *sslBytes -= RAN_LEN;
+
+    /* store session in case trying to resume */
+    bLen = *input++;
+    *sslBytes -= ENUM_LEN;
+    if (bLen) {
+        if (ID_LEN > *sslBytes) {
+            SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        Trace(CLIENT_RESUME_TRY_STR);
+        XMEMCPY(session->sslClient->arrays->sessionID, input, ID_LEN);
+        session->sslClient->options.haveSessionId = 1;
+    }
+#ifdef SHOW_SECRETS
+    {
+        int i;
+        printf("client random: ");
+        for (i = 0; i < RAN_LEN; i++)
+            printf("%02x", session->sslServer->arrays->clientRandom[i]);
+        printf("\n");
+    }
+#endif
+
+    input     += bLen;
+    *sslBytes -= bLen;
+
+    /* skip cipher suites */
+    /* make sure can read len */
+    if (SUITE_LEN > *sslBytes) {
+        SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    len = (word16)((input[0] << 8) | input[1]);
+    input     += SUITE_LEN;
+    *sslBytes -= SUITE_LEN;
+    /* make sure can read suites + comp len */
+    if (len + ENUM_LEN > *sslBytes) {
+        SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    input     += len;
+    *sslBytes -= len;
+
+    /* skip compression */
+    bLen       = *input++;
+    *sslBytes -= ENUM_LEN;
+    /* make sure can read len */
+    if (bLen > *sslBytes) {
+        SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    input     += bLen;
+    *sslBytes -= bLen;
+  
+    if (*sslBytes == 0) {
+        /* no extensions */
+        return 0;
+    }
+    
+    /* skip extensions until session ticket */
+    /* make sure can read len */
+    if (SUITE_LEN > *sslBytes) {
+        SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    len = (word16)((input[0] << 8) | input[1]);
+    input     += SUITE_LEN;
+    *sslBytes -= SUITE_LEN;
+    /* make sure can read through all extensions */
+    if (len > *sslBytes) {
+        SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    while (len > EXT_TYPE_SZ + LENGTH_SZ) {
+        byte   extType[EXT_TYPE_SZ];
+        word16 extLen;
+
+        extType[0] = input[0];
+        extType[1] = input[1];
+        input     += EXT_TYPE_SZ;
+        *sslBytes -= EXT_TYPE_SZ;
+
+        extLen = (word16)((input[0] << 8) | input[1]);
+        input     += LENGTH_SZ;
+        *sslBytes -= LENGTH_SZ;
+
+        /* make sure can read through individual extension */
+        if (extLen > *sslBytes) {
+            SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+
+        if (extType[0] == 0x00 && extType[1] == TICKET_EXT_ID) {
+
+            /* make sure can read through ticket if there is a non blank one */
+            if (extLen && extLen < ID_LEN) {
+                SetError(CLIENT_HELLO_INPUT_STR, error, session,
+                         FATAL_ERROR_STATE);
+                return -1;
+            }
+
+            if (extLen) {
+                if (session->ticketID == 0) {
+                    session->ticketID = (byte*)malloc(ID_LEN);
+                    if (session->ticketID == 0) {
+                        SetError(MEMORY_STR, error, session,
+                                 FATAL_ERROR_STATE);
+                        return -1;
+                    }
+                }
+                XMEMCPY(session->ticketID, input + extLen - ID_LEN, ID_LEN);
+            }
+        }
+
+        input     += extLen;
+        *sslBytes -= extLen;
+        len       -= extLen + EXT_TYPE_SZ + LENGTH_SZ;
+    }
+
+    return 0;
+}
+
+
+/* Process Finished */
+static int ProcessFinished(const byte* input, int size, int* sslBytes,
+                           SnifferSession* session, char* error)
+{
+    SSL*   ssl;
+    word32 inOutIdx = 0;
+    int    ret;
+                
+    if (session->flags.side == WOLFSSL_SERVER_END)
+        ssl = session->sslServer;
+    else
+        ssl = session->sslClient;
+
+    ret = DoFinished(ssl, input, &inOutIdx, (word32) size, (word32) *sslBytes,
+                                                                         SNIFF);
+    *sslBytes -= (int)inOutIdx;
+
+    if (ret < 0) {
+        SetError(BAD_FINISHED_MSG, error, session, FATAL_ERROR_STATE);
+        return ret;
+    }
+                
+    if (ret == 0 && session->flags.cached == 0) {
+        if (session->sslServer->options.haveSessionId) {
+            WOLFSSL_SESSION* sess = GetSession(session->sslServer, NULL);
+            if (sess == NULL)
+                AddSession(session->sslServer);  /* don't re add */
+            session->flags.cached = 1;
+         }
+    }
+
+    /* If receiving a finished message from one side, free the resources
+     * from the other side's tracker. */
+    if (session->flags.side == WOLFSSL_SERVER_END)
+        FreeHandshakeResources(session->sslClient);
+    else
+        FreeHandshakeResources(session->sslServer);
+
+    return ret;
+}
+
+
+/* Process HandShake input */
+static int DoHandShake(const byte* input, int* sslBytes,
+                       SnifferSession* session, char* error)
+{
+    byte type;
+    int  size;
+    int  ret = 0;
+    int  startBytes;
+
+    if (*sslBytes < HANDSHAKE_HEADER_SZ) {
+        SetError(HANDSHAKE_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    type = input[0];
+    size = (input[1] << 16) | (input[2] << 8) | input[3];
+    
+    input     += HANDSHAKE_HEADER_SZ;
+    *sslBytes -= HANDSHAKE_HEADER_SZ;
+    startBytes = *sslBytes;
+
+    if (*sslBytes < size) {
+        SetError(HANDSHAKE_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    
+    switch (type) {
+        case hello_verify_request:
+            Trace(GOT_HELLO_VERIFY_STR);
+            break;
+        case hello_request:
+            Trace(GOT_HELLO_REQUEST_STR);
+            break;
+        case session_ticket:
+            Trace(GOT_SESSION_TICKET_STR);
+            ret = ProcessSessionTicket(input, sslBytes, session, error);
+            break;
+        case server_hello:
+            Trace(GOT_SERVER_HELLO_STR);
+            ret = ProcessServerHello(input, sslBytes, session, error);
+            break;
+        case certificate_request:
+            Trace(GOT_CERT_REQ_STR);
+            break;
+        case server_key_exchange:
+            Trace(GOT_SERVER_KEY_EX_STR);
+            /* can't know temp key passively */
+            SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
+            ret = -1;
+            break;
+        case certificate:
+            Trace(GOT_CERT_STR);
+            break;
+        case server_hello_done:
+            Trace(GOT_SERVER_HELLO_DONE_STR);
+            break;
+        case finished:
+            Trace(GOT_FINISHED_STR);
+            ret = ProcessFinished(input, size, sslBytes, session, error);
+            break;
+        case client_hello:
+            Trace(GOT_CLIENT_HELLO_STR);
+            ret = ProcessClientHello(input, sslBytes, session, error);
+            break;
+        case client_key_exchange:
+            Trace(GOT_CLIENT_KEY_EX_STR);
+            ret = ProcessClientKeyExchange(input, sslBytes, session, error);
+            break;
+        case certificate_verify:
+            Trace(GOT_CERT_VER_STR);
+            break;
+        case certificate_status:
+            Trace(GOT_CERT_STATUS_STR);
+            break;
+        default:
+            SetError(GOT_UNKNOWN_HANDSHAKE_STR, error, session, 0);
+            return -1;
+    }
+
+    *sslBytes = startBytes - size;  /* actual bytes of full process */
+
+    return ret;
+}
+
+
+/* Decrypt input into plain output, 0 on success */
+static int Decrypt(SSL* ssl, byte* output, const byte* input, word32 sz)
+{
+    int ret = 0;
+
+    switch (ssl->specs.bulk_cipher_algorithm) {
+        #ifdef BUILD_ARC4
+        case wolfssl_rc4:
+            wc_Arc4Process(ssl->decrypt.arc4, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef BUILD_DES3
+        case wolfssl_triple_des:
+            ret = wc_Des3_CbcDecrypt(ssl->decrypt.des3, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef BUILD_AES
+        case wolfssl_aes:
+            ret = wc_AesCbcDecrypt(ssl->decrypt.aes, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef HAVE_HC128
+        case wolfssl_hc128:
+            wc_Hc128_Process(ssl->decrypt.hc128, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef BUILD_RABBIT
+        case wolfssl_rabbit:
+            wc_RabbitProcess(ssl->decrypt.rabbit, output, input, sz);
+            break;
+        #endif
+
+        #ifdef HAVE_CAMELLIA 
+        case wolfssl_camellia:
+            wc_CamelliaCbcDecrypt(ssl->decrypt.cam, output, input, sz);
+            break;
+        #endif
+
+        default:
+            Trace(BAD_DECRYPT_TYPE);
+            ret = -1;
+            break;
+    }
+
+    return ret;
+}
+
+
+/* Decrypt input message into output, adjust output steam if needed */
+static const byte* DecryptMessage(SSL* ssl, const byte* input, word32 sz,
+                                  byte* output, int* error, int* advance)
+{
+    int ivExtra = 0;
+
+    int ret = Decrypt(ssl, output, input, sz);
+    if (ret != 0) {
+        *error = ret;
+        return NULL;
+    }
+    ssl->keys.encryptSz = sz;
+    if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) {
+        output += ssl->specs.block_size;     /* go past TLSv1.1 IV */
+        ivExtra = ssl->specs.block_size;
+        *advance = ssl->specs.block_size;
+    }
+
+    ssl->keys.padSz = ssl->specs.hash_size;
+
+    if (ssl->specs.cipher_type == block)
+        ssl->keys.padSz += *(output + sz - ivExtra - 1) + 1;
+    
+    return output;
+}
+
+
+/* remove session from table, use rowHint if no info (means we have a lock) */
+static void RemoveSession(SnifferSession* session, IpInfo* ipInfo,
+                        TcpInfo* tcpInfo, word32 rowHint)
+{
+    SnifferSession* previous = 0;
+    SnifferSession* current;
+    word32          row = rowHint;
+    int             haveLock = 0;
+   
+    if (ipInfo && tcpInfo)
+        row = SessionHash(ipInfo, tcpInfo);
+    else
+        haveLock = 1;
+    
+    assert(row <= HASH_SIZE);
+    Trace(REMOVE_SESSION_STR);
+    
+    if (!haveLock)
+        LockMutex(&SessionMutex);
+    
+    current = SessionTable[row];
+    
+    while (current) {
+        if (current == session) {
+            if (previous)
+                previous->next = current->next;
+            else
+                SessionTable[row] = current->next;
+            FreeSnifferSession(session);
+            TraceRemovedSession();
+            break;
+        }
+        previous = current;
+        current  = current->next;
+    }
+    
+    if (!haveLock)
+        UnLockMutex(&SessionMutex);
+}
+
+
+/* Remove stale sessions from the Session Table, have a lock */
+static void RemoveStaleSessions(void)
+{
+    word32 i;
+    SnifferSession* session;
+    
+    for (i = 0; i < HASH_SIZE; i++) {
+        session = SessionTable[i];
+        while (session) {
+            SnifferSession* next = session->next; 
+            if (time(NULL) >= session->lastUsed + WOLFSSL_SNIFFER_TIMEOUT) {
+                TraceStaleSession();
+                RemoveSession(session, NULL, NULL, i);
+            }
+            session = next;
+        }
+    }
+}
+
+
+/* Create a new Sniffer Session */
+static SnifferSession* CreateSession(IpInfo* ipInfo, TcpInfo* tcpInfo,
+                                     char* error)
+{
+    SnifferSession* session = 0;
+    int row;
+        
+    Trace(NEW_SESSION_STR);
+    /* create a new one */
+    session = (SnifferSession*)malloc(sizeof(SnifferSession));
+    if (session == NULL) {
+        SetError(MEMORY_STR, error, NULL, 0);
+        return 0;
+    }
+    InitSession(session);
+    session->server  = ipInfo->dst;
+    session->client  = ipInfo->src;
+    session->srvPort = (word16)tcpInfo->dstPort;
+    session->cliPort = (word16)tcpInfo->srcPort;
+    session->cliSeqStart = tcpInfo->sequence;
+    session->cliExpected = 1;  /* relative */
+    session->lastUsed= time(NULL);
+                
+    session->context = GetSnifferServer(ipInfo, tcpInfo);
+    if (session->context == NULL) {
+        SetError(SERVER_NOT_REG_STR, error, NULL, 0);
+        free(session);
+        return 0;
+    }
+        
+    session->sslServer = SSL_new(session->context->ctx);
+    if (session->sslServer == NULL) {
+        SetError(BAD_NEW_SSL_STR, error, session, FATAL_ERROR_STATE);
+        free(session);
+        return 0;
+    }
+    session->sslClient = SSL_new(session->context->ctx);
+    if (session->sslClient == NULL) {
+        SSL_free(session->sslServer);
+        session->sslServer = 0;
+
+        SetError(BAD_NEW_SSL_STR, error, session, FATAL_ERROR_STATE);
+        free(session);
+        return 0;
+    }
+    /* put server back into server mode */
+    session->sslServer->options.side = WOLFSSL_SERVER_END;
+        
+    row = SessionHash(ipInfo, tcpInfo);
+    
+    /* add it to the session table */
+    LockMutex(&SessionMutex);
+        
+    session->next = SessionTable[row];
+    SessionTable[row] = session;
+    
+    SessionCount++;
+    
+    if ( (SessionCount % HASH_SIZE) == 0) {
+        TraceFindingStale();
+        RemoveStaleSessions();
+    }
+        
+    UnLockMutex(&SessionMutex);
+        
+    /* determine headed side */
+    if (ipInfo->dst == session->context->server &&
+        tcpInfo->dstPort == session->context->port)
+        session->flags.side = WOLFSSL_SERVER_END;
+    else
+        session->flags.side = WOLFSSL_CLIENT_END;        
+    
+    return session;
+}
+
+
+#ifdef OLD_HELLO_ALLOWED
+
+/* Process Old Client Hello Input */
+static int DoOldHello(SnifferSession* session, const byte* sslFrame,
+                      int* rhSize, int* sslBytes, char* error)
+{
+    const byte* input = sslFrame;
+    byte        b0, b1;
+    word32      idx = 0;
+    int         ret;
+
+    Trace(GOT_OLD_CLIENT_HELLO_STR);
+    session->flags.clientHello = 1;    /* don't process again */
+    b0 = *input++;
+    b1 = *input++;
+    *sslBytes -= 2;
+    *rhSize = ((b0 & 0x7f) << 8) | b1;
+
+    if (*rhSize > *sslBytes) {
+        SetError(OLD_CLIENT_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    ret = ProcessOldClientHello(session->sslServer, input, &idx, *sslBytes,
+                                (word16)*rhSize);    
+    if (ret < 0 && ret != MATCH_SUITE_ERROR) {
+        SetError(BAD_OLD_CLIENT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    
+    Trace(OLD_CLIENT_OK_STR);
+    XMEMCPY(session->sslClient->arrays->clientRandom,
+           session->sslServer->arrays->clientRandom, RAN_LEN);
+    
+    *sslBytes -= *rhSize;
+    return 0;
+}
+
+#endif /* OLD_HELLO_ALLOWED */
+
+
+#if 0
+/* Calculate the TCP checksum, see RFC 1071 */
+/* return 0 for success, -1 on error */
+/* can be called from decode() with
+   TcpChecksum(&ipInfo, &tcpInfo, sslBytes, packet + ipInfo.length);
+   could also add a 64bit version if type available and using this
+*/
+int TcpChecksum(IpInfo* ipInfo, TcpInfo* tcpInfo, int dataLen,
+                const byte* packet)
+{
+    TcpPseudoHdr  pseudo;
+    int           count = PSEUDO_HDR_SZ;
+    const word16* data = (word16*)&pseudo;
+    word32        sum = 0;
+    word16        checksum;
+    
+    pseudo.src = ipInfo->src;
+    pseudo.dst = ipInfo->dst;
+    pseudo.rsv = 0;
+    pseudo.protocol = TCP_PROTO;
+    pseudo.legnth = htons(tcpInfo->length + dataLen);
+    
+    /* pseudo header sum */
+    while (count >= 2) {
+        sum   += *data++;
+        count -= 2;
+    }
+    
+    count = tcpInfo->length + dataLen;
+    data = (word16*)packet;
+    
+    /* main sum */
+    while (count > 1) {
+        sum   += *data++;
+        count -=2;
+    }
+    
+    /* get left-over, if any */
+    packet = (byte*)data;
+    if (count > 0) {
+        sum += *packet;
+    }
+    
+    /* fold 32bit sum into 16 bits */
+    while (sum >> 16)
+        sum = (sum & 0xffff) + (sum >> 16);
+    
+    checksum = (word16)~sum;
+    /* checksum should now equal 0, since included already calcd checksum */
+    /* field, but tcp checksum offloading could negate calculation */
+    if (checksum == 0)
+        return 0;
+    return -1;
+}
+#endif
+
+
+/* Check IP and TCP headers, set payload */
+/* returns 0 on success, -1 on error */
+static int CheckHeaders(IpInfo* ipInfo, TcpInfo* tcpInfo, const byte* packet,
+                  int length, const byte** sslFrame, int* sslBytes, char* error)
+{
+    TraceHeader();
+    TracePacket();
+
+    /* ip header */
+    if (length < IP_HDR_SZ) {
+        SetError(PACKET_HDR_SHORT_STR, error, NULL, 0);
+        return -1;
+    }
+    if (CheckIpHdr((IpHdr*)packet, ipInfo, length, error) != 0)
+        return -1;
+   
+    /* tcp header */ 
+    if (length < (ipInfo->length + TCP_HDR_SZ)) {
+        SetError(PACKET_HDR_SHORT_STR, error, NULL, 0);
+        return -1;
+    }
+    if (CheckTcpHdr((TcpHdr*)(packet + ipInfo->length), tcpInfo, error) != 0)
+        return -1;
+   
+    /* setup */ 
+    *sslFrame = packet + ipInfo->length + tcpInfo->length;
+    if (*sslFrame > packet + length) {
+        SetError(PACKET_HDR_SHORT_STR, error, NULL, 0);
+        return -1;
+    }
+    *sslBytes = (int)(packet + length - *sslFrame);
+    
+    return 0;
+}
+
+
+/* Create or Find existing session */
+/* returns 0 on success (continue), -1 on error, 1 on success (end) */
+static int CheckSession(IpInfo* ipInfo, TcpInfo* tcpInfo, int sslBytes,
+                        SnifferSession** session, char* error)
+{
+    /* create a new SnifferSession on client SYN */
+    if (tcpInfo->syn && !tcpInfo->ack) {
+        TraceClientSyn(tcpInfo->sequence);
+        *session = CreateSession(ipInfo, tcpInfo, error);
+        if (*session == NULL) {
+            *session = GetSnifferSession(ipInfo, tcpInfo);
+            /* already had exisiting, so OK */
+            if (*session)
+                return 1;
+            
+            SetError(MEMORY_STR, error, NULL, 0);
+            return -1;
+        }
+        return 1;
+    }
+    /* get existing sniffer session */
+    else {
+        *session = GetSnifferSession(ipInfo, tcpInfo);
+        if (*session == NULL) {
+            /* don't worry about extraneous RST or duplicate FINs */
+            if (tcpInfo->fin || tcpInfo->rst)
+                return 1;
+            /* don't worry about duplicate ACKs either */
+            if (sslBytes == 0 && tcpInfo->ack)
+                return 1;
+            
+            SetError(BAD_SESSION_STR, error, NULL, 0);
+            return -1;
+        }        
+    }
+    return 0;
+}
+
+
+/* Create a Packet Buffer from *begin - end, adjust new *begin and bytesLeft */
+static PacketBuffer* CreateBuffer(word32* begin, word32 end, const byte* data,
+                                  int* bytesLeft)
+{
+    PacketBuffer* pb;
+    
+    int added = end - *begin + 1;
+    assert(*begin <= end);
+    
+    pb = (PacketBuffer*)malloc(sizeof(PacketBuffer));
+    if (pb == NULL) return NULL;
+    
+    pb->next  = 0;
+    pb->begin = *begin;
+    pb->end   = end;
+    pb->data = (byte*)malloc(added);
+    
+    if (pb->data == NULL) {
+        free(pb);
+        return NULL;
+    }
+    XMEMCPY(pb->data, data, added);
+    
+    *bytesLeft -= added;
+    *begin      = pb->end + 1;
+    
+    return pb;
+}
+
+
+/* Add sslFrame to Reassembly List */
+/* returns 1 (end) on success, -1, on error */
+static int AddToReassembly(byte from, word32 seq, const byte* sslFrame,
+                           int sslBytes, SnifferSession* session, char* error)
+{
+    PacketBuffer*  add;
+    PacketBuffer** front = (from == WOLFSSL_SERVER_END) ?
+                       &session->cliReassemblyList: &session->srvReassemblyList;
+    PacketBuffer*  curr = *front;
+    PacketBuffer*  prev = curr;
+    
+    word32  startSeq = seq;
+    word32  added;
+    int     bytesLeft = sslBytes;  /* could be overlapping fragment */
+
+    /* if list is empty add full frame to front */
+    if (!curr) {
+        add = CreateBuffer(&seq, seq + sslBytes - 1, sslFrame, &bytesLeft);
+        if (add == NULL) {
+            SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        *front = add;
+        return 1;
+    }
+    
+    /* add to front if before current front, up to next->begin */
+    if (seq < curr->begin) {
+        word32 end = seq + sslBytes - 1;
+        
+        if (end >= curr->begin)
+            end = curr->begin - 1;
+        
+        add = CreateBuffer(&seq, end, sslFrame, &bytesLeft);
+        if (add == NULL) {
+            SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        add->next = curr;
+        *front = add;
+    }
+    
+    /* while we have bytes left, try to find a gap to fill */
+    while (bytesLeft > 0) {
+        /* get previous packet in list */
+        while (curr && (seq >= curr->begin)) {
+            prev = curr;
+            curr = curr->next;
+        }
+        
+        /* don't add  duplicate data */
+        if (prev->end >= seq) {
+            if ( (seq + bytesLeft - 1) <= prev->end)
+                return 1;
+            seq = prev->end + 1;
+            bytesLeft = startSeq + sslBytes - seq;
+        }
+        
+        if (!curr)
+            /* we're at the end */
+            added = bytesLeft;
+        else 
+            /* we're in between two frames */
+            added = min((word32)bytesLeft, curr->begin - seq);
+        
+        /* data already there */
+        if (added == 0)
+            continue;
+        
+        add = CreateBuffer(&seq, seq + added - 1, &sslFrame[seq - startSeq],
+                           &bytesLeft);
+        if (add == NULL) {
+            SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        add->next  = prev->next;
+        prev->next = add;
+    }
+    return 1;
+}
+
+
+/* Add out of order FIN capture */
+/* returns 1 for success (end) */
+static int AddFinCapture(SnifferSession* session, word32 sequence)
+{
+    if (session->flags.side == WOLFSSL_SERVER_END) {
+        if (session->finCaputre.cliCounted == 0)
+            session->finCaputre.cliFinSeq = sequence;
+    }
+    else {
+        if (session->finCaputre.srvCounted == 0)
+            session->finCaputre.srvFinSeq = sequence;
+    }
+    return 1;
+}
+
+
+/* Adjust incoming sequence based on side */
+/* returns 0 on success (continue), -1 on error, 1 on success (end) */
+static int AdjustSequence(TcpInfo* tcpInfo, SnifferSession* session,
+                          int* sslBytes, const byte** sslFrame, char* error)
+{
+    word32  seqStart = (session->flags.side == WOLFSSL_SERVER_END) ? 
+                                     session->cliSeqStart :session->srvSeqStart;
+    word32  real     = tcpInfo->sequence - seqStart;
+    word32* expected = (session->flags.side == WOLFSSL_SERVER_END) ?
+                                  &session->cliExpected : &session->srvExpected;
+    PacketBuffer* reassemblyList = (session->flags.side == WOLFSSL_SERVER_END) ?
+                        session->cliReassemblyList : session->srvReassemblyList;
+    
+    /* handle rollover of sequence */
+    if (tcpInfo->sequence < seqStart)
+        real = 0xffffffffU - seqStart + tcpInfo->sequence;
+        
+    TraceRelativeSequence(*expected, real);
+    
+    if (real < *expected) {
+        Trace(DUPLICATE_STR);
+        if (real + *sslBytes > *expected) {
+            int overlap = *expected - real;
+            Trace(OVERLAP_DUPLICATE_STR);
+                
+            /* adjust to expected, remove duplicate */
+            *sslFrame += overlap;
+            *sslBytes -= overlap;
+                
+            if (reassemblyList) {
+                word32 newEnd = *expected + *sslBytes;
+                    
+                if (newEnd > reassemblyList->begin) {
+                    Trace(OVERLAP_REASSEMBLY_BEGIN_STR);
+                    
+                    /* remove bytes already on reassembly list */
+                    *sslBytes -= newEnd - reassemblyList->begin;
+                }
+                if (newEnd > reassemblyList->end) {
+                    Trace(OVERLAP_REASSEMBLY_END_STR);
+                    
+                    /* may be past reassembly list end (could have more on list)
+                       so try to add what's past the front->end */
+                    AddToReassembly(session->flags.side, reassemblyList->end +1,
+                                *sslFrame + reassemblyList->end - *expected + 1,
+                                 newEnd - reassemblyList->end, session, error);
+                }
+            }
+        }
+        else
+            return 1;
+    }
+    else if (real > *expected) {
+        Trace(OUT_OF_ORDER_STR);
+        if (*sslBytes > 0)
+            return AddToReassembly(session->flags.side, real, *sslFrame,
+                                   *sslBytes, session, error);
+        else if (tcpInfo->fin)
+            return AddFinCapture(session, real);
+    }
+    /* got expected sequence */
+    *expected += *sslBytes;
+    if (tcpInfo->fin)
+        *expected += 1;
+    
+    return 0;
+}
+
+
+/* Check latest ack number for missing packets
+   return 0 ok, <0 on error */
+static int CheckAck(TcpInfo* tcpInfo, SnifferSession* session)
+{
+    if (tcpInfo->ack) {
+        word32  seqStart = (session->flags.side == WOLFSSL_SERVER_END) ? 
+                                     session->srvSeqStart :session->cliSeqStart;
+        word32  real     = tcpInfo->ackNumber - seqStart;
+        word32  expected = (session->flags.side == WOLFSSL_SERVER_END) ?
+                                  session->srvExpected : session->cliExpected;
+    
+        /* handle rollover of sequence */
+        if (tcpInfo->ackNumber < seqStart)
+            real = 0xffffffffU - seqStart + tcpInfo->ackNumber;
+        
+        TraceAck(real, expected);
+
+        if (real > expected)
+            return -1;  /* we missed a packet, ACKing data we never saw */
+    }
+    return 0;
+}
+
+
+/* Check TCP Sequence status */
+/* returns 0 on success (continue), -1 on error, 1 on success (end) */
+static int CheckSequence(IpInfo* ipInfo, TcpInfo* tcpInfo,
+                         SnifferSession* session, int* sslBytes,
+                         const byte** sslFrame, char* error)
+{
+    int actualLen;
+    
+    /* init SEQ from server to client */
+    if (tcpInfo->syn && tcpInfo->ack) {
+        session->srvSeqStart = tcpInfo->sequence;
+        session->srvExpected = 1;
+        TraceServerSyn(tcpInfo->sequence);
+        return 1;
+    }
+    
+    /* adjust potential ethernet trailer */
+    actualLen = ipInfo->total - ipInfo->length - tcpInfo->length;
+    if (*sslBytes > actualLen) {
+        *sslBytes = actualLen;
+    }
+    
+    TraceSequence(tcpInfo->sequence, *sslBytes);
+    if (CheckAck(tcpInfo, session) < 0) {
+        SetError(ACK_MISSED_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    
+    return AdjustSequence(tcpInfo, session, sslBytes, sslFrame, error);    
+}
+
+
+/* Check Status before record processing */
+/* returns 0 on success (continue), -1 on error, 1 on success (end) */
+static int CheckPreRecord(IpInfo* ipInfo, TcpInfo* tcpInfo,
+                          const byte** sslFrame, SnifferSession** session,
+                          int* sslBytes, const byte** end, char* error)
+{
+    word32 length;
+    SSL*  ssl = ((*session)->flags.side == WOLFSSL_SERVER_END) ?
+                                  (*session)->sslServer : (*session)->sslClient;
+    /* remove SnifferSession on 2nd FIN or RST */
+    if (tcpInfo->fin || tcpInfo->rst) {
+        /* flag FIN and RST */
+        if (tcpInfo->fin)
+            (*session)->flags.finCount += 1;
+        else if (tcpInfo->rst)
+            (*session)->flags.finCount += 2;
+        
+        if ((*session)->flags.finCount >= 2) {
+            RemoveSession(*session, ipInfo, tcpInfo, 0);
+            *session = NULL;
+            return 1;
+        }
+    }
+    
+    if ((*session)->flags.fatalError == FATAL_ERROR_STATE) {
+        SetError(FATAL_ERROR_STR, error, NULL, 0);
+        return -1;
+    }
+    
+    if (*sslBytes == 0) {
+        Trace(NO_DATA_STR);
+        return 1;
+    }
+    
+    /* if current partial data, add to end of partial */
+    if ( (length = ssl->buffers.inputBuffer.length) ) {
+        Trace(PARTIAL_ADD_STR);
+        
+        if ( (*sslBytes + length) > ssl->buffers.inputBuffer.bufferSize) {
+            if (GrowInputBuffer(ssl, *sslBytes, length) < 0) {
+                SetError(MEMORY_STR, error, *session, FATAL_ERROR_STATE);
+                return -1;
+            }
+        }
+        XMEMCPY(&ssl->buffers.inputBuffer.buffer[length], *sslFrame, *sslBytes);
+        *sslBytes += length;
+        ssl->buffers.inputBuffer.length = *sslBytes;
+        *sslFrame = ssl->buffers.inputBuffer.buffer;
+        *end = *sslFrame + *sslBytes;
+    }
+
+    if ((*session)->flags.clientHello == 0 && **sslFrame != handshake) {
+        /* Sanity check the packet for an old style client hello. */
+        int rhSize = (((*sslFrame)[0] & 0x7f) << 8) | ((*sslFrame)[1]);
+
+        if ((rhSize <= (*sslBytes - 2)) &&
+            (*sslFrame)[2] == OLD_HELLO_ID && (*sslFrame)[3] == SSLv3_MAJOR) {
+#ifdef OLD_HELLO_ALLOWED
+        int ret = DoOldHello(*session, *sslFrame, &rhSize, sslBytes, error);
+        if (ret < 0)
+            return -1;  /* error already set */
+        if (*sslBytes <= 0)
+            return 1;
+#endif
+        }
+        else {
+#ifdef STARTTLS_ALLOWED
+            return 1;
+#endif
+        }
+    }
+
+    return 0;
+}
+
+
+/* See if input on the reassembly list is ready for consuming */
+/* returns 1 for TRUE, 0 for FALSE */
+static int HaveMoreInput(SnifferSession* session, const byte** sslFrame,
+                         int* sslBytes, const byte** end, char* error)
+{
+    /* sequence and reassembly based on from, not to */
+    int            moreInput = 0;
+    PacketBuffer** front = (session->flags.side == WOLFSSL_SERVER_END) ?
+                      &session->cliReassemblyList : &session->srvReassemblyList;
+    word32*        expected = (session->flags.side == WOLFSSL_SERVER_END) ?
+                                  &session->cliExpected : &session->srvExpected;
+    /* buffer is on receiving end */
+    word32*        length = (session->flags.side == WOLFSSL_SERVER_END) ?
+                               &session->sslServer->buffers.inputBuffer.length :
+                               &session->sslClient->buffers.inputBuffer.length;
+    byte*          myBuffer = (session->flags.side == WOLFSSL_SERVER_END) ?
+                                session->sslServer->buffers.inputBuffer.buffer :
+                                session->sslClient->buffers.inputBuffer.buffer;
+    word32       bufferSize = (session->flags.side == WOLFSSL_SERVER_END) ?
+                            session->sslServer->buffers.inputBuffer.bufferSize :
+                            session->sslClient->buffers.inputBuffer.bufferSize;
+    SSL*               ssl  = (session->flags.side == WOLFSSL_SERVER_END) ?
+                            session->sslServer : session->sslClient;
+    
+    while (*front && ((*front)->begin == *expected) ) {
+        word32 room = bufferSize - *length;
+        word32 packetLen = (*front)->end - (*front)->begin + 1;
+
+        if (packetLen > room && bufferSize < MAX_INPUT_SZ) {
+            if (GrowInputBuffer(ssl, packetLen, *length) < 0) {
+                SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
+                return 0;
+            }
+        }
+        
+        if (packetLen <= room) {
+            PacketBuffer* del = *front;
+            
+            XMEMCPY(&myBuffer[*length], (*front)->data, packetLen);
+            *length   += packetLen;
+            *expected += packetLen;
+            
+            /* remove used packet */
+            *front = (*front)->next;
+            FreePacketBuffer(del);
+            
+            moreInput = 1;
+        }
+        else
+            break;
+    }
+    if (moreInput) {
+        *sslFrame = myBuffer;
+        *sslBytes = *length;
+        *end      = myBuffer + *length;
+    }
+    return moreInput;
+}
+                         
+
+
+/* Process Message(s) from sslFrame */
+/* return Number of bytes on success, 0 for no data yet, and -1 on error */
+static int ProcessMessage(const byte* sslFrame, SnifferSession* session,
+                          int sslBytes, byte* data, const byte* end,char* error)
+{
+    const byte*       sslBegin = sslFrame;
+    const byte*       recordEnd;   /* end of record indicator */
+    const byte*       inRecordEnd; /* indictor from input stream not decrypt */
+    RecordLayerHeader rh;
+    int               rhSize = 0;
+    int               ret;
+    int               errCode = 0;
+    int               decoded = 0;      /* bytes stored for user in data */
+    int               notEnough;        /* notEnough bytes yet flag */
+    int               decrypted = 0;    /* was current msg decrypted */
+    SSL*              ssl = (session->flags.side == WOLFSSL_SERVER_END) ?
+                                        session->sslServer : session->sslClient;
+doMessage:
+    notEnough = 0;
+    if (sslBytes < 0) {
+        SetError(PACKET_HDR_SHORT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    if (sslBytes >= RECORD_HEADER_SZ) {
+        if (GetRecordHeader(sslFrame, &rh, &rhSize) != 0) {
+            SetError(BAD_RECORD_HDR_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+    }
+    else
+        notEnough = 1;
+
+    if (notEnough || rhSize > (sslBytes - RECORD_HEADER_SZ)) {
+        /* don't have enough input yet to process full SSL record */
+        Trace(PARTIAL_INPUT_STR);
+        
+        /* store partial if not there already or we advanced */
+        if (ssl->buffers.inputBuffer.length == 0 || sslBegin != sslFrame) {
+            if (sslBytes > (int)ssl->buffers.inputBuffer.bufferSize) {
+                if (GrowInputBuffer(ssl, sslBytes, 0) < 0) { 
+                    SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
+                    return -1;
+                }
+            }
+            XMEMMOVE(ssl->buffers.inputBuffer.buffer, sslFrame, sslBytes);
+            ssl->buffers.inputBuffer.length = sslBytes;
+        }
+        if (HaveMoreInput(session, &sslFrame, &sslBytes, &end, error))
+            goto doMessage;
+        return decoded;
+    }
+    sslFrame += RECORD_HEADER_SZ;
+    sslBytes -= RECORD_HEADER_SZ;
+    recordEnd = sslFrame + rhSize;   /* may have more than one record */
+    inRecordEnd = recordEnd;
+    
+    /* decrypt if needed */
+    if ((session->flags.side == WOLFSSL_SERVER_END &&
+                                               session->flags.serverCipherOn)
+     || (session->flags.side == WOLFSSL_CLIENT_END &&
+                                               session->flags.clientCipherOn)) {
+        int ivAdvance = 0;  /* TLSv1.1 advance amount */
+        if (ssl->decrypt.setup != 1) {
+            SetError(DECRYPT_KEYS_NOT_SETUP, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        if (CheckAvailableSize(ssl, rhSize) < 0) {
+            SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        sslFrame = DecryptMessage(ssl, sslFrame, rhSize,
+                                  ssl->buffers.outputBuffer.buffer, &errCode,
+                                  &ivAdvance);
+        recordEnd = sslFrame - ivAdvance + rhSize;  /* sslFrame moved so
+                                                       should recordEnd */
+        decrypted = 1;
+        if (errCode != 0) {
+            SetError(BAD_DECRYPT, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+    }
+
+doPart:
+            
+    switch ((enum ContentType)rh.type) {
+        case handshake:
+            {
+                int startIdx = sslBytes;
+                int used;
+
+                Trace(GOT_HANDSHAKE_STR);
+                ret = DoHandShake(sslFrame, &sslBytes, session, error);
+                if (ret != 0) {
+                    if (session->flags.fatalError == 0)
+                        SetError(BAD_HANDSHAKE_STR, error, session,
+                                 FATAL_ERROR_STATE);
+                    return -1;
+                }
+
+                /* DoHandShake now fully decrements sslBytes to remaining */
+                used = startIdx - sslBytes;
+                sslFrame += used;
+                if (decrypted)
+                    sslFrame += ssl->keys.padSz;
+            }
+            break;
+        case change_cipher_spec:
+            if (session->flags.side == WOLFSSL_SERVER_END)
+                session->flags.serverCipherOn = 1;
+            else
+                session->flags.clientCipherOn = 1;
+            Trace(GOT_CHANGE_CIPHER_STR);
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+            ssl->options.handShakeDone  = 1;
+
+            sslFrame += 1;
+            sslBytes -= 1;
+
+            break;
+        case application_data:
+            Trace(GOT_APP_DATA_STR);
+            {
+                word32 inOutIdx = 0;
+                    
+                ret = DoApplicationData(ssl, (byte*)sslFrame, &inOutIdx);
+                if (ret == 0) {
+                    ret = ssl->buffers.clearOutputBuffer.length;
+                    TraceGotData(ret);
+                    if (ret) {  /* may be blank message */
+                        XMEMCPY(&data[decoded],
+                               ssl->buffers.clearOutputBuffer.buffer, ret);
+                        TraceAddedData(ret, decoded);
+                        decoded += ret;
+                        ssl->buffers.clearOutputBuffer.length = 0;
+                    }
+                }
+                else {
+                    SetError(BAD_APP_DATA_STR, error,session,FATAL_ERROR_STATE);
+                    return -1;
+                }
+                if (ssl->buffers.outputBuffer.dynamicFlag)
+                    ShrinkOutputBuffer(ssl);
+
+                sslFrame += inOutIdx;
+                sslBytes -= inOutIdx;
+            }
+            break;
+        case alert:
+            Trace(GOT_ALERT_STR);
+            sslFrame += rhSize;
+            sslBytes -= rhSize;
+            break;
+        case no_type:
+        default:
+            SetError(GOT_UNKNOWN_RECORD_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+    }
+
+    /* do we have another msg in record ? */
+    if (sslFrame < recordEnd) {
+        Trace(ANOTHER_MSG_STR);
+        goto doPart;
+    }
+
+    /* back to input stream instead of potential decrypt buffer */
+    recordEnd = inRecordEnd;
+
+    /* do we have more records ? */
+    if (recordEnd < end) {
+        Trace(ANOTHER_MSG_STR);
+        sslFrame = recordEnd;
+        sslBytes = (int)(end - recordEnd);
+        goto doMessage;
+    }
+    
+    /* clear used input */
+    ssl->buffers.inputBuffer.length = 0;
+    
+    /* could have more input ready now */
+    if (HaveMoreInput(session, &sslFrame, &sslBytes, &end, error))
+        goto doMessage;
+
+    if (ssl->buffers.inputBuffer.dynamicFlag)
+        ShrinkInputBuffer(ssl, NO_FORCED_FREE);
+    
+    return decoded;
+}
+
+
+/* See if we need to process any pending FIN captures */
+static void CheckFinCapture(IpInfo* ipInfo, TcpInfo* tcpInfo, 
+                            SnifferSession* session)
+{
+    if (session->finCaputre.cliFinSeq && session->finCaputre.cliFinSeq <= 
+                                         session->cliExpected) {
+        if (session->finCaputre.cliCounted == 0) {
+            session->flags.finCount += 1;
+            session->finCaputre.cliCounted = 1;
+            TraceClientFin(session->finCaputre.cliFinSeq, session->cliExpected);
+        }
+    }
+        
+    if (session->finCaputre.srvFinSeq && session->finCaputre.srvFinSeq <= 
+                                         session->srvExpected) {
+        if (session->finCaputre.srvCounted == 0) {
+            session->flags.finCount += 1;
+            session->finCaputre.srvCounted = 1;
+            TraceServerFin(session->finCaputre.srvFinSeq, session->srvExpected);
+        }
+    }
+                
+    if (session->flags.finCount >= 2) 
+        RemoveSession(session, ipInfo, tcpInfo, 0);
+}
+
+
+/* If session is in fatal error state free resources now 
+   return true if removed, 0 otherwise */
+static int RemoveFatalSession(IpInfo* ipInfo, TcpInfo* tcpInfo,
+                              SnifferSession* session, char* error)
+{
+    if (session && session->flags.fatalError == FATAL_ERROR_STATE) {
+        RemoveSession(session, ipInfo, tcpInfo, 0);
+        SetError(FATAL_ERROR_STR, error, NULL, 0);
+        return 1;
+    }
+    return 0;
+}
+
+
+/* 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)
+{
+    TcpInfo           tcpInfo;
+    IpInfo            ipInfo;
+    const byte*       sslFrame;
+    const byte*       end = packet + length;
+    int               sslBytes;                /* ssl bytes unconsumed */
+    int               ret;
+    SnifferSession*   session = 0;
+
+    if (CheckHeaders(&ipInfo, &tcpInfo, packet, length, &sslFrame, &sslBytes,
+                     error) != 0)
+        return -1;
+    
+    ret = CheckSession(&ipInfo, &tcpInfo, sslBytes, &session, error);
+    if (RemoveFatalSession(&ipInfo, &tcpInfo, session, error)) return -1;
+    else if (ret == -1) return -1;
+    else if (ret ==  1) return  0;   /* done for now */
+    
+    ret = CheckSequence(&ipInfo, &tcpInfo, session, &sslBytes, &sslFrame,error);
+    if (RemoveFatalSession(&ipInfo, &tcpInfo, session, error)) return -1;
+    else if (ret == -1) return -1;
+    else if (ret ==  1) return  0;   /* done for now */
+    
+    ret = CheckPreRecord(&ipInfo, &tcpInfo, &sslFrame, &session, &sslBytes,
+                         &end, error);
+    if (RemoveFatalSession(&ipInfo, &tcpInfo, session, error)) return -1;
+    else if (ret == -1) return -1;
+    else if (ret ==  1) return  0;   /* done for now */
+
+    ret = ProcessMessage(sslFrame, session, sslBytes, data, end, error);
+    if (RemoveFatalSession(&ipInfo, &tcpInfo, session, error)) return -1;
+    CheckFinCapture(&ipInfo, &tcpInfo, session);
+    return ret;
+}
+
+
+/* Enables (if traceFile)/ Disables debug tracing */
+/* returns 0 on success, -1 on error */
+int ssl_Trace(const char* traceFile, char* error)
+{
+    if (traceFile) {
+        TraceFile = fopen(traceFile, "a");
+        if (!TraceFile) {
+            SetError(BAD_TRACE_FILE_STR, error, NULL, 0);
+            return -1;
+        }
+        TraceOn = 1;
+    }
+    else 
+        TraceOn = 0;
+
+    return 0;
+}
+
+
+
+
+#endif /* WOLFSSL_SNIFFER */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ssl.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,12938 @@
+/* ssl.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_ERRNO_H
+    #include <errno.h>
+#endif
+
+#include <wolfssl/internal.h>
+#include <wolfssl/error-ssl.h>
+#include <wolfssl/wolfcrypt/coding.h>
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+    #include <wolfssl/openssl/evp.h>
+#endif
+
+#ifdef OPENSSL_EXTRA
+    /* openssl headers begin */
+    #include <wolfssl/openssl/hmac.h>
+    #include <wolfssl/openssl/crypto.h>
+    #include <wolfssl/openssl/des.h>
+    #include <wolfssl/openssl/bn.h>
+    #include <wolfssl/openssl/dh.h>
+    #include <wolfssl/openssl/rsa.h>
+    #include <wolfssl/openssl/pem.h>
+    /* openssl headers end, wolfssl internal headers next */
+    #include <wolfssl/wolfcrypt/hmac.h>
+    #include <wolfssl/wolfcrypt/random.h>
+    #include <wolfssl/wolfcrypt/des3.h>
+    #include <wolfssl/wolfcrypt/md4.h>
+    #include <wolfssl/wolfcrypt/md5.h>
+    #include <wolfssl/wolfcrypt/arc4.h>
+    #ifdef WOLFSSL_SHA512
+        #include <wolfssl/wolfcrypt/sha512.h>
+    #endif
+#endif
+
+#ifndef NO_FILESYSTEM
+    #if !defined(USE_WINDOWS_API) && !defined(NO_WOLFSSL_DIR) \
+            && !defined(EBSNET)
+        #include <dirent.h>
+        #include <sys/stat.h>
+    #endif
+    #ifdef EBSNET
+        #include "vfapi.h"
+        #include "vfile.h"
+    #endif
+#endif /* NO_FILESYSTEM */
+
+#ifndef TRUE
+    #define TRUE  1
+#endif
+#ifndef FALSE
+    #define FALSE 0
+#endif
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* WOLFSSSL_HAVE_MIN */
+
+#ifndef WOLFSSL_HAVE_MAX
+#define WOLFSSL_HAVE_MAX
+
+#ifdef WOLFSSL_DTLS
+    static INLINE word32 max(word32 a, word32 b)
+    {
+        return a > b ? a : b;
+    }
+#endif /* WOLFSSL_DTLS */
+
+#endif /* WOLFSSL_HAVE_MAX */
+
+
+#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
+
+
+/* prevent multiple mutex initializations */
+static volatile int initRefCount = 0;
+static wolfSSL_Mutex count_mutex;   /* init ref count mutex */
+
+
+WOLFSSL_CTX* wolfSSL_CTX_new(WOLFSSL_METHOD* method)
+{
+    WOLFSSL_CTX* ctx = NULL;
+
+    WOLFSSL_ENTER("WOLFSSL_CTX_new");
+
+    if (initRefCount == 0)
+        wolfSSL_Init(); /* user no longer forced to call Init themselves */
+
+    if (method == NULL)
+        return ctx;
+
+    ctx = (WOLFSSL_CTX*) XMALLOC(sizeof(WOLFSSL_CTX), 0, DYNAMIC_TYPE_CTX);
+    if (ctx) {
+        if (InitSSL_Ctx(ctx, method) < 0) {
+            WOLFSSL_MSG("Init CTX failed");
+            wolfSSL_CTX_free(ctx);
+            ctx = NULL;
+        }
+    }
+    else {
+        WOLFSSL_MSG("Alloc CTX failed, method freed");
+        XFREE(method, NULL, DYNAMIC_TYPE_METHOD);
+    }
+
+    WOLFSSL_LEAVE("WOLFSSL_CTX_new", 0);
+    return ctx;
+}
+
+
+void wolfSSL_CTX_free(WOLFSSL_CTX* ctx)
+{
+    WOLFSSL_ENTER("SSL_CTX_free");
+    if (ctx)
+        FreeSSL_Ctx(ctx);
+    WOLFSSL_LEAVE("SSL_CTX_free", 0);
+}
+
+
+WOLFSSL* wolfSSL_new(WOLFSSL_CTX* ctx)
+{
+    WOLFSSL* ssl = NULL;
+    int ret = 0;
+
+    (void)ret;
+    WOLFSSL_ENTER("SSL_new");
+
+    if (ctx == NULL)
+        return ssl;
+
+    ssl = (WOLFSSL*) XMALLOC(sizeof(WOLFSSL), ctx->heap,DYNAMIC_TYPE_SSL);
+    if (ssl)
+        if ( (ret = InitSSL(ssl, ctx)) < 0) {
+            FreeSSL(ssl);
+            ssl = 0;
+        }
+
+    WOLFSSL_LEAVE("SSL_new", ret);
+    return ssl;
+}
+
+
+void wolfSSL_free(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("SSL_free");
+    if (ssl)
+        FreeSSL(ssl);
+    WOLFSSL_LEAVE("SSL_free", 0);
+}
+
+#ifdef HAVE_POLY1305
+/* set if to use old poly 1 for yes 0 to use new poly */
+int wolfSSL_use_old_poly(WOLFSSL* ssl, int value)
+{
+    WOLFSSL_ENTER("SSL_use_old_poly");
+    ssl->options.oldPoly = value;
+    WOLFSSL_LEAVE("SSL_use_old_poly", 0);
+    return 0;
+}
+#endif
+
+int wolfSSL_set_fd(WOLFSSL* ssl, int fd)
+{
+    WOLFSSL_ENTER("SSL_set_fd");
+    ssl->rfd = fd;      /* not used directly to allow IO callbacks */
+    ssl->wfd = fd;
+
+    ssl->IOCB_ReadCtx  = &ssl->rfd;
+    ssl->IOCB_WriteCtx = &ssl->wfd;
+
+    #ifdef WOLFSSL_DTLS
+        if (ssl->options.dtls) {
+            ssl->IOCB_ReadCtx = &ssl->buffers.dtlsCtx;
+            ssl->IOCB_WriteCtx = &ssl->buffers.dtlsCtx;
+            ssl->buffers.dtlsCtx.fd = fd;
+        }
+    #endif
+
+    WOLFSSL_LEAVE("SSL_set_fd", SSL_SUCCESS);
+    return SSL_SUCCESS;
+}
+
+
+/**
+  * Get the name of cipher at priotity level passed in.
+  */
+char* wolfSSL_get_cipher_list(int priority)
+{
+    const char* const* ciphers = GetCipherNames();
+
+    if (priority >= GetCipherNamesSize() || priority < 0) {
+        return 0;
+    }
+
+    return (char*)ciphers[priority];
+}
+
+
+int wolfSSL_get_ciphers(char* buf, int len)
+{
+    const char* const* ciphers = GetCipherNames();
+    int  totalInc = 0;
+    int  step     = 0;
+    char delim    = ':';
+    int  size     = GetCipherNamesSize();
+    int  i;
+
+    if (buf == NULL || len <= 0)
+        return BAD_FUNC_ARG;
+
+    /* Add each member to the buffer delimitted 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
+            return BUFFER_E;
+    }
+    return SSL_SUCCESS;
+}
+
+
+int wolfSSL_get_fd(const WOLFSSL* ssl)
+{
+    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;
+}
+
+
+int wolfSSL_dtls(WOLFSSL* ssl)
+{
+    return ssl->options.dtls;
+}
+
+
+#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);
+    if (sa != NULL) {
+        if (ssl->buffers.dtlsCtx.peer.sa != NULL)
+            XFREE(ssl->buffers.dtlsCtx.peer.sa,ssl->heap,DYNAMIC_TYPE_SOCKADDR);
+        XMEMCPY(sa, peer, peerSz);
+        ssl->buffers.dtlsCtx.peer.sa = sa;
+        ssl->buffers.dtlsCtx.peer.sz = peerSz;
+        return SSL_SUCCESS;
+    }
+    return SSL_FAILURE;
+#else
+    (void)ssl;
+    (void)peer;
+    (void)peerSz;
+    return SSL_NOT_IMPLEMENTED;
+#endif
+}
+
+int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz)
+{
+#ifdef WOLFSSL_DTLS
+    if (peer != NULL && peerSz != NULL
+            && *peerSz >= ssl->buffers.dtlsCtx.peer.sz) {
+        *peerSz = ssl->buffers.dtlsCtx.peer.sz;
+        XMEMCPY(peer, ssl->buffers.dtlsCtx.peer.sa, *peerSz);
+        return SSL_SUCCESS;
+    }
+    return SSL_FAILURE;
+#else
+    (void)ssl;
+    (void)peer;
+    (void)peerSz;
+    return SSL_NOT_IMPLEMENTED;
+#endif
+}
+#endif /* WOLFSSL_LEANPSK */
+
+
+/* return underlyig connect or accept, SSL_SUCCESS on ok */
+int wolfSSL_negotiate(WOLFSSL* ssl)
+{
+    int err = SSL_FATAL_ERROR;
+
+    WOLFSSL_ENTER("wolfSSL_negotiate");
+#ifndef NO_WOLFSSL_SERVER
+    if (ssl->options.side == WOLFSSL_SERVER_END)
+        err = wolfSSL_accept(ssl);
+#endif
+
+#ifndef NO_WOLFSSL_CLIENT
+    if (ssl->options.side == WOLFSSL_CLIENT_END)
+        err = wolfSSL_connect(ssl);
+#endif
+
+    WOLFSSL_LEAVE("wolfSSL_negotiate", err);
+
+    return err;
+}
+
+
+#ifndef WOLFSSL_LEANPSK
+/* object size based on build */
+int wolfSSL_GetObjectSize(void)
+{
+#ifdef SHOW_SIZES
+    printf("sizeof suites           = %lu\n", sizeof(Suites));
+    printf("sizeof ciphers(2)       = %lu\n", sizeof(Ciphers));
+#ifndef NO_RC4
+    printf("    sizeof arc4         = %lu\n", sizeof(Arc4));
+#endif
+    printf("    sizeof aes          = %lu\n", sizeof(Aes));
+#ifndef NO_DES3
+    printf("    sizeof des3         = %lu\n", sizeof(Des3));
+#endif
+#ifndef NO_RABBIT
+    printf("    sizeof rabbit       = %lu\n", sizeof(Rabbit));
+#endif
+#ifdef HAVE_CHACHA
+    printf("    sizeof chacha       = %lu\n", sizeof(Chacha));
+#endif
+    printf("sizeof cipher specs     = %lu\n", sizeof(CipherSpecs));
+    printf("sizeof keys             = %lu\n", sizeof(Keys));
+    printf("sizeof Hashes(2)        = %lu\n", sizeof(Hashes));
+#ifndef NO_MD5
+    printf("    sizeof MD5          = %lu\n", sizeof(Md5));
+#endif
+#ifndef NO_SHA
+    printf("    sizeof SHA          = %lu\n", sizeof(Sha));
+#endif
+#ifndef NO_SHA256
+    printf("    sizeof SHA256       = %lu\n", sizeof(Sha256));
+#endif
+#ifdef WOLFSSL_SHA384
+    printf("    sizeof SHA384       = %lu\n", sizeof(Sha384));
+#endif
+#ifdef WOLFSSL_SHA384
+    printf("    sizeof SHA512       = %lu\n", sizeof(Sha512));
+#endif
+    printf("sizeof Buffers          = %lu\n", sizeof(Buffers));
+    printf("sizeof Options          = %lu\n", sizeof(Options));
+    printf("sizeof Arrays           = %lu\n", sizeof(Arrays));
+#ifndef NO_RSA
+    printf("sizeof RsaKey           = %lu\n", sizeof(RsaKey));
+#endif
+#ifdef HAVE_ECC
+    printf("sizeof ecc_key          = %lu\n", sizeof(ecc_key));
+#endif
+    printf("sizeof WOLFSSL_CIPHER    = %lu\n", sizeof(WOLFSSL_CIPHER));
+    printf("sizeof WOLFSSL_SESSION   = %lu\n", sizeof(WOLFSSL_SESSION));
+    printf("sizeof WOLFSSL           = %lu\n", sizeof(WOLFSSL));
+    printf("sizeof WOLFSSL_CTX       = %lu\n", sizeof(WOLFSSL_CTX));
+#endif
+
+    return sizeof(WOLFSSL);
+}
+#endif
+
+
+#ifndef NO_DH
+/* server Diffie-Hellman parameters, SSL_SUCCESS on ok */
+int wolfSSL_SetTmpDH(WOLFSSL* ssl, const unsigned char* p, int pSz,
+                    const unsigned char* g, int gSz)
+{
+    byte havePSK = 0;
+    byte haveRSA = 1;
+
+    WOLFSSL_ENTER("wolfSSL_SetTmpDH");
+    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)
+        return SIDE_ERROR;
+
+    if (ssl->buffers.serverDH_P.buffer && ssl->buffers.weOwnDH)
+        XFREE(ssl->buffers.serverDH_P.buffer, ssl->ctx->heap, DYNAMIC_TYPE_DH);
+    if (ssl->buffers.serverDH_G.buffer && ssl->buffers.weOwnDH)
+        XFREE(ssl->buffers.serverDH_G.buffer, ssl->ctx->heap, DYNAMIC_TYPE_DH);
+
+    ssl->buffers.weOwnDH = 1;  /* SSL owns now */
+    ssl->buffers.serverDH_P.buffer = (byte*)XMALLOC(pSz, ssl->ctx->heap,
+                                                    DYNAMIC_TYPE_DH);
+    if (ssl->buffers.serverDH_P.buffer == NULL)
+        return MEMORY_E;
+
+    ssl->buffers.serverDH_G.buffer = (byte*)XMALLOC(gSz, ssl->ctx->heap,
+                                                    DYNAMIC_TYPE_DH);
+    if (ssl->buffers.serverDH_G.buffer == NULL) {
+        XFREE(ssl->buffers.serverDH_P.buffer, ssl->ctx->heap, DYNAMIC_TYPE_DH);
+        return MEMORY_E;
+    }
+
+    ssl->buffers.serverDH_P.length = pSz;
+    ssl->buffers.serverDH_G.length = gSz;
+
+    XMEMCPY(ssl->buffers.serverDH_P.buffer, p, pSz);
+    XMEMCPY(ssl->buffers.serverDH_G.buffer, g, gSz);
+
+    ssl->options.haveDH = 1;
+    #ifndef NO_PSK
+        havePSK = ssl->options.havePSK;
+    #endif
+    #ifdef NO_RSA
+        haveRSA = 0;
+    #endif
+    InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, ssl->options.haveDH,
+               ssl->options.haveNTRU, ssl->options.haveECDSAsig,
+               ssl->options.haveStaticECC, ssl->options.side);
+
+    WOLFSSL_LEAVE("wolfSSL_SetTmpDH", 0);
+    return SSL_SUCCESS;
+}
+
+/* server ctx Diffie-Hellman parameters, SSL_SUCCESS on ok */
+int wolfSSL_CTX_SetTmpDH(WOLFSSL_CTX* ctx, const unsigned char* p, int pSz,
+                         const unsigned char* g, int gSz)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_SetTmpDH");
+    if (ctx == NULL || p == NULL || g == NULL) return BAD_FUNC_ARG;
+
+    if (pSz < ctx->minDhKeySz)
+        return DH_KEY_SIZE_E;
+
+    XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_DH);
+    XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_DH);
+
+    ctx->serverDH_P.buffer = (byte*)XMALLOC(pSz, ctx->heap,DYNAMIC_TYPE_DH);
+    if (ctx->serverDH_P.buffer == NULL)
+       return MEMORY_E;
+
+    ctx->serverDH_G.buffer = (byte*)XMALLOC(gSz, ctx->heap,DYNAMIC_TYPE_DH);
+    if (ctx->serverDH_G.buffer == NULL) {
+        XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_DH);
+        return MEMORY_E;
+    }
+
+    ctx->serverDH_P.length = pSz;
+    ctx->serverDH_G.length = gSz;
+
+    XMEMCPY(ctx->serverDH_P.buffer, p, pSz);
+    XMEMCPY(ctx->serverDH_G.buffer, g, gSz);
+
+    ctx->haveDH = 1;
+
+    WOLFSSL_LEAVE("wolfSSL_CTX_SetTmpDH", 0);
+    return SSL_SUCCESS;
+}
+
+#endif /* !NO_DH */
+
+
+int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz)
+{
+    int ret;
+
+    WOLFSSL_ENTER("SSL_write()");
+
+    if (ssl == NULL || data == NULL || sz < 0)
+        return BAD_FUNC_ARG;
+
+#ifdef HAVE_ERRNO_H
+    errno = 0;
+#endif
+
+    ret = SendData(ssl, data, sz);
+
+    WOLFSSL_LEAVE("SSL_write()", ret);
+
+    if (ret < 0)
+        return SSL_FATAL_ERROR;
+    else
+        return ret;
+}
+
+
+static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, int sz, int peek)
+{
+    int ret;
+
+    WOLFSSL_ENTER("wolfSSL_read_internal()");
+
+    if (ssl == NULL || data == NULL || sz < 0)
+        return BAD_FUNC_ARG;
+
+#ifdef HAVE_ERRNO_H
+        errno = 0;
+#endif
+#ifdef WOLFSSL_DTLS
+    if (ssl->options.dtls)
+        ssl->dtls_expected_rx = max(sz + 100, MAX_MTU);
+#endif
+
+#ifdef HAVE_MAX_FRAGMENT
+    ret = ReceiveData(ssl, (byte*)data,
+                     min(sz, min(ssl->max_fragment, OUTPUT_RECORD_SIZE)), peek);
+#else
+    ret = ReceiveData(ssl, (byte*)data, min(sz, OUTPUT_RECORD_SIZE), peek);
+#endif
+
+    WOLFSSL_LEAVE("wolfSSL_read_internal()", ret);
+
+    if (ret < 0)
+        return SSL_FATAL_ERROR;
+    else
+        return ret;
+}
+
+
+int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz)
+{
+    WOLFSSL_ENTER("wolfSSL_peek()");
+
+    return wolfSSL_read_internal(ssl, data, sz, TRUE);
+}
+
+
+int wolfSSL_read(WOLFSSL* ssl, void* data, int sz)
+{
+    WOLFSSL_ENTER("wolfSSL_read()");
+
+    return wolfSSL_read_internal(ssl, data, sz, FALSE);
+}
+
+
+#ifdef HAVE_CAVIUM
+
+/* let's use cavium, SSL_SUCCESS on ok */
+int wolfSSL_UseCavium(WOLFSSL* ssl, int devId)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    ssl->devId = devId;
+
+    return SSL_SUCCESS;
+}
+
+
+/* let's use cavium, SSL_SUCCESS on ok */
+int wolfSSL_CTX_UseCavium(WOLFSSL_CTX* ctx, int devId)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    ctx->devId = devId;
+
+    return SSL_SUCCESS;
+}
+
+
+#endif /* HAVE_CAVIUM */
+
+#ifdef HAVE_SNI
+
+int wolfSSL_UseSNI(WOLFSSL* ssl, byte type, const void* data, word16 size)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    return TLSX_UseSNI(&ssl->extensions, type, data, size);
+}
+
+int wolfSSL_CTX_UseSNI(WOLFSSL_CTX* ctx, byte type, const void* data, word16 size)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    return TLSX_UseSNI(&ctx->extensions, type, data, size);
+}
+
+#ifndef NO_WOLFSSL_SERVER
+
+void wolfSSL_SNI_SetOptions(WOLFSSL* ssl, byte type, byte options)
+{
+    if (ssl && ssl->extensions)
+        TLSX_SNI_SetOptions(ssl->extensions, type, options);
+}
+
+void wolfSSL_CTX_SNI_SetOptions(WOLFSSL_CTX* ctx, byte type, byte options)
+{
+    if (ctx && ctx->extensions)
+        TLSX_SNI_SetOptions(ctx->extensions, type, options);
+}
+
+byte wolfSSL_SNI_Status(WOLFSSL* ssl, byte type)
+{
+    return TLSX_SNI_Status(ssl ? ssl->extensions : NULL, type);
+}
+
+word16 wolfSSL_SNI_GetRequest(WOLFSSL* ssl, byte type, void** data)
+{
+    if (data)
+        *data = NULL;
+
+    if (ssl && ssl->extensions)
+        return TLSX_SNI_GetRequest(ssl->extensions, type, data);
+
+    return 0;
+}
+
+int wolfSSL_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, byte type,
+                                                     byte* sni, word32* inOutSz)
+{
+    if (clientHello && helloSz > 0 && sni && inOutSz && *inOutSz > 0)
+        return TLSX_SNI_GetFromBuffer(clientHello, helloSz, type, sni, inOutSz);
+
+    return BAD_FUNC_ARG;
+}
+
+#endif /* NO_WOLFSSL_SERVER */
+
+#endif /* HAVE_SNI */
+
+
+#ifdef HAVE_MAX_FRAGMENT
+#ifndef NO_WOLFSSL_CLIENT
+int wolfSSL_UseMaxFragment(WOLFSSL* ssl, byte mfl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    return TLSX_UseMaxFragment(&ssl->extensions, mfl);
+}
+
+int wolfSSL_CTX_UseMaxFragment(WOLFSSL_CTX* ctx, byte mfl)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    return TLSX_UseMaxFragment(&ctx->extensions, mfl);
+}
+#endif /* NO_WOLFSSL_CLIENT */
+#endif /* HAVE_MAX_FRAGMENT */
+
+#ifdef HAVE_TRUNCATED_HMAC
+#ifndef NO_WOLFSSL_CLIENT
+int wolfSSL_UseTruncatedHMAC(WOLFSSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    return TLSX_UseTruncatedHMAC(&ssl->extensions);
+}
+
+int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    return TLSX_UseTruncatedHMAC(&ctx->extensions);
+}
+#endif /* NO_WOLFSSL_CLIENT */
+#endif /* HAVE_TRUNCATED_HMAC */
+
+/* Elliptic Curves */
+#ifdef HAVE_SUPPORTED_CURVES
+#ifndef NO_WOLFSSL_CLIENT
+
+int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    switch (name) {
+        case WOLFSSL_ECC_SECP160R1:
+        case WOLFSSL_ECC_SECP192R1:
+        case WOLFSSL_ECC_SECP224R1:
+        case WOLFSSL_ECC_SECP256R1:
+        case WOLFSSL_ECC_SECP384R1:
+        case WOLFSSL_ECC_SECP521R1:
+            break;
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    return TLSX_UseSupportedCurve(&ssl->extensions, name);
+}
+
+int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    switch (name) {
+        case WOLFSSL_ECC_SECP160R1:
+        case WOLFSSL_ECC_SECP192R1:
+        case WOLFSSL_ECC_SECP224R1:
+        case WOLFSSL_ECC_SECP256R1:
+        case WOLFSSL_ECC_SECP384R1:
+        case WOLFSSL_ECC_SECP521R1:
+            break;
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    return TLSX_UseSupportedCurve(&ctx->extensions, name);
+}
+
+#endif /* NO_WOLFSSL_CLIENT */
+#endif /* HAVE_SUPPORTED_CURVES */
+
+/* Secure Renegotiation */
+#ifdef HAVE_SECURE_RENEGOTIATION
+
+/* user is forcing ability to use secure renegotiation, we discourage it */
+int wolfSSL_UseSecureRenegotiation(WOLFSSL* ssl)
+{
+    int ret = BAD_FUNC_ARG;
+
+    if (ssl)
+        ret = TLSX_UseSecureRenegotiation(&ssl->extensions);
+
+    if (ret == SSL_SUCCESS) {
+        TLSX* extension = TLSX_Find(ssl->extensions, SECURE_RENEGOTIATION);
+        
+        if (extension)
+            ssl->secure_renegotiation = (SecureRenegotiation*)extension->data;
+    }
+
+    return ret;
+}
+
+
+/* do a secure renegotiation handshake, user forced, we discourage */
+int wolfSSL_Rehandshake(WOLFSSL* ssl)
+{
+    int ret;
+
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    if (ssl->secure_renegotiation == NULL) {
+        WOLFSSL_MSG("Secure Renegotiation not forced on by user");
+        return SECURE_RENEGOTIATION_E;
+    }
+
+    if (ssl->secure_renegotiation->enabled == 0) {
+        WOLFSSL_MSG("Secure Renegotiation not enabled at extension level");
+        return SECURE_RENEGOTIATION_E;
+    }
+
+    if (ssl->options.handShakeState != HANDSHAKE_DONE) {
+        WOLFSSL_MSG("Can't renegotiate until previous handshake complete");
+        return SECURE_RENEGOTIATION_E;
+    }
+
+#ifndef NO_FORCE_SCR_SAME_SUITE
+    /* force same suite */
+    if (ssl->suites) {
+        ssl->suites->suiteSz = SUITE_LEN;
+        ssl->suites->suites[0] = ssl->options.cipherSuite0;
+        ssl->suites->suites[1] = ssl->options.cipherSuite;
+    }
+#endif
+
+    /* reset handshake states */
+    ssl->options.serverState = NULL_STATE;
+    ssl->options.clientState = NULL_STATE;
+    ssl->options.connectState  = CONNECT_BEGIN;
+    ssl->options.acceptState   = ACCEPT_BEGIN;
+    ssl->options.handShakeState = NULL_STATE;
+    ssl->options.processReply  = 0;  /* TODO, move states in internal.h */
+
+    XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived));
+
+    ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED;
+
+#ifndef NO_OLD_TLS
+#ifndef NO_MD5
+    wc_InitMd5(&ssl->hsHashes->hashMd5);
+#endif
+#ifndef NO_SHA
+    ret = wc_InitSha(&ssl->hsHashes->hashSha);
+    if (ret !=0)
+        return ret;
+#endif
+#endif /* NO_OLD_TLS */
+#ifndef NO_SHA256
+    ret = wc_InitSha256(&ssl->hsHashes->hashSha256);
+    if (ret !=0)
+        return ret;
+#endif
+#ifdef WOLFSSL_SHA384
+    ret = wc_InitSha384(&ssl->hsHashes->hashSha384);
+    if (ret !=0)
+        return ret;
+#endif
+#ifdef WOLFSSL_SHA512
+    ret = wc_InitSha512(&ssl->hsHashes->hashSha512);
+    if (ret !=0)
+        return ret;
+#endif
+
+    ret = wolfSSL_negotiate(ssl);
+    return ret;
+}
+
+#endif /* HAVE_SECURE_RENEGOTIATION */
+
+/* Session Ticket */
+#if !defined(NO_WOLFSSL_SERVER) && defined(HAVE_SESSION_TICKET)
+/* SSL_SUCCESS on ok */
+int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx, SessionTicketEncCb cb)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    ctx->ticketEncCb = cb;
+
+    return SSL_SUCCESS;
+}
+
+/* set hint interval, SSL_SUCCESS on ok */
+int wolfSSL_CTX_set_TicketHint(WOLFSSL_CTX* ctx, int hint)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    ctx->ticketHint = hint;
+
+    return SSL_SUCCESS;
+}
+
+/* set user context, SSL_SUCCESS on ok */
+int wolfSSL_CTX_set_TicketEncCtx(WOLFSSL_CTX* ctx, void* userCtx)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    ctx->ticketEncCtx = userCtx;
+
+    return SSL_SUCCESS;
+}
+
+#endif /* !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET) */
+
+/* Session Ticket */
+#if !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET)
+int wolfSSL_UseSessionTicket(WOLFSSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    return TLSX_UseSessionTicket(&ssl->extensions, NULL);
+}
+
+int wolfSSL_CTX_UseSessionTicket(WOLFSSL_CTX* ctx)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    return TLSX_UseSessionTicket(&ctx->extensions, NULL);
+}
+
+WOLFSSL_API int wolfSSL_get_SessionTicket(WOLFSSL* ssl, byte* buf, word32* bufSz)
+{
+    if (ssl == NULL || buf == NULL || bufSz == NULL || *bufSz == 0)
+        return BAD_FUNC_ARG;
+
+    if (ssl->session.ticketLen <= *bufSz) {
+        XMEMCPY(buf, ssl->session.ticket, ssl->session.ticketLen);
+        *bufSz = ssl->session.ticketLen;
+    }
+    else
+        *bufSz = 0;
+
+    return SSL_SUCCESS;
+}
+
+WOLFSSL_API int wolfSSL_set_SessionTicket(WOLFSSL* ssl, byte* buf, word32 bufSz)
+{
+    if (ssl == NULL || (buf == NULL && bufSz > 0))
+        return BAD_FUNC_ARG;
+
+    if (bufSz > 0)
+        XMEMCPY(ssl->session.ticket, buf, bufSz);
+    ssl->session.ticketLen = (word16)bufSz;
+
+    return SSL_SUCCESS;
+}
+
+
+WOLFSSL_API int wolfSSL_set_SessionTicket_cb(WOLFSSL* ssl,
+                                            CallbackSessionTicket cb, void* ctx)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    ssl->session_ticket_cb = cb;
+    ssl->session_ticket_ctx = ctx;
+
+    return SSL_SUCCESS;
+}
+#endif
+
+#ifndef WOLFSSL_LEANPSK
+
+int wolfSSL_send(WOLFSSL* ssl, const void* data, int sz, int flags)
+{
+    int ret;
+    int oldFlags;
+
+    WOLFSSL_ENTER("wolfSSL_send()");
+
+    if (ssl == NULL || data == NULL || sz < 0)
+        return BAD_FUNC_ARG;
+
+    oldFlags = ssl->wflags;
+
+    ssl->wflags = flags;
+    ret = wolfSSL_write(ssl, data, sz);
+    ssl->wflags = oldFlags;
+
+    WOLFSSL_LEAVE("wolfSSL_send()", ret);
+
+    return ret;
+}
+
+
+int wolfSSL_recv(WOLFSSL* ssl, void* data, int sz, int flags)
+{
+    int ret;
+    int oldFlags;
+
+    WOLFSSL_ENTER("wolfSSL_recv()");
+
+    if (ssl == NULL || data == NULL || sz < 0)
+        return BAD_FUNC_ARG;
+
+    oldFlags = ssl->rflags;
+
+    ssl->rflags = flags;
+    ret = wolfSSL_read(ssl, data, sz);
+    ssl->rflags = oldFlags;
+
+    WOLFSSL_LEAVE("wolfSSL_recv()", ret);
+
+    return ret;
+}
+#endif
+
+
+/* SSL_SUCCESS on ok */
+int wolfSSL_shutdown(WOLFSSL* ssl)
+{
+    int  ret = SSL_FATAL_ERROR;
+    byte tmp;
+    WOLFSSL_ENTER("SSL_shutdown()");
+
+    if (ssl == NULL)
+        return SSL_FATAL_ERROR;
+
+    if (ssl->options.quietShutdown) {
+        WOLFSSL_MSG("quiet shutdown, no close notify sent");
+        return SSL_SUCCESS;
+    }
+
+    /* try to send close notify, not an error if can't */
+    if (!ssl->options.isClosed && !ssl->options.connReset &&
+                                  !ssl->options.sentNotify) {
+        ssl->error = SendAlert(ssl, alert_warning, close_notify);
+        if (ssl->error < 0) {
+            WOLFSSL_ERROR(ssl->error);
+            return SSL_FATAL_ERROR;
+        }
+        ssl->options.sentNotify = 1;  /* don't send close_notify twice */
+        if (ssl->options.closeNotify)
+            ret = SSL_SUCCESS;
+        else
+            ret = SSL_SHUTDOWN_NOT_DONE;
+
+        WOLFSSL_LEAVE("SSL_shutdown()", ret);
+        return ret;
+    }
+
+    /* call wolfSSL_shutdown again for bidirectional shudown */
+    if (ssl->options.sentNotify && !ssl->options.closeNotify) {
+        ret = wolfSSL_read(ssl, &tmp, 0);
+        if (ret < 0) {
+            WOLFSSL_ERROR(ssl->error);
+            ret = SSL_FATAL_ERROR;
+        } else if (ssl->options.closeNotify) {
+            ssl->error = SSL_ERROR_SYSCALL;   /* simulate OpenSSL behavior */
+            ret = SSL_SUCCESS;
+        }
+    }
+
+    WOLFSSL_LEAVE("SSL_shutdown()", ret);
+
+    return ret;
+}
+
+
+int wolfSSL_get_error(WOLFSSL* ssl, int ret)
+{
+    WOLFSSL_ENTER("SSL_get_error");
+
+    if (ret > 0)
+        return SSL_ERROR_NONE;
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    WOLFSSL_LEAVE("SSL_get_error", ssl->error);
+
+    /* make sure converted types are handled in SetErrorString() too */
+    if (ssl->error == WANT_READ)
+        return SSL_ERROR_WANT_READ;         /* convert to OpenSSL type */
+    else if (ssl->error == WANT_WRITE)
+        return SSL_ERROR_WANT_WRITE;        /* convert to OpenSSL type */
+    else if (ssl->error == ZERO_RETURN)
+        return SSL_ERROR_ZERO_RETURN;       /* convert to OpenSSL type */
+    return ssl->error;
+}
+
+
+/* retrive alert history, SSL_SUCCESS on ok */
+int wolfSSL_get_alert_history(WOLFSSL* ssl, WOLFSSL_ALERT_HISTORY *h)
+{
+    if (ssl && h) {
+        *h = ssl->alert_history;
+    }
+    return SSL_SUCCESS;
+}
+
+
+/* return TRUE if current error is want read */
+int wolfSSL_want_read(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("SSL_want_read");
+    if (ssl->error == WANT_READ)
+        return 1;
+
+    return 0;
+}
+
+
+/* return TRUE if current error is want write */
+int wolfSSL_want_write(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("SSL_want_write");
+    if (ssl->error == WANT_WRITE)
+        return 1;
+
+    return 0;
+}
+
+
+char* wolfSSL_ERR_error_string(unsigned long errNumber, char* data)
+{
+    static const char* msg = "Please supply a buffer for error string";
+
+    WOLFSSL_ENTER("ERR_error_string");
+    if (data) {
+        SetErrorString((int)errNumber, data);
+        return data;
+    }
+
+    return (char*)msg;
+}
+
+
+void wolfSSL_ERR_error_string_n(unsigned long e, char* buf, unsigned long len)
+{
+    WOLFSSL_ENTER("wolfSSL_ERR_error_string_n");
+    if (len >= WOLFSSL_MAX_ERROR_SZ)
+        wolfSSL_ERR_error_string(e, buf);
+    else {
+        char tmp[WOLFSSL_MAX_ERROR_SZ];
+
+        WOLFSSL_MSG("Error buffer too short, truncating");
+        if (len) {
+            wolfSSL_ERR_error_string(e, tmp);
+            XMEMCPY(buf, tmp, len-1);
+            buf[len-1] = '\0';
+        }
+    }
+}
+
+
+/* don't free temporary arrays at end of handshake */
+void wolfSSL_KeepArrays(WOLFSSL* ssl)
+{
+    if (ssl)
+        ssl->options.saveArrays = 1;
+}
+
+
+/* user doesn't need temporary arrays anymore, Free */
+void wolfSSL_FreeArrays(WOLFSSL* ssl)
+{
+    if (ssl && ssl->options.handShakeState == HANDSHAKE_DONE) {
+        ssl->options.saveArrays = 0;
+        FreeArrays(ssl, 1);
+    }
+}
+
+
+const byte* wolfSSL_GetMacSecret(WOLFSSL* ssl, int verify)
+{
+    if (ssl == NULL)
+        return NULL;
+
+    if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) ||
+         (ssl->options.side == WOLFSSL_SERVER_END &&  verify) )
+        return ssl->keys.client_write_MAC_secret;
+    else
+        return ssl->keys.server_write_MAC_secret;
+}
+
+
+#ifdef ATOMIC_USER
+
+void  wolfSSL_CTX_SetMacEncryptCb(WOLFSSL_CTX* ctx, CallbackMacEncrypt cb)
+{
+    if (ctx)
+        ctx->MacEncryptCb = cb;
+}
+
+
+void  wolfSSL_SetMacEncryptCtx(WOLFSSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->MacEncryptCtx = ctx;
+}
+
+
+void* wolfSSL_GetMacEncryptCtx(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->MacEncryptCtx;
+
+    return NULL;
+}
+
+
+void  wolfSSL_CTX_SetDecryptVerifyCb(WOLFSSL_CTX* ctx, CallbackDecryptVerify cb)
+{
+    if (ctx)
+        ctx->DecryptVerifyCb = cb;
+}
+
+
+void  wolfSSL_SetDecryptVerifyCtx(WOLFSSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->DecryptVerifyCtx = ctx;
+}
+
+
+void* wolfSSL_GetDecryptVerifyCtx(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->DecryptVerifyCtx;
+
+    return NULL;
+}
+
+
+const byte* wolfSSL_GetClientWriteKey(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->keys.client_write_key;
+
+    return NULL;
+}
+
+
+const byte* wolfSSL_GetClientWriteIV(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->keys.client_write_IV;
+
+    return NULL;
+}
+
+
+const byte* wolfSSL_GetServerWriteKey(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->keys.server_write_key;
+
+    return NULL;
+}
+
+
+const byte* wolfSSL_GetServerWriteIV(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->keys.server_write_IV;
+
+    return NULL;
+}
+
+
+int wolfSSL_GetKeySize(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->specs.key_size;
+
+    return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_GetIVSize(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->specs.iv_size;
+
+    return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_GetBulkCipher(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->specs.bulk_cipher_algorithm;
+
+    return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_GetCipherType(WOLFSSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    if (ssl->specs.cipher_type == block)
+        return WOLFSSL_BLOCK_TYPE;
+    if (ssl->specs.cipher_type == stream)
+        return WOLFSSL_STREAM_TYPE;
+    if (ssl->specs.cipher_type == aead)
+        return WOLFSSL_AEAD_TYPE;
+
+    return -1;
+}
+
+
+int wolfSSL_GetCipherBlockSize(WOLFSSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    return ssl->specs.block_size;
+}
+
+
+int wolfSSL_GetAeadMacSize(WOLFSSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    return ssl->specs.aead_mac_size;
+}
+
+
+int wolfSSL_IsTLSv1_1(WOLFSSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    if (ssl->options.tls1_1)
+        return 1;
+
+    return 0;
+}
+
+
+int wolfSSL_GetSide(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->options.side;
+
+    return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_GetHmacSize(WOLFSSL* ssl)
+{
+    /* AEAD ciphers don't have HMAC keys */
+    if (ssl)
+        return (ssl->specs.cipher_type != aead) ? ssl->specs.hash_size : 0;
+
+    return BAD_FUNC_ARG;
+}
+
+#endif /* ATOMIC_USER */
+
+#ifndef NO_CERTS
+
+WOLFSSL_CERT_MANAGER* wolfSSL_CertManagerNew(void)
+{
+    WOLFSSL_CERT_MANAGER* cm = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_CertManagerNew");
+
+    cm = (WOLFSSL_CERT_MANAGER*) XMALLOC(sizeof(WOLFSSL_CERT_MANAGER), 0,
+                                        DYNAMIC_TYPE_CERT_MANAGER);
+    if (cm) {
+        XMEMSET(cm, 0, sizeof(WOLFSSL_CERT_MANAGER));
+
+        if (InitMutex(&cm->caLock) != 0) {
+            WOLFSSL_MSG("Bad mutex init");
+            wolfSSL_CertManagerFree(cm);
+            return NULL;
+        }
+    }
+
+    return cm;
+}
+
+
+void wolfSSL_CertManagerFree(WOLFSSL_CERT_MANAGER* cm)
+{
+    WOLFSSL_ENTER("wolfSSL_CertManagerFree");
+
+    if (cm) {
+        #ifdef HAVE_CRL
+            if (cm->crl)
+                FreeCRL(cm->crl, 1);
+        #endif
+        #ifdef HAVE_OCSP
+            if (cm->ocsp)
+                FreeOCSP(cm->ocsp, 1);
+        #endif
+        FreeSignerTable(cm->caTable, CA_TABLE_SIZE, NULL);
+        FreeMutex(&cm->caLock);
+        XFREE(cm, NULL, DYNAMIC_TYPE_CERT_MANAGER);
+    }
+
+}
+
+
+/* Unload the CA signer list */
+int wolfSSL_CertManagerUnloadCAs(WOLFSSL_CERT_MANAGER* cm)
+{
+    WOLFSSL_ENTER("wolfSSL_CertManagerUnloadCAs");
+
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    if (LockMutex(&cm->caLock) != 0)
+        return BAD_MUTEX_E;
+
+    FreeSignerTable(cm->caTable, CA_TABLE_SIZE, NULL);
+
+    UnLockMutex(&cm->caLock);
+
+
+    return SSL_SUCCESS;
+}
+
+
+/* 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;
+    buffer         der;
+#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_TMP_BUFFER);
+    if (info == NULL)
+        return MEMORY_E;
+#endif
+
+    info->set      = 0;
+    info->ctx      = NULL;
+    info->consumed = 0;
+    der.buffer     = NULL;
+
+    ret = PemToDer(pem, pemSz, type, &der, NULL, info, &eccKey);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#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;
+        }
+    }
+
+    XFREE(der.buffer, NULL, DYNAMIC_TYPE_KEY);
+
+    return ret;
+}
+
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+
+/* 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 */
+
+
+/* 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;
+    buffer         der;
+#ifdef WOLFSSL_SMALL_STACK
+    EncryptedInfo* info = NULL;
+#else
+    EncryptedInfo  info[1];
+#endif
+
+    (void)pass;
+
+    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_TMP_BUFFER);
+    if (info == NULL)
+        return MEMORY_E;
+#endif
+
+    info->set      = 0;
+    info->ctx      = NULL;
+    info->consumed = 0;
+    der.buffer     = NULL;
+
+#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_TMP_BUFFER);
+        #endif
+            return MEMORY_E;
+        }
+
+        wolfSSL_CTX_set_default_passwd_cb(info->ctx, OurPasswordCb);
+        wolfSSL_CTX_set_default_passwd_cb_userdata(info->ctx, (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_TMP_BUFFER);
+#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;
+        }
+    }
+
+    XFREE(der.buffer, NULL, DYNAMIC_TYPE_KEY);
+
+    return ret;
+}
+
+
+#endif /* !NO_CERTS */
+
+
+
+#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)
+
+void wolfSSL_ERR_print_errors_fp(FILE* fp, int err)
+{
+    char data[WOLFSSL_MAX_ERROR_SZ + 1];
+
+    WOLFSSL_ENTER("wolfSSL_ERR_print_errors_fp");
+    SetErrorString(err, data);
+    fprintf(fp, "%s", data);
+}
+
+#endif
+
+
+int wolfSSL_pending(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("SSL_pending");
+    return ssl->buffers.clearOutputBuffer.length;
+}
+
+
+#ifndef WOLFSSL_LEANPSK
+/* trun on handshake group messages for context */
+int wolfSSL_CTX_set_group_messages(WOLFSSL_CTX* ctx)
+{
+    if (ctx == NULL)
+       return BAD_FUNC_ARG;
+
+    ctx->groupMessages = 1;
+
+    return SSL_SUCCESS;
+}
+#endif
+
+
+#ifndef NO_WOLFSSL_CLIENT
+/* connect enough to get peer cert chain */
+int wolfSSL_connect_cert(WOLFSSL* ssl)
+{
+    int  ret;
+
+    if (ssl == NULL)
+        return SSL_FAILURE;
+
+    ssl->options.certOnly = 1;
+    ret = wolfSSL_connect(ssl);
+    ssl->options.certOnly   = 0;
+
+    return ret;
+}
+#endif
+
+
+#ifndef WOLFSSL_LEANPSK
+/* trun on handshake group messages for ssl object */
+int wolfSSL_set_group_messages(WOLFSSL* ssl)
+{
+    if (ssl == NULL)
+       return BAD_FUNC_ARG;
+
+    ssl->options.groupMessages = 1;
+
+    return SSL_SUCCESS;
+}
+
+
+/* make minVersion the internal equivilant SSL version */
+static int SetMinVersionHelper(byte* minVersion, int version)
+{
+    switch (version) {
+#ifndef NO_OLD_TLS
+        case WOLFSSL_SSLV3:
+            *minVersion = SSLv3_MINOR;
+            break;
+#endif
+
+#ifndef NO_TLS
+    #ifndef NO_OLD_TLS
+        case WOLFSSL_TLSV1:
+            *minVersion = TLSv1_MINOR;
+            break;
+
+        case WOLFSSL_TLSV1_1:
+            *minVersion = TLSv1_1_MINOR;
+            break;
+    #endif
+        case WOLFSSL_TLSV1_2:
+            *minVersion = TLSv1_2_MINOR;
+            break;
+#endif
+
+        default:
+            WOLFSSL_MSG("Bad function argument");
+            return BAD_FUNC_ARG;
+    }
+
+    return SSL_SUCCESS;
+}
+
+
+/* Set minimum downgrade version allowed, SSL_SUCCESS on ok */
+int wolfSSL_CTX_SetMinVersion(WOLFSSL_CTX* ctx, int version)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_SetMinVersion");
+
+    if (ctx == NULL) {
+        WOLFSSL_MSG("Bad function argument");
+        return BAD_FUNC_ARG;
+    }
+
+    return SetMinVersionHelper(&ctx->minDowngrade, version);
+}
+
+
+/* Set minimum downgrade version allowed, SSL_SUCCESS on ok */
+int wolfSSL_SetMinVersion(WOLFSSL* ssl, int version)
+{
+    WOLFSSL_ENTER("wolfSSL_SetMinVersion");
+
+    if (ssl == NULL) {
+        WOLFSSL_MSG("Bad function argument");
+        return BAD_FUNC_ARG;
+    }
+
+    return SetMinVersionHelper(&ssl->options.minDowngrade, version);
+}
+
+
+int wolfSSL_SetVersion(WOLFSSL* ssl, int version)
+{
+    byte haveRSA = 1;
+    byte havePSK = 0;
+
+    WOLFSSL_ENTER("wolfSSL_SetVersion");
+
+    if (ssl == NULL) {
+        WOLFSSL_MSG("Bad function argument");
+        return BAD_FUNC_ARG;
+    }
+
+    switch (version) {
+#ifndef NO_OLD_TLS
+        case WOLFSSL_SSLV3:
+            ssl->version = MakeSSLv3();
+            break;
+#endif
+
+#ifndef NO_TLS
+    #ifndef NO_OLD_TLS
+        case WOLFSSL_TLSV1:
+            ssl->version = MakeTLSv1();
+            break;
+
+        case WOLFSSL_TLSV1_1:
+            ssl->version = MakeTLSv1_1();
+            break;
+    #endif
+        case WOLFSSL_TLSV1_2:
+            ssl->version = MakeTLSv1_2();
+            break;
+#endif
+
+        default:
+            WOLFSSL_MSG("Bad function argument");
+            return BAD_FUNC_ARG;
+    }
+
+    #ifdef NO_RSA
+        haveRSA = 0;
+    #endif
+    #ifndef NO_PSK
+        havePSK = ssl->options.havePSK;
+    #endif
+
+    InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, ssl->options.haveDH,
+                ssl->options.haveNTRU, ssl->options.haveECDSAsig,
+                ssl->options.haveStaticECC, ssl->options.side);
+
+    return SSL_SUCCESS;
+}
+#endif /* !leanpsk */
+
+
+#if !defined(NO_CERTS) || !defined(NO_SESSION_CACHE)
+
+/* 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];
+}
+
+#endif /* !NO_CERTS || !NO_SESSION_CACHE */
+
+
+#ifndef NO_CERTS
+
+/* hash is the SHA digest of name, just use first 32 bits as hash */
+static INLINE word32 HashSigner(const byte* hash)
+{
+    return MakeWordFromHash(hash) % CA_TABLE_SIZE;
+}
+
+
+/* does CA already exist on signer list */
+int AlreadySigner(WOLFSSL_CERT_MANAGER* cm, byte* hash)
+{
+    Signer* signers;
+    int     ret = 0;
+    word32  row = HashSigner(hash);
+
+    if (LockMutex(&cm->caLock) != 0)
+        return  ret;
+    signers = cm->caTable[row];
+    while (signers) {
+        byte* subjectHash;
+        #ifndef NO_SKID
+            subjectHash = signers->subjectKeyIdHash;
+        #else
+            subjectHash = signers->subjectNameHash;
+        #endif
+        if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) {
+            ret = 1;
+            break;
+        }
+        signers = signers->next;
+    }
+    UnLockMutex(&cm->caLock);
+
+    return ret;
+}
+
+
+/* return CA if found, otherwise NULL */
+Signer* GetCA(void* vp, byte* hash)
+{
+    WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp;
+    Signer* ret = NULL;
+    Signer* signers;
+    word32  row = HashSigner(hash);
+
+    if (cm == NULL)
+        return NULL;
+
+    if (LockMutex(&cm->caLock) != 0)
+        return ret;
+
+    signers = cm->caTable[row];
+    while (signers) {
+        byte* subjectHash;
+        #ifndef NO_SKID
+            subjectHash = signers->subjectKeyIdHash;
+        #else
+            subjectHash = signers->subjectNameHash;
+        #endif
+        if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) {
+            ret = signers;
+            break;
+        }
+        signers = signers->next;
+    }
+    UnLockMutex(&cm->caLock);
+
+    return ret;
+}
+
+
+#ifndef NO_SKID
+/* return CA if found, otherwise NULL. Walk through hash table. */
+Signer* GetCAByName(void* vp, byte* hash)
+{
+    WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp;
+    Signer* ret = NULL;
+    Signer* signers;
+    word32  row;
+
+    if (cm == NULL)
+        return NULL;
+
+    if (LockMutex(&cm->caLock) != 0)
+        return ret;
+
+    for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) {
+        signers = cm->caTable[row];
+        while (signers && ret == NULL) {
+            if (XMEMCMP(hash,
+                           signers->subjectNameHash, SIGNER_DIGEST_SIZE) == 0) {
+                ret = signers;
+            }
+            signers = signers->next;
+        }
+    }
+    UnLockMutex(&cm->caLock);
+
+    return ret;
+}
+#endif
+
+
+/* owns der, internal now uses too */
+/* type flag ids from user or from chain received during verify
+   don't allow chain ones to be added w/o isCA extension */
+int AddCA(WOLFSSL_CERT_MANAGER* cm, buffer der, int type, int verify)
+{
+    int         ret;
+    Signer*     signer = 0;
+    word32      row;
+    byte*       subjectHash;
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCert* cert = NULL;
+#else
+    DecodedCert  cert[1];
+#endif
+
+    WOLFSSL_MSG("Adding a CA");
+
+#ifdef WOLFSSL_SMALL_STACK
+    cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (cert == NULL)
+        return MEMORY_E;
+#endif
+
+    InitDecodedCert(cert, der.buffer, der.length, cm->heap);
+    ret = ParseCert(cert, CA_TYPE, verify, cm);
+    WOLFSSL_MSG("    Parsed new CA");
+
+#ifndef NO_SKID
+    subjectHash = cert->extSubjKeyId;
+#else
+    subjectHash = cert->subjectHash;
+#endif
+
+    if (ret == 0 && cert->isCA == 0 && type != WOLFSSL_USER_CA) {
+        WOLFSSL_MSG("    Can't add as CA if not actually one");
+        ret = NOT_CA_ERROR;
+    }
+#ifndef ALLOW_INVALID_CERTSIGN
+    else if (ret == 0 && cert->isCA == 1 && type != WOLFSSL_USER_CA &&
+                              (cert->extKeyUsage & KEYUSE_KEY_CERT_SIGN) == 0) {
+        /* Intermediate CA certs are required to have the keyCertSign
+        * extension set. User loaded root certs are not. */
+        WOLFSSL_MSG("    Doesn't have key usage certificate signing");
+        ret = NOT_CA_ERROR;
+    }
+#endif
+    else if (ret == 0 && AlreadySigner(cm, subjectHash)) {
+        WOLFSSL_MSG("    Already have this CA, not adding again");
+        (void)ret;
+    }
+    else if (ret == 0) {
+        /* take over signer parts */
+        signer = MakeSigner(cm->heap);
+        if (!signer)
+            ret = MEMORY_ERROR;
+        else {
+            signer->keyOID         = cert->keyOID;
+            signer->publicKey      = cert->publicKey;
+            signer->pubKeySize     = cert->pubKeySize;
+            signer->nameLen        = cert->subjectCNLen;
+            signer->name           = cert->subjectCN;
+        #ifndef IGNORE_NAME_CONSTRAINTS
+            signer->permittedNames = cert->permittedNames;
+            signer->excludedNames  = cert->excludedNames;
+        #endif
+        #ifndef NO_SKID
+            XMEMCPY(signer->subjectKeyIdHash, cert->extSubjKeyId,
+                                                            SIGNER_DIGEST_SIZE);
+        #endif
+            XMEMCPY(signer->subjectNameHash, cert->subjectHash,
+                                                            SIGNER_DIGEST_SIZE);
+            signer->keyUsage = cert->extKeyUsageSet ? cert->extKeyUsage
+                                                    : 0xFFFF;
+            signer->next    = NULL; /* If Key Usage not set, all uses valid. */
+            cert->publicKey = 0;    /* in case lock fails don't free here.   */
+            cert->subjectCN = 0;
+        #ifndef IGNORE_NAME_CONSTRAINTS
+            cert->permittedNames = NULL;
+            cert->excludedNames = NULL;
+        #endif
+
+        #ifndef NO_SKID
+            row = HashSigner(signer->subjectKeyIdHash);
+        #else
+            row = HashSigner(signer->subjectNameHash);
+        #endif
+
+            if (LockMutex(&cm->caLock) == 0) {
+                signer->next = cm->caTable[row];
+                cm->caTable[row] = signer;   /* takes ownership */
+                UnLockMutex(&cm->caLock);
+                if (cm->caCacheCallback)
+                    cm->caCacheCallback(der.buffer, (int)der.length, type);
+            }
+            else {
+                WOLFSSL_MSG("    CA Mutex Lock failed");
+                ret = BAD_MUTEX_E;
+                FreeSigner(signer, cm->heap);
+            }
+        }
+    }
+
+    WOLFSSL_MSG("    Freeing Parsed CA");
+    FreeDecodedCert(cert);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+    WOLFSSL_MSG("    Freeing der CA");
+    XFREE(der.buffer, cm->heap, DYNAMIC_TYPE_CA);
+    WOLFSSL_MSG("        OK Freeing der CA");
+
+    WOLFSSL_LEAVE("AddCA", ret);
+
+    return ret == 0 ? SSL_SUCCESS : ret;
+}
+
+#endif /* !NO_CERTS */
+
+
+#ifndef NO_SESSION_CACHE
+
+    /* basic config gives a cache with 33 sessions, adequate for clients and
+       embedded servers
+
+       MEDIUM_SESSION_CACHE allows 1055 sessions, adequate for servers that
+       aren't under heavy load, basically allows 200 new sessions per minute
+
+       BIG_SESSION_CACHE yields 20,027 sessions
+
+       HUGE_SESSION_CACHE yields 65,791 sessions, for servers under heavy load,
+       allows over 13,000 new sessions per minute or over 200 new sessions per
+       second
+
+       SMALL_SESSION_CACHE only stores 6 sessions, good for embedded clients
+       or systems where the default of nearly 3kB is too much RAM, this define
+       uses less than 500 bytes RAM
+
+       default SESSION_CACHE stores 33 sessions (no XXX_SESSION_CACHE defined)
+    */
+    #ifdef HUGE_SESSION_CACHE
+        #define SESSIONS_PER_ROW 11
+        #define SESSION_ROWS 5981
+    #elif defined(BIG_SESSION_CACHE)
+        #define SESSIONS_PER_ROW 7
+        #define SESSION_ROWS 2861
+    #elif defined(MEDIUM_SESSION_CACHE)
+        #define SESSIONS_PER_ROW 5
+        #define SESSION_ROWS 211
+    #elif defined(SMALL_SESSION_CACHE)
+        #define SESSIONS_PER_ROW 2
+        #define SESSION_ROWS 3
+    #else
+        #define SESSIONS_PER_ROW 3
+        #define SESSION_ROWS 11
+    #endif
+
+    typedef struct SessionRow {
+        int nextIdx;                           /* where to place next one   */
+        int totalCount;                        /* sessions ever on this row */
+        WOLFSSL_SESSION Sessions[SESSIONS_PER_ROW];
+    } SessionRow;
+
+    static SessionRow SessionCache[SESSION_ROWS];
+
+    #if defined(WOLFSSL_SESSION_STATS) && defined(WOLFSSL_PEAK_SESSIONS)
+        static word32 PeakSessions;
+    #endif
+
+    static wolfSSL_Mutex session_mutex;   /* SessionCache mutex */
+
+    #ifndef NO_CLIENT_CACHE
+
+        typedef struct ClientSession {
+            word16 serverRow;            /* SessionCache Row id */
+            word16 serverIdx;            /* SessionCache Idx (column) */
+        } ClientSession;
+
+        typedef struct ClientRow {
+            int nextIdx;                /* where to place next one   */
+            int totalCount;             /* sessions ever on this row */
+            ClientSession Clients[SESSIONS_PER_ROW];
+        } ClientRow;
+
+        static ClientRow ClientCache[SESSION_ROWS];  /* Client Cache */
+                                                     /* uses session mutex */
+    #endif  /* NO_CLIENT_CACHE */
+
+#endif /* NO_SESSION_CACHE */
+
+
+int wolfSSL_Init(void)
+{
+    int ret = SSL_SUCCESS;
+
+    WOLFSSL_ENTER("wolfSSL_Init");
+
+    if (initRefCount == 0) {
+#ifndef NO_SESSION_CACHE
+        if (InitMutex(&session_mutex) != 0)
+            ret = BAD_MUTEX_E;
+#endif
+        if (InitMutex(&count_mutex) != 0)
+            ret = BAD_MUTEX_E;
+    }
+    if (ret == SSL_SUCCESS) {
+        if (LockMutex(&count_mutex) != 0) {
+            WOLFSSL_MSG("Bad Lock Mutex count");
+            return BAD_MUTEX_E;
+        }
+        initRefCount++;
+        UnLockMutex(&count_mutex);
+    }
+
+    return ret;
+}
+
+
+#ifndef NO_CERTS
+
+static const char* BEGIN_CERT         = "-----BEGIN CERTIFICATE-----";
+static const char* END_CERT           = "-----END CERTIFICATE-----";
+static const char* BEGIN_CERT_REQ     = "-----BEGIN CERTIFICATE REQUEST-----";
+static const char* END_CERT_REQ       = "-----END CERTIFICATE REQUEST-----";
+static const char* BEGIN_DH_PARAM     = "-----BEGIN DH PARAMETERS-----";
+static const char* END_DH_PARAM       = "-----END DH PARAMETERS-----";
+static const char* BEGIN_X509_CRL     = "-----BEGIN X509 CRL-----";
+static const char* END_X509_CRL       = "-----END X509 CRL-----";
+static const char* BEGIN_RSA_PRIV     = "-----BEGIN RSA PRIVATE KEY-----";
+static const char* END_RSA_PRIV       = "-----END RSA PRIVATE KEY-----";
+static const char* BEGIN_PRIV_KEY     = "-----BEGIN PRIVATE KEY-----";
+static const char* END_PRIV_KEY       = "-----END PRIVATE KEY-----";
+static const char* BEGIN_ENC_PRIV_KEY = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
+static const char* END_ENC_PRIV_KEY   = "-----END ENCRYPTED PRIVATE KEY-----";
+static const char* BEGIN_EC_PRIV      = "-----BEGIN EC PRIVATE KEY-----";
+static const char* END_EC_PRIV        = "-----END EC PRIVATE KEY-----";
+static const char* BEGIN_DSA_PRIV     = "-----BEGIN DSA PRIVATE KEY-----";
+static const char* END_DSA_PRIV       = "-----END DSA PRIVATE KEY-----";
+
+/* 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,
+                  buffer* der, 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         dynamicType = 0;
+    int         sz          = (int)longSz;
+
+    switch (type) {
+        case CA_TYPE:       /* same as below */
+        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 CERTREQ_TYPE:  header= BEGIN_CERT_REQ; footer= END_CERT_REQ; break;
+        default:            header= BEGIN_RSA_PRIV; footer= END_RSA_PRIV; break;
+    }
+    
+    switch (type) {
+        case CA_TYPE:   dynamicType = DYNAMIC_TYPE_CA;   break;
+        case CERT_TYPE: dynamicType = DYNAMIC_TYPE_CERT; break;
+        case CRL_TYPE:  dynamicType = DYNAMIC_TYPE_CRL;  break;
+        default:        dynamicType = DYNAMIC_TYPE_KEY;  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
+            break;
+    }
+
+    if (!headerEnd) {
+        WOLFSSL_MSG("Couldn't find PEM header");
+        return SSL_NO_PEM_HEADER;
+    }
+
+    headerEnd += XSTRLEN(header);
+
+    /* eat end of line */
+    if (headerEnd[0] == '\n')
+        headerEnd++;
+    else if (headerEnd[1] == '\n')
+        headerEnd += 2;
+    else
+        return SSL_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";
+        char* line = XSTRNSTR(headerEnd, encHeader, PEM_LINE_LEN);
+        if (line) {
+            char* newline;
+            char* finish;
+            char* start  = XSTRNSTR(line, "DES", PEM_LINE_LEN);
+
+            if (!start)
+                start = XSTRNSTR(line, "AES", PEM_LINE_LEN);
+
+            if (!start) return SSL_BAD_FILE;
+            if (!info)  return SSL_BAD_FILE;
+
+            finish = XSTRNSTR(start, ",", PEM_LINE_LEN);
+
+            if (start && finish && (start < finish)) {
+                newline = XSTRNSTR(finish, "\r", PEM_LINE_LEN);
+
+                XMEMCPY(info->name, start, finish - start);
+                info->name[finish - start] = 0;
+                XMEMCPY(info->iv, finish + 1, sizeof(info->iv));
+
+                if (!newline) newline = XSTRNSTR(finish, "\n", PEM_LINE_LEN);
+                if (newline && (newline > finish)) {
+                    info->ivSz = (word32)(newline - (finish + 1));
+                    info->set = 1;
+                }
+                else
+                    return SSL_BAD_FILE;
+            }
+            else
+                return SSL_BAD_FILE;
+
+            /* eat blank line */
+            while (*newline == '\r' || *newline == '\n')
+                newline++;
+            headerEnd = newline;
+        }
+    }
+#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */
+
+    /* find footer */
+    footerEnd = XSTRNSTR((char*)buff, footer, sz);
+    if (!footerEnd)
+        return SSL_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] == '\n')
+            consumedEnd += 2;
+        else
+            return SSL_BAD_FILE;
+    }
+
+    if (info)
+        info->consumed = (long)(consumedEnd - (char*)buff);
+
+    /* set up der buffer */
+    neededSz = (long)(footerEnd - headerEnd);
+    if (neededSz > sz || neededSz < 0)
+        return SSL_BAD_FILE;
+
+    der->buffer = (byte*)XMALLOC(neededSz, heap, dynamicType);
+    if (!der->buffer)
+        return MEMORY_ERROR;
+
+    der->length = (word32)neededSz;
+
+    if (Base64_Decode((byte*)headerEnd, (word32)neededSz, der->buffer,
+                                                              &der->length) < 0)
+        return SSL_BAD_FILE;
+
+    if (header == BEGIN_PRIV_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 (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 SSL_BAD_FILE;  /* no callback error */
+
+    #ifdef WOLFSSL_SMALL_STACK
+        password = (char*)XMALLOC(80, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (password == NULL)
+            return MEMORY_E;
+    #endif
+        passwordSz = info->ctx->passwd_cb(password, sizeof(password), 0,
+                                                           info->ctx->userdata);
+        /* convert and adjust length */
+        ret = ToTraditionalEnc(der->buffer, der->length, password, passwordSz);
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(password, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+
+        if (ret < 0)
+            return ret;
+
+        der->length = ret;
+        return 0;
+    }
+#endif
+
+    return 0;
+}
+
+
+/* process the buffer buff, legnth sz, into ctx of format and type
+   used tracks bytes consumed, userChain specifies a user cert chain
+   to pass during the handshake */
+static int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff,
+                         long sz, int format, int type, WOLFSSL* ssl,
+                         long* used, int userChain)
+{
+    buffer        der;        /* holds DER or RAW (for NTRU) */
+    int           ret;
+    int           dynamicType = 0;
+    int           eccKey = 0;
+    int           rsaKey = 0;
+    void*         heap = ctx ? ctx->heap : NULL;
+#ifdef WOLFSSL_SMALL_STACK
+    EncryptedInfo* info = NULL;
+#else
+    EncryptedInfo  info[1];
+#endif
+
+    (void)dynamicType;
+    (void)rsaKey;
+
+    if (used)
+        *used = sz;     /* used bytes default to sz, PEM chain may shorten*/
+
+    if (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM
+                                    && format != SSL_FILETYPE_RAW)
+        return SSL_BAD_FILETYPE;
+
+    if (ctx == NULL && ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    if (type == CA_TYPE)
+        dynamicType = DYNAMIC_TYPE_CA;
+    else if (type == CERT_TYPE)
+        dynamicType = DYNAMIC_TYPE_CERT;
+    else
+        dynamicType = DYNAMIC_TYPE_KEY;
+
+#ifdef WOLFSSL_SMALL_STACK
+    info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (info == NULL)
+        return MEMORY_E;
+#endif
+
+    info->set      = 0;
+    info->ctx      = ctx;
+    info->consumed = 0;
+    der.buffer     = 0;
+
+    if (format == SSL_FILETYPE_PEM) {
+        ret = PemToDer(buff, sz, type, &der, heap, info, &eccKey);
+        if (ret < 0) {
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+            XFREE(der.buffer, heap, dynamicType);
+            return ret;
+        }
+
+        if (used)
+            *used = info->consumed;
+
+        /* we may have a user cert chain, try to consume */
+        if (userChain && type == CERT_TYPE && info->consumed < sz) {
+        #ifdef WOLFSSL_SMALL_STACK
+            byte   staticBuffer[1];                 /* force heap usage */
+        #else
+            byte   staticBuffer[FILE_BUFFER_SIZE];  /* tmp chain buffer */
+        #endif
+            byte*  chainBuffer = staticBuffer;
+            byte*  shrinked    = NULL;   /* shrinked to size chainBuffer
+                                          * or staticBuffer */
+            int    dynamicBuffer = 0;
+            word32 bufferSz = sizeof(staticBuffer);
+            long   consumed = info->consumed;
+            word32 idx = 0;
+            int    gotOne = 0;
+
+            if ( (sz - consumed) > (int)bufferSz) {
+                WOLFSSL_MSG("Growing Tmp Chain Buffer");
+                bufferSz = (word32)(sz - consumed);
+                           /* will shrink to actual size */
+                chainBuffer = (byte*)XMALLOC(bufferSz, heap, DYNAMIC_TYPE_FILE);
+                if (chainBuffer == NULL) {
+                #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                #endif
+                    XFREE(der.buffer, heap, dynamicType);
+                    return MEMORY_E;
+                }
+                dynamicBuffer = 1;
+            }
+
+            WOLFSSL_MSG("Processing Cert Chain");
+            while (consumed < sz) {
+                buffer part;
+                info->consumed = 0;
+                part.buffer = 0;
+
+                ret = PemToDer(buff + consumed, sz - consumed, type, &part,
+                                                           heap, info, &eccKey);
+                if (ret == 0) {
+                    gotOne = 1;
+                    if ( (idx + part.length) > bufferSz) {
+                        WOLFSSL_MSG("   Cert Chain bigger than buffer");
+                        ret = BUFFER_E;
+                    }
+                    else {
+                        c32to24(part.length, &chainBuffer[idx]);
+                        idx += CERT_HEADER_SZ;
+                        XMEMCPY(&chainBuffer[idx], part.buffer,part.length);
+                        idx += part.length;
+                        consumed  += info->consumed;
+                        if (used)
+                            *used += info->consumed;
+                    }
+                }
+
+                XFREE(part.buffer, heap, dynamicType);
+
+                if (ret == SSL_NO_PEM_HEADER && gotOne) {
+                    WOLFSSL_MSG("We got one good PEM so stuff at end ok");
+                    break;
+                }
+
+                if (ret < 0) {
+                    WOLFSSL_MSG("   Error in Cert in Chain");
+                    if (dynamicBuffer)
+                        XFREE(chainBuffer, heap, DYNAMIC_TYPE_FILE);
+                #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                #endif
+                    XFREE(der.buffer, heap, dynamicType);
+                    return ret;
+                }
+                WOLFSSL_MSG("   Consumed another Cert in Chain");
+            }
+            WOLFSSL_MSG("Finished Processing Cert Chain");
+
+            /* only retain actual size used */
+            shrinked = (byte*)XMALLOC(idx, heap, dynamicType);
+            if (shrinked) {
+                if (ssl) {
+                    if (ssl->buffers.certChain.buffer &&
+                                                  ssl->buffers.weOwnCertChain) {
+                        XFREE(ssl->buffers.certChain.buffer, heap,
+                              dynamicType);
+                    }
+                    ssl->buffers.certChain.buffer = shrinked;
+                    ssl->buffers.certChain.length = idx;
+                    XMEMCPY(ssl->buffers.certChain.buffer, chainBuffer,idx);
+                    ssl->buffers.weOwnCertChain = 1;
+                } else if (ctx) {
+                    if (ctx->certChain.buffer)
+                        XFREE(ctx->certChain.buffer, heap, dynamicType);
+                    ctx->certChain.buffer = shrinked;
+                    ctx->certChain.length = idx;
+                    XMEMCPY(ctx->certChain.buffer, chainBuffer, idx);
+                }
+            }
+
+            if (dynamicBuffer)
+                XFREE(chainBuffer, heap, DYNAMIC_TYPE_FILE);
+
+            if (shrinked == NULL) {
+            #ifdef WOLFSSL_SMALL_STACK
+                XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            #endif
+                XFREE(der.buffer, heap, dynamicType);
+                return MEMORY_E;
+            }
+        }
+    }
+    else {  /* ASN1 (DER) or RAW (NTRU) */
+        der.buffer = (byte*) XMALLOC(sz, heap, dynamicType);
+        if (!der.buffer) {
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+            return MEMORY_ERROR;
+        }
+
+        XMEMCPY(der.buffer, buff, sz);
+        der.length = (word32)sz;
+    }
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+    if (info->set) {
+        /* decrypt */
+        int   passwordSz;
+#ifdef WOLFSSL_SMALL_STACK
+        char* password = NULL;
+        byte* key      = NULL;
+        byte* iv       = NULL;
+#else
+        char  password[80];
+        byte  key[AES_256_KEY_SIZE];
+        #ifndef NO_MD5
+        byte  iv[AES_IV_SIZE];
+        #endif
+#endif
+
+    #ifdef WOLFSSL_SMALL_STACK
+        password = (char*)XMALLOC(80, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        key      = (byte*)XMALLOC(AES_256_KEY_SIZE, NULL,
+                                                   DYNAMIC_TYPE_TMP_BUFFER);
+        iv       = (byte*)XMALLOC(AES_IV_SIZE, NULL, 
+                                                   DYNAMIC_TYPE_TMP_BUFFER);
+
+        if (password == NULL || key == NULL || iv == NULL) {
+            XFREE(password, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(key,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(iv,       NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            ret = MEMORY_E;
+        }
+        else
+    #endif
+        if (!ctx || !ctx->passwd_cb) {
+            ret = NO_PASSWORD;
+        }
+        else {
+            passwordSz = ctx->passwd_cb(password, sizeof(password), 0,
+                                                             ctx->userdata);
+
+            /* use file's salt for key derivation, hex decode first */
+            if (Base16_Decode(info->iv, info->ivSz, info->iv, &info->ivSz)
+                                                                         != 0) {
+                ret = ASN_INPUT_E;
+            }
+#ifndef NO_MD5
+            else if ((ret = EVP_BytesToKey(info->name, "MD5", info->iv,
+                           (byte*)password, passwordSz, 1, key, iv)) <= 0) {
+                /* empty */
+            }
+#endif
+#ifndef NO_DES3
+            else if (XSTRNCMP(info->name, "DES-CBC", 7) == 0) {
+                ret = wc_Des_CbcDecryptWithKey(der.buffer, der.buffer, der.length,
+                                                                 key, info->iv);
+            }
+            else if (XSTRNCMP(info->name, "DES-EDE3-CBC", 13) == 0) {
+                ret = wc_Des3_CbcDecryptWithKey(der.buffer, der.buffer, der.length,
+                                                                 key, info->iv);
+            }
+#endif
+#ifndef NO_AES
+            else if (XSTRNCMP(info->name, "AES-128-CBC", 13) == 0) {
+                ret = wc_AesCbcDecryptWithKey(der.buffer, der.buffer, der.length,
+                                               key, AES_128_KEY_SIZE, info->iv);
+            }
+            else if (XSTRNCMP(info->name, "AES-192-CBC", 13) == 0) {
+                ret = wc_AesCbcDecryptWithKey(der.buffer, der.buffer, der.length,
+                                               key, AES_192_KEY_SIZE, info->iv);
+            }
+            else if (XSTRNCMP(info->name, "AES-256-CBC", 13) == 0) {
+                ret = wc_AesCbcDecryptWithKey(der.buffer, der.buffer, der.length,
+                                               key, AES_256_KEY_SIZE, info->iv);
+            }
+#endif
+            else {
+                ret = SSL_BAD_FILE;
+            }
+        }
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(password, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(key,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(iv,       NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+
+        if (ret != 0) {
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+            XFREE(der.buffer, heap, dynamicType);
+            return ret;
+        }
+    }
+#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    if (type == CA_TYPE) {
+        if (ctx == NULL) {
+            WOLFSSL_MSG("Need context for CA load");
+            XFREE(der.buffer, heap, dynamicType);
+            return BAD_FUNC_ARG;
+        }
+        return AddCA(ctx->cm, der, WOLFSSL_USER_CA, ctx->verifyPeer);
+                                                      /* takes der over */
+    }
+    else if (type == CERT_TYPE) {
+        if (ssl) {
+            if (ssl->buffers.weOwnCert && ssl->buffers.certificate.buffer)
+                XFREE(ssl->buffers.certificate.buffer, heap, dynamicType);
+            ssl->buffers.certificate = der;
+            ssl->buffers.weOwnCert = 1;
+        }
+        else if (ctx) {
+            if (ctx->certificate.buffer)
+                XFREE(ctx->certificate.buffer, heap, dynamicType);
+            ctx->certificate = der;     /* takes der over */
+        }
+    }
+    else if (type == PRIVATEKEY_TYPE) {
+        if (ssl) {
+            if (ssl->buffers.weOwnKey && ssl->buffers.key.buffer)
+                XFREE(ssl->buffers.key.buffer, heap, dynamicType);
+            ssl->buffers.key = der;
+            ssl->buffers.weOwnKey = 1;
+        }
+        else if (ctx) {
+            if (ctx->privateKey.buffer)
+                XFREE(ctx->privateKey.buffer, heap, dynamicType);
+            ctx->privateKey = der;      /* takes der over */
+        }
+    }
+    else {
+        XFREE(der.buffer, heap, dynamicType);
+        return SSL_BAD_CERTTYPE;
+    }
+
+    if (type == PRIVATEKEY_TYPE && format != SSL_FILETYPE_RAW) {
+    #ifndef NO_RSA
+        if (!eccKey) {
+            /* make sure RSA key can be used */
+            word32 idx = 0;
+        #ifdef WOLFSSL_SMALL_STACK
+            RsaKey* key = NULL;
+        #else
+            RsaKey  key[1];
+        #endif
+
+        #ifdef WOLFSSL_SMALL_STACK
+            key = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            if (key == NULL)
+                return MEMORY_E;
+        #endif
+
+            ret = wc_InitRsaKey(key, 0);
+            if (ret == 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 */
+                #endif
+                    if (!eccKey)
+                        ret = SSL_BAD_FILE;
+                } else {
+                    rsaKey = 1;
+                    (void)rsaKey;  /* for no ecc builds */
+                }
+            }
+
+            wc_FreeRsaKey(key);
+
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+
+            if (ret != 0)
+                return ret;
+        }
+    #endif
+    #ifdef HAVE_ECC
+        if (!rsaKey) {
+            /* make sure ECC key can be used */
+            word32  idx = 0;
+            ecc_key key;
+
+            wc_ecc_init(&key);
+            if (wc_EccPrivateKeyDecode(der.buffer,&idx,&key,der.length) != 0) {
+                wc_ecc_free(&key);
+                return SSL_BAD_FILE;
+            }
+            wc_ecc_free(&key);
+            eccKey = 1;
+            if (ctx)
+                ctx->haveStaticECC = 1;
+            if (ssl)
+                ssl->options.haveStaticECC = 1;
+        }
+    #endif /* HAVE_ECC */
+    }
+    else if (type == CERT_TYPE) {
+    #ifdef WOLFSSL_SMALL_STACK
+        DecodedCert* cert = NULL;
+    #else
+        DecodedCert  cert[1];
+    #endif
+
+    #ifdef WOLFSSL_SMALL_STACK
+        cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        if (cert == NULL)
+            return MEMORY_E;
+    #endif
+
+        WOLFSSL_MSG("Checking cert signature type");
+        InitDecodedCert(cert, der.buffer, der.length, heap);
+
+        if (DecodeToKey(cert, 0) < 0) {
+            WOLFSSL_MSG("Decode to key failed");
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+            return SSL_BAD_FILE;
+        }
+        switch (cert->signatureOID) {
+            case CTC_SHAwECDSA:
+            case CTC_SHA256wECDSA:
+            case CTC_SHA384wECDSA:
+            case CTC_SHA512wECDSA:
+                WOLFSSL_MSG("ECDSA cert signature");
+                if (ctx)
+                    ctx->haveECDSAsig = 1;
+                if (ssl)
+                    ssl->options.haveECDSAsig = 1;
+                break;
+            default:
+                WOLFSSL_MSG("Not ECDSA cert signature");
+                break;
+        }
+
+    #ifdef HAVE_ECC
+        if (ctx)
+            ctx->pkCurveOID = cert->pkCurveOID;
+        if (ssl)
+            ssl->pkCurveOID = cert->pkCurveOID;
+    #endif
+
+        FreeDecodedCert(cert);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+    }
+
+    return SSL_SUCCESS;
+}
+
+
+/* CA PEM file for verification, may have multiple/chain certs to process */
+static int ProcessChainBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff,
+                            long sz, int format, int type, WOLFSSL* ssl)
+{
+    long used   = 0;
+    int  ret    = 0;
+    int  gotOne = 0;
+
+    WOLFSSL_MSG("Processing CA PEM file");
+    while (used < sz) {
+        long consumed = 0;
+
+        ret = ProcessBuffer(ctx, buff + used, sz - used, format, type, ssl,
+                            &consumed, 0);
+
+        if (ret == SSL_NO_PEM_HEADER && gotOne) {
+            WOLFSSL_MSG("We got one good PEM file so stuff at end ok");
+            ret = SSL_SUCCESS;
+            break;
+        }
+
+        if (ret < 0)
+            break;
+
+        WOLFSSL_MSG("   Processed a CA");
+        gotOne = 1;
+        used += consumed;
+    }
+
+    return ret;
+}
+
+
+/* Verify the ceritficate, SSL_SUCCESS for ok, < 0 for error */
+int wolfSSL_CertManagerVerifyBuffer(WOLFSSL_CERT_MANAGER* cm, const byte* buff,
+                                   long sz, int format)
+{
+    int ret = 0;
+    buffer der;
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCert* cert = NULL;
+#else
+    DecodedCert  cert[1];
+#endif
+
+    WOLFSSL_ENTER("wolfSSL_CertManagerVerifyBuffer");
+
+#ifdef WOLFSSL_SMALL_STACK
+    cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (cert == NULL)
+        return MEMORY_E;
+#endif
+
+    der.buffer = NULL;
+    der.length = 0;
+
+    if (format == SSL_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), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        if (info == NULL) {
+            XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            return MEMORY_E;
+        }
+    #endif
+
+        info->set      = 0;
+        info->ctx      = NULL;
+        info->consumed = 0;
+
+        ret = PemToDer(buff, sz, CERT_TYPE, &der, cm->heap, info, &eccKey);
+
+        if (ret == 0)
+            InitDecodedCert(cert, der.buffer, der.length, cm->heap);
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+    }
+    else
+        InitDecodedCert(cert, (byte*)buff, (word32)sz, cm->heap);
+
+    if (ret == 0)
+        ret = ParseCertRelative(cert, CERT_TYPE, 1, cm);
+
+#ifdef HAVE_CRL
+    if (ret == 0 && cm->crlEnabled)
+        ret = CheckCertCRL(cm->crl, cert);
+#endif
+
+    FreeDecodedCert(cert);
+
+    XFREE(der.buffer, cm->heap, DYNAMIC_TYPE_CERT);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret == 0 ? SSL_SUCCESS : ret;
+}
+
+
+/* turn on OCSP if off and compiled in, set options */
+int wolfSSL_CertManagerEnableOCSP(WOLFSSL_CERT_MANAGER* cm, int options)
+{
+    int ret = SSL_SUCCESS;
+
+    (void)options;
+
+    WOLFSSL_ENTER("wolfSSL_CertManagerEnableOCSP");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    #ifdef HAVE_OCSP
+        if (cm->ocsp == NULL) {
+            cm->ocsp = (WOLFSSL_OCSP*)XMALLOC(sizeof(WOLFSSL_OCSP), cm->heap,
+                                                             DYNAMIC_TYPE_OCSP);
+            if (cm->ocsp == NULL)
+                return MEMORY_E;
+
+            if (InitOCSP(cm->ocsp, cm) != 0) {
+                WOLFSSL_MSG("Init OCSP failed");
+                FreeOCSP(cm->ocsp, 1);
+                cm->ocsp = NULL;
+                return SSL_FAILURE;
+            }
+        }
+        cm->ocspEnabled = 1;
+        if (options & WOLFSSL_OCSP_URL_OVERRIDE)
+            cm->ocspUseOverrideURL = 1;
+        if (options & WOLFSSL_OCSP_NO_NONCE)
+            cm->ocspSendNonce = 0;
+        else
+            cm->ocspSendNonce = 1;
+        if (options & WOLFSSL_OCSP_CHECKALL)
+            cm->ocspCheckAll = 1;
+        #ifndef WOLFSSL_USER_IO
+            cm->ocspIOCb = EmbedOcspLookup;
+            cm->ocspRespFreeCb = EmbedOcspRespFree;
+        #endif /* WOLFSSL_USER_IO */
+    #else
+        ret = NOT_COMPILED_IN;
+    #endif
+
+    return ret;
+}
+
+
+int wolfSSL_CertManagerDisableOCSP(WOLFSSL_CERT_MANAGER* cm)
+{
+    WOLFSSL_ENTER("wolfSSL_CertManagerDisableOCSP");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    cm->ocspEnabled = 0;
+
+    return SSL_SUCCESS;
+}
+
+
+#ifdef HAVE_OCSP
+
+
+/* check CRL if enabled, SSL_SUCCESS  */
+int wolfSSL_CertManagerCheckOCSP(WOLFSSL_CERT_MANAGER* cm, byte* der, int sz)
+{
+    int ret;
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCert* cert = NULL;
+#else
+    DecodedCert  cert[1];
+#endif
+
+    WOLFSSL_ENTER("wolfSSL_CertManagerCheckOCSP");
+
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    if (cm->ocspEnabled == 0)
+        return SSL_SUCCESS;
+
+#ifdef WOLFSSL_SMALL_STACK
+    cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (cert == NULL)
+        return MEMORY_E;
+#endif
+
+    InitDecodedCert(cert, der, sz, NULL);
+
+    if ((ret = ParseCertRelative(cert, CERT_TYPE, NO_VERIFY, cm)) != 0) {
+        WOLFSSL_MSG("ParseCert failed");
+    }
+    else if ((ret = CheckCertOCSP(cm->ocsp, cert)) != 0) {
+        WOLFSSL_MSG("CheckCertOCSP failed");
+    }
+
+    FreeDecodedCert(cert);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret == 0 ? SSL_SUCCESS : ret;
+}
+
+
+int wolfSSL_CertManagerSetOCSPOverrideURL(WOLFSSL_CERT_MANAGER* cm,
+                                                                const char* url)
+{
+    WOLFSSL_ENTER("wolfSSL_CertManagerSetOCSPOverrideURL");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    XFREE(cm->ocspOverrideURL, cm->heap, 0);
+    if (url != NULL) {
+        int urlSz = (int)XSTRLEN(url) + 1;
+        cm->ocspOverrideURL = (char*)XMALLOC(urlSz, cm->heap, 0);
+        if (cm->ocspOverrideURL != NULL) {
+            XMEMCPY(cm->ocspOverrideURL, url, urlSz);
+        }
+        else
+            return MEMORY_E;
+    }
+    else
+        cm->ocspOverrideURL = NULL;
+
+    return SSL_SUCCESS;
+}
+
+
+int wolfSSL_CertManagerSetOCSP_Cb(WOLFSSL_CERT_MANAGER* cm,
+                        CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx)
+{
+    WOLFSSL_ENTER("wolfSSL_CertManagerSetOCSP_Cb");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    cm->ocspIOCb = ioCb;
+    cm->ocspRespFreeCb = respFreeCb;
+    cm->ocspIOCtx = ioCbCtx;
+
+    return SSL_SUCCESS;
+}
+
+
+int wolfSSL_EnableOCSP(WOLFSSL* ssl, int options)
+{
+    WOLFSSL_ENTER("wolfSSL_EnableOCSP");
+    if (ssl)
+        return wolfSSL_CertManagerEnableOCSP(ssl->ctx->cm, options);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_DisableOCSP(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("wolfSSL_DisableOCSP");
+    if (ssl)
+        return wolfSSL_CertManagerDisableOCSP(ssl->ctx->cm);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_SetOCSP_OverrideURL(WOLFSSL* ssl, const char* url)
+{
+    WOLFSSL_ENTER("wolfSSL_SetOCSP_OverrideURL");
+    if (ssl)
+        return wolfSSL_CertManagerSetOCSPOverrideURL(ssl->ctx->cm, url);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_SetOCSP_Cb(WOLFSSL* ssl,
+                        CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx)
+{
+    WOLFSSL_ENTER("wolfSSL_SetOCSP_Cb");
+    if (ssl)
+        return wolfSSL_CertManagerSetOCSP_Cb(ssl->ctx->cm,
+                                                     ioCb, respFreeCb, ioCbCtx);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_CTX_EnableOCSP(WOLFSSL_CTX* ctx, int options)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSP");
+    if (ctx)
+        return wolfSSL_CertManagerEnableOCSP(ctx->cm, options);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_CTX_DisableOCSP(WOLFSSL_CTX* ctx)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSP");
+    if (ctx)
+        return wolfSSL_CertManagerDisableOCSP(ctx->cm);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_CTX_SetOCSP_OverrideURL(WOLFSSL_CTX* ctx, const char* url)
+{
+    WOLFSSL_ENTER("wolfSSL_SetOCSP_OverrideURL");
+    if (ctx)
+        return wolfSSL_CertManagerSetOCSPOverrideURL(ctx->cm, url);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_CTX_SetOCSP_Cb(WOLFSSL_CTX* ctx,
+                        CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_SetOCSP_Cb");
+    if (ctx)
+        return wolfSSL_CertManagerSetOCSP_Cb(ctx->cm, ioCb, respFreeCb, ioCbCtx);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+#endif /* HAVE_OCSP */
+
+
+#ifndef NO_FILESYSTEM
+
+    #if defined(WOLFSSL_MDK_ARM)
+        extern FILE * wolfSSL_fopen(const char *name, const char *mode) ;
+        #define XFOPEN     wolfSSL_fopen
+    #else
+        #define XFOPEN     fopen
+    #endif
+
+/* process a file with name fname into ctx of format and type
+   userChain specifies a user certificate chain to pass during handshake */
+int ProcessFile(WOLFSSL_CTX* ctx, const char* fname, int format, int type,
+                WOLFSSL* ssl, int userChain, WOLFSSL_CRL* crl)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    byte   staticBuffer[1]; /* force heap usage */
+#else
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+#endif
+    byte*  myBuffer = staticBuffer;
+    int    dynamic = 0;
+    int    ret;
+    long   sz = 0;
+    XFILE  file;
+    void*  heapHint = ctx ? ctx->heap : NULL;
+
+    (void)crl;
+    (void)heapHint;
+
+    if (fname == NULL) return SSL_BAD_FILE;
+
+    file = XFOPEN(fname, "rb");
+    if (file == XBADFILE) return SSL_BAD_FILE;
+    XFSEEK(file, 0, XSEEK_END);
+    sz = XFTELL(file);
+    XREWIND(file);
+
+    if (sz > (long)sizeof(staticBuffer)) {
+        WOLFSSL_MSG("Getting dynamic buffer");
+        myBuffer = (byte*)XMALLOC(sz, heapHint, DYNAMIC_TYPE_FILE);
+        if (myBuffer == NULL) {
+            XFCLOSE(file);
+            return SSL_BAD_FILE;
+        }
+        dynamic = 1;
+    }
+    else if (sz < 0) {
+        XFCLOSE(file);
+        return SSL_BAD_FILE;
+    }
+
+    if ( (ret = (int)XFREAD(myBuffer, sz, 1, file)) < 0)
+        ret = SSL_BAD_FILE;
+    else {
+        if (type == CA_TYPE && format == SSL_FILETYPE_PEM)
+            ret = ProcessChainBuffer(ctx, myBuffer, sz, format, type, ssl);
+#ifdef HAVE_CRL
+        else if (type == CRL_TYPE)
+            ret = BufferLoadCRL(crl, myBuffer, sz, format);
+#endif
+        else
+            ret = ProcessBuffer(ctx, myBuffer, sz, format, type, ssl, NULL,
+                                userChain);
+    }
+
+    XFCLOSE(file);
+    if (dynamic)
+        XFREE(myBuffer, heapHint, DYNAMIC_TYPE_FILE);
+
+    return ret;
+}
+
+
+/* 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 ret = SSL_SUCCESS;
+
+    WOLFSSL_ENTER("wolfSSL_CTX_load_verify_locations");
+    (void)path;
+
+    if (ctx == NULL || (file == NULL && path == NULL) )
+        return SSL_FAILURE;
+
+    if (file)
+        ret = ProcessFile(ctx, file, SSL_FILETYPE_PEM, CA_TYPE, NULL, 0, NULL);
+
+    if (ret == SSL_SUCCESS && path) {
+        /* try to load each regular file in path */
+    #ifdef USE_WINDOWS_API
+        WIN32_FIND_DATAA FindFileData;
+        HANDLE hFind;
+    #ifdef WOLFSSL_SMALL_STACK
+        char*  name = NULL;
+    #else
+        char   name[MAX_FILENAME_SZ];
+    #endif
+
+    #ifdef WOLFSSL_SMALL_STACK
+        name = (char*)XMALLOC(MAX_FILENAME_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (name == NULL)
+            return MEMORY_E;
+    #endif
+
+        XMEMSET(name, 0, MAX_FILENAME_SZ);
+        XSTRNCPY(name, path, MAX_FILENAME_SZ - 4);
+        XSTRNCAT(name, "\\*", 3);
+
+        hFind = FindFirstFileA(name, &FindFileData);
+        if (hFind == INVALID_HANDLE_VALUE) {
+            WOLFSSL_MSG("FindFirstFile for path verify locations failed");
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(name, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+            return BAD_PATH_ERROR;
+        }
+
+        do {
+            if (FindFileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY) {
+                XSTRNCPY(name, path, MAX_FILENAME_SZ/2 - 3);
+                XSTRNCAT(name, "\\", 2);
+                XSTRNCAT(name, FindFileData.cFileName, MAX_FILENAME_SZ/2);
+
+                ret = ProcessFile(ctx, name, SSL_FILETYPE_PEM, CA_TYPE, NULL,0,
+                                                                          NULL);
+            }
+        } while (ret == SSL_SUCCESS && FindNextFileA(hFind, &FindFileData));
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(name, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+
+        FindClose(hFind);
+    #elif !defined(NO_WOLFSSL_DIR)
+        struct dirent* entry;
+        DIR*   dir = opendir(path);
+    #ifdef WOLFSSL_SMALL_STACK
+        char*  name = NULL;
+    #else
+        char   name[MAX_FILENAME_SZ];
+    #endif
+
+        if (dir == NULL) {
+            WOLFSSL_MSG("opendir path verify locations failed");
+            return BAD_PATH_ERROR;
+        }
+
+    #ifdef WOLFSSL_SMALL_STACK
+        name = (char*)XMALLOC(MAX_FILENAME_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (name == NULL)
+            return MEMORY_E;
+    #endif
+
+        while ( ret == SSL_SUCCESS && (entry = readdir(dir)) != NULL) {
+            struct stat s;
+
+            XMEMSET(name, 0, MAX_FILENAME_SZ);
+            XSTRNCPY(name, path, MAX_FILENAME_SZ/2 - 2);
+            XSTRNCAT(name, "/", 1);
+            XSTRNCAT(name, entry->d_name, MAX_FILENAME_SZ/2);
+
+            if (stat(name, &s) != 0) {
+                WOLFSSL_MSG("stat on name failed");
+                ret = BAD_PATH_ERROR;
+            } else if (s.st_mode & S_IFREG)
+                ret = ProcessFile(ctx, name, SSL_FILETYPE_PEM, CA_TYPE, NULL,0,
+                                                                          NULL);
+        }
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(name, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+
+        closedir(dir);
+    #endif
+    }
+
+    return ret;
+}
+
+
+/* Verify the ceritficate, SSL_SUCCESS for ok, < 0 for error */
+int wolfSSL_CertManagerVerify(WOLFSSL_CERT_MANAGER* cm, const char* fname,
+                             int format)
+{
+    int    ret = SSL_FATAL_ERROR;
+#ifdef WOLFSSL_SMALL_STACK
+    byte   staticBuffer[1]; /* force heap usage */
+#else
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+#endif
+    byte*  myBuffer = staticBuffer;
+    int    dynamic = 0;
+    long   sz = 0;
+    XFILE  file = XFOPEN(fname, "rb");
+
+    WOLFSSL_ENTER("wolfSSL_CertManagerVerify");
+
+    if (file == XBADFILE) return SSL_BAD_FILE;
+    XFSEEK(file, 0, XSEEK_END);
+    sz = XFTELL(file);
+    XREWIND(file);
+
+    if (sz > MAX_WOLFSSL_FILE_SIZE || sz < 0) {
+        WOLFSSL_MSG("CertManagerVerify file bad size");
+        XFCLOSE(file);
+        return SSL_BAD_FILE;
+    }
+
+    if (sz > (long)sizeof(staticBuffer)) {
+        WOLFSSL_MSG("Getting dynamic buffer");
+        myBuffer = (byte*) XMALLOC(sz, cm->heap, DYNAMIC_TYPE_FILE);
+        if (myBuffer == NULL) {
+            XFCLOSE(file);
+            return SSL_BAD_FILE;
+        }
+        dynamic = 1;
+    }
+
+    if ( (ret = (int)XFREAD(myBuffer, sz, 1, file)) < 0)
+        ret = SSL_BAD_FILE;
+    else
+        ret = wolfSSL_CertManagerVerifyBuffer(cm, myBuffer, sz, format);
+
+    XFCLOSE(file);
+    if (dynamic)
+        XFREE(myBuffer, cm->heap, DYNAMIC_TYPE_FILE);
+
+    return ret;
+}
+
+
+static INLINE WOLFSSL_METHOD* cm_pick_method(void)
+{
+    #ifndef NO_WOLFSSL_CLIENT
+        #ifdef NO_OLD_TLS
+            return wolfTLSv1_2_client_method();
+        #else
+            return wolfSSLv3_client_method();
+        #endif      
+    #elif !defined(NO_WOLFSSL_SERVER)
+        #ifdef NO_OLD_TLS
+            return wolfTLSv1_2_server_method();
+        #else
+            return wolfSSLv3_server_method();
+        #endif
+    #else
+        return NULL;
+    #endif
+}
+
+
+/* like load verify locations, 1 for success, < 0 for error */
+int wolfSSL_CertManagerLoadCA(WOLFSSL_CERT_MANAGER* cm, const char* file,
+                             const char* path)
+{
+    int ret = SSL_FATAL_ERROR;
+    WOLFSSL_CTX* tmp;
+
+    WOLFSSL_ENTER("wolfSSL_CertManagerLoadCA");
+
+    if (cm == NULL) {
+        WOLFSSL_MSG("No CertManager error");
+        return ret;
+    }
+    tmp = wolfSSL_CTX_new(cm_pick_method());
+
+    if (tmp == NULL) {
+        WOLFSSL_MSG("CTX new failed");
+        return ret;
+    }
+
+    /* for tmp use */
+    wolfSSL_CertManagerFree(tmp->cm);
+    tmp->cm = cm;
+
+    ret = wolfSSL_CTX_load_verify_locations(tmp, file, path);
+
+    /* don't loose our good one */
+    tmp->cm = NULL;
+    wolfSSL_CTX_free(tmp);
+
+    return ret;
+}
+
+
+
+/* turn on CRL if off and compiled in, set options */
+int wolfSSL_CertManagerEnableCRL(WOLFSSL_CERT_MANAGER* cm, int options)
+{
+    int ret = SSL_SUCCESS;
+
+    (void)options;
+
+    WOLFSSL_ENTER("wolfSSL_CertManagerEnableCRL");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    #ifdef HAVE_CRL
+        if (cm->crl == NULL) {
+            cm->crl = (WOLFSSL_CRL*)XMALLOC(sizeof(WOLFSSL_CRL), cm->heap,
+                                           DYNAMIC_TYPE_CRL);
+            if (cm->crl == NULL)
+                return MEMORY_E;
+
+            if (InitCRL(cm->crl, cm) != 0) {
+                WOLFSSL_MSG("Init CRL failed");
+                FreeCRL(cm->crl, 1);
+                cm->crl = NULL;
+                return SSL_FAILURE;
+            }
+        }
+        cm->crlEnabled = 1;
+        if (options & WOLFSSL_CRL_CHECKALL)
+            cm->crlCheckAll = 1;
+    #else
+        ret = NOT_COMPILED_IN;
+    #endif
+
+    return ret;
+}
+
+
+int wolfSSL_CertManagerDisableCRL(WOLFSSL_CERT_MANAGER* cm)
+{
+    WOLFSSL_ENTER("wolfSSL_CertManagerDisableCRL");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    cm->crlEnabled = 0;
+
+    return SSL_SUCCESS;
+}
+
+
+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 SSL_SUCCESS;
+}
+
+
+#ifdef HAVE_CRL
+
+
+/* check CRL if enabled, SSL_SUCCESS  */
+int wolfSSL_CertManagerCheckCRL(WOLFSSL_CERT_MANAGER* cm, byte* der, int sz)
+{
+    int ret = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCert* cert = NULL;
+#else
+    DecodedCert  cert[1];
+#endif
+
+    WOLFSSL_ENTER("wolfSSL_CertManagerCheckCRL");
+
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    if (cm->crlEnabled == 0)
+        return SSL_SUCCESS;
+
+#ifdef WOLFSSL_SMALL_STACK
+    cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (cert == NULL)
+        return MEMORY_E;
+#endif
+
+    InitDecodedCert(cert, der, sz, NULL);
+
+    if ((ret = ParseCertRelative(cert, CERT_TYPE, NO_VERIFY, cm)) != 0) {
+        WOLFSSL_MSG("ParseCert failed");
+    }
+    else if ((ret = CheckCertCRL(cm->crl, cert)) != 0) {
+        WOLFSSL_MSG("CheckCertCRL failed");
+    }
+
+    FreeDecodedCert(cert);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret == 0 ? SSL_SUCCESS : ret;
+}
+
+
+int wolfSSL_CertManagerSetCRL_Cb(WOLFSSL_CERT_MANAGER* cm, CbMissingCRL cb)
+{
+    WOLFSSL_ENTER("wolfSSL_CertManagerSetCRL_Cb");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    cm->cbMissingCRL = cb;
+
+    return SSL_SUCCESS;
+}
+
+
+int wolfSSL_CertManagerLoadCRL(WOLFSSL_CERT_MANAGER* cm, const char* path,
+                              int type, int monitor)
+{
+    WOLFSSL_ENTER("wolfSSL_CertManagerLoadCRL");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    if (cm->crl == NULL) {
+        if (wolfSSL_CertManagerEnableCRL(cm, 0) != SSL_SUCCESS) {
+            WOLFSSL_MSG("Enable CRL failed");
+            return SSL_FATAL_ERROR;
+        }
+    }
+
+    return LoadCRL(cm->crl, path, type, monitor);
+}
+
+
+int wolfSSL_EnableCRL(WOLFSSL* ssl, int options)
+{
+    WOLFSSL_ENTER("wolfSSL_EnableCRL");
+    if (ssl)
+        return wolfSSL_CertManagerEnableCRL(ssl->ctx->cm, options);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_DisableCRL(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("wolfSSL_DisableCRL");
+    if (ssl)
+        return wolfSSL_CertManagerDisableCRL(ssl->ctx->cm);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_LoadCRL(WOLFSSL* ssl, const char* path, int type, int monitor)
+{
+    WOLFSSL_ENTER("wolfSSL_LoadCRL");
+    if (ssl)
+        return wolfSSL_CertManagerLoadCRL(ssl->ctx->cm, path, type, monitor);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_SetCRL_Cb(WOLFSSL* ssl, CbMissingCRL cb)
+{
+    WOLFSSL_ENTER("wolfSSL_SetCRL_Cb");
+    if (ssl)
+        return wolfSSL_CertManagerSetCRL_Cb(ssl->ctx->cm, cb);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_CTX_EnableCRL(WOLFSSL_CTX* ctx, int options)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_EnableCRL");
+    if (ctx)
+        return wolfSSL_CertManagerEnableCRL(ctx->cm, options);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_CTX_DisableCRL(WOLFSSL_CTX* ctx)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_DisableCRL");
+    if (ctx)
+        return wolfSSL_CertManagerDisableCRL(ctx->cm);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_CTX_LoadCRL(WOLFSSL_CTX* ctx, const char* path, int type, int monitor)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_LoadCRL");
+    if (ctx)
+        return wolfSSL_CertManagerLoadCRL(ctx->cm, path, type, monitor);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_CTX_SetCRL_Cb(WOLFSSL_CTX* ctx, CbMissingCRL cb)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_Cb");
+    if (ctx)
+        return wolfSSL_CertManagerSetCRL_Cb(ctx->cm, cb);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+#endif /* HAVE_CRL */
+
+
+#ifdef WOLFSSL_DER_LOAD
+
+/* Add format parameter to allow DER load of CA files */
+int wolfSSL_CTX_der_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
+                                         int format)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_der_load_verify_locations");
+    if (ctx == NULL || file == NULL)
+        return SSL_FAILURE;
+
+    if (ProcessFile(ctx, file, format, CA_TYPE, NULL, 0, NULL) == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+#endif /* WOLFSSL_DER_LOAD */
+
+
+#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");
+    buffer converted;
+
+    WOLFSSL_ENTER("wolfSSL_PemCertToDer");
+
+    if (file == XBADFILE)
+        ret = SSL_BAD_FILE;
+    else {
+        XFSEEK(file, 0, XSEEK_END);
+        sz = XFTELL(file);
+        XREWIND(file);
+
+        if (sz < 0) {
+            ret = SSL_BAD_FILE;
+        }
+        else if (sz > (long)sizeof(staticBuffer)) {
+            fileBuf = (byte*)XMALLOC(sz, 0, DYNAMIC_TYPE_FILE);
+            if (fileBuf == NULL)
+                ret = MEMORY_E;
+            else
+                dynamic = 1;
+        }
+
+        converted.buffer = 0;
+
+        if (ret == 0) {
+            if ( (ret = (int)XFREAD(fileBuf, sz, 1, file)) < 0)
+                ret = SSL_BAD_FILE;
+            else {
+            #ifdef WOLFSSL_SMALL_STACK
+                info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+                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_TMP_BUFFER);
+                #endif
+                }
+            }
+
+            if (ret == 0) {
+                if (converted.length < (word32)derSz) {
+                    XMEMCPY(derBuf, converted.buffer, converted.length);
+                    ret = converted.length;
+                }
+                else
+                    ret = BUFFER_E;
+            }
+
+            XFREE(converted.buffer, 0, DYNAMIC_TYPE_CA);
+        }
+
+        XFCLOSE(file);
+        if (dynamic)
+            XFREE(fileBuf, 0, DYNAMIC_TYPE_FILE);
+    }
+
+    return ret;
+}
+
+#endif /* WOLFSSL_CERT_GEN */
+
+
+int wolfSSL_CTX_use_certificate_file(WOLFSSL_CTX* ctx, const char* file,
+                                    int format)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_file");
+    if (ProcessFile(ctx, file, format, CERT_TYPE, NULL, 0, NULL) == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_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)
+                    == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+
+/* get cert chaining depth using ssl struct */
+long wolfSSL_get_verify_depth(WOLFSSL* ssl)
+{
+    if(ssl == NULL) {
+        return BAD_FUNC_ARG;
+    }
+    return MAX_CHAIN_DEPTH;
+}
+
+
+/* get cert chaining depth using ctx struct */
+long wolfSSL_CTX_get_verify_depth(WOLFSSL_CTX* ctx)
+{
+    if(ctx == NULL) {
+        return BAD_FUNC_ARG;
+    }
+    return MAX_CHAIN_DEPTH;
+}
+
+
+int wolfSSL_CTX_use_certificate_chain_file(WOLFSSL_CTX* ctx, const char* file)
+{
+   /* procces up to MAX_CHAIN_DEPTH plus subject cert */
+   WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file");
+   if (ProcessFile(ctx, file, SSL_FILETYPE_PEM,CERT_TYPE,NULL,1, NULL)
+                   == SSL_SUCCESS)
+       return SSL_SUCCESS;
+
+   return SSL_FAILURE;
+}
+
+
+#ifndef NO_DH
+
+/* server wrapper for ctx or ssl Diffie-Hellman parameters */
+static int wolfSSL_SetTmpDH_buffer_wrapper(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
+                                  const unsigned char* buf, long sz, int format)
+{
+    buffer der;
+    int    ret      = 0;
+    int    weOwnDer = 0;
+    word32 pSz = MAX_DH_SIZE;
+    word32 gSz = MAX_DH_SIZE;
+#ifdef WOLFSSL_SMALL_STACK
+    byte*  p = NULL;
+    byte*  g = NULL;
+#else
+    byte   p[MAX_DH_SIZE];
+    byte   g[MAX_DH_SIZE];
+#endif
+
+    der.buffer = (byte*)buf;
+    der.length = (word32)sz;
+
+#ifdef WOLFSSL_SMALL_STACK
+    p = (byte*)XMALLOC(pSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    g = (byte*)XMALLOC(gSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    if (p == NULL || g == NULL) {
+        XFREE(p, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(g, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    if (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM)
+        ret = SSL_BAD_FILETYPE;
+    else {
+        if (format == SSL_FILETYPE_PEM) {
+            der.buffer = NULL;
+            ret = PemToDer(buf, sz, DH_PARAM_TYPE, &der, ctx->heap, NULL,NULL);
+            weOwnDer = 1;
+        }
+        
+        if (ret == 0) {
+            if (wc_DhParamsLoad(der.buffer, der.length, p, &pSz, g, &gSz) < 0)
+                ret = SSL_BAD_FILETYPE;
+            else if (ssl)
+                ret = wolfSSL_SetTmpDH(ssl, p, pSz, g, gSz);
+            else
+                ret = wolfSSL_CTX_SetTmpDH(ctx, p, pSz, g, gSz);
+        }
+    }
+
+    if (weOwnDer)
+        XFREE(der.buffer, ctx->heap, DYNAMIC_TYPE_KEY);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(p, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(g, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+/* server Diffie-Hellman parameters, SSL_SUCCESS on ok */
+int wolfSSL_SetTmpDH_buffer(WOLFSSL* ssl, const unsigned char* buf, long sz,
+                           int format)
+{
+    return wolfSSL_SetTmpDH_buffer_wrapper(ssl->ctx, ssl, buf, sz, format);
+}
+
+
+/* server ctx Diffie-Hellman parameters, SSL_SUCCESS on ok */
+int wolfSSL_CTX_SetTmpDH_buffer(WOLFSSL_CTX* ctx, const unsigned char* buf,
+                               long sz, int format)
+{
+    return wolfSSL_SetTmpDH_buffer_wrapper(ctx, NULL, buf, sz, format);
+}
+
+
+/* server Diffie-Hellman parameters */
+static int wolfSSL_SetTmpDH_file_wrapper(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
+                                        const char* fname, int format)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    byte   staticBuffer[1]; /* force heap usage */
+#else
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+#endif
+    byte*  myBuffer = staticBuffer;
+    int    dynamic = 0;
+    int    ret;
+    long   sz = 0;
+    XFILE  file = XFOPEN(fname, "rb");
+
+    if (file == XBADFILE) return SSL_BAD_FILE;
+    XFSEEK(file, 0, XSEEK_END);
+    sz = XFTELL(file);
+    XREWIND(file);
+
+    if (sz > (long)sizeof(staticBuffer)) {
+        WOLFSSL_MSG("Getting dynamic buffer");
+        myBuffer = (byte*) XMALLOC(sz, ctx->heap, DYNAMIC_TYPE_FILE);
+        if (myBuffer == NULL) {
+            XFCLOSE(file);
+            return SSL_BAD_FILE;
+        }
+        dynamic = 1;
+    }
+    else if (sz < 0) {
+        XFCLOSE(file);
+        return SSL_BAD_FILE;
+    }
+
+    if ( (ret = (int)XFREAD(myBuffer, sz, 1, file)) < 0)
+        ret = SSL_BAD_FILE;
+    else {
+        if (ssl)
+            ret = wolfSSL_SetTmpDH_buffer(ssl, myBuffer, sz, format);
+        else
+            ret = wolfSSL_CTX_SetTmpDH_buffer(ctx, myBuffer, sz, format);
+    }
+
+    XFCLOSE(file);
+    if (dynamic)
+        XFREE(myBuffer, ctx->heap, DYNAMIC_TYPE_FILE);
+
+    return ret;
+}
+
+/* server Diffie-Hellman parameters */
+int wolfSSL_SetTmpDH_file(WOLFSSL* ssl, const char* fname, int format)
+{
+    return wolfSSL_SetTmpDH_file_wrapper(ssl->ctx, ssl, fname, format);
+}
+
+
+/* server Diffie-Hellman parameters */
+int wolfSSL_CTX_SetTmpDH_file(WOLFSSL_CTX* ctx, const char* fname, int format)
+{
+    return wolfSSL_SetTmpDH_file_wrapper(ctx, NULL, fname, format);
+}
+
+
+int wolfSSL_CTX_SetMinDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz)
+{
+    if (ctx == NULL || keySz > 16000 || keySz % 8 != 0)
+        return BAD_FUNC_ARG;
+
+    ctx->minDhKeySz = keySz / 8;
+    return SSL_SUCCESS;
+}
+
+
+int wolfSSL_SetMinDhKey_Sz(WOLFSSL* ssl, word16 keySz)
+{
+    if (ssl == NULL || keySz > 16000 || keySz % 8 != 0)
+        return BAD_FUNC_ARG;
+
+    ssl->options.minDhKeySz = keySz / 8;
+    return SSL_SUCCESS;
+}
+
+
+int wolfSSL_GetDhKey_Sz(WOLFSSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    return (ssl->options.dhKeySz * 8);
+}
+
+
+#endif /* NO_DH */
+
+
+#ifdef OPENSSL_EXTRA
+/* put SSL type in extra for now, not very common */
+
+int wolfSSL_use_certificate_file(WOLFSSL* ssl, const char* file, int format)
+{
+    WOLFSSL_ENTER("wolfSSL_use_certificate_file");
+    if (ProcessFile(ssl->ctx, file, format, CERT_TYPE, ssl, 0, NULL)
+                    == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+
+int wolfSSL_use_PrivateKey_file(WOLFSSL* ssl, const char* file, int format)
+{
+    WOLFSSL_ENTER("wolfSSL_use_PrivateKey_file");
+    if (ProcessFile(ssl->ctx, file, format, PRIVATEKEY_TYPE, ssl, 0, NULL)
+                                                                 == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+
+int wolfSSL_use_certificate_chain_file(WOLFSSL* ssl, const char* file)
+{
+   /* procces up to MAX_CHAIN_DEPTH plus subject cert */
+   WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file");
+   if (ProcessFile(ssl->ctx, file, SSL_FILETYPE_PEM, CERT_TYPE, ssl, 1, NULL)
+                                                                 == SSL_SUCCESS)
+       return SSL_SUCCESS;
+
+   return SSL_FAILURE;
+}
+
+
+
+#ifdef HAVE_ECC
+
+/* Set Temp CTX EC-DHE size in octets, should be 20 - 66 for 160 - 521 bit */
+int wolfSSL_CTX_SetTmpEC_DHE_Sz(WOLFSSL_CTX* ctx, word16 sz)
+{
+    if (ctx == NULL || sz < ECC_MINSIZE || sz > ECC_MAXSIZE)
+        return BAD_FUNC_ARG;
+
+    ctx->eccTempKeySz = sz;
+
+    return SSL_SUCCESS;
+}
+
+
+/* Set Temp SSL EC-DHE size in octets, should be 20 - 66 for 160 - 521 bit */
+int wolfSSL_SetTmpEC_DHE_Sz(WOLFSSL* ssl, word16 sz)
+{
+    if (ssl == NULL || sz < ECC_MINSIZE || sz > ECC_MAXSIZE)
+        return BAD_FUNC_ARG;
+
+    ssl->eccTempKeySz = sz;
+
+    return SSL_SUCCESS;
+}
+
+#endif /* HAVE_ECC */
+
+
+
+
+int wolfSSL_CTX_use_RSAPrivateKey_file(WOLFSSL_CTX* ctx,const char* file,
+                                   int format)
+{
+    WOLFSSL_ENTER("SSL_CTX_use_RSAPrivateKey_file");
+
+    return wolfSSL_CTX_use_PrivateKey_file(ctx, file, format);
+}
+
+
+int wolfSSL_use_RSAPrivateKey_file(WOLFSSL* ssl, const char* file, int format)
+{
+    WOLFSSL_ENTER("wolfSSL_use_RSAPrivateKey_file");
+
+    return wolfSSL_use_PrivateKey_file(ssl, file, format);
+}
+
+#endif /* OPENSSL_EXTRA */
+
+#ifdef HAVE_NTRU
+
+int wolfSSL_CTX_use_NTRUPrivateKey_file(WOLFSSL_CTX* ctx, const char* file)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_use_NTRUPrivateKey_file");
+    if (ctx == NULL)
+        return SSL_FAILURE;
+
+    if (ProcessFile(ctx, file, SSL_FILETYPE_RAW, PRIVATEKEY_TYPE, NULL, 0, NULL)
+                         == SSL_SUCCESS) {
+        ctx->haveNTRU = 1;
+        return SSL_SUCCESS;
+    }
+
+    return SSL_FAILURE;
+}
+
+#endif /* HAVE_NTRU */
+
+
+#endif /* NO_FILESYSTEM */
+
+
+void wolfSSL_CTX_set_verify(WOLFSSL_CTX* ctx, int mode, VerifyCallback vc)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_set_verify");
+    if (mode & SSL_VERIFY_PEER) {
+        ctx->verifyPeer = 1;
+        ctx->verifyNone = 0;  /* in case perviously set */
+    }
+
+    if (mode == SSL_VERIFY_NONE) {
+        ctx->verifyNone = 1;
+        ctx->verifyPeer = 0;  /* in case previously set */
+    }
+
+    if (mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+        ctx->failNoCert = 1;
+
+    ctx->verifyCallback = vc;
+}
+
+
+void wolfSSL_set_verify(WOLFSSL* ssl, int mode, VerifyCallback vc)
+{
+    WOLFSSL_ENTER("wolfSSL_set_verify");
+    if (mode & SSL_VERIFY_PEER) {
+        ssl->options.verifyPeer = 1;
+        ssl->options.verifyNone = 0;  /* in case perviously set */
+    }
+
+    if (mode == SSL_VERIFY_NONE) {
+        ssl->options.verifyNone = 1;
+        ssl->options.verifyPeer = 0;  /* in case previously set */
+    }
+
+    if (mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+        ssl->options.failNoCert = 1;
+
+    ssl->verifyCallback = vc;
+}
+
+
+/* store user ctx for verify callback */
+void wolfSSL_SetCertCbCtx(WOLFSSL* ssl, void* ctx)
+{
+    WOLFSSL_ENTER("wolfSSL_SetCertCbCtx");
+    if (ssl)
+        ssl->verifyCbCtx = ctx;
+}
+
+
+/* store context CA Cache addition callback */
+void wolfSSL_CTX_SetCACb(WOLFSSL_CTX* ctx, CallbackCACache cb)
+{
+    if (ctx && ctx->cm)
+        ctx->cm->caCacheCallback = cb;
+}
+
+
+#if defined(PERSIST_CERT_CACHE)
+
+#if !defined(NO_FILESYSTEM)
+
+/* Persist cert cache to file */
+int wolfSSL_CTX_save_cert_cache(WOLFSSL_CTX* ctx, const char* fname)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_save_cert_cache");
+
+    if (ctx == NULL || fname == NULL)
+        return BAD_FUNC_ARG;
+
+    return CM_SaveCertCache(ctx->cm, fname);
+}
+
+
+/* Persist cert cache from file */
+int wolfSSL_CTX_restore_cert_cache(WOLFSSL_CTX* ctx, const char* fname)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_restore_cert_cache");
+
+    if (ctx == NULL || fname == NULL)
+        return BAD_FUNC_ARG;
+
+    return CM_RestoreCertCache(ctx->cm, fname);
+}
+
+#endif /* NO_FILESYSTEM */
+
+/* Persist cert cache to memory */
+int wolfSSL_CTX_memsave_cert_cache(WOLFSSL_CTX* ctx, void* mem, int sz, int* used)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_memsave_cert_cache");
+
+    if (ctx == NULL || mem == NULL || used == NULL || sz <= 0)
+        return BAD_FUNC_ARG;
+
+    return CM_MemSaveCertCache(ctx->cm, mem, sz, used);
+}
+
+
+/* Restore cert cache from memory */
+int wolfSSL_CTX_memrestore_cert_cache(WOLFSSL_CTX* ctx, const void* mem, int sz)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_memrestore_cert_cache");
+
+    if (ctx == NULL || mem == NULL || sz <= 0)
+        return BAD_FUNC_ARG;
+
+    return CM_MemRestoreCertCache(ctx->cm, mem, sz);
+}
+
+
+/* get how big the the cert cache save buffer needs to be */
+int wolfSSL_CTX_get_cert_cache_memsize(WOLFSSL_CTX* ctx)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_get_cert_cache_memsize");
+
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    return CM_GetCertCacheMemSize(ctx->cm);
+}
+
+#endif /* PERSISTE_CERT_CACHE */
+#endif /* !NO_CERTS */
+
+
+#ifndef NO_SESSION_CACHE
+
+WOLFSSL_SESSION* wolfSSL_get_session(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("SSL_get_session");
+    if (ssl)
+        return GetSession(ssl, 0);
+
+    return NULL;
+}
+
+
+int wolfSSL_set_session(WOLFSSL* ssl, WOLFSSL_SESSION* session)
+{
+    WOLFSSL_ENTER("SSL_set_session");
+    if (session)
+        return SetSession(ssl, session);
+
+    return SSL_FAILURE;
+}
+
+
+#ifndef NO_CLIENT_CACHE
+
+/* Associate client session with serverID, find existing or store for saving
+   if newSession flag on, don't reuse existing session
+   SSL_SUCCESS on ok */
+int wolfSSL_SetServerID(WOLFSSL* ssl, const byte* id, int len, int newSession)
+{
+    WOLFSSL_SESSION* session = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_SetServerID");
+
+    if (ssl == NULL || id == NULL || len <= 0)
+        return BAD_FUNC_ARG;
+
+    if (newSession == 0) {
+        session = GetSessionClient(ssl, id, len);
+        if (session) {
+            if (SetSession(ssl, session) != SSL_SUCCESS) {
+                WOLFSSL_MSG("SetSession failed");
+                session = NULL;
+            }
+        }
+    }
+
+    if (session == NULL) {
+        WOLFSSL_MSG("Valid ServerID not cached already");
+
+        ssl->session.idLen = (word16)min(SERVER_ID_LEN, (word32)len);
+        XMEMCPY(ssl->session.serverID, id, ssl->session.idLen);
+    }
+
+    return SSL_SUCCESS;
+}
+
+#endif /* NO_CLIENT_CACHE */
+
+#if defined(PERSIST_SESSION_CACHE)
+
+/* for persistance, if changes to layout need to increment and modify
+   save_session_cache() and restore_session_cache and memory versions too */
+#define WOLFSSL_CACHE_VERSION 2
+
+/* Session Cache Header information */
+typedef struct {
+    int version;     /* cache layout version id */
+    int rows;        /* session rows */
+    int columns;     /* session columns */
+    int sessionSz;   /* sizeof WOLFSSL_SESSION */
+} cache_header_t;
+
+/* current persistence layout is:
+
+   1) cache_header_t
+   2) SessionCache
+   3) ClientCache
+
+   update WOLFSSL_CACHE_VERSION if change layout for the following
+   PERSISTENT_SESSION_CACHE functions
+*/
+
+
+/* get how big the the session cache save buffer needs to be */
+int wolfSSL_get_session_cache_memsize(void)
+{
+    int sz  = (int)(sizeof(SessionCache) + sizeof(cache_header_t));
+
+    #ifndef NO_CLIENT_CACHE
+        sz += (int)(sizeof(ClientCache));
+    #endif
+
+    return sz;
+}
+
+
+/* Persist session cache to memory */
+int wolfSSL_memsave_session_cache(void* mem, int sz)
+{
+    int i;
+    cache_header_t cache_header;
+    SessionRow*    row  = (SessionRow*)((byte*)mem + sizeof(cache_header));
+#ifndef NO_CLIENT_CACHE
+    ClientRow*     clRow;
+#endif
+
+    WOLFSSL_ENTER("wolfSSL_memsave_session_cache");
+
+    if (sz < wolfSSL_get_session_cache_memsize()) {
+        WOLFSSL_MSG("Memory buffer too small");
+        return BUFFER_E;
+    }
+
+    cache_header.version   = WOLFSSL_CACHE_VERSION;
+    cache_header.rows      = SESSION_ROWS;
+    cache_header.columns   = SESSIONS_PER_ROW;
+    cache_header.sessionSz = (int)sizeof(WOLFSSL_SESSION);
+    XMEMCPY(mem, &cache_header, sizeof(cache_header));
+
+    if (LockMutex(&session_mutex) != 0) {
+        WOLFSSL_MSG("Session cache mutex lock failed");
+        return BAD_MUTEX_E;
+    }
+
+    for (i = 0; i < cache_header.rows; ++i)
+        XMEMCPY(row++, SessionCache + i, sizeof(SessionRow));
+
+#ifndef NO_CLIENT_CACHE
+    clRow = (ClientRow*)row;
+    for (i = 0; i < cache_header.rows; ++i)
+        XMEMCPY(clRow++, ClientCache + i, sizeof(ClientRow));
+#endif
+
+    UnLockMutex(&session_mutex);
+
+    WOLFSSL_LEAVE("wolfSSL_memsave_session_cache", SSL_SUCCESS);
+
+    return SSL_SUCCESS;
+}
+
+
+/* Restore the persistant session cache from memory */
+int wolfSSL_memrestore_session_cache(const void* mem, int sz)
+{
+    int    i;
+    cache_header_t cache_header;
+    SessionRow*    row  = (SessionRow*)((byte*)mem + sizeof(cache_header));
+#ifndef NO_CLIENT_CACHE
+    ClientRow*     clRow;
+#endif
+
+    WOLFSSL_ENTER("wolfSSL_memrestore_session_cache");
+
+    if (sz < wolfSSL_get_session_cache_memsize()) {
+        WOLFSSL_MSG("Memory buffer too small");
+        return BUFFER_E;
+    }
+
+    XMEMCPY(&cache_header, mem, sizeof(cache_header));
+    if (cache_header.version   != WOLFSSL_CACHE_VERSION ||
+        cache_header.rows      != SESSION_ROWS ||
+        cache_header.columns   != SESSIONS_PER_ROW ||
+        cache_header.sessionSz != (int)sizeof(WOLFSSL_SESSION)) {
+
+        WOLFSSL_MSG("Session cache header match failed");
+        return CACHE_MATCH_ERROR;
+    }
+
+    if (LockMutex(&session_mutex) != 0) {
+        WOLFSSL_MSG("Session cache mutex lock failed");
+        return BAD_MUTEX_E;
+    }
+
+    for (i = 0; i < cache_header.rows; ++i)
+        XMEMCPY(SessionCache + i, row++, sizeof(SessionRow));
+
+#ifndef NO_CLIENT_CACHE
+    clRow = (ClientRow*)row;
+    for (i = 0; i < cache_header.rows; ++i)
+        XMEMCPY(ClientCache + i, clRow++, sizeof(ClientRow));
+#endif
+
+    UnLockMutex(&session_mutex);
+
+    WOLFSSL_LEAVE("wolfSSL_memrestore_session_cache", SSL_SUCCESS);
+
+    return SSL_SUCCESS;
+}
+
+#if !defined(NO_FILESYSTEM)
+
+/* Persist session cache to file */
+/* doesn't use memsave because of additional memory use */
+int wolfSSL_save_session_cache(const char *fname)
+{
+    XFILE  file;
+    int    ret;
+    int    rc = SSL_SUCCESS;
+    int    i;
+    cache_header_t cache_header;
+
+    WOLFSSL_ENTER("wolfSSL_save_session_cache");
+
+    file = XFOPEN(fname, "w+b");
+    if (file == XBADFILE) {
+        WOLFSSL_MSG("Couldn't open session cache save file");
+        return SSL_BAD_FILE;
+    }
+    cache_header.version   = WOLFSSL_CACHE_VERSION;
+    cache_header.rows      = SESSION_ROWS;
+    cache_header.columns   = SESSIONS_PER_ROW;
+    cache_header.sessionSz = (int)sizeof(WOLFSSL_SESSION);
+
+    /* cache header */
+    ret = (int)XFWRITE(&cache_header, sizeof cache_header, 1, file);
+    if (ret != 1) {
+        WOLFSSL_MSG("Session cache header file write failed");
+        XFCLOSE(file);
+        return FWRITE_ERROR;
+    }
+
+    if (LockMutex(&session_mutex) != 0) {
+        WOLFSSL_MSG("Session cache mutex lock failed");
+        XFCLOSE(file);
+        return BAD_MUTEX_E;
+    }
+
+    /* session cache */
+    for (i = 0; i < cache_header.rows; ++i) {
+        ret = (int)XFWRITE(SessionCache + i, sizeof(SessionRow), 1, file);
+        if (ret != 1) {
+            WOLFSSL_MSG("Session cache member file write failed");
+            rc = FWRITE_ERROR;
+            break;
+        }
+    }
+
+#ifndef NO_CLIENT_CACHE
+    /* client cache */
+    for (i = 0; i < cache_header.rows; ++i) {
+        ret = (int)XFWRITE(ClientCache + i, sizeof(ClientRow), 1, file);
+        if (ret != 1) {
+            WOLFSSL_MSG("Client cache member file write failed");
+            rc = FWRITE_ERROR;
+            break;
+        }
+    }
+#endif /* NO_CLIENT_CACHE */
+
+    UnLockMutex(&session_mutex);
+
+    XFCLOSE(file);
+    WOLFSSL_LEAVE("wolfSSL_save_session_cache", rc);
+
+    return rc;
+}
+
+
+/* Restore the persistant session cache from file */
+/* doesn't use memstore because of additional memory use */
+int wolfSSL_restore_session_cache(const char *fname)
+{
+    XFILE  file;
+    int    rc = SSL_SUCCESS;
+    int    ret;
+    int    i;
+    cache_header_t cache_header;
+
+    WOLFSSL_ENTER("wolfSSL_restore_session_cache");
+
+    file = XFOPEN(fname, "rb");
+    if (file == XBADFILE) {
+        WOLFSSL_MSG("Couldn't open session cache save file");
+        return SSL_BAD_FILE;
+    }
+    /* cache header */
+    ret = (int)XFREAD(&cache_header, sizeof cache_header, 1, file);
+    if (ret != 1) {
+        WOLFSSL_MSG("Session cache header file read failed");
+        XFCLOSE(file);
+        return FREAD_ERROR;
+    }
+    if (cache_header.version   != WOLFSSL_CACHE_VERSION ||
+        cache_header.rows      != SESSION_ROWS ||
+        cache_header.columns   != SESSIONS_PER_ROW ||
+        cache_header.sessionSz != (int)sizeof(WOLFSSL_SESSION)) {
+
+        WOLFSSL_MSG("Session cache header match failed");
+        XFCLOSE(file);
+        return CACHE_MATCH_ERROR;
+    }
+
+    if (LockMutex(&session_mutex) != 0) {
+        WOLFSSL_MSG("Session cache mutex lock failed");
+        XFCLOSE(file);
+        return BAD_MUTEX_E;
+    }
+
+    /* session cache */
+    for (i = 0; i < cache_header.rows; ++i) {
+        ret = (int)XFREAD(SessionCache + i, sizeof(SessionRow), 1, file);
+        if (ret != 1) {
+            WOLFSSL_MSG("Session cache member file read failed");
+            XMEMSET(SessionCache, 0, sizeof SessionCache);
+            rc = FREAD_ERROR;
+            break;
+        }
+    }
+
+#ifndef NO_CLIENT_CACHE
+    /* client cache */
+    for (i = 0; i < cache_header.rows; ++i) {
+        ret = (int)XFREAD(ClientCache + i, sizeof(ClientRow), 1, file);
+        if (ret != 1) {
+            WOLFSSL_MSG("Client cache member file read failed");
+            XMEMSET(ClientCache, 0, sizeof ClientCache);
+            rc = FREAD_ERROR;
+            break;
+        }
+    }
+
+#endif /* NO_CLIENT_CACHE */
+
+    UnLockMutex(&session_mutex);
+
+    XFCLOSE(file);
+    WOLFSSL_LEAVE("wolfSSL_restore_session_cache", rc);
+
+    return rc;
+}
+
+#endif /* !NO_FILESYSTEM */
+#endif /* PERSIST_SESSION_CACHE */
+#endif /* NO_SESSION_CACHE */
+
+
+void wolfSSL_load_error_strings(void)   /* compatibility only */
+{}
+
+
+int wolfSSL_library_init(void)
+{
+    WOLFSSL_ENTER("SSL_library_init");
+    if (wolfSSL_Init() == SSL_SUCCESS)
+        return SSL_SUCCESS;
+    else
+        return SSL_FATAL_ERROR;
+}
+
+
+#ifdef HAVE_SECRET_CALLBACK
+
+int wolfSSL_set_session_secret_cb(WOLFSSL* ssl, SessionSecretCb cb, void* ctx)
+{
+    WOLFSSL_ENTER("wolfSSL_set_session_secret_cb");
+    if (ssl == NULL)
+        return SSL_FATAL_ERROR;
+
+    ssl->sessionSecretCb = cb;
+    ssl->sessionSecretCtx = ctx;
+    /* If using a pre-set key, assume session resumption. */
+    ssl->session.sessionIDSz = 0;
+    ssl->options.resuming = 1;
+
+    return SSL_SUCCESS;
+}
+
+#endif
+
+
+#ifndef NO_SESSION_CACHE
+
+/* on by default if built in but allow user to turn off */
+long wolfSSL_CTX_set_session_cache_mode(WOLFSSL_CTX* ctx, long mode)
+{
+    WOLFSSL_ENTER("SSL_CTX_set_session_cache_mode");
+    if (mode == SSL_SESS_CACHE_OFF)
+        ctx->sessionCacheOff = 1;
+
+    if (mode == SSL_SESS_CACHE_NO_AUTO_CLEAR)
+        ctx->sessionCacheFlushOff = 1;
+
+    return SSL_SUCCESS;
+}
+
+#endif /* NO_SESSION_CACHE */
+
+
+#if !defined(NO_CERTS)
+#if defined(PERSIST_CERT_CACHE)
+
+
+#define WOLFSSL_CACHE_CERT_VERSION 1
+
+typedef struct {
+    int version;                 /* cache cert layout version id */
+    int rows;                    /* hash table rows, CA_TABLE_SIZE */
+    int columns[CA_TABLE_SIZE];  /* columns per row on list */
+    int signerSz;                /* sizeof Signer object */
+} CertCacheHeader;
+
+/* current cert persistance layout is:
+
+   1) CertCacheHeader
+   2) caTable
+
+   update WOLFSSL_CERT_CACHE_VERSION if change layout for the following
+   PERSIST_CERT_CACHE functions
+*/
+
+
+/* Return memory needed to persist this signer, have lock */
+static INLINE int GetSignerMemory(Signer* signer)
+{
+    int sz = sizeof(signer->pubKeySize) + sizeof(signer->keyOID)
+           + sizeof(signer->nameLen)    + sizeof(signer->subjectNameHash);
+
+#if !defined(NO_SKID)
+        sz += (int)sizeof(signer->subjectKeyIdHash);
+#endif
+
+    /* add dynamic bytes needed */
+    sz += signer->pubKeySize;
+    sz += signer->nameLen;
+
+    return sz;
+}
+
+
+/* Return memory needed to persist this row, have lock */
+static INLINE int GetCertCacheRowMemory(Signer* row)
+{
+    int sz = 0;
+
+    while (row) {
+        sz += GetSignerMemory(row);
+        row = row->next;
+    }
+
+    return sz;
+}
+
+
+/* get the size of persist cert cache, have lock */
+static INLINE int GetCertCacheMemSize(WOLFSSL_CERT_MANAGER* cm)
+{
+    int sz;
+    int i;
+
+    sz = sizeof(CertCacheHeader);
+
+    for (i = 0; i < CA_TABLE_SIZE; i++)
+        sz += GetCertCacheRowMemory(cm->caTable[i]);
+
+    return sz;
+}
+
+
+/* Store cert cache header columns with number of items per list, have lock */
+static INLINE void SetCertHeaderColumns(WOLFSSL_CERT_MANAGER* cm, int* columns)
+{
+    int     i;
+    Signer* row;
+
+    for (i = 0; i < CA_TABLE_SIZE; i++) {
+        int count = 0;
+        row = cm->caTable[i];
+
+        while (row) {
+            ++count;
+            row = row->next;
+        }
+        columns[i] = count;
+    }
+}
+
+
+/* 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,
+                                 int row, int listSz, const byte* end)
+{
+    int idx = 0;
+
+    if (listSz < 0) {
+        WOLFSSL_MSG("Row header corrupted, negative value");
+        return PARSE_ERROR;
+    }
+
+    while (listSz) {
+        Signer* signer;
+        byte*   start = current + idx;  /* for end checks on this signer */
+        int     minSz = sizeof(signer->pubKeySize) + sizeof(signer->keyOID) +
+                      sizeof(signer->nameLen) + sizeof(signer->subjectNameHash);
+        #ifndef NO_SKID
+                minSz += (int)sizeof(signer->subjectKeyIdHash);
+        #endif
+
+        if (start + minSz > end) {
+            WOLFSSL_MSG("Would overread restore buffer");
+            return BUFFER_E;
+        }
+        signer = MakeSigner(cm->heap);
+        if (signer == NULL)
+            return MEMORY_E;
+
+        /* pubKeySize */
+        XMEMCPY(&signer->pubKeySize, current + idx, sizeof(signer->pubKeySize));
+        idx += (int)sizeof(signer->pubKeySize);
+
+        /* keyOID */
+        XMEMCPY(&signer->keyOID, current + idx, sizeof(signer->keyOID));
+        idx += (int)sizeof(signer->keyOID);
+
+        /* pulicKey */
+        if (start + minSz + signer->pubKeySize > end) {
+            WOLFSSL_MSG("Would overread restore buffer");
+            FreeSigner(signer, cm->heap);
+            return BUFFER_E;
+        }
+        signer->publicKey = (byte*)XMALLOC(signer->pubKeySize, cm->heap,
+                                           DYNAMIC_TYPE_KEY);
+        if (signer->publicKey == NULL) {
+            FreeSigner(signer, cm->heap);
+            return MEMORY_E;
+        }
+
+        XMEMCPY(signer->publicKey, current + idx, signer->pubKeySize);
+        idx += signer->pubKeySize;
+
+        /* nameLen */
+        XMEMCPY(&signer->nameLen, current + idx, sizeof(signer->nameLen));
+        idx += (int)sizeof(signer->nameLen);
+
+        /* name */
+        if (start + minSz + signer->pubKeySize + signer->nameLen > end) {
+            WOLFSSL_MSG("Would overread restore buffer");
+            FreeSigner(signer, cm->heap);
+            return BUFFER_E;
+        }
+        signer->name = (char*)XMALLOC(signer->nameLen, cm->heap,
+                                      DYNAMIC_TYPE_SUBJECT_CN);
+        if (signer->name == NULL) {
+            FreeSigner(signer, cm->heap);
+            return MEMORY_E;
+        }
+
+        XMEMCPY(signer->name, current + idx, signer->nameLen);
+        idx += signer->nameLen;
+
+        /* subjectNameHash */
+        XMEMCPY(signer->subjectNameHash, current + idx, SIGNER_DIGEST_SIZE);
+        idx += SIGNER_DIGEST_SIZE;
+
+        #ifndef NO_SKID
+            /* subjectKeyIdHash */
+            XMEMCPY(signer->subjectKeyIdHash, current + idx,SIGNER_DIGEST_SIZE);
+            idx += SIGNER_DIGEST_SIZE;
+        #endif
+
+        signer->next = cm->caTable[row];
+        cm->caTable[row] = signer;
+
+        --listSz;
+    }
+
+    return idx;
+}
+
+
+/* Store whole cert row into memory, have lock, return bytes added */
+static INLINE int StoreCertRow(WOLFSSL_CERT_MANAGER* cm, byte* current, int row)
+{
+    int     added  = 0;
+    Signer* list   = cm->caTable[row];
+
+    while (list) {
+        XMEMCPY(current + added, &list->pubKeySize, sizeof(list->pubKeySize));
+        added += (int)sizeof(list->pubKeySize);
+
+        XMEMCPY(current + added, &list->keyOID,     sizeof(list->keyOID));
+        added += (int)sizeof(list->keyOID);
+
+        XMEMCPY(current + added, list->publicKey, list->pubKeySize);
+        added += list->pubKeySize;
+
+        XMEMCPY(current + added, &list->nameLen, sizeof(list->nameLen));
+        added += (int)sizeof(list->nameLen);
+
+        XMEMCPY(current + added, list->name, list->nameLen);
+        added += list->nameLen;
+
+        XMEMCPY(current + added, list->subjectNameHash, SIGNER_DIGEST_SIZE);
+        added += SIGNER_DIGEST_SIZE;
+
+        #ifndef NO_SKID
+            XMEMCPY(current + added, list->subjectKeyIdHash,SIGNER_DIGEST_SIZE);
+            added += SIGNER_DIGEST_SIZE;
+        #endif
+
+        list = list->next;
+    }
+
+    return added;
+}
+
+
+/* Persist cert cache to memory, have lock */
+static INLINE int DoMemSaveCertCache(WOLFSSL_CERT_MANAGER* cm, void* mem, int sz)
+{
+    int realSz;
+    int ret = SSL_SUCCESS;
+    int i;
+
+    WOLFSSL_ENTER("DoMemSaveCertCache");
+
+    realSz = GetCertCacheMemSize(cm);
+    if (realSz > sz) {
+        WOLFSSL_MSG("Mem output buffer too small");
+        ret = BUFFER_E;
+    }
+    else {
+        byte*           current;
+        CertCacheHeader hdr;
+
+        hdr.version  = WOLFSSL_CACHE_CERT_VERSION;
+        hdr.rows     = CA_TABLE_SIZE;
+        SetCertHeaderColumns(cm, hdr.columns);
+        hdr.signerSz = (int)sizeof(Signer);
+
+        XMEMCPY(mem, &hdr, sizeof(CertCacheHeader));
+        current = (byte*)mem + sizeof(CertCacheHeader);
+
+        for (i = 0; i < CA_TABLE_SIZE; ++i)
+            current += StoreCertRow(cm, current, i);
+    }
+
+    return ret;
+}
+
+
+#if !defined(NO_FILESYSTEM)
+
+/* Persist cert cache to file */
+int CM_SaveCertCache(WOLFSSL_CERT_MANAGER* cm, const char* fname)
+{
+    XFILE file;
+    int   rc = SSL_SUCCESS;
+    int   memSz;
+    byte* mem;
+
+    WOLFSSL_ENTER("CM_SaveCertCache");
+
+    file = XFOPEN(fname, "w+b");
+    if (file == XBADFILE) {
+       WOLFSSL_MSG("Couldn't open cert cache save file");
+       return SSL_BAD_FILE;
+    }
+
+    if (LockMutex(&cm->caLock) != 0) {
+        WOLFSSL_MSG("LockMutex on caLock failed");
+        XFCLOSE(file);
+        return BAD_MUTEX_E;
+    }
+
+    memSz = GetCertCacheMemSize(cm);
+    mem   = (byte*)XMALLOC(memSz, cm->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (mem == NULL) {
+        WOLFSSL_MSG("Alloc for tmp buffer failed");
+        rc = MEMORY_E;
+    } else {
+        rc = DoMemSaveCertCache(cm, mem, memSz);
+        if (rc == SSL_SUCCESS) {
+            int ret = (int)XFWRITE(mem, memSz, 1, file);
+            if (ret != 1) {
+                WOLFSSL_MSG("Cert cache file write failed");
+                rc = FWRITE_ERROR;
+            }
+        }
+        XFREE(mem, cm->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    }
+
+    UnLockMutex(&cm->caLock);
+    XFCLOSE(file);
+
+    return rc;
+}
+
+
+/* Restore cert cache from file */
+int CM_RestoreCertCache(WOLFSSL_CERT_MANAGER* cm, const char* fname)
+{
+    XFILE file;
+    int   rc = SSL_SUCCESS;
+    int   ret;
+    int   memSz;
+    byte* mem;
+
+    WOLFSSL_ENTER("CM_RestoreCertCache");
+
+    file = XFOPEN(fname, "rb");
+    if (file == XBADFILE) {
+       WOLFSSL_MSG("Couldn't open cert cache save file");
+       return SSL_BAD_FILE;
+    }
+
+    XFSEEK(file, 0, XSEEK_END);
+    memSz = (int)XFTELL(file);
+    XREWIND(file);
+
+    if (memSz <= 0) {
+        WOLFSSL_MSG("Bad file size");
+        XFCLOSE(file);
+        return SSL_BAD_FILE;
+    }
+
+    mem = (byte*)XMALLOC(memSz, cm->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (mem == NULL) {
+        WOLFSSL_MSG("Alloc for tmp buffer failed");
+        XFCLOSE(file);
+        return MEMORY_E;
+    }
+
+    ret = (int)XFREAD(mem, memSz, 1, file);
+    if (ret != 1) {
+        WOLFSSL_MSG("Cert file read error");
+        rc = FREAD_ERROR;
+    } else {
+        rc = CM_MemRestoreCertCache(cm, mem, memSz);
+        if (rc != SSL_SUCCESS) {
+            WOLFSSL_MSG("Mem restore cert cache failed");
+        }
+    }
+
+    XFREE(mem, cm->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    XFCLOSE(file);
+
+    return rc;
+}
+
+#endif /* NO_FILESYSTEM */
+
+
+/* Persist cert cache to memory */
+int CM_MemSaveCertCache(WOLFSSL_CERT_MANAGER* cm, void* mem, int sz, int* used)
+{
+    int ret = SSL_SUCCESS;
+
+    WOLFSSL_ENTER("CM_MemSaveCertCache");
+
+    if (LockMutex(&cm->caLock) != 0) {
+        WOLFSSL_MSG("LockMutex on caLock failed");
+        return BAD_MUTEX_E;
+    }
+
+    ret = DoMemSaveCertCache(cm, mem, sz);
+    if (ret == SSL_SUCCESS)
+        *used  = GetCertCacheMemSize(cm);
+
+    UnLockMutex(&cm->caLock);
+
+    return ret;
+}
+
+
+/* Restore cert cache from memory */
+int CM_MemRestoreCertCache(WOLFSSL_CERT_MANAGER* cm, const void* mem, int sz)
+{
+    int ret = SSL_SUCCESS;
+    int i;
+    CertCacheHeader* hdr = (CertCacheHeader*)mem;
+    byte*            current = (byte*)mem + sizeof(CertCacheHeader);
+    byte*            end     = (byte*)mem + sz;  /* don't go over */
+
+    WOLFSSL_ENTER("CM_MemRestoreCertCache");
+
+    if (current > end) {
+        WOLFSSL_MSG("Cert Cache Memory buffer too small");
+        return BUFFER_E;
+    }
+
+    if (hdr->version  != WOLFSSL_CACHE_CERT_VERSION ||
+        hdr->rows     != CA_TABLE_SIZE ||
+        hdr->signerSz != (int)sizeof(Signer)) {
+
+        WOLFSSL_MSG("Cert Cache Memory header mismatch");
+        return CACHE_MATCH_ERROR;
+    }
+
+    if (LockMutex(&cm->caLock) != 0) {
+        WOLFSSL_MSG("LockMutex on caLock failed");
+        return BAD_MUTEX_E;
+    }
+
+    FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap);
+
+    for (i = 0; i < CA_TABLE_SIZE; ++i) {
+        int added = RestoreCertRow(cm, current, i, hdr->columns[i], end);
+        if (added < 0) {
+            WOLFSSL_MSG("RestoreCertRow error");
+            ret = added;
+            break;
+        }
+        current += added;
+    }
+
+    UnLockMutex(&cm->caLock);
+
+    return ret;
+}
+
+
+/* get how big the the cert cache save buffer needs to be */
+int CM_GetCertCacheMemSize(WOLFSSL_CERT_MANAGER* cm)
+{
+    int sz;
+
+    WOLFSSL_ENTER("CM_GetCertCacheMemSize");
+
+    if (LockMutex(&cm->caLock) != 0) {
+        WOLFSSL_MSG("LockMutex on caLock failed");
+        return BAD_MUTEX_E;
+    }
+
+    sz = GetCertCacheMemSize(cm);
+
+    UnLockMutex(&cm->caLock);
+
+    return sz;
+}
+
+#endif /* PERSIST_CERT_CACHE */
+#endif /* NO_CERTS */
+
+
+int wolfSSL_CTX_set_cipher_list(WOLFSSL_CTX* ctx, const char* list)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_set_cipher_list");
+
+    /* alloc/init on demand only */
+    if (ctx->suites == NULL) {
+        ctx->suites = (Suites*)XMALLOC(sizeof(Suites), ctx->heap,
+                                       DYNAMIC_TYPE_SUITES);
+        if (ctx->suites == NULL) {
+            WOLFSSL_MSG("Memory alloc for Suites failed");
+            return SSL_FAILURE;
+        }
+        XMEMSET(ctx->suites, 0, sizeof(Suites));
+    }
+
+    return (SetCipherList(ctx->suites, list)) ? SSL_SUCCESS : SSL_FAILURE;
+}
+
+
+int wolfSSL_set_cipher_list(WOLFSSL* ssl, const char* list)
+{
+    WOLFSSL_ENTER("wolfSSL_set_cipher_list");
+    return (SetCipherList(ssl->suites, list)) ? SSL_SUCCESS : SSL_FAILURE;
+}
+
+
+#ifndef WOLFSSL_LEANPSK
+#ifdef WOLFSSL_DTLS
+
+int wolfSSL_dtls_get_current_timeout(WOLFSSL* ssl)
+{
+    (void)ssl;
+
+    return ssl->dtls_timeout;
+}
+
+
+/* user may need to alter init dtls recv timeout, SSL_SUCCESS on ok */
+int wolfSSL_dtls_set_timeout_init(WOLFSSL* ssl, int timeout)
+{
+    if (ssl == NULL || timeout < 0)
+        return BAD_FUNC_ARG;
+
+    if (timeout > ssl->dtls_timeout_max) {
+        WOLFSSL_MSG("Can't set dtls timeout init greater than dtls timeout max");
+        return BAD_FUNC_ARG;
+    }
+
+    ssl->dtls_timeout_init = timeout;
+    ssl->dtls_timeout = timeout;
+
+    return SSL_SUCCESS;
+}
+
+
+/* user may need to alter max dtls recv timeout, SSL_SUCCESS on ok */
+int wolfSSL_dtls_set_timeout_max(WOLFSSL* ssl, int timeout)
+{
+    if (ssl == NULL || timeout < 0)
+        return BAD_FUNC_ARG;
+
+    if (timeout < ssl->dtls_timeout_init) {
+        WOLFSSL_MSG("Can't set dtls timeout max less than dtls timeout init");
+        return BAD_FUNC_ARG;
+    }
+
+    ssl->dtls_timeout_max = timeout;
+
+    return SSL_SUCCESS;
+}
+
+
+int wolfSSL_dtls_got_timeout(WOLFSSL* ssl)
+{
+    int result = SSL_SUCCESS;
+
+    DtlsMsgListDelete(ssl->dtls_msg_list, ssl->heap);
+    ssl->dtls_msg_list = NULL;
+    if (DtlsPoolTimeout(ssl) < 0 || DtlsPoolSend(ssl) < 0) {
+        result = SSL_FATAL_ERROR;
+    }
+    return result;
+}
+
+#endif /* DTLS */
+#endif /* LEANPSK */
+
+
+/* client only parts */
+#ifndef NO_WOLFSSL_CLIENT
+
+    #ifndef NO_OLD_TLS
+    WOLFSSL_METHOD* wolfSSLv3_client_method(void)
+    {
+        WOLFSSL_METHOD* method =
+                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+        WOLFSSL_ENTER("SSLv3_client_method");
+        if (method)
+            InitSSL_Method(method, MakeSSLv3());
+        return method;
+    }
+    #endif
+
+    #ifdef WOLFSSL_DTLS
+
+        #ifndef NO_OLD_TLS
+        WOLFSSL_METHOD* wolfDTLSv1_client_method(void)
+        {
+            WOLFSSL_METHOD* method =
+                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+            WOLFSSL_ENTER("DTLSv1_client_method");
+            if (method)
+                InitSSL_Method(method, MakeDTLSv1());
+            return method;
+        }
+        #endif  /* NO_OLD_TLS */
+
+        WOLFSSL_METHOD* wolfDTLSv1_2_client_method(void)
+        {
+            WOLFSSL_METHOD* method =
+                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+            WOLFSSL_ENTER("DTLSv1_2_client_method");
+            if (method)
+                InitSSL_Method(method, MakeDTLSv1_2());
+            return method;
+        }
+    #endif
+
+
+    /* please see note at top of README if you get an error from connect */
+    int wolfSSL_connect(WOLFSSL* ssl)
+    {
+        int neededState;
+
+        WOLFSSL_ENTER("SSL_connect()");
+
+        #ifdef HAVE_ERRNO_H
+            errno = 0;
+        #endif
+
+        if (ssl->options.side != WOLFSSL_CLIENT_END) {
+            WOLFSSL_ERROR(ssl->error = SIDE_ERROR);
+            return SSL_FATAL_ERROR;
+        }
+
+        #ifdef WOLFSSL_DTLS
+            if (ssl->version.major == DTLS_MAJOR) {
+                ssl->options.dtls   = 1;
+                ssl->options.tls    = 1;
+                ssl->options.tls1_1 = 1;
+
+                if (DtlsPoolInit(ssl) != 0) {
+                    ssl->error = MEMORY_ERROR;
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            }
+        #endif
+
+        if (ssl->buffers.outputBuffer.length > 0) {
+            if ( (ssl->error = SendBuffered(ssl)) == 0) {
+                ssl->options.connectState++;
+                WOLFSSL_MSG("connect state: Advanced from buffered send");
+            }
+            else {
+                WOLFSSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+        }
+
+        switch (ssl->options.connectState) {
+
+        case CONNECT_BEGIN :
+            /* always send client hello first */
+            if ( (ssl->error = SendClientHello(ssl)) != 0) {
+                WOLFSSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.connectState = CLIENT_HELLO_SENT;
+            WOLFSSL_MSG("connect state: CLIENT_HELLO_SENT");
+
+        case CLIENT_HELLO_SENT :
+            neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE :
+                                          SERVER_HELLODONE_COMPLETE;
+            #ifdef WOLFSSL_DTLS
+                /* In DTLS, when resuming, we can go straight to FINISHED,
+                 * or do a cookie exchange and then skip to FINISHED, assume
+                 * we need the cookie exchange first. */
+                if (ssl->options.dtls)
+                    neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE;
+            #endif
+            /* get response */
+            while (ssl->options.serverState < neededState) {
+                if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+                /* if resumption failed, reset needed state */
+                else if (neededState == SERVER_FINISHED_COMPLETE)
+                    if (!ssl->options.resuming) {
+                        if (!ssl->options.dtls)
+                            neededState = SERVER_HELLODONE_COMPLETE;
+                        else
+                            neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE;
+                    }
+            }
+
+            ssl->options.connectState = HELLO_AGAIN;
+            WOLFSSL_MSG("connect state: HELLO_AGAIN");
+
+        case HELLO_AGAIN :
+            if (ssl->options.certOnly)
+                return SSL_SUCCESS;
+
+            #ifdef WOLFSSL_DTLS
+                if (ssl->options.dtls) {
+                    /* re-init hashes, exclude first hello and verify request */
+#ifndef NO_OLD_TLS
+                    wc_InitMd5(&ssl->hsHashes->hashMd5);
+                    if ( (ssl->error = wc_InitSha(&ssl->hsHashes->hashSha))
+                                                                         != 0) {
+                        WOLFSSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+#endif
+                    if (IsAtLeastTLSv1_2(ssl)) {
+                        #ifndef NO_SHA256
+                            if ( (ssl->error = wc_InitSha256(
+                                            &ssl->hsHashes->hashSha256)) != 0) {
+                                WOLFSSL_ERROR(ssl->error);
+                                return SSL_FATAL_ERROR;
+                            }
+                        #endif
+                        #ifdef WOLFSSL_SHA384
+                            if ( (ssl->error = wc_InitSha384(
+                                            &ssl->hsHashes->hashSha384)) != 0) {
+                                WOLFSSL_ERROR(ssl->error);
+                                return SSL_FATAL_ERROR;
+                            }
+                        #endif
+                        #ifdef WOLFSSL_SHA512
+                            if ( (ssl->error = wc_InitSha512(
+                                            &ssl->hsHashes->hashSha512)) != 0) {
+                                WOLFSSL_ERROR(ssl->error);
+                                return SSL_FATAL_ERROR;
+                            }
+                        #endif
+                    }
+                    if ( (ssl->error = SendClientHello(ssl)) != 0) {
+                        WOLFSSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+                }
+            #endif
+
+            ssl->options.connectState = HELLO_AGAIN_REPLY;
+            WOLFSSL_MSG("connect state: HELLO_AGAIN_REPLY");
+
+        case HELLO_AGAIN_REPLY :
+            #ifdef WOLFSSL_DTLS
+                if (ssl->options.dtls) {
+                    neededState = ssl->options.resuming ?
+                           SERVER_FINISHED_COMPLETE : SERVER_HELLODONE_COMPLETE;
+
+                    /* get response */
+                    while (ssl->options.serverState < neededState) {
+                        if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                                WOLFSSL_ERROR(ssl->error);
+                                return SSL_FATAL_ERROR;
+                        }
+                        /* if resumption failed, reset needed state */
+                        else if (neededState == SERVER_FINISHED_COMPLETE)
+                            if (!ssl->options.resuming)
+                                neededState = SERVER_HELLODONE_COMPLETE;
+                    }
+                }
+            #endif
+
+            ssl->options.connectState = FIRST_REPLY_DONE;
+            WOLFSSL_MSG("connect state: FIRST_REPLY_DONE");
+
+        case FIRST_REPLY_DONE :
+            #ifndef NO_CERTS
+                if (ssl->options.sendVerify) {
+                    if ( (ssl->error = SendCertificate(ssl)) != 0) {
+                        WOLFSSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+                    WOLFSSL_MSG("sent: certificate");
+                }
+
+            #endif
+            ssl->options.connectState = FIRST_REPLY_FIRST;
+            WOLFSSL_MSG("connect state: FIRST_REPLY_FIRST");
+
+        case FIRST_REPLY_FIRST :
+            if (!ssl->options.resuming) {
+                if ( (ssl->error = SendClientKeyExchange(ssl)) != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+                WOLFSSL_MSG("sent: client key exchange");
+            }
+
+            ssl->options.connectState = FIRST_REPLY_SECOND;
+            WOLFSSL_MSG("connect state: FIRST_REPLY_SECOND");
+
+        case FIRST_REPLY_SECOND :
+            #ifndef NO_CERTS
+                if (ssl->options.sendVerify) {
+                    if ( (ssl->error = SendCertificateVerify(ssl)) != 0) {
+                        WOLFSSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+                    WOLFSSL_MSG("sent: certificate verify");
+                }
+            #endif
+            ssl->options.connectState = FIRST_REPLY_THIRD;
+            WOLFSSL_MSG("connect state: FIRST_REPLY_THIRD");
+
+        case FIRST_REPLY_THIRD :
+            if ( (ssl->error = SendChangeCipher(ssl)) != 0) {
+                WOLFSSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            WOLFSSL_MSG("sent: change cipher spec");
+            ssl->options.connectState = FIRST_REPLY_FOURTH;
+            WOLFSSL_MSG("connect state: FIRST_REPLY_FOURTH");
+
+        case FIRST_REPLY_FOURTH :
+            if ( (ssl->error = SendFinished(ssl)) != 0) {
+                WOLFSSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            WOLFSSL_MSG("sent: finished");
+            ssl->options.connectState = FINISHED_DONE;
+            WOLFSSL_MSG("connect state: FINISHED_DONE");
+
+        case FINISHED_DONE :
+            /* get response */
+            while (ssl->options.serverState < SERVER_FINISHED_COMPLETE)
+                if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+
+            ssl->options.connectState = SECOND_REPLY_DONE;
+            WOLFSSL_MSG("connect state: SECOND_REPLY_DONE");
+
+        case SECOND_REPLY_DONE:
+#ifndef NO_HANDSHAKE_DONE_CB
+            if (ssl->hsDoneCb) {
+                int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx);
+                if (cbret < 0) {
+                    ssl->error = cbret;
+                    WOLFSSL_MSG("HandShake Done Cb don't continue error");
+                    return SSL_FATAL_ERROR;
+                }
+            }
+#endif /* NO_HANDSHAKE_DONE_CB */
+            FreeHandshakeResources(ssl);
+            WOLFSSL_LEAVE("SSL_connect()", SSL_SUCCESS);
+            return SSL_SUCCESS;
+
+        default:
+            WOLFSSL_MSG("Unknown connect state ERROR");
+            return SSL_FATAL_ERROR; /* unknown connect state */
+        }
+    }
+
+#endif /* NO_WOLFSSL_CLIENT */
+
+
+/* server only parts */
+#ifndef NO_WOLFSSL_SERVER
+
+    #ifndef NO_OLD_TLS
+    WOLFSSL_METHOD* wolfSSLv3_server_method(void)
+    {
+        WOLFSSL_METHOD* method =
+                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+        WOLFSSL_ENTER("SSLv3_server_method");
+        if (method) {
+            InitSSL_Method(method, MakeSSLv3());
+            method->side = WOLFSSL_SERVER_END;
+        }
+        return method;
+    }
+    #endif
+
+
+    #ifdef WOLFSSL_DTLS
+
+        #ifndef NO_OLD_TLS
+        WOLFSSL_METHOD* wolfDTLSv1_server_method(void)
+        {
+            WOLFSSL_METHOD* method =
+                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+                                                        0, DYNAMIC_TYPE_METHOD);
+            WOLFSSL_ENTER("DTLSv1_server_method");
+            if (method) {
+                InitSSL_Method(method, MakeDTLSv1());
+                method->side = WOLFSSL_SERVER_END;
+            }
+            return method;
+        }
+        #endif /* NO_OLD_TLS */
+
+        WOLFSSL_METHOD* wolfDTLSv1_2_server_method(void)
+        {
+            WOLFSSL_METHOD* method =
+                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+                                                        0, DYNAMIC_TYPE_METHOD);
+            WOLFSSL_ENTER("DTLSv1_2_server_method");
+            if (method) {
+                InitSSL_Method(method, MakeDTLSv1_2());
+                method->side = WOLFSSL_SERVER_END;
+            }
+            return method;
+        }
+    #endif
+
+
+    int wolfSSL_accept(WOLFSSL* ssl)
+    {
+        byte havePSK = 0;
+        byte haveAnon = 0;
+        WOLFSSL_ENTER("SSL_accept()");
+
+        #ifdef HAVE_ERRNO_H
+            errno = 0;
+        #endif
+
+        #ifndef NO_PSK
+            havePSK = ssl->options.havePSK;
+        #endif
+        (void)havePSK;
+
+        #ifdef HAVE_ANON
+            haveAnon = ssl->options.haveAnon;
+        #endif
+        (void)haveAnon;
+
+        if (ssl->options.side != WOLFSSL_SERVER_END) {
+            WOLFSSL_ERROR(ssl->error = SIDE_ERROR);
+            return SSL_FATAL_ERROR;
+        }
+
+        #ifndef NO_CERTS
+            /* in case used set_accept_state after init */
+            if (!havePSK && !haveAnon &&
+                            (ssl->buffers.certificate.buffer == NULL ||
+                             ssl->buffers.key.buffer == NULL)) {
+                WOLFSSL_MSG("accept error: don't have server cert and key");
+                ssl->error = NO_PRIVATE_KEY;
+                WOLFSSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+        #endif
+
+        #ifdef WOLFSSL_DTLS
+            if (ssl->version.major == DTLS_MAJOR) {
+                ssl->options.dtls   = 1;
+                ssl->options.tls    = 1;
+                ssl->options.tls1_1 = 1;
+
+                if (DtlsPoolInit(ssl) != 0) {
+                    ssl->error = MEMORY_ERROR;
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            }
+        #endif
+
+        if (ssl->buffers.outputBuffer.length > 0) {
+            if ( (ssl->error = SendBuffered(ssl)) == 0) {
+                ssl->options.acceptState++;
+                WOLFSSL_MSG("accept state: Advanced from buffered send");
+            }
+            else {
+                WOLFSSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+        }
+
+        switch (ssl->options.acceptState) {
+
+        case ACCEPT_BEGIN :
+            /* get response */
+            while (ssl->options.clientState < CLIENT_HELLO_COMPLETE)
+                if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            ssl->options.acceptState = ACCEPT_CLIENT_HELLO_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE");
+
+        case ACCEPT_CLIENT_HELLO_DONE :
+            #ifdef WOLFSSL_DTLS
+                if (ssl->options.dtls)
+                    if ( (ssl->error = SendHelloVerifyRequest(ssl)) != 0) {
+                        WOLFSSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+            #endif
+            ssl->options.acceptState = HELLO_VERIFY_SENT;
+            WOLFSSL_MSG("accept state HELLO_VERIFY_SENT");
+
+        case HELLO_VERIFY_SENT:
+            #ifdef WOLFSSL_DTLS
+                if (ssl->options.dtls) {
+                    ssl->options.clientState = NULL_STATE;  /* get again */
+                    /* reset messages received */
+                    XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived));
+                    /* re-init hashes, exclude first hello and verify request */
+#ifndef NO_OLD_TLS
+                    wc_InitMd5(&ssl->hsHashes->hashMd5);
+                    if ( (ssl->error = wc_InitSha(&ssl->hsHashes->hashSha))
+                                                                         != 0) {
+                        WOLFSSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+#endif
+                    if (IsAtLeastTLSv1_2(ssl)) {
+                        #ifndef NO_SHA256
+                            if ( (ssl->error = wc_InitSha256(
+                                            &ssl->hsHashes->hashSha256)) != 0) {
+                               WOLFSSL_ERROR(ssl->error);
+                               return SSL_FATAL_ERROR;
+                            }
+                        #endif
+                        #ifdef WOLFSSL_SHA384
+                            if ( (ssl->error = wc_InitSha384(
+                                            &ssl->hsHashes->hashSha384)) != 0) {
+                               WOLFSSL_ERROR(ssl->error);
+                               return SSL_FATAL_ERROR;
+                            }
+                        #endif
+                        #ifdef WOLFSSL_SHA512
+                            if ( (ssl->error = wc_InitSha512(
+                                            &ssl->hsHashes->hashSha512)) != 0) {
+                               WOLFSSL_ERROR(ssl->error);
+                               return SSL_FATAL_ERROR;
+                            }
+                        #endif
+                    }
+
+                    while (ssl->options.clientState < CLIENT_HELLO_COMPLETE)
+                        if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                            WOLFSSL_ERROR(ssl->error);
+                            return SSL_FATAL_ERROR;
+                        }
+                }
+            #endif
+            ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE");
+
+        case ACCEPT_FIRST_REPLY_DONE :
+            if ( (ssl->error = SendServerHello(ssl)) != 0) {
+                WOLFSSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.acceptState = SERVER_HELLO_SENT;
+            WOLFSSL_MSG("accept state SERVER_HELLO_SENT");
+
+        case SERVER_HELLO_SENT :
+            #ifndef NO_CERTS
+                if (!ssl->options.resuming)
+                    if ( (ssl->error = SendCertificate(ssl)) != 0) {
+                        WOLFSSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+            #endif
+            ssl->options.acceptState = CERT_SENT;
+            WOLFSSL_MSG("accept state CERT_SENT");
+
+        case CERT_SENT :
+            if (!ssl->options.resuming)
+                if ( (ssl->error = SendServerKeyExchange(ssl)) != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            ssl->options.acceptState = KEY_EXCHANGE_SENT;
+            WOLFSSL_MSG("accept state KEY_EXCHANGE_SENT");
+
+        case KEY_EXCHANGE_SENT :
+            #ifndef NO_CERTS
+                if (!ssl->options.resuming)
+                    if (ssl->options.verifyPeer)
+                        if ( (ssl->error = SendCertificateRequest(ssl)) != 0) {
+                            WOLFSSL_ERROR(ssl->error);
+                            return SSL_FATAL_ERROR;
+                        }
+            #endif
+            ssl->options.acceptState = CERT_REQ_SENT;
+            WOLFSSL_MSG("accept state CERT_REQ_SENT");
+
+        case CERT_REQ_SENT :
+            if (!ssl->options.resuming)
+                if ( (ssl->error = SendServerHelloDone(ssl)) != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            ssl->options.acceptState = SERVER_HELLO_DONE;
+            WOLFSSL_MSG("accept state SERVER_HELLO_DONE");
+
+        case SERVER_HELLO_DONE :
+            if (!ssl->options.resuming) {
+                while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE)
+                    if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                        WOLFSSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+            }
+            ssl->options.acceptState = ACCEPT_SECOND_REPLY_DONE;
+            WOLFSSL_MSG("accept state  ACCEPT_SECOND_REPLY_DONE");
+
+        case ACCEPT_SECOND_REPLY_DONE :
+#ifdef HAVE_SESSION_TICKET
+            if (ssl->options.createTicket) {
+                if ( (ssl->error = SendTicket(ssl)) != 0) {
+                    WOLFSSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            }
+#endif /* HAVE_SESSION_TICKET */
+            ssl->options.acceptState = TICKET_SENT;
+            WOLFSSL_MSG("accept state  TICKET_SENT");
+
+        case TICKET_SENT:
+            if ( (ssl->error = SendChangeCipher(ssl)) != 0) {
+                WOLFSSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.acceptState = CHANGE_CIPHER_SENT;
+            WOLFSSL_MSG("accept state  CHANGE_CIPHER_SENT");
+
+        case CHANGE_CIPHER_SENT :
+            if ( (ssl->error = SendFinished(ssl)) != 0) {
+                WOLFSSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+
+            ssl->options.acceptState = ACCEPT_FINISHED_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_FINISHED_DONE");
+
+        case ACCEPT_FINISHED_DONE :
+            if (ssl->options.resuming)
+                while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE)
+                    if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                        WOLFSSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+
+            ssl->options.acceptState = ACCEPT_THIRD_REPLY_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_THIRD_REPLY_DONE");
+
+        case ACCEPT_THIRD_REPLY_DONE :
+#ifndef NO_HANDSHAKE_DONE_CB
+            if (ssl->hsDoneCb) {
+                int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx);
+                if (cbret < 0) {
+                    ssl->error = cbret;
+                    WOLFSSL_MSG("HandShake Done Cb don't continue error");
+                    return SSL_FATAL_ERROR;
+                }
+            }
+#endif /* NO_HANDSHAKE_DONE_CB */
+            FreeHandshakeResources(ssl);
+            WOLFSSL_LEAVE("SSL_accept()", SSL_SUCCESS);
+            return SSL_SUCCESS;
+
+        default :
+            WOLFSSL_MSG("Unknown accept state ERROR");
+            return SSL_FATAL_ERROR;
+        }
+    }
+
+#endif /* NO_WOLFSSL_SERVER */
+
+
+#ifndef NO_HANDSHAKE_DONE_CB
+
+int wolfSSL_SetHsDoneCb(WOLFSSL* ssl, HandShakeDoneCb cb, void* user_ctx)
+{
+    WOLFSSL_ENTER("wolfSSL_SetHsDoneCb");
+
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    ssl->hsDoneCb  = cb;
+    ssl->hsDoneCtx = user_ctx;
+
+
+    return SSL_SUCCESS;
+}
+
+#endif /* NO_HANDSHAKE_DONE_CB */
+
+
+int wolfSSL_Cleanup(void)
+{
+    int ret = SSL_SUCCESS;
+    int release = 0;
+
+    WOLFSSL_ENTER("wolfSSL_Cleanup");
+
+    if (initRefCount == 0)
+        return ret;  /* possibly no init yet, but not failure either way */
+
+    if (LockMutex(&count_mutex) != 0) {
+        WOLFSSL_MSG("Bad Lock Mutex count");
+        return BAD_MUTEX_E;
+    }
+
+    release = initRefCount-- == 1;
+    if (initRefCount < 0)
+        initRefCount = 0;
+
+    UnLockMutex(&count_mutex);
+
+    if (!release)
+        return ret;
+
+#ifndef NO_SESSION_CACHE
+    if (FreeMutex(&session_mutex) != 0)
+        ret = BAD_MUTEX_E;
+#endif
+    if (FreeMutex(&count_mutex) != 0)
+        ret = BAD_MUTEX_E;
+
+#if defined(HAVE_ECC) && defined(FP_ECC)
+    wc_ecc_fp_free();
+#endif
+
+    return ret;
+}
+
+
+#ifndef NO_SESSION_CACHE
+
+
+/* some session IDs aren't random afterall, let's make them random */
+static INLINE word32 HashSession(const byte* sessionID, word32 len, int* error)
+{
+    byte digest[MAX_DIGEST_SIZE];
+
+#ifndef NO_MD5
+    *error =  wc_Md5Hash(sessionID, len, digest);
+#elif !defined(NO_SHA)
+    *error =  wc_ShaHash(sessionID, len, digest);
+#elif !defined(NO_SHA256)
+    *error =  wc_Sha256Hash(sessionID, len, digest);
+#else
+    #error "We need a digest to hash the session IDs"
+#endif
+
+    return *error == 0 ? MakeWordFromHash(digest) : 0; /* 0 on failure */
+}
+
+
+void wolfSSL_flush_sessions(WOLFSSL_CTX* ctx, long tm)
+{
+    /* static table now, no flusing needed */
+    (void)ctx;
+    (void)tm;
+}
+
+
+/* set ssl session timeout in seconds */
+int wolfSSL_set_timeout(WOLFSSL* ssl, unsigned int to)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    ssl->timeout = to;
+
+    return SSL_SUCCESS;
+}
+
+
+/* set ctx session timeout in seconds */
+int wolfSSL_CTX_set_timeout(WOLFSSL_CTX* ctx, unsigned int to)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    ctx->timeout = to;
+
+    return SSL_SUCCESS;
+}
+
+
+#ifndef NO_CLIENT_CACHE
+
+/* Get Session from Client cache based on id/len, return NULL on failure */
+WOLFSSL_SESSION* GetSessionClient(WOLFSSL* ssl, const byte* id, int len)
+{
+    WOLFSSL_SESSION* ret = NULL;
+    word32          row;
+    int             idx;
+    int             count;
+    int             error = 0;
+
+    WOLFSSL_ENTER("GetSessionClient");
+
+    if (ssl->options.side == WOLFSSL_SERVER_END)
+        return NULL;
+
+    len = min(SERVER_ID_LEN, (word32)len);
+    row = HashSession(id, len, &error) % SESSION_ROWS;
+    if (error != 0) {
+        WOLFSSL_MSG("Hash session failed");
+        return NULL;
+    }
+
+    if (LockMutex(&session_mutex) != 0) {
+        WOLFSSL_MSG("Lock session mutex failed");
+        return NULL;
+    }
+
+    /* start from most recently used */
+    count = min((word32)ClientCache[row].totalCount, SESSIONS_PER_ROW);
+    idx = ClientCache[row].nextIdx - 1;
+    if (idx < 0)
+        idx = SESSIONS_PER_ROW - 1; /* if back to front, the previous was end */
+
+    for (; count > 0; --count, idx = idx ? idx - 1 : SESSIONS_PER_ROW - 1) {
+        WOLFSSL_SESSION* current;
+        ClientSession   clSess;
+
+        if (idx >= SESSIONS_PER_ROW || idx < 0) { /* sanity check */
+            WOLFSSL_MSG("Bad idx");
+            break;
+        }
+
+        clSess = ClientCache[row].Clients[idx];
+
+        current = &SessionCache[clSess.serverRow].Sessions[clSess.serverIdx];
+        if (XMEMCMP(current->serverID, id, len) == 0) {
+            WOLFSSL_MSG("Found a serverid match for client");
+            if (LowResTimer() < (current->bornOn + current->timeout)) {
+                WOLFSSL_MSG("Session valid");
+                ret = current;
+                break;
+            } else {
+                WOLFSSL_MSG("Session timed out");  /* could have more for id */
+            }
+        } else {
+            WOLFSSL_MSG("ServerID not a match from client table");
+        }
+    }
+
+    UnLockMutex(&session_mutex);
+
+    return ret;
+}
+
+#endif /* NO_CLIENT_CACHE */
+
+
+WOLFSSL_SESSION* GetSession(WOLFSSL* ssl, byte* masterSecret)
+{
+    WOLFSSL_SESSION* ret = 0;
+    const byte*  id = NULL;
+    word32       row;
+    int          idx;
+    int          count;
+    int          error = 0;
+
+    if (ssl->options.sessionCacheOff)
+        return NULL;
+
+    if (ssl->options.haveSessionId == 0)
+        return NULL;
+
+#ifdef HAVE_SESSION_TICKET
+    if (ssl->options.side == WOLFSSL_SERVER_END && ssl->options.useTicket == 1)
+        return NULL;
+#endif
+
+    if (ssl->arrays)
+        id = ssl->arrays->sessionID;
+    else
+        id = ssl->session.sessionID;
+
+    row = HashSession(id, ID_LEN, &error) % SESSION_ROWS;
+    if (error != 0) {
+        WOLFSSL_MSG("Hash session failed");
+        return NULL;
+    }
+
+    if (LockMutex(&session_mutex) != 0)
+        return 0;
+
+    /* start from most recently used */
+    count = min((word32)SessionCache[row].totalCount, SESSIONS_PER_ROW);
+    idx = SessionCache[row].nextIdx - 1;
+    if (idx < 0)
+        idx = SESSIONS_PER_ROW - 1; /* if back to front, the previous was end */
+
+    for (; count > 0; --count, idx = idx ? idx - 1 : SESSIONS_PER_ROW - 1) {
+        WOLFSSL_SESSION* current;
+
+        if (idx >= SESSIONS_PER_ROW || idx < 0) { /* sanity check */
+            WOLFSSL_MSG("Bad idx");
+            break;
+        }
+
+        current = &SessionCache[row].Sessions[idx];
+        if (XMEMCMP(current->sessionID, id, ID_LEN) == 0) {
+            WOLFSSL_MSG("Found a session match");
+            if (LowResTimer() < (current->bornOn + current->timeout)) {
+                WOLFSSL_MSG("Session valid");
+                ret = current;
+                if (masterSecret)
+                    XMEMCPY(masterSecret, current->masterSecret, SECRET_LEN);
+            } else {
+                WOLFSSL_MSG("Session timed out");
+            }
+            break;  /* no more sessionIDs whether valid or not that match */
+        } else {
+            WOLFSSL_MSG("SessionID not a match at this idx");
+        }
+    }
+
+    UnLockMutex(&session_mutex);
+
+    return ret;
+}
+
+
+int SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session)
+{
+    if (ssl->options.sessionCacheOff)
+        return SSL_FAILURE;
+
+    if (LowResTimer() < (session->bornOn + session->timeout)) {
+        ssl->session  = *session;
+        ssl->options.resuming = 1;
+
+#ifdef SESSION_CERTS
+        ssl->version              = session->version;
+        ssl->options.cipherSuite0 = session->cipherSuite0;
+        ssl->options.cipherSuite  = session->cipherSuite;
+#endif
+
+        return SSL_SUCCESS;
+    }
+    return SSL_FAILURE;  /* session timed out */
+}
+
+
+#ifdef WOLFSSL_SESSION_STATS
+static int get_locked_session_stats(word32* active, word32* total,
+                                    word32* peak);
+#endif
+
+int AddSession(WOLFSSL* ssl)
+{
+    word32 row, idx;
+    int    error = 0;
+
+    if (ssl->options.sessionCacheOff)
+        return 0;
+
+    if (ssl->options.haveSessionId == 0)
+        return 0;
+
+#ifdef HAVE_SESSION_TICKET
+    if (ssl->options.side == WOLFSSL_SERVER_END && ssl->options.useTicket == 1)
+        return 0;
+#endif
+
+    row = HashSession(ssl->arrays->sessionID, ID_LEN, &error) % SESSION_ROWS;
+    if (error != 0) {
+        WOLFSSL_MSG("Hash session failed");
+        return error;
+    }
+
+    if (LockMutex(&session_mutex) != 0)
+        return BAD_MUTEX_E;
+
+    idx = SessionCache[row].nextIdx++;
+#ifdef SESSION_INDEX
+    ssl->sessionIndex = (row << SESSIDX_ROW_SHIFT) | idx;
+#endif
+
+    XMEMCPY(SessionCache[row].Sessions[idx].masterSecret,
+           ssl->arrays->masterSecret, SECRET_LEN);
+    XMEMCPY(SessionCache[row].Sessions[idx].sessionID, ssl->arrays->sessionID,
+           ID_LEN);
+    SessionCache[row].Sessions[idx].sessionIDSz = ssl->arrays->sessionIDSz;
+
+    SessionCache[row].Sessions[idx].timeout = ssl->timeout;
+    SessionCache[row].Sessions[idx].bornOn  = LowResTimer();
+
+#ifdef HAVE_SESSION_TICKET
+    SessionCache[row].Sessions[idx].ticketLen     = ssl->session.ticketLen;
+    XMEMCPY(SessionCache[row].Sessions[idx].ticket,
+                                   ssl->session.ticket, ssl->session.ticketLen);
+#endif
+
+#ifdef SESSION_CERTS
+    SessionCache[row].Sessions[idx].chain.count = ssl->session.chain.count;
+    XMEMCPY(SessionCache[row].Sessions[idx].chain.certs,
+           ssl->session.chain.certs, sizeof(x509_buffer) * MAX_CHAIN_DEPTH);
+
+    SessionCache[row].Sessions[idx].version      = ssl->version;
+    SessionCache[row].Sessions[idx].cipherSuite0 = ssl->options.cipherSuite0;
+    SessionCache[row].Sessions[idx].cipherSuite  = ssl->options.cipherSuite;
+#endif /* SESSION_CERTS */
+
+    SessionCache[row].totalCount++;
+    if (SessionCache[row].nextIdx == SESSIONS_PER_ROW)
+        SessionCache[row].nextIdx = 0;
+
+#ifndef NO_CLIENT_CACHE
+    if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->session.idLen) {
+        word32 clientRow, clientIdx;
+
+        WOLFSSL_MSG("Adding client cache entry");
+
+        SessionCache[row].Sessions[idx].idLen = ssl->session.idLen;
+        XMEMCPY(SessionCache[row].Sessions[idx].serverID, ssl->session.serverID,
+                ssl->session.idLen);
+
+        clientRow = HashSession(ssl->session.serverID, ssl->session.idLen,
+                                &error) % SESSION_ROWS;
+        if (error != 0) {
+            WOLFSSL_MSG("Hash session failed");
+        } else {
+            clientIdx = ClientCache[clientRow].nextIdx++;
+
+            ClientCache[clientRow].Clients[clientIdx].serverRow = (word16)row;
+            ClientCache[clientRow].Clients[clientIdx].serverIdx = (word16)idx;
+
+            ClientCache[clientRow].totalCount++;
+            if (ClientCache[clientRow].nextIdx == SESSIONS_PER_ROW)
+                ClientCache[clientRow].nextIdx = 0;
+        }
+    }
+    else
+        SessionCache[row].Sessions[idx].idLen = 0;
+#endif /* NO_CLIENT_CACHE */
+
+#if defined(WOLFSSL_SESSION_STATS) && defined(WOLFSSL_PEAK_SESSIONS)
+    if (error == 0) {
+        word32 active = 0;
+
+        error = get_locked_session_stats(&active, NULL, NULL);
+        if (error == SSL_SUCCESS) {
+            error = 0;  /* back to this function ok */
+
+            if (active > PeakSessions)
+                PeakSessions = active;
+        }
+    }
+#endif /* defined(WOLFSSL_SESSION_STATS) && defined(WOLFSSL_PEAK_SESSIONS) */
+
+    if (UnLockMutex(&session_mutex) != 0)
+        return BAD_MUTEX_E;
+
+    return error;
+}
+
+
+#ifdef SESSION_INDEX
+
+int wolfSSL_GetSessionIndex(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("wolfSSL_GetSessionIndex");
+    WOLFSSL_LEAVE("wolfSSL_GetSessionIndex", ssl->sessionIndex);
+    return ssl->sessionIndex;
+}
+
+
+int wolfSSL_GetSessionAtIndex(int idx, WOLFSSL_SESSION* session)
+{
+    int row, col, result = SSL_FAILURE;
+
+    WOLFSSL_ENTER("wolfSSL_GetSessionAtIndex");
+
+    row = idx >> SESSIDX_ROW_SHIFT;
+    col = idx & SESSIDX_IDX_MASK;
+
+    if (LockMutex(&session_mutex) != 0) {
+        return BAD_MUTEX_E;
+    }
+
+    if (row < SESSION_ROWS &&
+        col < (int)min(SessionCache[row].totalCount, SESSIONS_PER_ROW)) {
+        XMEMCPY(session,
+                 &SessionCache[row].Sessions[col], sizeof(WOLFSSL_SESSION));
+        result = SSL_SUCCESS;
+    }
+
+    if (UnLockMutex(&session_mutex) != 0)
+        result = BAD_MUTEX_E;
+
+    WOLFSSL_LEAVE("wolfSSL_GetSessionAtIndex", result);
+    return result;
+}
+
+#endif /* SESSION_INDEX */
+
+#if defined(SESSION_INDEX) && defined(SESSION_CERTS)
+
+WOLFSSL_X509_CHAIN* wolfSSL_SESSION_get_peer_chain(WOLFSSL_SESSION* session)
+{
+    WOLFSSL_X509_CHAIN* chain = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_SESSION_get_peer_chain");
+    if (session)
+        chain = &session->chain;
+
+    WOLFSSL_LEAVE("wolfSSL_SESSION_get_peer_chain", chain ? 1 : 0);
+    return chain;
+}
+
+#endif /* SESSION_INDEX && SESSION_CERTS */
+
+
+#ifdef WOLFSSL_SESSION_STATS
+
+/* requires session_mutex lock held, SSL_SUCCESS on ok */
+static int get_locked_session_stats(word32* active, word32* total, word32* peak)
+{
+    int result = SSL_SUCCESS;
+    int i;
+    int count;
+    int idx;
+    word32 now   = 0;
+    word32 seen  = 0;
+    word32 ticks = LowResTimer();
+
+    (void)peak;
+
+    WOLFSSL_ENTER("get_locked_session_stats");
+
+    for (i = 0; i < SESSION_ROWS; i++) {
+        seen += SessionCache[i].totalCount;
+
+        if (active == NULL)
+            continue;  /* no need to calculate what we can't set */
+
+        count = min((word32)SessionCache[i].totalCount, SESSIONS_PER_ROW);
+        idx   = SessionCache[i].nextIdx - 1;
+        if (idx < 0)
+            idx = SESSIONS_PER_ROW - 1; /* if back to front previous was end */
+
+        for (; count > 0; --count, idx = idx ? idx - 1 : SESSIONS_PER_ROW - 1) {
+            if (idx >= SESSIONS_PER_ROW || idx < 0) {  /* sanity check */
+                WOLFSSL_MSG("Bad idx");
+                break;
+            }
+
+            /* if not expried then good */
+            if (ticks < (SessionCache[i].Sessions[idx].bornOn +
+                         SessionCache[i].Sessions[idx].timeout) ) {
+                now++;
+            }
+        }
+    }
+
+    if (active)
+        *active = now;
+
+    if (total)
+        *total = seen;
+
+#ifdef WOLFSSL_PEAK_SESSIONS
+    if (peak)
+        *peak = PeakSessions;
+#endif
+
+    WOLFSSL_LEAVE("get_locked_session_stats", result);
+
+    return result;
+}
+
+
+/* return SSL_SUCCESS on ok */
+int wolfSSL_get_session_stats(word32* active, word32* total, word32* peak,
+                              word32* maxSessions)
+{
+    int result = SSL_SUCCESS;
+
+    WOLFSSL_ENTER("wolfSSL_get_session_stats");
+
+    if (maxSessions) {
+        *maxSessions = SESSIONS_PER_ROW * SESSION_ROWS;
+
+        if (active == NULL && total == NULL && peak == NULL)
+            return result;  /* we're done */
+    }
+
+    /* user must provide at least one query value */
+    if (active == NULL && total == NULL && peak == NULL)
+        return BAD_FUNC_ARG;
+
+    if (LockMutex(&session_mutex) != 0) {
+        return BAD_MUTEX_E;
+    }
+
+    result = get_locked_session_stats(active, total, peak);
+
+    if (UnLockMutex(&session_mutex) != 0)
+        result = BAD_MUTEX_E;
+
+    WOLFSSL_LEAVE("wolfSSL_get_session_stats", result);
+
+    return result;
+}
+
+#endif /* WOLFSSL_SESSION_STATS */
+
+
+    #ifdef PRINT_SESSION_STATS
+
+    /* SSL_SUCCESS on ok */
+    int wolfSSL_PrintSessionStats(void)
+    {
+        word32 totalSessionsSeen = 0;
+        word32 totalSessionsNow = 0;
+        word32 peak = 0;
+        word32 maxSessions = 0;
+        int    i;
+        int    ret;
+        double E;               /* expected freq */
+        double chiSquare = 0;
+
+        ret = wolfSSL_get_session_stats(&totalSessionsNow, &totalSessionsSeen,
+                                        &peak, &maxSessions);
+        if (ret != SSL_SUCCESS)
+            return ret;
+        printf("Total Sessions Seen = %d\n", totalSessionsSeen);
+        printf("Total Sessions Now  = %d\n", totalSessionsNow);
+#ifdef WOLFSSL_PEAK_SESSIONS
+        printf("Peak  Sessions      = %d\n", peak);
+#endif
+        printf("Max   Sessions      = %d\n", maxSessions);
+
+        E = (double)totalSessionsSeen / SESSION_ROWS;
+
+        for (i = 0; i < SESSION_ROWS; i++) {
+            double diff = SessionCache[i].totalCount - E;
+            diff *= diff;                /* square    */
+            diff /= E;                   /* normalize */
+
+            chiSquare += diff;
+        }
+        printf("  chi-square = %5.1f, d.f. = %d\n", chiSquare,
+                                                     SESSION_ROWS - 1);
+        #if (SESSION_ROWS == 11)
+            printf(" .05 p value =  18.3, chi-square should be less\n");
+        #elif (SESSION_ROWS == 211)
+            printf(".05 p value  = 244.8, chi-square should be less\n");
+        #elif (SESSION_ROWS == 5981)
+            printf(".05 p value  = 6161.0, chi-square should be less\n");
+        #elif (SESSION_ROWS == 3)
+            printf(".05 p value  =   6.0, chi-square should be less\n");
+        #elif (SESSION_ROWS == 2861)
+            printf(".05 p value  = 2985.5, chi-square should be less\n");
+        #endif
+        printf("\n");
+
+        return ret;
+    }
+
+    #endif /* SESSION_STATS */
+
+#else  /* NO_SESSION_CACHE */
+
+/* No session cache version */
+WOLFSSL_SESSION* GetSession(WOLFSSL* ssl, byte* masterSecret)
+{
+    (void)ssl;
+    (void)masterSecret;
+
+    return NULL;
+}
+
+#endif /* NO_SESSION_CACHE */
+
+
+/* call before SSL_connect, if verifying will add name check to
+   date check and signature check */
+int wolfSSL_check_domain_name(WOLFSSL* ssl, const char* dn)
+{
+    WOLFSSL_ENTER("wolfSSL_check_domain_name");
+    if (ssl->buffers.domainName.buffer)
+        XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN);
+
+    ssl->buffers.domainName.length = (word32)XSTRLEN(dn) + 1;
+    ssl->buffers.domainName.buffer = (byte*) XMALLOC(
+                ssl->buffers.domainName.length, ssl->heap, DYNAMIC_TYPE_DOMAIN);
+
+    if (ssl->buffers.domainName.buffer) {
+        XSTRNCPY((char*)ssl->buffers.domainName.buffer, dn,
+                ssl->buffers.domainName.length);
+        return SSL_SUCCESS;
+    }
+    else {
+        ssl->error = MEMORY_ERROR;
+        return SSL_FAILURE;
+    }
+}
+
+
+/* turn on wolfSSL zlib compression
+   returns SSL_SUCCESS for success, else error (not built in)
+*/
+int wolfSSL_set_compression(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("wolfSSL_set_compression");
+    (void)ssl;
+#ifdef HAVE_LIBZ
+    ssl->options.usingCompression = 1;
+    return SSL_SUCCESS;
+#else
+    return NOT_COMPILED_IN;
+#endif
+}
+
+
+#ifndef USE_WINDOWS_API
+    #ifndef NO_WRITEV
+
+        /* simulate writev semantics, doesn't actually do block at a time though
+           because of SSL_write behavior and because front adds may be small */
+        int wolfSSL_writev(WOLFSSL* ssl, const struct iovec* iov, int iovcnt)
+        {
+        #ifdef WOLFSSL_SMALL_STACK
+            byte   staticBuffer[1]; /* force heap usage */
+        #else
+            byte   staticBuffer[FILE_BUFFER_SIZE];
+        #endif
+            byte* myBuffer  = staticBuffer;
+            int   dynamic   = 0;
+            int   sending   = 0;
+            int   idx       = 0;
+            int   i;
+            int   ret;
+
+            WOLFSSL_ENTER("wolfSSL_writev");
+
+            for (i = 0; i < iovcnt; i++)
+                sending += (int)iov[i].iov_len;
+
+            if (sending > (int)sizeof(staticBuffer)) {
+                myBuffer = (byte*)XMALLOC(sending, ssl->heap,
+                                                           DYNAMIC_TYPE_WRITEV);
+                if (!myBuffer)
+                    return MEMORY_ERROR;
+
+                dynamic = 1;
+            }
+
+            for (i = 0; i < iovcnt; i++) {
+                XMEMCPY(&myBuffer[idx], iov[i].iov_base, iov[i].iov_len);
+                idx += (int)iov[i].iov_len;
+            }
+
+            ret = wolfSSL_write(ssl, myBuffer, sending);
+
+            if (dynamic)
+                XFREE(myBuffer, ssl->heap, DYNAMIC_TYPE_WRITEV);
+
+            return ret;
+        }
+    #endif
+#endif
+
+
+#ifdef WOLFSSL_CALLBACKS
+
+    typedef struct itimerval Itimerval;
+
+    /* don't keep calling simple functions while setting up timer and singals
+       if no inlining these are the next best */
+
+    #define AddTimes(a, b, c)                       \
+        do {                                        \
+            c.tv_sec  = a.tv_sec  + b.tv_sec;       \
+            c.tv_usec = a.tv_usec + b.tv_usec;      \
+            if (c.tv_usec >=  1000000) {            \
+                c.tv_sec++;                         \
+                c.tv_usec -= 1000000;               \
+            }                                       \
+        } while (0)
+
+
+    #define SubtractTimes(a, b, c)                  \
+        do {                                        \
+            c.tv_sec  = a.tv_sec  - b.tv_sec;       \
+            c.tv_usec = a.tv_usec - b.tv_usec;      \
+            if (c.tv_usec < 0) {                    \
+                c.tv_sec--;                         \
+                c.tv_usec += 1000000;               \
+            }                                       \
+        } while (0)
+
+    #define CmpTimes(a, b, cmp)                     \
+        ((a.tv_sec  ==  b.tv_sec) ?                 \
+            (a.tv_usec cmp b.tv_usec) :             \
+            (a.tv_sec  cmp b.tv_sec))               \
+
+
+    /* do nothing handler */
+    static void myHandler(int signo)
+    {
+        (void)signo;
+        return;
+    }
+
+
+    static int wolfSSL_ex_wrapper(WOLFSSL* ssl, HandShakeCallBack hsCb,
+                                 TimeoutCallBack toCb, Timeval timeout)
+    {
+        int       ret        = SSL_FATAL_ERROR;
+        int       oldTimerOn = 0;   /* was timer already on */
+        Timeval   startTime;
+        Timeval   endTime;
+        Timeval   totalTime;
+        Itimerval myTimeout;
+        Itimerval oldTimeout; /* if old timer adjust from total time to reset */
+        struct sigaction act, oact;
+
+        #define ERR_OUT(x) { ssl->hsInfoOn = 0; ssl->toInfoOn = 0; return x; }
+
+        if (hsCb) {
+            ssl->hsInfoOn = 1;
+            InitHandShakeInfo(&ssl->handShakeInfo);
+        }
+        if (toCb) {
+            ssl->toInfoOn = 1;
+            InitTimeoutInfo(&ssl->timeoutInfo);
+
+            if (gettimeofday(&startTime, 0) < 0)
+                ERR_OUT(GETTIME_ERROR);
+
+            /* use setitimer to simulate getitimer, init 0 myTimeout */
+            myTimeout.it_interval.tv_sec  = 0;
+            myTimeout.it_interval.tv_usec = 0;
+            myTimeout.it_value.tv_sec     = 0;
+            myTimeout.it_value.tv_usec    = 0;
+            if (setitimer(ITIMER_REAL, &myTimeout, &oldTimeout) < 0)
+                ERR_OUT(SETITIMER_ERROR);
+
+            if (oldTimeout.it_value.tv_sec || oldTimeout.it_value.tv_usec) {
+                oldTimerOn = 1;
+
+                /* is old timer going to expire before ours */
+                if (CmpTimes(oldTimeout.it_value, timeout, <)) {
+                    timeout.tv_sec  = oldTimeout.it_value.tv_sec;
+                    timeout.tv_usec = oldTimeout.it_value.tv_usec;
+                }
+            }
+            myTimeout.it_value.tv_sec  = timeout.tv_sec;
+            myTimeout.it_value.tv_usec = timeout.tv_usec;
+
+            /* set up signal handler, don't restart socket send/recv */
+            act.sa_handler = myHandler;
+            sigemptyset(&act.sa_mask);
+            act.sa_flags = 0;
+#ifdef SA_INTERRUPT
+            act.sa_flags |= SA_INTERRUPT;
+#endif
+            if (sigaction(SIGALRM, &act, &oact) < 0)
+                ERR_OUT(SIGACT_ERROR);
+
+            if (setitimer(ITIMER_REAL, &myTimeout, 0) < 0)
+                ERR_OUT(SETITIMER_ERROR);
+        }
+
+        /* do main work */
+#ifndef NO_WOLFSSL_CLIENT
+        if (ssl->options.side == WOLFSSL_CLIENT_END)
+            ret = wolfSSL_connect(ssl);
+#endif
+#ifndef NO_WOLFSSL_SERVER
+        if (ssl->options.side == WOLFSSL_SERVER_END)
+            ret = wolfSSL_accept(ssl);
+#endif
+
+        /* do callbacks */
+        if (toCb) {
+            if (oldTimerOn) {
+                gettimeofday(&endTime, 0);
+                SubtractTimes(endTime, startTime, totalTime);
+                /* adjust old timer for elapsed time */
+                if (CmpTimes(totalTime, oldTimeout.it_value, <))
+                    SubtractTimes(oldTimeout.it_value, totalTime,
+                                  oldTimeout.it_value);
+                else {
+                    /* reset value to interval, may be off */
+                    oldTimeout.it_value.tv_sec = oldTimeout.it_interval.tv_sec;
+                    oldTimeout.it_value.tv_usec =oldTimeout.it_interval.tv_usec;
+                }
+                /* keep iter the same whether there or not */
+            }
+            /* restore old handler */
+            if (sigaction(SIGALRM, &oact, 0) < 0)
+                ret = SIGACT_ERROR;    /* more pressing error, stomp */
+            else
+                /* use old settings which may turn off (expired or not there) */
+                if (setitimer(ITIMER_REAL, &oldTimeout, 0) < 0)
+                    ret = SETITIMER_ERROR;
+
+            /* if we had a timeout call callback */
+            if (ssl->timeoutInfo.timeoutName[0]) {
+                ssl->timeoutInfo.timeoutValue.tv_sec  = timeout.tv_sec;
+                ssl->timeoutInfo.timeoutValue.tv_usec = timeout.tv_usec;
+                (toCb)(&ssl->timeoutInfo);
+            }
+            /* clean up */
+            FreeTimeoutInfo(&ssl->timeoutInfo, ssl->heap);
+            ssl->toInfoOn = 0;
+        }
+        if (hsCb) {
+            FinishHandShakeInfo(&ssl->handShakeInfo, ssl);
+            (hsCb)(&ssl->handShakeInfo);
+            ssl->hsInfoOn = 0;
+        }
+        return ret;
+    }
+
+
+#ifndef NO_WOLFSSL_CLIENT
+
+    int wolfSSL_connect_ex(WOLFSSL* ssl, HandShakeCallBack hsCb,
+                          TimeoutCallBack toCb, Timeval timeout)
+    {
+        WOLFSSL_ENTER("wolfSSL_connect_ex");
+        return wolfSSL_ex_wrapper(ssl, hsCb, toCb, timeout);
+    }
+
+#endif
+
+
+#ifndef NO_WOLFSSL_SERVER
+
+    int wolfSSL_accept_ex(WOLFSSL* ssl, HandShakeCallBack hsCb,
+                         TimeoutCallBack toCb,Timeval timeout)
+    {
+        WOLFSSL_ENTER("wolfSSL_accept_ex");
+        return wolfSSL_ex_wrapper(ssl, hsCb, toCb, timeout);
+    }
+
+#endif
+
+#endif /* WOLFSSL_CALLBACKS */
+
+
+#ifndef NO_PSK
+
+    void wolfSSL_CTX_set_psk_client_callback(WOLFSSL_CTX* ctx,
+                                         psk_client_callback cb)
+    {
+        WOLFSSL_ENTER("SSL_CTX_set_psk_client_callback");
+        ctx->havePSK = 1;
+        ctx->client_psk_cb = cb;
+    }
+
+
+    void wolfSSL_set_psk_client_callback(WOLFSSL* ssl, psk_client_callback cb)
+    {
+        byte haveRSA = 1;
+
+        WOLFSSL_ENTER("SSL_set_psk_client_callback");
+        ssl->options.havePSK = 1;
+        ssl->options.client_psk_cb = cb;
+
+        #ifdef NO_RSA
+            haveRSA = 0;
+        #endif
+        InitSuites(ssl->suites, ssl->version, haveRSA, TRUE,
+                   ssl->options.haveDH, ssl->options.haveNTRU,
+                   ssl->options.haveECDSAsig, ssl->options.haveStaticECC,
+                   ssl->options.side);
+    }
+
+
+    void wolfSSL_CTX_set_psk_server_callback(WOLFSSL_CTX* ctx,
+                                         psk_server_callback cb)
+    {
+        WOLFSSL_ENTER("SSL_CTX_set_psk_server_callback");
+        ctx->havePSK = 1;
+        ctx->server_psk_cb = cb;
+    }
+
+
+    void wolfSSL_set_psk_server_callback(WOLFSSL* ssl, psk_server_callback cb)
+    {
+        byte haveRSA = 1;
+
+        WOLFSSL_ENTER("SSL_set_psk_server_callback");
+        ssl->options.havePSK = 1;
+        ssl->options.server_psk_cb = cb;
+
+        #ifdef NO_RSA
+            haveRSA = 0;
+        #endif
+        InitSuites(ssl->suites, ssl->version, haveRSA, TRUE,
+                   ssl->options.haveDH, ssl->options.haveNTRU,
+                   ssl->options.haveECDSAsig, ssl->options.haveStaticECC,
+                   ssl->options.side);
+    }
+
+
+    const char* wolfSSL_get_psk_identity_hint(const WOLFSSL* ssl)
+    {
+        WOLFSSL_ENTER("SSL_get_psk_identity_hint");
+
+        if (ssl == NULL || ssl->arrays == NULL)
+            return NULL;
+
+        return ssl->arrays->server_hint;
+    }
+
+
+    const char* wolfSSL_get_psk_identity(const WOLFSSL* ssl)
+    {
+        WOLFSSL_ENTER("SSL_get_psk_identity");
+
+        if (ssl == NULL || ssl->arrays == NULL)
+            return NULL;
+
+        return ssl->arrays->client_identity;
+    }
+
+
+    int wolfSSL_CTX_use_psk_identity_hint(WOLFSSL_CTX* ctx, const char* hint)
+    {
+        WOLFSSL_ENTER("SSL_CTX_use_psk_identity_hint");
+        if (hint == 0)
+            ctx->server_hint[0] = 0;
+        else {
+            XSTRNCPY(ctx->server_hint, hint, MAX_PSK_ID_LEN);
+            ctx->server_hint[MAX_PSK_ID_LEN - 1] = '\0';
+        }
+        return SSL_SUCCESS;
+    }
+
+
+    int wolfSSL_use_psk_identity_hint(WOLFSSL* ssl, const char* hint)
+    {
+        WOLFSSL_ENTER("SSL_use_psk_identity_hint");
+
+        if (ssl == NULL || ssl->arrays == NULL)
+            return SSL_FAILURE;
+
+        if (hint == 0)
+            ssl->arrays->server_hint[0] = 0;
+        else {
+            XSTRNCPY(ssl->arrays->server_hint, hint, MAX_PSK_ID_LEN);
+            ssl->arrays->server_hint[MAX_PSK_ID_LEN - 1] = '\0';
+        }
+        return SSL_SUCCESS;
+    }
+
+#endif /* NO_PSK */
+
+
+#ifdef HAVE_ANON
+
+    int wolfSSL_CTX_allow_anon_cipher(WOLFSSL_CTX* ctx)
+    {
+        WOLFSSL_ENTER("wolfSSL_CTX_allow_anon_cipher");
+
+        if (ctx == NULL)
+            return SSL_FAILURE;
+
+        ctx->haveAnon = 1;
+
+        return SSL_SUCCESS;
+    }
+
+#endif /* HAVE_ANON */
+
+
+#ifndef NO_CERTS
+/* used to be defined on NO_FILESYSTEM only, but are generally useful */
+
+    /* wolfSSL extension allows DER files to be loaded from buffers as well */
+    int wolfSSL_CTX_load_verify_buffer(WOLFSSL_CTX* ctx, const unsigned char* in,
+                                      long sz, int format)
+    {
+        WOLFSSL_ENTER("wolfSSL_CTX_load_verify_buffer");
+        if (format == SSL_FILETYPE_PEM)
+            return ProcessChainBuffer(ctx, in, sz, format, CA_TYPE, NULL);
+        else
+            return ProcessBuffer(ctx, in, sz, format, CA_TYPE, NULL,NULL,0);
+    }
+
+
+    int wolfSSL_CTX_use_certificate_buffer(WOLFSSL_CTX* ctx,
+                                 const unsigned char* in, long sz, int format)
+    {
+        WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_buffer");
+        return ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 0);
+    }
+
+
+    int wolfSSL_CTX_use_PrivateKey_buffer(WOLFSSL_CTX* ctx,
+                                 const unsigned char* in, long sz, int format)
+    {
+        WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_buffer");
+        return ProcessBuffer(ctx, in, sz, format, PRIVATEKEY_TYPE, NULL,NULL,0);
+    }
+
+
+    int wolfSSL_CTX_use_certificate_chain_buffer(WOLFSSL_CTX* ctx,
+                                 const unsigned char* in, long sz)
+    {
+        WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_buffer");
+        return ProcessBuffer(ctx, in, sz, SSL_FILETYPE_PEM, CERT_TYPE, NULL,
+                             NULL, 1);
+    }
+
+    int wolfSSL_use_certificate_buffer(WOLFSSL* ssl,
+                                 const unsigned char* in, long sz, int format)
+    {
+        WOLFSSL_ENTER("wolfSSL_use_certificate_buffer");
+        return ProcessBuffer(ssl->ctx, in, sz, format,CERT_TYPE,ssl,NULL,0);
+    }
+
+
+    int wolfSSL_use_PrivateKey_buffer(WOLFSSL* ssl,
+                                 const unsigned char* in, long sz, int format)
+    {
+        WOLFSSL_ENTER("wolfSSL_use_PrivateKey_buffer");
+        return ProcessBuffer(ssl->ctx, in, sz, format, PRIVATEKEY_TYPE,
+                             ssl, NULL, 0);
+    }
+
+
+    int wolfSSL_use_certificate_chain_buffer(WOLFSSL* ssl,
+                                 const unsigned char* in, long sz)
+    {
+        WOLFSSL_ENTER("wolfSSL_use_certificate_chain_buffer");
+        return ProcessBuffer(ssl->ctx, in, sz, SSL_FILETYPE_PEM, CERT_TYPE,
+                             ssl, NULL, 1);
+    }
+
+
+    /* unload any certs or keys that SSL owns, leave CTX as is
+       SSL_SUCCESS on ok */
+    int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl)
+    {
+        if (ssl == NULL) {
+            WOLFSSL_MSG("Null function arg");
+            return BAD_FUNC_ARG;
+        }
+
+        if (ssl->buffers.weOwnCert) {
+            WOLFSSL_MSG("Unloading cert");
+            XFREE(ssl->buffers.certificate.buffer, ssl->heap,DYNAMIC_TYPE_CERT);
+            ssl->buffers.weOwnCert = 0;
+            ssl->buffers.certificate.length = 0;
+            ssl->buffers.certificate.buffer = NULL;
+        }
+
+        if (ssl->buffers.weOwnCertChain) {
+            WOLFSSL_MSG("Unloading cert chain");
+            XFREE(ssl->buffers.certChain.buffer, ssl->heap,DYNAMIC_TYPE_CERT);
+            ssl->buffers.weOwnCertChain = 0;
+            ssl->buffers.certChain.length = 0;
+            ssl->buffers.certChain.buffer = NULL;
+        }
+
+        if (ssl->buffers.weOwnKey) {
+            WOLFSSL_MSG("Unloading key");
+            XFREE(ssl->buffers.key.buffer, ssl->heap, DYNAMIC_TYPE_KEY);
+            ssl->buffers.weOwnKey = 0;
+            ssl->buffers.key.length = 0;
+            ssl->buffers.key.buffer = NULL;
+        }
+
+        return SSL_SUCCESS;
+    }
+
+
+    int wolfSSL_CTX_UnloadCAs(WOLFSSL_CTX* ctx)
+    {
+        WOLFSSL_ENTER("wolfSSL_CTX_UnloadCAs");
+
+        if (ctx == NULL)
+            return BAD_FUNC_ARG;
+
+        return wolfSSL_CertManagerUnloadCAs(ctx->cm);
+    }
+
+/* old NO_FILESYSTEM end */
+#endif /* !NO_CERTS */
+
+
+#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+
+
+    int wolfSSL_add_all_algorithms(void)
+    {
+        WOLFSSL_ENTER("wolfSSL_add_all_algorithms");
+        wolfSSL_Init();
+        return SSL_SUCCESS;
+    }
+
+
+    long wolfSSL_CTX_sess_set_cache_size(WOLFSSL_CTX* ctx, long sz)
+    {
+        /* cache size fixed at compile time in wolfSSL */
+        (void)ctx;
+        (void)sz;
+        return 0;
+    }
+
+
+    void wolfSSL_CTX_set_quiet_shutdown(WOLFSSL_CTX* ctx, int mode)
+    {
+        WOLFSSL_ENTER("wolfSSL_CTX_set_quiet_shutdown");
+        if (mode)
+            ctx->quietShutdown = 1;
+    }
+
+
+    void wolfSSL_set_quiet_shutdown(WOLFSSL* ssl, int mode)
+    {
+        WOLFSSL_ENTER("wolfSSL_CTX_set_quiet_shutdown");
+        if (mode)
+            ssl->options.quietShutdown = 1;
+    }
+
+
+    void wolfSSL_set_bio(WOLFSSL* ssl, WOLFSSL_BIO* rd, WOLFSSL_BIO* wr)
+    {
+        WOLFSSL_ENTER("SSL_set_bio");
+        wolfSSL_set_rfd(ssl, rd->fd);
+        wolfSSL_set_wfd(ssl, wr->fd);
+
+        ssl->biord = rd;
+        ssl->biowr = wr;
+    }
+
+
+    void wolfSSL_CTX_set_client_CA_list(WOLFSSL_CTX* ctx,
+                                       STACK_OF(WOLFSSL_X509_NAME)* names)
+    {
+        (void)ctx;
+        (void)names;
+    }
+
+
+    STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_load_client_CA_file(const char* fname)
+    {
+        (void)fname;
+        return 0;
+    }
+
+
+    int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx)
+    {
+        /* TODO:, not needed in goahead */
+        (void)ctx;
+        return SSL_NOT_IMPLEMENTED;
+    }
+
+
+    /* keyblock size in bytes or -1 */
+    int wolfSSL_get_keyblock_size(WOLFSSL* ssl)
+    {
+        if (ssl == NULL)
+            return SSL_FATAL_ERROR;
+
+        return 2 * (ssl->specs.key_size + ssl->specs.iv_size +
+                    ssl->specs.hash_size);
+    }
+
+
+    /* store keys returns SSL_SUCCESS or -1 on error */
+    int wolfSSL_get_keys(WOLFSSL* ssl, unsigned char** ms, unsigned int* msLen,
+                                     unsigned char** sr, unsigned int* srLen,
+                                     unsigned char** cr, unsigned int* crLen)
+    {
+        if (ssl == NULL || ssl->arrays == NULL)
+            return SSL_FATAL_ERROR;
+
+        *ms = ssl->arrays->masterSecret;
+        *sr = ssl->arrays->serverRandom;
+        *cr = ssl->arrays->clientRandom;
+
+        *msLen = SECRET_LEN;
+        *srLen = RAN_LEN;
+        *crLen = RAN_LEN;
+
+        return SSL_SUCCESS;
+    }
+
+
+    void wolfSSL_set_accept_state(WOLFSSL* ssl)
+    {
+        byte haveRSA = 1;
+        byte havePSK = 0;
+
+        WOLFSSL_ENTER("SSL_set_accept_state");
+        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, haveRSA, havePSK,
+                   ssl->options.haveDH, ssl->options.haveNTRU,
+                   ssl->options.haveECDSAsig, ssl->options.haveStaticECC,
+                   ssl->options.side);
+    }
+#endif
+
+    /* return true if connection established */
+    int wolfSSL_is_init_finished(WOLFSSL* ssl)
+    {
+        if (ssl == NULL)
+            return 0;
+
+        if (ssl->options.handShakeState == HANDSHAKE_DONE)
+            return 1;
+
+        return 0;
+    }
+
+#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+    void wolfSSL_CTX_set_tmp_rsa_callback(WOLFSSL_CTX* ctx,
+                                      WOLFSSL_RSA*(*f)(WOLFSSL*, int, int))
+    {
+        /* wolfSSL verifies all these internally */
+        (void)ctx;
+        (void)f;
+    }
+
+
+    void wolfSSL_set_shutdown(WOLFSSL* ssl, int opt)
+    {
+        (void)ssl;
+        (void)opt;
+    }
+
+
+    long wolfSSL_CTX_set_options(WOLFSSL_CTX* ctx, long opt)
+    {
+        /* goahead calls with 0, do nothing */
+        WOLFSSL_ENTER("SSL_CTX_set_options");
+        (void)ctx;
+        return opt;
+    }
+
+
+    int wolfSSL_set_rfd(WOLFSSL* ssl, int rfd)
+    {
+        WOLFSSL_ENTER("SSL_set_rfd");
+        ssl->rfd = rfd;      /* not used directly to allow IO callbacks */
+
+        ssl->IOCB_ReadCtx  = &ssl->rfd;
+
+        return SSL_SUCCESS;
+    }
+
+
+    int wolfSSL_set_wfd(WOLFSSL* ssl, int wfd)
+    {
+        WOLFSSL_ENTER("SSL_set_wfd");
+        ssl->wfd = wfd;      /* not used directly to allow IO callbacks */
+
+        ssl->IOCB_WriteCtx  = &ssl->wfd;
+
+        return SSL_SUCCESS;
+    }
+
+
+    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;
+    }
+
+
+
+    WOLFSSL_X509* wolfSSL_X509_STORE_CTX_get_current_cert(
+                                                     WOLFSSL_X509_STORE_CTX* ctx)
+    {
+        (void)ctx;
+        return 0;
+    }
+
+
+    int wolfSSL_X509_STORE_CTX_get_error(WOLFSSL_X509_STORE_CTX* ctx)
+    {
+        if (ctx != NULL)
+            return ctx->error;
+        return 0;
+    }
+
+
+    int wolfSSL_X509_STORE_CTX_get_error_depth(WOLFSSL_X509_STORE_CTX* ctx)
+    {
+        (void)ctx;
+        return 0;
+    }
+
+
+    WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_buffer(void)
+    {
+        static WOLFSSL_BIO_METHOD meth;
+
+        WOLFSSL_ENTER("BIO_f_buffer");
+        meth.type = BIO_BUFFER;
+
+        return &meth;
+    }
+
+
+    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");
+        (void)bio;
+        return size;
+    }
+
+
+    WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_ssl(void)
+    {
+        static WOLFSSL_BIO_METHOD meth;
+
+        WOLFSSL_ENTER("BIO_f_ssl");
+        meth.type = BIO_SSL;
+
+        return &meth;
+    }
+
+
+    WOLFSSL_BIO* wolfSSL_BIO_new_socket(int sfd, int closeF)
+    {
+        WOLFSSL_BIO* bio = (WOLFSSL_BIO*) XMALLOC(sizeof(WOLFSSL_BIO), 0,
+                                                DYNAMIC_TYPE_OPENSSL);
+
+        WOLFSSL_ENTER("BIO_new_socket");
+        if (bio) {
+            bio->type  = BIO_SOCKET;
+            bio->close = (byte)closeF;
+            bio->eof   = 0;
+            bio->ssl   = 0;
+            bio->fd    = sfd;
+            bio->prev  = 0;
+            bio->next  = 0;
+            bio->mem   = NULL;
+            bio->memLen = 0;
+        }
+        return bio;
+    }
+
+
+    int wolfSSL_BIO_eof(WOLFSSL_BIO* b)
+    {
+        WOLFSSL_ENTER("BIO_eof");
+        if (b->eof)
+            return 1;
+
+        return 0;
+    }
+
+
+    long wolfSSL_BIO_set_ssl(WOLFSSL_BIO* b, WOLFSSL* ssl, int closeF)
+    {
+        WOLFSSL_ENTER("BIO_set_ssl");
+        b->ssl   = ssl;
+        b->close = (byte)closeF;
+    /* add to ssl for bio free if SSL_free called before/instead of free_all? */
+
+        return 0;
+    }
+
+
+    WOLFSSL_BIO* wolfSSL_BIO_new(WOLFSSL_BIO_METHOD* method)
+    {
+        WOLFSSL_BIO* bio = (WOLFSSL_BIO*) XMALLOC(sizeof(WOLFSSL_BIO), 0,
+                                                DYNAMIC_TYPE_OPENSSL);
+        WOLFSSL_ENTER("BIO_new");
+        if (bio) {
+            bio->type   = method->type;
+            bio->close  = 0;
+            bio->eof    = 0;
+            bio->ssl    = NULL;
+            bio->mem    = NULL;
+            bio->memLen = 0;
+            bio->fd     = 0;
+            bio->prev   = NULL;
+            bio->next   = NULL;
+        }
+        return bio;
+    }
+
+
+    int wolfSSL_BIO_get_mem_data(WOLFSSL_BIO* bio, const byte** p)
+    {
+        if (bio == NULL || p == NULL)
+            return SSL_FATAL_ERROR;
+
+        *p = bio->mem;
+
+        return bio->memLen;
+    }
+
+
+    WOLFSSL_BIO* wolfSSL_BIO_new_mem_buf(void* buf, int len)
+    {
+        WOLFSSL_BIO* bio = NULL;
+        if (buf == NULL)
+            return bio;
+
+        bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem());
+        if (bio == NULL)
+            return bio;
+
+        bio->memLen = len;
+        bio->mem    = (byte*)XMALLOC(len, 0, DYNAMIC_TYPE_OPENSSL);
+        if (bio->mem == NULL) {
+            XFREE(bio, 0, DYNAMIC_TYPE_OPENSSL);
+            return NULL;
+        }
+
+        XMEMCPY(bio->mem, buf, len);
+
+        return bio;
+    }
+
+
+#ifdef USE_WINDOWS_API
+    #define CloseSocket(s) closesocket(s)
+#elif defined(WOLFSSL_MDK_ARM)
+    #define CloseSocket(s) closesocket(s)
+    extern int closesocket(int) ;
+#else
+    #define CloseSocket(s) close(s)
+#endif
+
+    int wolfSSL_BIO_free(WOLFSSL_BIO* bio)
+    {
+        /* unchain?, doesn't matter in goahead since from free all */
+        WOLFSSL_ENTER("BIO_free");
+        if (bio) {
+            if (bio->close) {
+                if (bio->ssl)
+                    wolfSSL_free(bio->ssl);
+                if (bio->fd)
+                    CloseSocket(bio->fd);
+            }
+            if (bio->mem)
+                XFREE(bio->mem, 0, DYNAMIC_TYPE_OPENSSL);
+            XFREE(bio, 0, DYNAMIC_TYPE_OPENSSL);
+        }
+        return 0;
+    }
+
+
+    int wolfSSL_BIO_free_all(WOLFSSL_BIO* bio)
+    {
+        WOLFSSL_ENTER("BIO_free_all");
+        while (bio) {
+            WOLFSSL_BIO* next = bio->next;
+            wolfSSL_BIO_free(bio);
+            bio = next;
+        }
+        return 0;
+    }
+
+
+    int wolfSSL_BIO_read(WOLFSSL_BIO* bio, void* buf, int len)
+    {
+        int  ret;
+        WOLFSSL* ssl = 0;
+        WOLFSSL_BIO* front = bio;
+
+        WOLFSSL_ENTER("BIO_read");
+        /* already got eof, again is error */
+        if (front->eof)
+            return SSL_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 == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) )
+                front->eof = 1;
+        }
+        return ret;
+    }
+
+
+    int wolfSSL_BIO_write(WOLFSSL_BIO* bio, const void* data, int len)
+    {
+        int  ret;
+        WOLFSSL* ssl = 0;
+        WOLFSSL_BIO* front = bio;
+
+        WOLFSSL_ENTER("BIO_write");
+        /* already got eof, again is error */
+        if (front->eof)
+            return SSL_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 == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) )
+                front->eof = 1;
+        }
+
+        return ret;
+    }
+
+
+    WOLFSSL_BIO* wolfSSL_BIO_push(WOLFSSL_BIO* top, WOLFSSL_BIO* append)
+    {
+        WOLFSSL_ENTER("BIO_push");
+        top->next    = append;
+        append->prev = top;
+
+        return top;
+    }
+
+
+    int wolfSSL_BIO_flush(WOLFSSL_BIO* bio)
+    {
+        /* for wolfSSL no flushing needed */
+        WOLFSSL_ENTER("BIO_flush");
+        (void)bio;
+        return 1;
+    }
+
+
+#endif /* OPENSSL_EXTRA || GOAHEAD_WS */
+
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+
+    void wolfSSL_CTX_set_default_passwd_cb_userdata(WOLFSSL_CTX* ctx,
+                                                   void* userdata)
+    {
+        WOLFSSL_ENTER("SSL_CTX_set_default_passwd_cb_userdata");
+        ctx->userdata = userdata;
+    }
+
+
+    void wolfSSL_CTX_set_default_passwd_cb(WOLFSSL_CTX* ctx, pem_password_cb cb)
+    {
+        WOLFSSL_ENTER("SSL_CTX_set_default_passwd_cb");
+        ctx->passwd_cb = cb;
+    }
+
+    int wolfSSL_num_locks(void)
+    {
+        return 0;
+    }
+
+    void wolfSSL_set_locking_callback(void (*f)(int, int, const char*, int))
+    {
+        (void)f;
+    }
+
+    void wolfSSL_set_id_callback(unsigned long (*f)(void))
+    {
+        (void)f;
+    }
+
+    unsigned long wolfSSL_ERR_get_error(void)
+    {
+        /* TODO: */
+        return 0;
+    }
+
+#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[MD5_DIGEST_SIZE];
+    #ifdef WOLFSSL_SMALL_STACK
+        Md5* md5 = NULL;
+    #else
+        Md5  md5[1];
+    #endif
+
+    #ifdef WOLFSSL_SMALL_STACK
+        md5 = (Md5*)XMALLOC(sizeof(Md5), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (md5 == NULL)
+            return 0;
+    #endif
+
+        WOLFSSL_ENTER("EVP_BytesToKey");
+        wc_InitMd5(md5);
+
+        /* only support MD5 for now */
+        if (XSTRNCMP(md, "MD5", 3) != 0) return 0;
+
+        /* only support CBC DES and AES for now */
+        if (XSTRNCMP(type, "DES-CBC", 7) == 0) {
+            keyLen = DES_KEY_SIZE;
+            ivLen  = DES_IV_SIZE;
+        }
+        else if (XSTRNCMP(type, "DES-EDE3-CBC", 12) == 0) {
+            keyLen = DES3_KEY_SIZE;
+            ivLen  = DES_IV_SIZE;
+        }
+        else if (XSTRNCMP(type, "AES-128-CBC", 11) == 0) {
+            keyLen = AES_128_KEY_SIZE;
+            ivLen  = AES_IV_SIZE;
+        }
+        else if (XSTRNCMP(type, "AES-192-CBC", 11) == 0) {
+            keyLen = AES_192_KEY_SIZE;
+            ivLen  = AES_IV_SIZE;
+        }
+        else if (XSTRNCMP(type, "AES-256-CBC", 11) == 0) {
+            keyLen = AES_256_KEY_SIZE;
+            ivLen  = AES_IV_SIZE;
+        }
+        else {
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+            return 0;
+        }
+
+        keyLeft   = keyLen;
+        ivLeft    = ivLen;
+
+        while (keyOutput < (keyLen + ivLen)) {
+            int digestLeft = MD5_DIGEST_SIZE;
+            /* D_(i - 1) */
+            if (keyOutput)                      /* first time D_0 is empty */
+                wc_Md5Update(md5, digest, 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, MD5_DIGEST_SIZE);
+                wc_Md5Final(md5, digest);
+            }
+
+            if (keyLeft) {
+                int store = min(keyLeft, MD5_DIGEST_SIZE);
+                XMEMCPY(&key[keyLen - keyLeft], digest, store);
+
+                keyOutput  += store;
+                keyLeft    -= store;
+                digestLeft -= store;
+            }
+
+            if (ivLeft && digestLeft) {
+                int store = min(ivLeft, digestLeft);
+                XMEMCPY(&iv[ivLen - ivLeft], &digest[MD5_DIGEST_SIZE -
+                                                    digestLeft], store);
+                keyOutput += store;
+                ivLeft    -= store;
+            }
+        }
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+
+        return keyOutput == (keyLen + ivLen) ? keyOutput : 0;
+    }
+
+#endif /* NO_MD5 */
+
+#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */
+
+
+#ifdef OPENSSL_EXTRA
+
+    unsigned long wolfSSLeay(void)
+    {
+        return SSLEAY_VERSION_NUMBER;
+    }
+
+
+    const char* wolfSSLeay_version(int type)
+    {
+        static const char* version = "SSLeay wolfSSL compatibility";
+        (void)type;
+        return version;
+    }
+
+
+#ifndef NO_MD5
+    void wolfSSL_MD5_Init(WOLFSSL_MD5_CTX* md5)
+    {
+        typedef char md5_test[sizeof(MD5_CTX) >= sizeof(Md5) ? 1 : -1];
+        (void)sizeof(md5_test);
+
+        WOLFSSL_ENTER("MD5_Init");
+        wc_InitMd5((Md5*)md5);
+    }
+
+
+    void wolfSSL_MD5_Update(WOLFSSL_MD5_CTX* md5, const void* input,
+                           unsigned long sz)
+    {
+        WOLFSSL_ENTER("wolfSSL_MD5_Update");
+        wc_Md5Update((Md5*)md5, (const byte*)input, (word32)sz);
+    }
+
+
+    void wolfSSL_MD5_Final(byte* input, WOLFSSL_MD5_CTX* md5)
+    {
+        WOLFSSL_ENTER("MD5_Final");
+        wc_Md5Final((Md5*)md5, input);
+    }
+#endif /* NO_MD5 */
+
+
+#ifndef NO_SHA
+    void wolfSSL_SHA_Init(WOLFSSL_SHA_CTX* sha)
+    {
+        typedef char sha_test[sizeof(SHA_CTX) >= sizeof(Sha) ? 1 : -1];
+        (void)sizeof(sha_test);
+
+        WOLFSSL_ENTER("SHA_Init");
+        wc_InitSha((Sha*)sha);  /* OpenSSL compat, no ret */
+    }
+
+
+    void wolfSSL_SHA_Update(WOLFSSL_SHA_CTX* sha, const void* input,
+                           unsigned long sz)
+    {
+        WOLFSSL_ENTER("SHA_Update");
+        wc_ShaUpdate((Sha*)sha, (const byte*)input, (word32)sz);
+    }
+
+
+    void wolfSSL_SHA_Final(byte* input, WOLFSSL_SHA_CTX* sha)
+    {
+        WOLFSSL_ENTER("SHA_Final");
+        wc_ShaFinal((Sha*)sha, input);
+    }
+
+
+    void wolfSSL_SHA1_Init(WOLFSSL_SHA_CTX* sha)
+    {
+        WOLFSSL_ENTER("SHA1_Init");
+        SHA_Init(sha);
+    }
+
+
+    void wolfSSL_SHA1_Update(WOLFSSL_SHA_CTX* sha, const void* input,
+                            unsigned long sz)
+    {
+        WOLFSSL_ENTER("SHA1_Update");
+        SHA_Update(sha, input, sz);
+    }
+
+
+    void wolfSSL_SHA1_Final(byte* input, WOLFSSL_SHA_CTX* sha)
+    {
+        WOLFSSL_ENTER("SHA1_Final");
+        SHA_Final(input, sha);
+    }
+#endif /* NO_SHA */
+
+
+    void wolfSSL_SHA256_Init(WOLFSSL_SHA256_CTX* sha256)
+    {
+        typedef char sha_test[sizeof(SHA256_CTX) >= sizeof(Sha256) ? 1 : -1];
+        (void)sizeof(sha_test);
+
+        WOLFSSL_ENTER("SHA256_Init");
+        wc_InitSha256((Sha256*)sha256);  /* OpenSSL compat, no error */
+    }
+
+
+    void wolfSSL_SHA256_Update(WOLFSSL_SHA256_CTX* sha, const void* input,
+                              unsigned long sz)
+    {
+        WOLFSSL_ENTER("SHA256_Update");
+        wc_Sha256Update((Sha256*)sha, (const byte*)input, (word32)sz);
+        /* OpenSSL compat, no error */
+    }
+
+
+    void wolfSSL_SHA256_Final(byte* input, WOLFSSL_SHA256_CTX* sha)
+    {
+        WOLFSSL_ENTER("SHA256_Final");
+        wc_Sha256Final((Sha256*)sha, input);
+        /* OpenSSL compat, no error */
+    }
+
+
+    #ifdef WOLFSSL_SHA384
+
+    void wolfSSL_SHA384_Init(WOLFSSL_SHA384_CTX* sha)
+    {
+        typedef char sha_test[sizeof(SHA384_CTX) >= sizeof(Sha384) ? 1 : -1];
+        (void)sizeof(sha_test);
+
+        WOLFSSL_ENTER("SHA384_Init");
+        wc_InitSha384((Sha384*)sha);   /* OpenSSL compat, no error */
+    }
+
+
+    void wolfSSL_SHA384_Update(WOLFSSL_SHA384_CTX* sha, const void* input,
+                           unsigned long sz)
+    {
+        WOLFSSL_ENTER("SHA384_Update");
+        wc_Sha384Update((Sha384*)sha, (const byte*)input, (word32)sz);
+        /* OpenSSL compat, no error */
+    }
+
+
+    void wolfSSL_SHA384_Final(byte* input, WOLFSSL_SHA384_CTX* sha)
+    {
+        WOLFSSL_ENTER("SHA384_Final");
+        wc_Sha384Final((Sha384*)sha, input);
+        /* OpenSSL compat, no error */
+    }
+
+    #endif /* WOLFSSL_SHA384 */
+
+
+   #ifdef WOLFSSL_SHA512
+
+    void wolfSSL_SHA512_Init(WOLFSSL_SHA512_CTX* sha)
+    {
+        typedef char sha_test[sizeof(SHA512_CTX) >= sizeof(Sha512) ? 1 : -1];
+        (void)sizeof(sha_test);
+
+        WOLFSSL_ENTER("SHA512_Init");
+        wc_InitSha512((Sha512*)sha);  /* OpenSSL compat, no error */
+    }
+
+
+    void wolfSSL_SHA512_Update(WOLFSSL_SHA512_CTX* sha, const void* input,
+                           unsigned long sz)
+    {
+        WOLFSSL_ENTER("SHA512_Update");
+        wc_Sha512Update((Sha512*)sha, (const byte*)input, (word32)sz);
+        /* OpenSSL compat, no error */
+    }
+
+
+    void wolfSSL_SHA512_Final(byte* input, WOLFSSL_SHA512_CTX* sha)
+    {
+        WOLFSSL_ENTER("SHA512_Final");
+        wc_Sha512Final((Sha512*)sha, input);
+        /* OpenSSL compat, no error */
+    }
+
+    #endif /* WOLFSSL_SHA512 */
+
+
+    #ifndef NO_MD5
+
+    const WOLFSSL_EVP_MD* wolfSSL_EVP_md5(void)
+    {
+        static const char* type = "MD5";
+        WOLFSSL_ENTER("EVP_md5");
+        return type;
+    }
+
+    #endif /* NO_MD5 */
+
+
+#ifndef NO_SHA
+    const WOLFSSL_EVP_MD* wolfSSL_EVP_sha1(void)
+    {
+        static const char* type = "SHA";
+        WOLFSSL_ENTER("EVP_sha1");
+        return type;
+    }
+#endif /* NO_SHA */
+
+
+    const WOLFSSL_EVP_MD* wolfSSL_EVP_sha256(void)
+    {
+        static const char* type = "SHA256";
+        WOLFSSL_ENTER("EVP_sha256");
+        return type;
+    }
+
+    #ifdef WOLFSSL_SHA384
+
+    const WOLFSSL_EVP_MD* wolfSSL_EVP_sha384(void)
+    {
+        static const char* type = "SHA384";
+        WOLFSSL_ENTER("EVP_sha384");
+        return type;
+    }
+
+    #endif /* WOLFSSL_SHA384 */
+
+    #ifdef WOLFSSL_SHA512
+
+    const WOLFSSL_EVP_MD* wolfSSL_EVP_sha512(void)
+    {
+        static const char* type = "SHA512";
+        WOLFSSL_ENTER("EVP_sha512");
+        return type;
+    }
+
+    #endif /* WOLFSSL_SHA512 */
+
+
+    void wolfSSL_EVP_MD_CTX_init(WOLFSSL_EVP_MD_CTX* ctx)
+    {
+        WOLFSSL_ENTER("EVP_CIPHER_MD_CTX_init");
+        (void)ctx;
+        /* do nothing */
+    }
+
+
+    const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_128_cbc(void)
+    {
+        static const char* type = "AES128-CBC";
+        WOLFSSL_ENTER("wolfSSL_EVP_aes_128_cbc");
+        return type;
+    }
+
+
+    const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_192_cbc(void)
+    {
+        static const char* type = "AES192-CBC";
+        WOLFSSL_ENTER("wolfSSL_EVP_aes_192_cbc");
+        return type;
+    }
+
+
+    const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_256_cbc(void)
+    {
+        static const char* type = "AES256-CBC";
+        WOLFSSL_ENTER("wolfSSL_EVP_aes_256_cbc");
+        return type;
+    }
+
+
+    const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_128_ctr(void)
+    {
+        static const char* type = "AES128-CTR";
+        WOLFSSL_ENTER("wolfSSL_EVP_aes_128_ctr");
+        return type;
+    }
+
+
+    const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_192_ctr(void)
+    {
+        static const char* type = "AES192-CTR";
+        WOLFSSL_ENTER("wolfSSL_EVP_aes_192_ctr");
+        return type;
+    }
+
+
+    const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_256_ctr(void)
+    {
+        static const char* type = "AES256-CTR";
+        WOLFSSL_ENTER("wolfSSL_EVP_aes_256_ctr");
+        return type;
+    }
+
+
+    const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_des_cbc(void)
+    {
+        static const char* type = "DES-CBC";
+        WOLFSSL_ENTER("wolfSSL_EVP_des_cbc");
+        return type;
+    }
+
+
+    const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_des_ede3_cbc(void)
+    {
+        static const char* type = "DES-EDE3-CBC";
+        WOLFSSL_ENTER("wolfSSL_EVP_des_ede3_cbc");
+        return type;
+    }
+
+
+    const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_rc4(void)
+    {
+        static const char* type = "ARC4";
+        WOLFSSL_ENTER("wolfSSL_EVP_rc4");
+        return type;
+    }
+
+
+    const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_enc_null(void)
+    {
+        static const char* type = "NULL";
+        WOLFSSL_ENTER("wolfSSL_EVP_enc_null");
+        return type;
+    }
+
+
+    int wolfSSL_EVP_MD_CTX_cleanup(WOLFSSL_EVP_MD_CTX* ctx)
+    {
+        WOLFSSL_ENTER("EVP_MD_CTX_cleanup");
+        (void)ctx;
+        return 0;
+    }
+
+
+
+    void wolfSSL_EVP_CIPHER_CTX_init(WOLFSSL_EVP_CIPHER_CTX* ctx)
+    {
+        WOLFSSL_ENTER("EVP_CIPHER_CTX_init");
+        if (ctx) {
+            ctx->cipherType = 0xff;   /* no init */
+            ctx->keyLen     = 0;
+            ctx->enc        = 1;      /* start in encrypt mode */
+        }
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int wolfSSL_EVP_CIPHER_CTX_cleanup(WOLFSSL_EVP_CIPHER_CTX* ctx)
+    {
+        WOLFSSL_ENTER("EVP_CIPHER_CTX_cleanup");
+        if (ctx) {
+            ctx->cipherType = 0xff;  /* no more init */
+            ctx->keyLen     = 0;
+        }
+
+        return SSL_SUCCESS;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int  wolfSSL_EVP_CipherInit(WOLFSSL_EVP_CIPHER_CTX* ctx,
+                               const WOLFSSL_EVP_CIPHER* type, byte* key,
+                               byte* iv, int enc)
+    {
+#if defined(NO_AES) && defined(NO_DES3)
+        (void)iv;
+        (void)enc;
+#else
+        int ret = 0;
+#endif
+
+        WOLFSSL_ENTER("wolfSSL_EVP_CipherInit");
+        if (ctx == NULL) {
+            WOLFSSL_MSG("no ctx");
+            return 0;   /* failure */
+        }
+
+        if (type == NULL && ctx->cipherType == 0xff) {
+            WOLFSSL_MSG("no type set");
+            return 0;   /* failure */
+        }
+
+#ifndef NO_AES
+        if (ctx->cipherType == AES_128_CBC_TYPE || (type &&
+                                       XSTRNCMP(type, "AES128-CBC", 10) == 0)) {
+            WOLFSSL_MSG("AES-128-CBC");
+            ctx->cipherType = AES_128_CBC_TYPE;
+            ctx->keyLen     = 16;
+            if (enc == 0 || enc == 1)
+                ctx->enc = enc ? 1 : 0;
+            if (key) {
+                ret = wc_AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                                ctx->enc ? AES_ENCRYPTION : AES_DECRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+            if (iv && key == NULL) {
+                ret = wc_AesSetIV(&ctx->cipher.aes, iv);
+                if (ret != 0)
+                    return ret;
+            }
+        }
+        else if (ctx->cipherType == AES_192_CBC_TYPE || (type &&
+                                       XSTRNCMP(type, "AES192-CBC", 10) == 0)) {
+            WOLFSSL_MSG("AES-192-CBC");
+            ctx->cipherType = AES_192_CBC_TYPE;
+            ctx->keyLen     = 24;
+            if (enc == 0 || enc == 1)
+                ctx->enc = enc ? 1 : 0;
+            if (key) {
+                ret = wc_AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                                ctx->enc ? AES_ENCRYPTION : AES_DECRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+            if (iv && key == NULL) {
+                ret = wc_AesSetIV(&ctx->cipher.aes, iv);
+                if (ret != 0)
+                    return ret;
+            }
+        }
+        else if (ctx->cipherType == AES_256_CBC_TYPE || (type &&
+                                       XSTRNCMP(type, "AES256-CBC", 10) == 0)) {
+            WOLFSSL_MSG("AES-256-CBC");
+            ctx->cipherType = AES_256_CBC_TYPE;
+            ctx->keyLen     = 32;
+            if (enc == 0 || enc == 1)
+                ctx->enc = enc ? 1 : 0;
+            if (key) {
+                ret = wc_AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                                ctx->enc ? AES_ENCRYPTION : AES_DECRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+            if (iv && key == NULL) {
+                ret = wc_AesSetIV(&ctx->cipher.aes, iv);
+                if (ret != 0)
+                    return ret;
+            }
+        }
+#ifdef WOLFSSL_AES_COUNTER
+        else if (ctx->cipherType == AES_128_CTR_TYPE || (type &&
+                                       XSTRNCMP(type, "AES128-CTR", 10) == 0)) {
+            WOLFSSL_MSG("AES-128-CTR");
+            ctx->cipherType = AES_128_CTR_TYPE;
+            ctx->keyLen     = 16;
+            if (enc == 0 || enc == 1)
+                ctx->enc = enc ? 1 : 0;
+            if (key) {
+                ret = wc_AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                                AES_ENCRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+            if (iv && key == NULL) {
+                ret = wc_AesSetIV(&ctx->cipher.aes, iv);
+                if (ret != 0)
+                    return ret;
+            }
+        }
+        else if (ctx->cipherType == AES_192_CTR_TYPE || (type &&
+                                       XSTRNCMP(type, "AES192-CTR", 10) == 0)) {
+            WOLFSSL_MSG("AES-192-CTR");
+            ctx->cipherType = AES_192_CTR_TYPE;
+            ctx->keyLen     = 24;
+            if (enc == 0 || enc == 1)
+                ctx->enc = enc ? 1 : 0;
+            if (key) {
+                ret = wc_AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                                AES_ENCRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+            if (iv && key == NULL) {
+                ret = wc_AesSetIV(&ctx->cipher.aes, iv);
+                if (ret != 0)
+                    return ret;
+            }
+        }
+        else if (ctx->cipherType == AES_256_CTR_TYPE || (type &&
+                                       XSTRNCMP(type, "AES256-CTR", 10) == 0)) {
+            WOLFSSL_MSG("AES-256-CTR");
+            ctx->cipherType = AES_256_CTR_TYPE;
+            ctx->keyLen     = 32;
+            if (enc == 0 || enc == 1)
+                ctx->enc = enc ? 1 : 0;
+            if (key) {
+                ret = wc_AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                                AES_ENCRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+            if (iv && key == NULL) {
+                ret = wc_AesSetIV(&ctx->cipher.aes, iv);
+                if (ret != 0)
+                    return ret;
+            }
+        }
+#endif /* WOLFSSL_AES_CTR */
+#endif /* NO_AES */
+
+#ifndef NO_DES3
+        else if (ctx->cipherType == DES_CBC_TYPE || (type &&
+                                       XSTRNCMP(type, "DES-CBC", 7) == 0)) {
+            WOLFSSL_MSG("DES-CBC");
+            ctx->cipherType = DES_CBC_TYPE;
+            ctx->keyLen     = 8;
+            if (enc == 0 || enc == 1)
+                ctx->enc = enc ? 1 : 0;
+            if (key) {
+                ret = wc_Des_SetKey(&ctx->cipher.des, key, iv,
+                          ctx->enc ? DES_ENCRYPTION : DES_DECRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+
+            if (iv && key == NULL)
+                wc_Des_SetIV(&ctx->cipher.des, iv);
+        }
+        else if (ctx->cipherType == DES_EDE3_CBC_TYPE || (type &&
+                                     XSTRNCMP(type, "DES-EDE3-CBC", 11) == 0)) {
+            WOLFSSL_MSG("DES-EDE3-CBC");
+            ctx->cipherType = DES_EDE3_CBC_TYPE;
+            ctx->keyLen     = 24;
+            if (enc == 0 || enc == 1)
+                ctx->enc = enc ? 1 : 0;
+            if (key) {
+                ret = wc_Des3_SetKey(&ctx->cipher.des3, key, iv,
+                          ctx->enc ? DES_ENCRYPTION : DES_DECRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+
+            if (iv && key == NULL) {
+                ret = wc_Des3_SetIV(&ctx->cipher.des3, iv);
+                if (ret != 0)
+                    return ret;
+            }
+        }
+#endif /* NO_DES3 */
+#ifndef NO_RC4
+        else if (ctx->cipherType == ARC4_TYPE || (type &&
+                                     XSTRNCMP(type, "ARC4", 4) == 0)) {
+            WOLFSSL_MSG("ARC4");
+            ctx->cipherType = ARC4_TYPE;
+            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);
+        }
+#endif /* NO_RC4 */
+        else if (ctx->cipherType == NULL_CIPHER_TYPE || (type &&
+                                     XSTRNCMP(type, "NULL", 4) == 0)) {
+            WOLFSSL_MSG("NULL cipher");
+            ctx->cipherType = NULL_CIPHER_TYPE;
+            ctx->keyLen = 0;
+        }
+        else
+            return 0;   /* failure */
+
+
+        return SSL_SUCCESS;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int wolfSSL_EVP_CIPHER_CTX_key_length(WOLFSSL_EVP_CIPHER_CTX* ctx)
+    {
+        WOLFSSL_ENTER("wolfSSL_EVP_CIPHER_CTX_key_length");
+        if (ctx)
+            return ctx->keyLen;
+
+        return 0;   /* failure */
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int wolfSSL_EVP_CIPHER_CTX_set_key_length(WOLFSSL_EVP_CIPHER_CTX* ctx,
+                                             int keylen)
+    {
+        WOLFSSL_ENTER("wolfSSL_EVP_CIPHER_CTX_set_key_length");
+        if (ctx)
+            ctx->keyLen = keylen;
+        else
+            return 0;  /* failure */
+
+        return SSL_SUCCESS;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int wolfSSL_EVP_Cipher(WOLFSSL_EVP_CIPHER_CTX* ctx, byte* dst, byte* src,
+                          word32 len)
+    {
+        int ret = 0;
+        WOLFSSL_ENTER("wolfSSL_EVP_Cipher");
+
+        if (ctx == NULL || dst == NULL || src == NULL) {
+            WOLFSSL_MSG("Bad function argument");
+            return 0;  /* failure */
+        }
+
+        if (ctx->cipherType == 0xff) {
+            WOLFSSL_MSG("no init");
+            return 0;  /* failure */
+        }
+
+        switch (ctx->cipherType) {
+
+#ifndef NO_AES
+            case AES_128_CBC_TYPE :
+            case AES_192_CBC_TYPE :
+            case AES_256_CBC_TYPE :
+                WOLFSSL_MSG("AES CBC");
+                if (ctx->enc)
+                    ret = wc_AesCbcEncrypt(&ctx->cipher.aes, dst, src, len);
+                else
+                    ret = wc_AesCbcDecrypt(&ctx->cipher.aes, dst, src, len);
+                break;
+
+#ifdef WOLFSSL_AES_COUNTER
+            case AES_128_CTR_TYPE :
+            case AES_192_CTR_TYPE :
+            case AES_256_CTR_TYPE :
+                    WOLFSSL_MSG("AES CTR");
+                    wc_AesCtrEncrypt(&ctx->cipher.aes, dst, src, len);
+                break;
+#endif
+#endif /* NO_AES */
+
+#ifndef NO_DES3
+            case DES_CBC_TYPE :
+                if (ctx->enc)
+                    wc_Des_CbcEncrypt(&ctx->cipher.des, dst, src, len);
+                else
+                    wc_Des_CbcDecrypt(&ctx->cipher.des, dst, src, len);
+                break;
+
+            case DES_EDE3_CBC_TYPE :
+                if (ctx->enc)
+                    ret = wc_Des3_CbcEncrypt(&ctx->cipher.des3, dst, src, len);
+                else
+                    ret = wc_Des3_CbcDecrypt(&ctx->cipher.des3, dst, src, len);
+                break;
+#endif
+
+#ifndef NO_RC4
+            case ARC4_TYPE :
+                wc_Arc4Process(&ctx->cipher.arc4, dst, src, len);
+                break;
+#endif
+
+            case NULL_CIPHER_TYPE :
+                XMEMCPY(dst, src, len);
+                break;
+
+            default: {
+                WOLFSSL_MSG("bad type");
+                return 0;  /* failure */
+            }
+        }
+
+        if (ret != 0) {
+            WOLFSSL_MSG("wolfSSL_EVP_Cipher failure");
+            return 0;  /* failuer */
+        }
+
+        WOLFSSL_MSG("wolfSSL_EVP_Cipher success");
+        return SSL_SUCCESS;  /* success */
+    }
+
+
+    /* store for external read of iv, SSL_SUCCESS on success */
+    int  wolfSSL_StoreExternalIV(WOLFSSL_EVP_CIPHER_CTX* ctx)
+    {
+        WOLFSSL_ENTER("wolfSSL_StoreExternalIV");
+
+        if (ctx == NULL) {
+            WOLFSSL_MSG("Bad function argument");
+            return SSL_FATAL_ERROR;
+        }
+
+        switch (ctx->cipherType) {
+
+#ifndef NO_AES
+            case AES_128_CBC_TYPE :
+            case AES_192_CBC_TYPE :
+            case AES_256_CBC_TYPE :
+                WOLFSSL_MSG("AES CBC");
+                memcpy(ctx->iv, &ctx->cipher.aes.reg, AES_BLOCK_SIZE);
+                break;
+
+#ifdef WOLFSSL_AES_COUNTER
+            case AES_128_CTR_TYPE :
+            case AES_192_CTR_TYPE :
+            case AES_256_CTR_TYPE :
+                WOLFSSL_MSG("AES CTR");
+                memcpy(ctx->iv, &ctx->cipher.aes.reg, AES_BLOCK_SIZE);
+                break;
+#endif /* WOLFSSL_AES_COUNTER */
+
+#endif /* NO_AES */
+
+#ifndef NO_DES3
+            case DES_CBC_TYPE :
+                WOLFSSL_MSG("DES CBC");
+                memcpy(ctx->iv, &ctx->cipher.des.reg, DES_BLOCK_SIZE);
+                break;
+
+            case DES_EDE3_CBC_TYPE :
+                WOLFSSL_MSG("DES EDE3 CBC");
+                memcpy(ctx->iv, &ctx->cipher.des3.reg, DES_BLOCK_SIZE);
+                break;
+#endif
+
+            case ARC4_TYPE :
+                WOLFSSL_MSG("ARC4");
+                break;
+
+            case NULL_CIPHER_TYPE :
+                WOLFSSL_MSG("NULL");
+                break;
+
+            default: {
+                WOLFSSL_MSG("bad type");
+                return SSL_FATAL_ERROR;
+            }
+        }
+        return SSL_SUCCESS;
+    }
+
+
+    /* set internal IV from external, SSL_SUCCESS on success */
+    int  wolfSSL_SetInternalIV(WOLFSSL_EVP_CIPHER_CTX* ctx)
+    {
+
+        WOLFSSL_ENTER("wolfSSL_SetInternalIV");
+
+        if (ctx == NULL) {
+            WOLFSSL_MSG("Bad function argument");
+            return SSL_FATAL_ERROR;
+        }
+
+        switch (ctx->cipherType) {
+
+#ifndef NO_AES
+            case AES_128_CBC_TYPE :
+            case AES_192_CBC_TYPE :
+            case AES_256_CBC_TYPE :
+                WOLFSSL_MSG("AES CBC");
+                memcpy(&ctx->cipher.aes.reg, ctx->iv, AES_BLOCK_SIZE);
+                break;
+
+#ifdef WOLFSSL_AES_COUNTER
+            case AES_128_CTR_TYPE :
+            case AES_192_CTR_TYPE :
+            case AES_256_CTR_TYPE :
+                WOLFSSL_MSG("AES CTR");
+                memcpy(&ctx->cipher.aes.reg, ctx->iv, AES_BLOCK_SIZE);
+                break;
+#endif
+
+#endif /* NO_AES */
+
+#ifndef NO_DES3
+            case DES_CBC_TYPE :
+                WOLFSSL_MSG("DES CBC");
+                memcpy(&ctx->cipher.des.reg, ctx->iv, DES_BLOCK_SIZE);
+                break;
+
+            case DES_EDE3_CBC_TYPE :
+                WOLFSSL_MSG("DES EDE3 CBC");
+                memcpy(&ctx->cipher.des3.reg, ctx->iv, DES_BLOCK_SIZE);
+                break;
+#endif
+
+            case ARC4_TYPE :
+                WOLFSSL_MSG("ARC4");
+                break;
+
+            case NULL_CIPHER_TYPE :
+                WOLFSSL_MSG("NULL");
+                break;
+
+            default: {
+                WOLFSSL_MSG("bad type");
+                return SSL_FATAL_ERROR;
+            }
+        }
+        return SSL_SUCCESS;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int wolfSSL_EVP_DigestInit(WOLFSSL_EVP_MD_CTX* ctx, const WOLFSSL_EVP_MD* type)
+    {
+        WOLFSSL_ENTER("EVP_DigestInit");
+        if (XSTRNCMP(type, "SHA256", 6) == 0) {
+             ctx->macType = SHA256;
+             wolfSSL_SHA256_Init((SHA256_CTX*)&ctx->hash);
+        }
+    #ifdef WOLFSSL_SHA384
+        else if (XSTRNCMP(type, "SHA384", 6) == 0) {
+             ctx->macType = SHA384;
+             wolfSSL_SHA384_Init((SHA384_CTX*)&ctx->hash);
+        }
+    #endif
+    #ifdef WOLFSSL_SHA512
+        else if (XSTRNCMP(type, "SHA512", 6) == 0) {
+             ctx->macType = SHA512;
+             wolfSSL_SHA512_Init((SHA512_CTX*)&ctx->hash);
+        }
+    #endif
+    #ifndef NO_MD5
+        else if (XSTRNCMP(type, "MD5", 3) == 0) {
+            ctx->macType = MD5;
+            wolfSSL_MD5_Init((MD5_CTX*)&ctx->hash);
+        }
+    #endif
+    #ifndef NO_SHA
+        /* has to be last since would pick or 256, 384, or 512 too */
+        else if (XSTRNCMP(type, "SHA", 3) == 0) {
+             ctx->macType = SHA;
+             wolfSSL_SHA_Init((SHA_CTX*)&ctx->hash);
+        }
+    #endif /* NO_SHA */
+        else
+             return BAD_FUNC_ARG;
+
+        return SSL_SUCCESS;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int wolfSSL_EVP_DigestUpdate(WOLFSSL_EVP_MD_CTX* ctx, const void* data,
+                                unsigned long sz)
+    {
+        WOLFSSL_ENTER("EVP_DigestUpdate");
+
+        switch (ctx->macType) {
+#ifndef NO_MD5
+            case MD5:
+                wolfSSL_MD5_Update((MD5_CTX*)&ctx->hash, data,
+                                  (unsigned long)sz);
+                break;
+#endif
+#ifndef NO_SHA
+            case SHA:
+                wolfSSL_SHA_Update((SHA_CTX*)&ctx->hash, data,
+                                  (unsigned long)sz);
+                break;
+#endif
+#ifndef NO_SHA256
+            case SHA256:
+                wolfSSL_SHA256_Update((SHA256_CTX*)&ctx->hash, data,
+                                     (unsigned long)sz);
+                break;
+#endif
+#ifdef WOLFSSL_SHA384
+            case SHA384:
+                wolfSSL_SHA384_Update((SHA384_CTX*)&ctx->hash, data,
+                                     (unsigned long)sz);
+                break;
+#endif
+#ifdef WOLFSSL_SHA512
+            case SHA512:
+                wolfSSL_SHA512_Update((SHA512_CTX*)&ctx->hash, data,
+                                     (unsigned long)sz);
+                break;
+#endif
+            default:
+                return BAD_FUNC_ARG;
+        }
+
+        return SSL_SUCCESS;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int wolfSSL_EVP_DigestFinal(WOLFSSL_EVP_MD_CTX* ctx, unsigned char* md,
+                               unsigned int* s)
+    {
+        WOLFSSL_ENTER("EVP_DigestFinal");
+        switch (ctx->macType) {
+#ifndef NO_MD5
+            case MD5:
+                wolfSSL_MD5_Final(md, (MD5_CTX*)&ctx->hash);
+                if (s) *s = MD5_DIGEST_SIZE;
+                break;
+#endif
+#ifndef NO_SHA
+            case SHA:
+                wolfSSL_SHA_Final(md, (SHA_CTX*)&ctx->hash);
+                if (s) *s = SHA_DIGEST_SIZE;
+                break;
+#endif
+#ifndef NO_SHA256
+            case SHA256:
+                wolfSSL_SHA256_Final(md, (SHA256_CTX*)&ctx->hash);
+                if (s) *s = SHA256_DIGEST_SIZE;
+                break;
+#endif
+#ifdef WOLFSSL_SHA384
+            case SHA384:
+                wolfSSL_SHA384_Final(md, (SHA384_CTX*)&ctx->hash);
+                if (s) *s = SHA384_DIGEST_SIZE;
+                break;
+#endif
+#ifdef WOLFSSL_SHA512
+            case SHA512:
+                wolfSSL_SHA512_Final(md, (SHA512_CTX*)&ctx->hash);
+                if (s) *s = SHA512_DIGEST_SIZE;
+                break;
+#endif
+            default:
+                return BAD_FUNC_ARG;
+        }
+
+        return SSL_SUCCESS;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int wolfSSL_EVP_DigestFinal_ex(WOLFSSL_EVP_MD_CTX* ctx, unsigned char* md,
+                                  unsigned int* s)
+    {
+        WOLFSSL_ENTER("EVP_DigestFinal_ex");
+        return EVP_DigestFinal(ctx, md, s);
+    }
+
+
+    unsigned char* wolfSSL_HMAC(const WOLFSSL_EVP_MD* evp_md, const void* key,
+                               int key_len, const unsigned char* d, int n,
+                               unsigned char* md, unsigned int* md_len)
+    {
+        int type;
+        unsigned char* ret = NULL;
+#ifdef WOLFSSL_SMALL_STACK
+        Hmac* hmac = NULL;
+#else
+        Hmac  hmac[1];
+#endif
+
+        WOLFSSL_ENTER("HMAC");
+        if (!md)
+            return NULL;  /* no static buffer support */
+
+        if (XSTRNCMP(evp_md, "MD5", 3) == 0)
+            type = MD5;
+        else if (XSTRNCMP(evp_md, "SHA", 3) == 0)
+            type = SHA;
+        else
+            return NULL;
+
+    #ifdef WOLFSSL_SMALL_STACK
+        hmac = (Hmac*)XMALLOC(sizeof(Hmac), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (hmac == NULL)
+            return NULL;
+    #endif
+
+        if (wc_HmacSetKey(hmac, type, (const byte*)key, key_len) == 0)
+            if (wc_HmacUpdate(hmac, d, n) == 0)
+                if (wc_HmacFinal(hmac, md) == 0) {
+                    if (md_len)
+                        *md_len = (type == MD5) ? (int)MD5_DIGEST_SIZE
+                                                : (int)SHA_DIGEST_SIZE;
+                    ret = md;
+                }
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(hmac, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+
+        return ret;
+    }
+
+    void wolfSSL_ERR_clear_error(void)
+    {
+        /* TODO: */
+    }
+
+
+    int wolfSSL_RAND_status(void)
+    {
+        return SSL_SUCCESS;  /* wolfCrypt provides enough seed internally */
+    }
+
+
+
+    void wolfSSL_RAND_add(const void* add, int len, double entropy)
+    {
+        (void)add;
+        (void)len;
+        (void)entropy;
+
+        /* wolfSSL seeds/adds internally, use explicit RNG if you want
+           to take control */
+    }
+
+
+#ifndef NO_DES3
+    /* SSL_SUCCESS 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 SSL_SUCCESS;
+    }
+
+
+    void wolfSSL_DES_cbc_encrypt(const unsigned char* input,
+                     unsigned char* output, long length,
+                     WOLFSSL_DES_key_schedule* schedule, WOLFSSL_DES_cblock* ivec,
+                     int enc)
+    {
+        Des myDes;
+
+        WOLFSSL_ENTER("DES_cbc_encrypt");
+
+        /* 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);
+    }
+
+
+    /* correctly sets ivec for next call */
+    void wolfSSL_DES_ncbc_encrypt(const unsigned char* input,
+                     unsigned char* output, long length,
+                     WOLFSSL_DES_key_schedule* schedule, WOLFSSL_DES_cblock* ivec,
+                     int enc)
+    {
+        Des myDes;
+
+        WOLFSSL_ENTER("DES_ncbc_encrypt");
+
+        /* 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));
+    }
+
+#endif /* NO_DES3 */
+
+
+    void wolfSSL_ERR_free_strings(void)
+    {
+        /* handled internally */
+    }
+
+
+    void wolfSSL_ERR_remove_state(unsigned long state)
+    {
+        /* TODO: GetErrors().Remove(); */
+        (void)state;
+    }
+
+
+    void wolfSSL_EVP_cleanup(void)
+    {
+        /* nothing to do here */
+    }
+
+
+    void wolfSSL_cleanup_all_ex_data(void)
+    {
+        /* nothing to do here */
+    }
+
+
+    int wolfSSL_clear(WOLFSSL* ssl)
+    {
+        (void)ssl;
+        /* TODO: GetErrors().Remove(); */
+        return SSL_SUCCESS;
+    }
+
+
+    long wolfSSL_SSL_SESSION_set_timeout(WOLFSSL_SESSION* ses, long t)
+    {
+        word32 tmptime;
+        if (!ses || t < 0)
+            return BAD_FUNC_ARG;
+
+        tmptime = t & 0xFFFFFFFF;
+
+        ses->timeout = tmptime;
+
+        return SSL_SUCCESS;
+    }
+
+
+    long wolfSSL_CTX_set_mode(WOLFSSL_CTX* ctx, long mode)
+    {
+        /* SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER is wolfSSL default mode */
+
+        WOLFSSL_ENTER("SSL_CTX_set_mode");
+        if (mode == SSL_MODE_ENABLE_PARTIAL_WRITE)
+            ctx->partialWrite = 1;
+
+        return mode;
+    }
+
+
+    long wolfSSL_SSL_get_mode(WOLFSSL* ssl)
+    {
+        /* TODO: */
+        (void)ssl;
+        return 0;
+    }
+
+
+    long wolfSSL_CTX_get_mode(WOLFSSL_CTX* ctx)
+    {
+        /* TODO: */
+        (void)ctx;
+        return 0;
+    }
+
+
+    void wolfSSL_CTX_set_default_read_ahead(WOLFSSL_CTX* ctx, int m)
+    {
+        /* TODO: maybe? */
+        (void)ctx;
+        (void)m;
+    }
+
+
+    int wolfSSL_CTX_set_session_id_context(WOLFSSL_CTX* ctx,
+                                       const unsigned char* sid_ctx,
+                                       unsigned int sid_ctx_len)
+    {
+        /* No application specific context needed for wolfSSL */
+        (void)ctx;
+        (void)sid_ctx;
+        (void)sid_ctx_len;
+        return SSL_SUCCESS;
+    }
+
+
+    long wolfSSL_CTX_sess_get_cache_size(WOLFSSL_CTX* ctx)
+    {
+        /* TODO: maybe? */
+        (void)ctx;
+        return (~0);
+    }
+
+    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;
+    }
+
+#endif /* OPENSSL_EXTRA */
+
+
+#if defined(KEEP_PEER_CERT)
+
+    WOLFSSL_X509* wolfSSL_get_peer_certificate(WOLFSSL* ssl)
+    {
+        WOLFSSL_ENTER("SSL_get_peer_certificate");
+        if (ssl->peerCert.issuer.sz)
+            return &ssl->peerCert;
+        else
+            return 0;
+    }
+
+#endif /* KEEP_PEER_CERT */
+
+
+#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
+
+    void wolfSSL_FreeX509(WOLFSSL_X509* x509)
+    {
+        WOLFSSL_ENTER("wolfSSL_FreeX509");
+        FreeX509(x509);
+    }
+
+
+    /* return the next, if any, altname from the peer cert */
+    char* wolfSSL_X509_get_next_altname(WOLFSSL_X509* cert)
+    {
+        char* ret = NULL;
+        WOLFSSL_ENTER("wolfSSL_X509_get_next_altname");
+
+        /* don't have any to work with */
+        if (cert == NULL || cert->altNames == NULL)
+            return NULL;
+
+        /* already went through them */
+        if (cert->altNamesNext == NULL)
+            return NULL;
+
+        ret = cert->altNamesNext->name;
+        cert->altNamesNext = cert->altNamesNext->next;
+
+        return ret;
+    }
+
+
+    WOLFSSL_X509_NAME* wolfSSL_X509_get_issuer_name(WOLFSSL_X509* cert)
+    {
+        WOLFSSL_ENTER("X509_get_issuer_name");
+        return &cert->issuer;
+    }
+
+
+    WOLFSSL_X509_NAME* wolfSSL_X509_get_subject_name(WOLFSSL_X509* cert)
+    {
+        WOLFSSL_ENTER("X509_get_subject_name");
+        return &cert->subject;
+    }
+
+
+    int wolfSSL_X509_get_isCA(WOLFSSL_X509* x509)
+    {
+        int isCA = 0;
+
+        WOLFSSL_ENTER("wolfSSL_X509_get_isCA");
+
+        if (x509 != NULL)
+            isCA = x509->isCa;
+
+        WOLFSSL_LEAVE("wolfSSL_X509_get_isCA", isCA);
+
+        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;
+    }
+
+
+    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:
+                break;
+        }
+
+        if (buf != NULL && text != NULL) {
+            textSz = min(textSz, len);
+            XMEMCPY(buf, text, textSz);
+            buf[textSz] = '\0';
+        }
+
+        WOLFSSL_LEAVE("wolfSSL_X509_NAME_get_text_by_NID", textSz);
+        return textSz;
+    }
+#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 = min(sz, name->sz);
+
+        WOLFSSL_ENTER("wolfSSL_X509_NAME_oneline");
+        if (!name->sz) return in;
+
+        if (!in) {
+            in = (char*)XMALLOC(name->sz, 0, DYNAMIC_TYPE_OPENSSL);
+            if (!in ) return in;
+            copySz = name->sz;
+        }
+
+        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,
+                                                 unsigned char* buf, int* bufSz)
+    {
+        WOLFSSL_ENTER("wolfSSL_X509_get_signature");
+        if (x509 == NULL || bufSz == NULL || *bufSz < (int)x509->sig.length)
+            return SSL_FATAL_ERROR;
+
+        if (buf != NULL)
+            XMEMCPY(buf, x509->sig.buffer, x509->sig.length);
+        *bufSz = x509->sig.length;
+
+        return SSL_SUCCESS;
+    }
+
+
+    /* write X509 serial number in unsigned binary to buffer
+       buffer needs to be at least EXTERNAL_SERIAL_SIZE (32) for all cases
+       return SSL_SUCCESS on success */
+    int wolfSSL_X509_get_serial_number(WOLFSSL_X509* x509, byte* in, int* inOutSz)
+    {
+        WOLFSSL_ENTER("wolfSSL_X509_get_serial_number");
+        if (x509 == NULL || in == NULL ||
+                                   inOutSz == NULL || *inOutSz < x509->serialSz)
+            return BAD_FUNC_ARG;
+
+        XMEMCPY(in, x509->serial, x509->serialSz);
+        *inOutSz = x509->serialSz;
+
+        return SSL_SUCCESS;
+    }
+
+
+    const byte* wolfSSL_X509_get_der(WOLFSSL_X509* x509, int* outSz)
+    {
+        WOLFSSL_ENTER("wolfSSL_X509_get_der");
+
+        if (x509 == NULL || outSz == NULL)
+            return NULL;
+
+        *outSz = (int)x509->derCert.length;
+        return x509->derCert.buffer;
+    }
+
+
+    int wolfSSL_X509_version(WOLFSSL_X509* x509)
+    {
+        WOLFSSL_ENTER("wolfSSL_X509_version");
+
+        if (x509 == NULL)
+            return 0;
+
+        return x509->version;
+    }
+
+
+    const byte* wolfSSL_X509_notBefore(WOLFSSL_X509* x509)
+    {
+        WOLFSSL_ENTER("wolfSSL_X509_notBefore");
+
+        if (x509 == NULL)
+            return NULL;
+
+        return x509->notBefore;
+    }
+
+
+    const byte* wolfSSL_X509_notAfter(WOLFSSL_X509* x509)
+    {
+        WOLFSSL_ENTER("wolfSSL_X509_notAfter");
+
+        if (x509 == NULL)
+            return NULL;
+
+        return x509->notAfter;
+    }
+
+
+#ifdef WOLFSSL_SEP
+
+/* copy oid into in buffer, at most *inOutSz bytes, if buffer is null will
+   malloc buffer, call responsible for freeing. Actual size returned in
+   *inOutSz. Requires inOutSz be non-null */
+byte* wolfSSL_X509_get_device_type(WOLFSSL_X509* x509, byte* in, int *inOutSz)
+{
+    int copySz;
+
+    WOLFSSL_ENTER("wolfSSL_X509_get_dev_type");
+    if (inOutSz == NULL) return NULL;
+    if (!x509->deviceTypeSz) return in;
+
+    copySz = min(*inOutSz, x509->deviceTypeSz);
+
+    if (!in) {
+        in = (byte*)XMALLOC(x509->deviceTypeSz, 0, DYNAMIC_TYPE_OPENSSL);
+        if (!in) return in;
+        copySz = x509->deviceTypeSz;
+    }
+
+    XMEMCPY(in, x509->deviceType, copySz);
+    *inOutSz = copySz;
+
+    return in;
+}
+
+
+byte* wolfSSL_X509_get_hw_type(WOLFSSL_X509* x509, byte* in, int* inOutSz)
+{
+    int copySz;
+
+    WOLFSSL_ENTER("wolfSSL_X509_get_hw_type");
+    if (inOutSz == NULL) return NULL;
+    if (!x509->hwTypeSz) return in;
+
+    copySz = min(*inOutSz, x509->hwTypeSz);
+
+    if (!in) {
+        in = (byte*)XMALLOC(x509->hwTypeSz, 0, DYNAMIC_TYPE_OPENSSL);
+        if (!in) return in;
+        copySz = x509->hwTypeSz;
+    }
+
+    XMEMCPY(in, x509->hwType, copySz);
+    *inOutSz = copySz;
+
+    return in;
+}
+
+
+byte* wolfSSL_X509_get_hw_serial_number(WOLFSSL_X509* x509,byte* in,int* inOutSz)
+{
+    int copySz;
+
+    WOLFSSL_ENTER("wolfSSL_X509_get_hw_serial_number");
+    if (inOutSz == NULL) return NULL;
+    if (!x509->hwTypeSz) return in;
+
+    copySz = min(*inOutSz, x509->hwSerialNumSz);
+
+    if (!in) {
+        in = (byte*)XMALLOC(x509->hwSerialNumSz, 0, DYNAMIC_TYPE_OPENSSL);
+        if (!in) return in;
+        copySz = x509->hwSerialNumSz;
+    }
+
+    XMEMCPY(in, x509->hwSerialNum, copySz);
+    *inOutSz = copySz;
+
+    return in;
+}
+
+#endif /* WOLFSSL_SEP */
+
+
+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_TMP_BUFFER);
+        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);
+                if (CopyDecodedToX509(newX509, cert) != 0) {
+                    XFREE(newX509, NULL, DYNAMIC_TYPE_X509);
+                    newX509 = NULL;
+                }
+            }
+        }
+        FreeDecodedCert(cert);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+    }
+
+    if (x509 != NULL)
+        *x509 = newX509;
+
+    return newX509;
+}
+
+
+#ifndef NO_FILESYSTEM
+
+#ifndef NO_STDIO_FILESYSTEM
+
+WOLFSSL_X509* wolfSSL_X509_d2i_fp(WOLFSSL_X509** x509, XFILE file)
+{
+    WOLFSSL_X509* newX509 = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_X509_d2i_fp");
+
+    if (file != XBADFILE) {
+        byte* fileBuffer = NULL;
+        long sz = 0;
+
+        XFSEEK(file, 0, XSEEK_END);
+        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) {
+            int ret = (int)XFREAD(fileBuffer, sz, 1, file);
+            if (ret > 0) {
+                newX509 = wolfSSL_X509_d2i(NULL, fileBuffer, (int)sz);
+            }
+            XFREE(fileBuffer, NULL, DYNAMIC_TYPE_FILE);
+        }
+    }
+
+    if (x509 != NULL)
+        *x509 = newX509;
+
+    return newX509;
+}
+
+#endif /* NO_STDIO_FILESYSTEM */
+
+WOLFSSL_X509* wolfSSL_X509_load_certificate_file(const char* fname, int format)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    byte  staticBuffer[1]; /* force heap usage */
+#else
+    byte  staticBuffer[FILE_BUFFER_SIZE];
+#endif
+    byte* fileBuffer = staticBuffer;
+    int   dynamic = 0;
+    int   ret;
+    long  sz = 0;
+    XFILE file;
+
+    WOLFSSL_X509* x509 = NULL;
+    buffer der;
+
+    WOLFSSL_ENTER("wolfSSL_X509_load_certificate");
+
+    /* Check the inputs */
+    if ((fname == NULL) ||
+        (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM))
+        return NULL;
+
+    file = XFOPEN(fname, "rb");
+    if (file == XBADFILE)
+        return NULL;
+
+    XFSEEK(file, 0, XSEEK_END);
+    sz = XFTELL(file);
+    XREWIND(file);
+
+    if (sz > (long)sizeof(staticBuffer)) {
+        fileBuffer = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE);
+        if (fileBuffer == NULL) {
+            XFCLOSE(file);
+            return NULL;
+        }
+        dynamic = 1;
+    }
+    else if (sz < 0) {
+        XFCLOSE(file);
+        return NULL;
+    }
+
+    ret = (int)XFREAD(fileBuffer, sz, 1, file);
+    if (ret < 0) {
+        XFCLOSE(file);
+        if (dynamic)
+            XFREE(fileBuffer, NULL, DYNAMIC_TYPE_FILE);
+        return NULL;
+    }
+
+    XFCLOSE(file);
+
+    der.buffer = NULL;
+    der.length = 0;
+
+    if (format == SSL_FILETYPE_PEM) {
+        int ecc = 0;
+    #ifdef WOLFSSL_SMALL_STACK
+        EncryptedInfo* info = NULL;
+    #else
+        EncryptedInfo  info[1];
+    #endif
+
+    #ifdef WOLFSSL_SMALL_STACK
+        info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        if (info == NULL) {
+            if (dynamic)
+                XFREE(fileBuffer, NULL, DYNAMIC_TYPE_FILE);
+
+            return NULL;
+        }
+    #endif
+
+        info->set = 0;
+        info->ctx = NULL;
+        info->consumed = 0;
+
+        if (PemToDer(fileBuffer, sz, CERT_TYPE, &der, NULL, info, &ecc) != 0)
+        {
+            /* Only time this should fail, and leave `der` with a buffer
+               is when the Base64 Decode fails. Release `der.buffer` in
+               that case. */
+            if (der.buffer != NULL) {
+                XFREE(der.buffer, NULL, DYNAMIC_TYPE_CERT);
+                der.buffer = NULL;
+            }
+        }
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+    }
+    else {
+        der.buffer = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_CERT);
+        if (der.buffer != NULL) {
+            XMEMCPY(der.buffer, fileBuffer, sz);
+            der.length = (word32)sz;
+        }
+    }
+
+    if (dynamic)
+        XFREE(fileBuffer, NULL, DYNAMIC_TYPE_FILE);
+
+    /* At this point we want `der` to have the certificate in DER format */
+    /* ready to be decoded. */
+    if (der.buffer != NULL) {
+    #ifdef WOLFSSL_SMALL_STACK
+        DecodedCert* cert = NULL;
+    #else
+        DecodedCert  cert[1];
+    #endif
+
+    #ifdef WOLFSSL_SMALL_STACK
+        cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        if (cert != NULL)
+    #endif
+        {
+            InitDecodedCert(cert, der.buffer, der.length, NULL);
+            if (ParseCertRelative(cert, CERT_TYPE, 0, NULL) == 0) {
+                x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL,
+                                                             DYNAMIC_TYPE_X509);
+                if (x509 != NULL) {
+                    InitX509(x509, 1);
+                    if (CopyDecodedToX509(x509, cert) != 0) {
+                        XFREE(x509, NULL, DYNAMIC_TYPE_X509);
+                        x509 = NULL;
+                    }
+                }
+            }
+
+            FreeDecodedCert(cert);
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+        }
+
+        XFREE(der.buffer, NULL, DYNAMIC_TYPE_CERT);
+    }
+
+    return x509;
+}
+
+#endif /* NO_FILESYSTEM */
+
+#endif /* KEEP_PEER_CERT || SESSION_CERTS */
+
+
+#ifdef OPENSSL_EXTRA
+int wolfSSL_set_ex_data(WOLFSSL* ssl, int idx, void* data)
+{
+#ifdef FORTRESS
+    if (ssl != NULL && idx < MAX_EX_DATA)
+    {
+        ssl->ex_data[idx] = data;
+        return SSL_SUCCESS;
+    }
+#else
+    (void)ssl;
+    (void)idx;
+    (void)data;
+#endif
+    return SSL_FAILURE;
+}
+
+
+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)
+{
+    (void)ssl;
+    /* client by default */
+}
+#endif
+
+int wolfSSL_get_shutdown(const WOLFSSL* ssl)
+{
+    return (ssl->options.isClosed  ||
+            ssl->options.connReset ||
+            ssl->options.sentNotify);
+}
+
+
+int wolfSSL_session_reused(WOLFSSL* ssl)
+{
+    return ssl->options.resuming;
+}
+
+#ifdef OPENSSL_EXTRA
+void wolfSSL_SESSION_free(WOLFSSL_SESSION* session)
+{
+    (void)session;
+}
+#endif
+
+const char* wolfSSL_get_version(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("SSL_get_version");
+    if (ssl->version.major == SSLv3_MAJOR) {
+        switch (ssl->version.minor) {
+            case SSLv3_MINOR :
+                return "SSLv3";
+            case TLSv1_MINOR :
+                return "TLSv1";
+            case TLSv1_1_MINOR :
+                return "TLSv1.1";
+            case TLSv1_2_MINOR :
+                return "TLSv1.2";
+            default:
+                return "unknown";
+        }
+    }
+    else if (ssl->version.major == DTLS_MAJOR) {
+        switch (ssl->version.minor) {
+            case DTLS_MINOR :
+                return "DTLS";
+            case DTLSv1_2_MINOR :
+                return "DTLSv1.2";
+            default:
+                return "unknown";
+        }
+    }
+    return "unknown";
+}
+
+
+/* current library version */
+const char* wolfSSL_lib_version(void)
+{
+    return LIBWOLFSSL_VERSION_STRING;
+}
+
+
+/* current library version in hex */
+word32 wolfSSL_lib_version_hex(void)
+{
+    return LIBWOLFSSL_VERSION_HEX;
+}
+
+
+int wolfSSL_get_current_cipher_suite(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("SSL_get_current_cipher_suite");
+    if (ssl)
+        return (ssl->options.cipherSuite0 << 8) | ssl->options.cipherSuite;
+    return 0;
+}
+
+WOLFSSL_CIPHER* wolfSSL_get_current_cipher(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("SSL_get_current_cipher");
+    if (ssl)
+        return &ssl->cipher;
+    else
+        return NULL;
+}
+
+
+const char* wolfSSL_CIPHER_get_name(const WOLFSSL_CIPHER* cipher)
+{
+    (void)cipher;
+
+    WOLFSSL_ENTER("SSL_CIPHER_get_name");
+#ifndef NO_ERROR_STRINGS
+    if (cipher) {
+#if defined(HAVE_CHACHA)
+        if (cipher->ssl->options.cipherSuite0 == CHACHA_BYTE) {
+        /* ChaCha suites */
+        switch (cipher->ssl->options.cipherSuite) {
+#ifdef HAVE_CHACHA
+#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";
+#endif
+            case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 :
+                return "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256";
+#endif
+            }
+        }
+#endif
+
+#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 (cipher->ssl->options.cipherSuite0 == ECC_BYTE) {
+        /* ECC suites */
+        switch (cipher->ssl->options.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
+            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
+            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
+            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
+            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
+            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
+            case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA :
+                return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA";
+#endif
+#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
+            case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA :
+                return "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA";
+#endif
+
+#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
+            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
+            case TLS_ECDH_ECDSA_WITH_RC4_128_SHA :
+                return "TLS_ECDH_ECDSA_WITH_RC4_128_SHA";
+#endif
+#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
+            case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA :
+                return "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA";
+#endif
+#endif /* NO_SHA */
+
+#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
+            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
+            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
+#endif /* HAVE_ECC */
+
+#ifdef HAVE_AESCCM
+#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
+#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
+#ifdef HAVE_ECC
+            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
+#endif
+
+            default:
+                return "NONE";
+        }
+        }
+#endif  /* ECC */
+        if (cipher->ssl->options.cipherSuite0 != ECC_BYTE &&
+            cipher->ssl->options.cipherSuite0 != CHACHA_BYTE) {
+
+            /* normal suites */
+        switch (cipher->ssl->options.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
+    #ifndef NO_MD5
+            case SSL_RSA_WITH_RC4_128_MD5 :
+                return "SSL_RSA_WITH_RC4_128_MD5";
+    #endif
+#endif
+#ifndef NO_SHA
+    #ifndef NO_DES3
+            case SSL_RSA_WITH_3DES_EDE_CBC_SHA :
+                return "SSL_RSA_WITH_3DES_EDE_CBC_SHA";
+    #endif
+            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
+            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
+#ifndef NO_SHA
+            case TLS_RSA_WITH_NULL_SHA :
+                return "TLS_RSA_WITH_NULL_SHA";
+#endif
+            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
+#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
+#endif
+#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
+#endif
+#ifndef NO_SHA
+            case TLS_PSK_WITH_NULL_SHA :
+                return "TLS_PSK_WITH_NULL_SHA";
+#endif
+#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";
+#endif
+#ifndef NO_HC128
+    #ifndef NO_MD5
+            case TLS_RSA_WITH_HC_128_MD5 :
+                return "TLS_RSA_WITH_HC_128_MD5";
+    #endif
+    #ifndef NO_SHA
+            case TLS_RSA_WITH_HC_128_SHA :
+                return "TLS_RSA_WITH_HC_128_SHA";
+    #endif
+    #ifdef HAVE_BLAKE2
+            case TLS_RSA_WITH_HC_128_B2B256:
+                return "TLS_RSA_WITH_HC_128_B2B256";
+    #endif
+#endif /* NO_HC128 */
+#ifndef NO_SHA
+    #ifndef NO_RABBIT
+            case TLS_RSA_WITH_RABBIT_SHA :
+                return "TLS_RSA_WITH_RABBIT_SHA";
+    #endif
+    #ifdef HAVE_NTRU
+        #ifndef NO_RC4
+            case TLS_NTRU_RSA_WITH_RC4_128_SHA :
+                return "TLS_NTRU_RSA_WITH_RC4_128_SHA";
+        #endif
+        #ifndef NO_DES3
+            case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA :
+                return "TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA";
+        #endif
+            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 */
+#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
+            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
+            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_RSA */
+#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
+            default:
+                return "NONE";
+        }  /* switch */
+        }  /* normal / ECC */
+    }
+#endif /* NO_ERROR_STRINGS */
+    return "NONE";
+}
+
+
+const char* wolfSSL_get_cipher(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("wolfSSL_get_cipher");
+    return wolfSSL_CIPHER_get_name(wolfSSL_get_current_cipher(ssl));
+}
+
+#ifdef OPENSSL_EXTRA
+
+
+
+char* wolfSSL_CIPHER_description(WOLFSSL_CIPHER* cipher, char* in, int len)
+{
+    (void)cipher;
+    (void)in;
+    (void)len;
+    return 0;
+}
+
+
+WOLFSSL_SESSION* wolfSSL_get1_session(WOLFSSL* ssl)  /* what's ref count */
+{
+    (void)ssl;
+    return 0;
+}
+
+
+void wolfSSL_X509_free(WOLFSSL_X509* buf)
+{
+    FreeX509(buf);
+}
+
+
+/* was do nothing */
+/*
+void OPENSSL_free(void* buf)
+{
+    (void)buf;
+}
+*/
+
+
+int wolfSSL_OCSP_parse_url(char* url, char** host, char** port, char** path,
+                   int* ssl)
+{
+    (void)url;
+    (void)host;
+    (void)port;
+    (void)path;
+    (void)ssl;
+    return 0;
+}
+
+
+WOLFSSL_METHOD* wolfSSLv2_client_method(void)
+{
+    return 0;
+}
+
+
+WOLFSSL_METHOD* wolfSSLv2_server_method(void)
+{
+    return 0;
+}
+
+
+#ifndef NO_MD4
+
+void wolfSSL_MD4_Init(WOLFSSL_MD4_CTX* md4)
+{
+    /* make sure we have a big enough buffer */
+    typedef char ok[sizeof(md4->buffer) >= sizeof(Md4) ? 1 : -1];
+    (void) sizeof(ok);
+
+    WOLFSSL_ENTER("MD4_Init");
+    wc_InitMd4((Md4*)md4);
+}
+
+
+void wolfSSL_MD4_Update(WOLFSSL_MD4_CTX* md4, const void* data,
+                       unsigned long len)
+{
+    WOLFSSL_ENTER("MD4_Update");
+    wc_Md4Update((Md4*)md4, (const byte*)data, (word32)len);
+}
+
+
+void wolfSSL_MD4_Final(unsigned char* digest, WOLFSSL_MD4_CTX* md4)
+{
+    WOLFSSL_ENTER("MD4_Final");
+    wc_Md4Final((Md4*)md4, digest);
+}
+
+#endif /* NO_MD4 */
+
+
+WOLFSSL_BIO* wolfSSL_BIO_pop(WOLFSSL_BIO* top)
+{
+    (void)top;
+    return 0;
+}
+
+
+int wolfSSL_BIO_pending(WOLFSSL_BIO* bio)
+{
+    (void)bio;
+    return 0;
+}
+
+
+
+WOLFSSL_BIO_METHOD* wolfSSL_BIO_s_mem(void)
+{
+    static WOLFSSL_BIO_METHOD meth;
+
+    WOLFSSL_ENTER("BIO_s_mem");
+    meth.type = BIO_MEMORY;
+
+    return &meth;
+}
+
+
+WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_base64(void)
+{
+    return 0;
+}
+
+
+void wolfSSL_BIO_set_flags(WOLFSSL_BIO* bio, int flags)
+{
+    (void)bio;
+    (void)flags;
+}
+
+
+
+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;
+}
+
+
+int wolfSSL_RAND_load_file(const char* fname, long len)
+{
+    (void)fname;
+    /* wolfCrypt provides enough entropy internally or will report error */
+    if (len == -1)
+        return 1024;
+    else
+        return (int)len;
+}
+
+
+int wolfSSL_RAND_egd(const char* path)
+{
+    (void)path;
+    return 0;
+}
+
+
+
+WOLFSSL_COMP_METHOD* wolfSSL_COMP_zlib(void)
+{
+    return 0;
+}
+
+
+WOLFSSL_COMP_METHOD* wolfSSL_COMP_rle(void)
+{
+    return 0;
+}
+
+
+int wolfSSL_COMP_add_compression_method(int method, void* data)
+{
+    (void)method;
+    (void)data;
+    return 0;
+}
+
+
+
+int wolfSSL_get_ex_new_index(long idx, void* data, void* cb1, void* cb2,
+                         void* cb3)
+{
+    (void)idx;
+    (void)data;
+    (void)cb1;
+    (void)cb2;
+    (void)cb3;
+    return 0;
+}
+
+
+void wolfSSL_set_dynlock_create_callback(WOLFSSL_dynlock_value* (*f)(
+                                                          const char*, int))
+{
+    (void)f;
+}
+
+
+void wolfSSL_set_dynlock_lock_callback(
+             void (*f)(int, WOLFSSL_dynlock_value*, const char*, int))
+{
+    (void)f;
+}
+
+
+void wolfSSL_set_dynlock_destroy_callback(
+                  void (*f)(WOLFSSL_dynlock_value*, const char*, int))
+{
+    (void)f;
+}
+
+
+
+const char* wolfSSL_X509_verify_cert_error_string(long err)
+{
+    (void)err;
+    return 0;
+}
+
+
+
+int wolfSSL_X509_LOOKUP_add_dir(WOLFSSL_X509_LOOKUP* lookup, const char* dir,
+                               long len)
+{
+    (void)lookup;
+    (void)dir;
+    (void)len;
+    return 0;
+}
+
+
+int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP* lookup,
+                                 const char* file, long len)
+{
+    (void)lookup;
+    (void)file;
+    (void)len;
+    return 0;
+}
+
+
+WOLFSSL_X509_LOOKUP_METHOD* wolfSSL_X509_LOOKUP_hash_dir(void)
+{
+    return 0;
+}
+
+
+WOLFSSL_X509_LOOKUP_METHOD* wolfSSL_X509_LOOKUP_file(void)
+{
+    return 0;
+}
+
+
+
+WOLFSSL_X509_LOOKUP* wolfSSL_X509_STORE_add_lookup(WOLFSSL_X509_STORE* store,
+                                               WOLFSSL_X509_LOOKUP_METHOD* m)
+{
+    (void)store;
+    (void)m;
+    return 0;
+}
+
+
+int wolfSSL_X509_STORE_add_cert(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509)
+{
+    int result = SSL_FATAL_ERROR;
+
+    WOLFSSL_ENTER("wolfSSL_X509_STORE_add_cert");
+    if (store != NULL && store->cm != NULL && x509 != NULL) {
+        buffer derCert;
+        derCert.buffer = (byte*)XMALLOC(x509->derCert.length,
+                                                   NULL, DYNAMIC_TYPE_CERT);
+        if (derCert.buffer != NULL) {
+            derCert.length = x509->derCert.length;
+                /* AddCA() frees the buffer. */
+            XMEMCPY(derCert.buffer,
+                                x509->derCert.buffer, x509->derCert.length);
+            result = AddCA(store->cm, derCert, WOLFSSL_USER_CA, 1);
+            if (result != SSL_SUCCESS) result = SSL_FATAL_ERROR;
+        }
+    }
+
+    WOLFSSL_LEAVE("wolfSSL_X509_STORE_add_cert", result);
+    return result;
+}
+
+
+WOLFSSL_X509_STORE* wolfSSL_X509_STORE_new(void)
+{
+    WOLFSSL_X509_STORE* store = NULL;
+
+    store = (WOLFSSL_X509_STORE*)XMALLOC(sizeof(WOLFSSL_X509_STORE), NULL, 0);
+    if (store != NULL) {
+        store->cm = wolfSSL_CertManagerNew();
+        if (store->cm == NULL) {
+            XFREE(store, NULL, 0);
+            store = NULL;
+        }
+    }
+
+    return store;
+}
+
+
+void wolfSSL_X509_STORE_free(WOLFSSL_X509_STORE* store)
+{
+    if (store != NULL) {
+        if (store->cm != NULL)
+        wolfSSL_CertManagerFree(store->cm);
+        XFREE(store, NULL, 0);
+    }
+}
+
+
+int wolfSSL_X509_STORE_set_default_paths(WOLFSSL_X509_STORE* store)
+{
+    (void)store;
+    return SSL_SUCCESS;
+}
+
+
+int wolfSSL_X509_STORE_get_by_subject(WOLFSSL_X509_STORE_CTX* ctx, int idx,
+                            WOLFSSL_X509_NAME* name, WOLFSSL_X509_OBJECT* obj)
+{
+    (void)ctx;
+    (void)idx;
+    (void)name;
+    (void)obj;
+    return 0;
+}
+
+
+WOLFSSL_X509_STORE_CTX* wolfSSL_X509_STORE_CTX_new(void)
+{
+    WOLFSSL_X509_STORE_CTX* ctx = (WOLFSSL_X509_STORE_CTX*)XMALLOC(
+                                    sizeof(WOLFSSL_X509_STORE_CTX), NULL, 0);
+
+    if (ctx != NULL)
+        wolfSSL_X509_STORE_CTX_init(ctx, NULL, NULL, NULL);
+
+    return ctx;
+}
+
+
+int wolfSSL_X509_STORE_CTX_init(WOLFSSL_X509_STORE_CTX* ctx,
+     WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509, STACK_OF(WOLFSSL_X509)* sk)
+{
+    (void)sk;
+    if (ctx != NULL) {
+        ctx->store = store;
+        ctx->current_cert = x509;
+        ctx->domain = NULL;
+        ctx->ex_data = NULL;
+        ctx->userCtx = NULL;
+        ctx->error = 0;
+        ctx->error_depth = 0;
+        ctx->discardSessionCerts = 0;
+        return SSL_SUCCESS;
+    }
+    return SSL_FATAL_ERROR;
+}
+
+
+void wolfSSL_X509_STORE_CTX_free(WOLFSSL_X509_STORE_CTX* ctx)
+{
+    if (ctx != NULL) {
+        if (ctx->store != NULL)
+            wolfSSL_X509_STORE_free(ctx->store);
+        if (ctx->current_cert != NULL)
+            wolfSSL_FreeX509(ctx->current_cert);
+        XFREE(ctx, NULL, 0);
+    }
+}
+
+
+void wolfSSL_X509_STORE_CTX_cleanup(WOLFSSL_X509_STORE_CTX* ctx)
+{
+    (void)ctx;
+}
+
+
+int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
+{
+    if (ctx != NULL && ctx->store != NULL && ctx->store->cm != NULL
+                                             && ctx->current_cert != NULL) {
+        return wolfSSL_CertManagerVerifyBuffer(ctx->store->cm,
+                    ctx->current_cert->derCert.buffer,
+                    ctx->current_cert->derCert.length,
+                    SSL_FILETYPE_ASN1);
+    }
+    return SSL_FATAL_ERROR;
+}
+
+
+WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_lastUpdate(WOLFSSL_X509_CRL* crl)
+{
+    (void)crl;
+    return 0;
+}
+
+
+WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_nextUpdate(WOLFSSL_X509_CRL* crl)
+{
+    (void)crl;
+    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), NULL, DYNAMIC_TYPE_PUBLIC_KEY);
+        if (key != NULL) {
+            key->type = x509->pubKeyOID;
+            key->save_type = 0;
+            key->pkey.ptr = (char*)XMALLOC(
+                        x509->pubKey.length, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
+            if (key->pkey.ptr == NULL) {
+                XFREE(key, NULL, 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;
+}
+
+
+int wolfSSL_X509_CRL_verify(WOLFSSL_X509_CRL* crl, WOLFSSL_EVP_PKEY* key)
+{
+    (void)crl;
+    (void)key;
+    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;
+}
+
+
+void wolfSSL_EVP_PKEY_free(WOLFSSL_EVP_PKEY* key)
+{
+    if (key != NULL) {
+        if (key->pkey.ptr != NULL)
+            XFREE(key->pkey.ptr, NULL, 0);
+        XFREE(key, NULL, 0);
+    }
+}
+
+
+int wolfSSL_X509_cmp_current_time(const WOLFSSL_ASN1_TIME* asnTime)
+{
+    (void)asnTime;
+    return 0;
+}
+
+
+int wolfSSL_sk_X509_REVOKED_num(WOLFSSL_X509_REVOKED* revoked)
+{
+    (void)revoked;
+    return 0;
+}
+
+
+
+WOLFSSL_X509_REVOKED* wolfSSL_X509_CRL_get_REVOKED(WOLFSSL_X509_CRL* crl)
+{
+    (void)crl;
+    return 0;
+}
+
+
+WOLFSSL_X509_REVOKED* wolfSSL_sk_X509_REVOKED_value(
+                                    WOLFSSL_X509_REVOKED* revoked, int value)
+{
+    (void)revoked;
+    (void)value;
+    return 0;
+}
+
+
+
+WOLFSSL_ASN1_INTEGER* wolfSSL_X509_get_serialNumber(WOLFSSL_X509* x509)
+{
+    (void)x509;
+    return 0;
+}
+
+
+int wolfSSL_ASN1_TIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_TIME* asnTime)
+{
+    (void)bio;
+    (void)asnTime;
+    return 0;
+}
+
+
+
+int wolfSSL_ASN1_INTEGER_cmp(const WOLFSSL_ASN1_INTEGER* a,
+                            const WOLFSSL_ASN1_INTEGER* b)
+{
+    (void)a;
+    (void)b;
+    return 0;
+}
+
+
+long wolfSSL_ASN1_INTEGER_get(const WOLFSSL_ASN1_INTEGER* i)
+{
+    (void)i;
+    return 0;
+}
+
+
+
+void* wolfSSL_X509_STORE_CTX_get_ex_data(WOLFSSL_X509_STORE_CTX* ctx, int idx)
+{
+#ifdef FORTRESS
+    if (ctx != NULL && idx == 0)
+        return ctx->ex_data;
+#else
+    (void)ctx;
+    (void)idx;
+#endif
+    return 0;
+}
+
+
+int wolfSSL_get_ex_data_X509_STORE_CTX_idx(void)
+{
+    return 0;
+}
+
+
+void* wolfSSL_get_ex_data(const WOLFSSL* ssl, int idx)
+{
+#ifdef FORTRESS
+    if (ssl != NULL && idx < MAX_EX_DATA)
+        return ssl->ex_data[idx];
+#else
+    (void)ssl;
+    (void)idx;
+#endif
+    return 0;
+}
+
+
+void wolfSSL_CTX_set_info_callback(WOLFSSL_CTX* ctx, void (*f)(void))
+{
+    (void)ctx;
+    (void)f;
+}
+
+
+unsigned long wolfSSL_ERR_peek_error(void)
+{
+    return 0;
+}
+
+
+int wolfSSL_ERR_GET_REASON(int err)
+{
+    (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(WOLFSSL* ssl)
+{
+    (void)ssl;
+    return 0;
+}
+
+
+int wolfSSL_PEM_def_callback(char* name, int num, int w, void* key)
+{
+    (void)name;
+    (void)num;
+    (void)w;
+    (void)key;
+    return 0;
+}
+
+
+long wolfSSL_CTX_sess_accept(WOLFSSL_CTX* ctx)
+{
+    (void)ctx;
+    return 0;
+}
+
+
+long wolfSSL_CTX_sess_connect(WOLFSSL_CTX* ctx)
+{
+    (void)ctx;
+    return 0;
+}
+
+
+long wolfSSL_CTX_sess_accept_good(WOLFSSL_CTX* ctx)
+{
+    (void)ctx;
+    return 0;
+}
+
+
+long wolfSSL_CTX_sess_connect_good(WOLFSSL_CTX* ctx)
+{
+    (void)ctx;
+    return 0;
+}
+
+
+long wolfSSL_CTX_sess_accept_renegotiate(WOLFSSL_CTX* ctx)
+{
+    (void)ctx;
+    return 0;
+}
+
+
+long wolfSSL_CTX_sess_connect_renegotiate(WOLFSSL_CTX* ctx)
+{
+    (void)ctx;
+    return 0;
+}
+
+
+long wolfSSL_CTX_sess_hits(WOLFSSL_CTX* ctx)
+{
+    (void)ctx;
+    return 0;
+}
+
+
+long wolfSSL_CTX_sess_cb_hits(WOLFSSL_CTX* ctx)
+{
+    (void)ctx;
+    return 0;
+}
+
+
+long wolfSSL_CTX_sess_cache_full(WOLFSSL_CTX* ctx)
+{
+    (void)ctx;
+    return 0;
+}
+
+
+long wolfSSL_CTX_sess_misses(WOLFSSL_CTX* ctx)
+{
+    (void)ctx;
+    return 0;
+}
+
+
+long wolfSSL_CTX_sess_timeouts(WOLFSSL_CTX* ctx)
+{
+    (void)ctx;
+    return 0;
+}
+
+
+long wolfSSL_CTX_sess_number(WOLFSSL_CTX* ctx)
+{
+    (void)ctx;
+    return 0;
+}
+
+#ifndef NO_DES3
+
+void wolfSSL_DES_set_key_unchecked(WOLFSSL_const_DES_cblock* myDes,
+                                               WOLFSSL_DES_key_schedule* key)
+{
+    (void)myDes;
+    (void)key;
+}
+
+
+void wolfSSL_DES_set_odd_parity(WOLFSSL_DES_cblock* myDes)
+{
+    (void)myDes;
+}
+
+
+void wolfSSL_DES_ecb_encrypt(WOLFSSL_DES_cblock* desa,
+             WOLFSSL_DES_cblock* desb, WOLFSSL_DES_key_schedule* key, int len)
+{
+    (void)desa;
+    (void)desb;
+    (void)key;
+    (void)len;
+}
+
+#endif /* NO_DES3 */
+
+int wolfSSL_BIO_printf(WOLFSSL_BIO* bio, const char* format, ...)
+{
+    (void)bio;
+    (void)format;
+    return 0;
+}
+
+
+int wolfSSL_ASN1_UTCTIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_UTCTIME* a)
+{
+    (void)bio;
+    (void)a;
+    return 0;
+}
+
+
+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;
+}
+
+
+/* stunnel 4.28 needs */
+void* wolfSSL_CTX_get_ex_data(const WOLFSSL_CTX* ctx, int d)
+{
+    (void)ctx;
+    (void)d;
+    return 0;
+}
+
+
+int wolfSSL_CTX_set_ex_data(WOLFSSL_CTX* ctx, int d, void* p)
+{
+    (void)ctx;
+    (void)d;
+    (void)p;
+    return SSL_SUCCESS;
+}
+
+
+void wolfSSL_CTX_sess_set_get_cb(WOLFSSL_CTX* ctx,
+                    WOLFSSL_SESSION*(*f)(WOLFSSL*, unsigned char*, int, int*))
+{
+    (void)ctx;
+    (void)f;
+}
+
+
+void wolfSSL_CTX_sess_set_new_cb(WOLFSSL_CTX* ctx,
+                             int (*f)(WOLFSSL*, WOLFSSL_SESSION*))
+{
+    (void)ctx;
+    (void)f;
+}
+
+
+void wolfSSL_CTX_sess_set_remove_cb(WOLFSSL_CTX* ctx, void (*f)(WOLFSSL_CTX*,
+                                                        WOLFSSL_SESSION*))
+{
+    (void)ctx;
+    (void)f;
+}
+
+
+int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p)
+{
+    (void)sess;
+    (void)p;
+    return sizeof(WOLFSSL_SESSION);
+}
+
+
+WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION** sess,
+                                const unsigned char** p, long i)
+{
+    (void)p;
+    (void)i;
+    if (sess)
+        return *sess;
+    return NULL;
+}
+
+
+long wolfSSL_SESSION_get_timeout(const WOLFSSL_SESSION* sess)
+{
+    WOLFSSL_ENTER("wolfSSL_SESSION_get_timeout");
+    return sess->timeout;
+}
+
+
+long wolfSSL_SESSION_get_time(const WOLFSSL_SESSION* sess)
+{
+    WOLFSSL_ENTER("wolfSSL_SESSION_get_time");
+    return sess->bornOn;
+}
+
+
+int wolfSSL_CTX_get_ex_new_index(long idx, void* arg, void* a, void* b,
+                                void* c)
+{
+    (void)idx;
+    (void)arg;
+    (void)a;
+    (void)b;
+    (void)c;
+    return 0;
+}
+
+#endif /* OPENSSL_EXTRA */
+
+
+#ifdef KEEP_PEER_CERT
+char*  wolfSSL_X509_get_subjectCN(WOLFSSL_X509* x509)
+{
+    if (x509 == NULL)
+        return NULL;
+
+    return x509->subjectCN;
+}
+#endif /* KEEP_PEER_CERT */
+
+#ifdef OPENSSL_EXTRA
+
+#ifdef FORTRESS
+int wolfSSL_cmp_peer_cert_to_file(WOLFSSL* ssl, const char *fname)
+{
+    int ret = SSL_FATAL_ERROR;
+
+    WOLFSSL_ENTER("wolfSSL_cmp_peer_cert_to_file");
+    if (ssl != NULL && fname != NULL)
+    {
+    #ifdef WOLFSSL_SMALL_STACK
+        EncryptedInfo* info = NULL;
+        byte           staticBuffer[1]; /* force heap usage */
+    #else
+        EncryptedInfo  info[1];
+        byte           staticBuffer[FILE_BUFFER_SIZE];
+    #endif
+        byte*          myBuffer  = staticBuffer;
+        int            dynamic   = 0;
+        XFILE          file      = XBADFILE;
+        long           sz        = 0;
+        int            eccKey    = 0;
+        WOLFSSL_CTX*    ctx       = ssl->ctx;
+        WOLFSSL_X509*   peer_cert = &ssl->peerCert;
+        buffer         fileDer;
+
+        file = XFOPEN(fname, "rb");
+        if (file == XBADFILE)
+            return SSL_BAD_FILE;
+
+        XFSEEK(file, 0, XSEEK_END);
+        sz = XFTELL(file);
+        XREWIND(file);
+
+        if (sz > (long)sizeof(staticBuffer)) {
+            WOLFSSL_MSG("Getting dynamic buffer");
+            myBuffer = (byte*)XMALLOC(sz, ctx->heap, DYNAMIC_TYPE_FILE);
+            dynamic = 1;
+        }
+
+    #ifdef WOLFSSL_SMALL_STACK
+        info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL,
+                                                   DYNAMIC_TYPE_TMP_BUFFER);
+        if (info == NULL)
+            ret = MEMORY_E;
+        else
+    #endif
+        {
+            info->set = 0;
+            info->ctx = ctx;
+            info->consumed = 0;
+            fileDer.buffer = 0;
+
+            if ((myBuffer != NULL) &&
+                (sz > 0) &&
+                (XFREAD(myBuffer, sz, 1, file) > 0) &&
+                (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_TMP_BUFFER);
+        #endif
+        }
+
+        XFREE(fileDer.buffer, ctx->heap, DYNAMIC_TYPE_CERT);
+        if (dynamic)
+            XFREE(myBuffer, ctx->heap, DYNAMIC_TYPE_FILE);
+
+        XFCLOSE(file);
+    }
+
+    return ret;
+}
+#endif
+
+
+static RNG globalRNG;
+static int initGlobalRNG = 0;
+
+/* SSL_SUCCESS on ok */
+int wolfSSL_RAND_seed(const void* seed, int len)
+{
+
+    WOLFSSL_MSG("wolfSSL_RAND_seed");
+
+    (void)seed;
+    (void)len;
+
+    if (initGlobalRNG == 0) {
+        if (wc_InitRng(&globalRNG) < 0) {
+            WOLFSSL_MSG("wolfSSL Init Global RNG failed");
+            return 0;
+        }
+        initGlobalRNG = 1;
+    }
+
+    return SSL_SUCCESS;
+}
+
+
+/* SSL_SUCCESS on ok */
+int wolfSSL_RAND_bytes(unsigned char* buf, int num)
+{
+    int    ret = 0;
+    int    initTmpRng = 0;
+    RNG*   rng = NULL;
+#ifdef WOLFSSL_SMALL_STACK
+    RNG*   tmpRNG = NULL;
+#else
+    RNG    tmpRNG[1];
+#endif
+
+    WOLFSSL_ENTER("RAND_bytes");
+
+#ifdef WOLFSSL_SMALL_STACK
+    tmpRNG = (RNG*)XMALLOC(sizeof(RNG), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (tmpRNG == NULL)
+        return ret;
+#endif
+
+    if (wc_InitRng(tmpRNG) == 0) {
+        rng = tmpRNG;
+        initTmpRng = 1;
+    }
+    else if (initGlobalRNG)
+        rng = &globalRNG;
+
+    if (rng) {
+        if (wc_RNG_GenerateBlock(rng, buf, num) != 0)
+            WOLFSSL_MSG("Bad wc_RNG_GenerateBlock");
+        else
+            ret = SSL_SUCCESS;
+    }
+
+    if (initTmpRng)
+        wc_FreeRng(tmpRNG);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+WOLFSSL_BN_CTX* wolfSSL_BN_CTX_new(void)
+{
+    static int ctx;  /* wolfcrypt doesn't now need ctx */
+
+    WOLFSSL_MSG("wolfSSL_BN_CTX_new");
+
+    return (WOLFSSL_BN_CTX*)&ctx;
+}
+
+void wolfSSL_BN_CTX_init(WOLFSSL_BN_CTX* ctx)
+{
+    (void)ctx;
+    WOLFSSL_MSG("wolfSSL_BN_CTX_init");
+}
+
+
+void wolfSSL_BN_CTX_free(WOLFSSL_BN_CTX* ctx)
+{
+    (void)ctx;
+    WOLFSSL_MSG("wolfSSL_BN_CTX_free");
+
+    /* do free since static ctx that does nothing */
+}
+
+
+static void InitwolfSSL_BigNum(WOLFSSL_BIGNUM* bn)
+{
+    WOLFSSL_MSG("InitwolfSSL_BigNum");
+    if (bn) {
+        bn->neg      = 0;
+        bn->internal = NULL;
+    }
+}
+
+
+WOLFSSL_BIGNUM* wolfSSL_BN_new(void)
+{
+    WOLFSSL_BIGNUM* external;
+    mp_int*        mpi;
+
+    WOLFSSL_MSG("wolfSSL_BN_new");
+
+    mpi = (mp_int*) XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT);
+    if (mpi == NULL) {
+        WOLFSSL_MSG("wolfSSL_BN_new malloc mpi failure");
+        return NULL;
+    }
+
+    external = (WOLFSSL_BIGNUM*) XMALLOC(sizeof(WOLFSSL_BIGNUM), NULL,
+                                        DYNAMIC_TYPE_BIGINT);
+    if (external == NULL) {
+        WOLFSSL_MSG("wolfSSL_BN_new malloc WOLFSSL_BIGNUM failure");
+        XFREE(mpi, NULL, DYNAMIC_TYPE_BIGINT);
+        return NULL;
+    }
+
+    InitwolfSSL_BigNum(external);
+    external->internal = mpi;
+    if (mp_init(mpi) != MP_OKAY) {
+        wolfSSL_BN_free(external);
+        return NULL;
+    }
+
+    return external;
+}
+
+
+void wolfSSL_BN_free(WOLFSSL_BIGNUM* bn)
+{
+    WOLFSSL_MSG("wolfSSL_BN_free");
+    if (bn) {
+        if (bn->internal) {
+            mp_clear((mp_int*)bn->internal);
+            XFREE(bn->internal, NULL, DYNAMIC_TYPE_BIGINT);
+            bn->internal = NULL;
+        }
+        XFREE(bn, NULL, DYNAMIC_TYPE_BIGINT);
+    }
+}
+
+
+void wolfSSL_BN_clear_free(WOLFSSL_BIGNUM* bn)
+{
+    WOLFSSL_MSG("wolfSSL_BN_clear_free");
+
+    wolfSSL_BN_free(bn);
+}
+
+
+/* SSL_SUCCESS on ok */
+int wolfSSL_BN_sub(WOLFSSL_BIGNUM* r, const WOLFSSL_BIGNUM* a,
+                  const WOLFSSL_BIGNUM* b)
+{
+    WOLFSSL_MSG("wolfSSL_BN_sub");
+
+    if (r == NULL || a == NULL || b == NULL)
+        return 0;
+
+    if (mp_sub((mp_int*)a->internal,(mp_int*)b->internal,
+               (mp_int*)r->internal) == MP_OKAY)
+        return SSL_SUCCESS;
+
+    WOLFSSL_MSG("wolfSSL_BN_sub mp_sub failed");
+    return 0;
+}
+
+
+/* SSL_SUCCESS on ok */
+int wolfSSL_BN_mod(WOLFSSL_BIGNUM* r, const WOLFSSL_BIGNUM* a,
+                  const WOLFSSL_BIGNUM* b, const WOLFSSL_BN_CTX* c)
+{
+    (void)c;
+    WOLFSSL_MSG("wolfSSL_BN_mod");
+
+    if (r == NULL || a == NULL || b == NULL)
+        return 0;
+
+    if (mp_mod((mp_int*)a->internal,(mp_int*)b->internal,
+               (mp_int*)r->internal) == MP_OKAY)
+        return SSL_SUCCESS;
+
+    WOLFSSL_MSG("wolfSSL_BN_mod mp_mod failed");
+    return 0;
+}
+
+
+const WOLFSSL_BIGNUM* wolfSSL_BN_value_one(void)
+{
+    static WOLFSSL_BIGNUM* bn_one = NULL;
+
+    WOLFSSL_MSG("wolfSSL_BN_value_one");
+
+    if (bn_one == NULL) {
+        bn_one = wolfSSL_BN_new();
+        if (bn_one)
+            mp_set_int((mp_int*)bn_one->internal, 1);
+    }
+
+    return bn_one;
+}
+
+
+int wolfSSL_BN_num_bytes(const WOLFSSL_BIGNUM* bn)
+{
+    WOLFSSL_MSG("wolfSSL_BN_num_bytes");
+
+    if (bn == NULL || bn->internal == NULL)
+        return 0;
+
+    return mp_unsigned_bin_size((mp_int*)bn->internal);
+}
+
+
+int wolfSSL_BN_num_bits(const WOLFSSL_BIGNUM* bn)
+{
+    WOLFSSL_MSG("wolfSSL_BN_num_bits");
+
+    if (bn == NULL || bn->internal == NULL)
+        return 0;
+
+    return mp_count_bits((mp_int*)bn->internal);
+}
+
+
+int wolfSSL_BN_is_zero(const WOLFSSL_BIGNUM* bn)
+{
+    WOLFSSL_MSG("wolfSSL_BN_is_zero");
+
+    if (bn == NULL || bn->internal == NULL)
+        return 0;
+
+    return mp_iszero((mp_int*)bn->internal);
+}
+
+
+int wolfSSL_BN_is_one(const WOLFSSL_BIGNUM* bn)
+{
+    WOLFSSL_MSG("wolfSSL_BN_is_one");
+
+    if (bn == NULL || bn->internal == NULL)
+        return 0;
+
+    if (mp_cmp_d((mp_int*)bn->internal, 1) == 0)
+        return 1;
+
+    return 0;
+}
+
+
+int wolfSSL_BN_is_odd(const WOLFSSL_BIGNUM* bn)
+{
+    WOLFSSL_MSG("wolfSSL_BN_is_odd");
+
+    if (bn == NULL || bn->internal == NULL)
+        return 0;
+
+    return mp_isodd((mp_int*)bn->internal);
+}
+
+
+int wolfSSL_BN_cmp(const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* b)
+{
+    WOLFSSL_MSG("wolfSSL_BN_cmp");
+
+    if (a == NULL || a->internal == NULL || b == NULL || b->internal ==NULL)
+        return 0;
+
+    return mp_cmp((mp_int*)a->internal, (mp_int*)b->internal);
+}
+
+
+int wolfSSL_BN_bn2bin(const WOLFSSL_BIGNUM* bn, unsigned char* r)
+{
+    WOLFSSL_MSG("wolfSSL_BN_bn2bin");
+
+    if (bn == NULL || bn->internal == NULL) {
+        WOLFSSL_MSG("NULL bn error");
+        return SSL_FATAL_ERROR;
+    }
+
+    if (r == NULL)
+        return mp_unsigned_bin_size((mp_int*)bn->internal);
+
+    if (mp_to_unsigned_bin((mp_int*)bn->internal, r) != MP_OKAY) {
+        WOLFSSL_MSG("mp_to_unsigned_bin error");
+        return SSL_FATAL_ERROR;
+    }
+
+    return mp_unsigned_bin_size((mp_int*)bn->internal);
+}
+
+
+WOLFSSL_BIGNUM* wolfSSL_BN_bin2bn(const unsigned char* str, int len,
+                            WOLFSSL_BIGNUM* ret)
+{
+    WOLFSSL_MSG("wolfSSL_BN_bin2bn");
+
+    if (ret && ret->internal) {
+        if (mp_read_unsigned_bin((mp_int*)ret->internal, str, len) != 0) {
+            WOLFSSL_MSG("mp_read_unsigned_bin failure");
+            return NULL;
+        }
+    }
+    else {
+        WOLFSSL_MSG("wolfSSL_BN_bin2bn wants return bignum");
+    }
+
+    return ret;
+}
+
+
+int wolfSSL_mask_bits(WOLFSSL_BIGNUM* bn, int n)
+{
+    (void)bn;
+    (void)n;
+    WOLFSSL_MSG("wolfSSL_BN_mask_bits");
+
+    return SSL_FATAL_ERROR;
+}
+
+
+/* SSL_SUCCESS on ok */
+int wolfSSL_BN_rand(WOLFSSL_BIGNUM* bn, int bits, int top, int bottom)
+{
+    int           ret    = 0;
+    int           len    = bits / 8;
+    int           initTmpRng = 0;
+    RNG*          rng    = NULL;
+#ifdef WOLFSSL_SMALL_STACK
+    RNG*          tmpRNG = NULL;
+    byte*         buff   = NULL;
+#else
+    RNG           tmpRNG[1];
+    byte          buff[1024];
+#endif
+
+    (void)top;
+    (void)bottom;
+    WOLFSSL_MSG("wolfSSL_BN_rand");
+
+    if (bits % 8)
+        len++;
+
+#ifdef WOLFSSL_SMALL_STACK
+    buff   = (byte*)XMALLOC(1024,        NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    tmpRNG = (RNG*) XMALLOC(sizeof(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 {
+            buff[0]     |= 0x80 | 0x40;
+            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 = SSL_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
+
+    return ret;
+}
+
+
+int wolfSSL_BN_is_bit_set(const WOLFSSL_BIGNUM* bn, int n)
+{
+    (void)bn;
+    (void)n;
+
+    WOLFSSL_MSG("wolfSSL_BN_is_bit_set");
+
+    return 0;
+}
+
+
+/* SSL_SUCCESS on ok */
+int wolfSSL_BN_hex2bn(WOLFSSL_BIGNUM** bn, const char* str)
+{
+    int     ret     = 0;
+    word32  decSz   = 1024;
+#ifdef WOLFSSL_SMALL_STACK
+    byte*   decoded = NULL;
+#else
+    byte    decoded[1024];
+#endif
+
+    WOLFSSL_MSG("wolfSSL_BN_hex2bn");
+
+#ifdef WOLFSSL_SMALL_STACK
+    decoded = (byte*)XMALLOC(decSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (decoded == NULL)
+        return ret;
+#endif
+
+    if (str == NULL)
+        WOLFSSL_MSG("Bad function argument");
+    else if (Base16_Decode((byte*)str, (int)XSTRLEN(str), decoded, &decSz) < 0)
+        WOLFSSL_MSG("Bad Base16_Decode error");
+    else if (bn == NULL)
+        ret = decSz;
+    else {
+        if (*bn == NULL)
+            *bn = wolfSSL_BN_new();
+
+        if (*bn == NULL)
+            WOLFSSL_MSG("BN new failed");
+        else if (wolfSSL_BN_bin2bn(decoded, decSz, *bn) == NULL)
+            WOLFSSL_MSG("Bad bin2bn error");
+        else
+            ret = SSL_SUCCESS;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+WOLFSSL_BIGNUM* wolfSSL_BN_dup(const WOLFSSL_BIGNUM* bn)
+{
+    WOLFSSL_BIGNUM* ret;
+
+    WOLFSSL_MSG("wolfSSL_BN_dup");
+
+    if (bn == NULL || bn->internal == NULL) {
+        WOLFSSL_MSG("bn NULL error");
+        return NULL;
+    }
+
+    ret = wolfSSL_BN_new();
+    if (ret == NULL) {
+        WOLFSSL_MSG("bn new error");
+        return NULL;
+    }
+
+    if (mp_copy((mp_int*)bn->internal, (mp_int*)ret->internal) != MP_OKAY) {
+        WOLFSSL_MSG("mp_copy error");
+        wolfSSL_BN_free(ret);
+        return NULL;
+    }
+
+    return ret;
+}
+
+
+WOLFSSL_BIGNUM* wolfSSL_BN_copy(WOLFSSL_BIGNUM* r, const WOLFSSL_BIGNUM* bn)
+{
+    (void)r;
+    (void)bn;
+
+    WOLFSSL_MSG("wolfSSL_BN_copy");
+
+    return NULL;
+}
+
+
+int wolfSSL_BN_set_word(WOLFSSL_BIGNUM* bn, unsigned long w)
+{
+    (void)bn;
+    (void)w;
+
+    WOLFSSL_MSG("wolfSSL_BN_set_word");
+
+    return SSL_FATAL_ERROR;
+}
+
+
+int wolfSSL_BN_dec2bn(WOLFSSL_BIGNUM** bn, const char* str)
+{
+    (void)bn;
+    (void)str;
+
+    WOLFSSL_MSG("wolfSSL_BN_dec2bn");
+
+    return SSL_FATAL_ERROR;
+}
+
+
+char* wolfSSL_BN_bn2dec(const WOLFSSL_BIGNUM* bn)
+{
+    (void)bn;
+
+    WOLFSSL_MSG("wolfSSL_BN_bn2dec");
+
+    return NULL;
+}
+
+
+#ifndef NO_DH
+
+static void InitwolfSSL_DH(WOLFSSL_DH* dh)
+{
+    if (dh) {
+        dh->p        = NULL;
+        dh->g        = NULL;
+        dh->pub_key  = NULL;
+        dh->priv_key = NULL;
+        dh->internal = NULL;
+        dh->inSet    = 0;
+        dh->exSet    = 0;
+    }
+}
+
+
+WOLFSSL_DH* wolfSSL_DH_new(void)
+{
+    WOLFSSL_DH* external;
+    DhKey*     key;
+
+    WOLFSSL_MSG("wolfSSL_DH_new");
+
+    key = (DhKey*) XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH);
+    if (key == NULL) {
+        WOLFSSL_MSG("wolfSSL_DH_new malloc DhKey failure");
+        return NULL;
+    }
+
+    external = (WOLFSSL_DH*) XMALLOC(sizeof(WOLFSSL_DH), NULL,
+                                    DYNAMIC_TYPE_DH);
+    if (external == NULL) {
+        WOLFSSL_MSG("wolfSSL_DH_new malloc WOLFSSL_DH failure");
+        XFREE(key, NULL, DYNAMIC_TYPE_DH);
+        return NULL;
+    }
+
+    InitwolfSSL_DH(external);
+    wc_InitDhKey(key);
+    external->internal = key;
+
+    return external;
+}
+
+
+void wolfSSL_DH_free(WOLFSSL_DH* dh)
+{
+    WOLFSSL_MSG("wolfSSL_DH_free");
+
+    if (dh) {
+        if (dh->internal) {
+            wc_FreeDhKey((DhKey*)dh->internal);
+            XFREE(dh->internal, NULL, DYNAMIC_TYPE_DH);
+            dh->internal = NULL;
+        }
+        wolfSSL_BN_free(dh->priv_key);
+        wolfSSL_BN_free(dh->pub_key);
+        wolfSSL_BN_free(dh->g);
+        wolfSSL_BN_free(dh->p);
+        InitwolfSSL_DH(dh);  /* set back to NULLs for safety */
+
+        XFREE(dh, NULL, DYNAMIC_TYPE_DH);
+    }
+}
+
+
+static int SetDhInternal(WOLFSSL_DH* dh)
+{
+    int            ret = SSL_FATAL_ERROR;
+    int            pSz = 1024;
+    int            gSz = 1024;
+#ifdef WOLFSSL_SMALL_STACK
+    unsigned char* p   = NULL;
+    unsigned char* g   = NULL;
+#else
+    unsigned char  p[1024];
+    unsigned char  g[1024];
+#endif
+
+    WOLFSSL_ENTER("SetDhInternal");
+
+    if (dh == NULL || dh->p == NULL || dh->g == NULL)
+        WOLFSSL_MSG("Bad function arguments");
+    else if (wolfSSL_BN_bn2bin(dh->p, NULL) > pSz)
+        WOLFSSL_MSG("Bad p internal size");
+    else if (wolfSSL_BN_bn2bin(dh->g, NULL) > gSz)
+        WOLFSSL_MSG("Bad g internal size");
+    else {
+    #ifdef WOLFSSL_SMALL_STACK
+        p = (unsigned char*)XMALLOC(pSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        g = (unsigned char*)XMALLOC(gSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+        if (p == NULL || g == NULL) {
+            XFREE(p, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(g, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            return ret;
+        }
+    #endif
+
+        pSz = wolfSSL_BN_bn2bin(dh->p, p);
+        gSz = wolfSSL_BN_bn2bin(dh->g, g);
+
+        if (pSz <= 0 || gSz <= 0)
+            WOLFSSL_MSG("Bad BN2bin set");
+        else if (wc_DhSetKey((DhKey*)dh->internal, p, pSz, g, gSz) < 0)
+            WOLFSSL_MSG("Bad DH SetKey");
+        else {
+            dh->inSet = 1;
+            ret = 0;
+        }
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(p, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(g, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+    }
+
+
+    return ret;
+}
+
+
+int wolfSSL_DH_size(WOLFSSL_DH* dh)
+{
+    WOLFSSL_MSG("wolfSSL_DH_size");
+
+    if (dh == NULL)
+        return 0;
+
+    return wolfSSL_BN_num_bytes(dh->p);
+}
+
+
+/* return SSL_SUCCESS on ok, else 0 */
+int wolfSSL_DH_generate_key(WOLFSSL_DH* dh)
+{
+    int            ret    = 0;
+    word32         pubSz  = 768;
+    word32         privSz = 768;
+    int            initTmpRng = 0;
+    RNG*           rng    = NULL;
+#ifdef WOLFSSL_SMALL_STACK
+    unsigned char* pub    = NULL;
+    unsigned char* priv   = NULL;
+    RNG*           tmpRNG = NULL;
+#else
+    unsigned char  pub [768];
+    unsigned char  priv[768];
+    RNG            tmpRNG[1];
+#endif
+
+    WOLFSSL_MSG("wolfSSL_DH_generate_key");
+
+#ifdef WOLFSSL_SMALL_STACK
+    tmpRNG = (RNG*)XMALLOC(sizeof(RNG),      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    pub    = (unsigned char*)XMALLOC(pubSz,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    priv   = (unsigned char*)XMALLOC(privSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    if (tmpRNG == NULL || pub == NULL || priv == NULL) {
+        XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(pub,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(priv,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return ret;
+    }
+#endif
+
+    if (dh == NULL || dh->p == NULL || dh->g == NULL)
+        WOLFSSL_MSG("Bad function arguments");
+    else if (dh->inSet == 0 && SetDhInternal(dh) < 0)
+            WOLFSSL_MSG("Bad DH set internal");
+    else 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 (wc_DhGenerateKeyPair((DhKey*)dh->internal, rng, priv, &privSz,
+                                                               pub, &pubSz) < 0)
+            WOLFSSL_MSG("Bad wc_DhGenerateKeyPair");
+       else {
+            if (dh->pub_key)
+                wolfSSL_BN_free(dh->pub_key);
+   
+            dh->pub_key = wolfSSL_BN_new();
+            if (dh->pub_key == NULL) {
+                WOLFSSL_MSG("Bad DH new pub");
+            }
+            if (dh->priv_key)
+                wolfSSL_BN_free(dh->priv_key);
+
+            dh->priv_key = wolfSSL_BN_new();
+
+            if (dh->priv_key == NULL) {
+                WOLFSSL_MSG("Bad DH new priv");
+            }
+
+            if (dh->pub_key && dh->priv_key) {
+               if (wolfSSL_BN_bin2bn(pub, pubSz, dh->pub_key) == NULL)
+                   WOLFSSL_MSG("Bad DH bn2bin error pub");
+               else if (wolfSSL_BN_bin2bn(priv, privSz, dh->priv_key) == NULL)
+                   WOLFSSL_MSG("Bad DH bn2bin error priv");
+               else
+                   ret = SSL_SUCCESS;
+            }
+        }
+    }
+
+    if (initTmpRng)
+        wc_FreeRng(tmpRNG);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(pub,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(priv,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+/* return key size on ok, 0 otherwise */
+int wolfSSL_DH_compute_key(unsigned char* key, WOLFSSL_BIGNUM* otherPub,
+                          WOLFSSL_DH* dh)
+{
+    int            ret    = 0;
+    word32         keySz  = 0;
+    word32         pubSz  = 1024;
+    word32         privSz = 1024;
+#ifdef WOLFSSL_SMALL_STACK
+    unsigned char* pub    = NULL;
+    unsigned char* priv   = NULL;
+#else
+    unsigned char  pub [1024];
+    unsigned char  priv[1024];
+#endif
+
+    WOLFSSL_MSG("wolfSSL_DH_compute_key");
+
+#ifdef WOLFSSL_SMALL_STACK
+    pub = (unsigned char*)XMALLOC(pubSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (pub == NULL)
+        return ret;
+
+    priv = (unsigned char*)XMALLOC(privSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (priv == NULL) {
+        XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return 0;
+    }
+#endif
+
+    if (dh == NULL || dh->priv_key == NULL || otherPub == NULL)
+        WOLFSSL_MSG("Bad function arguments");
+    else if ((keySz = (word32)DH_size(dh)) == 0)
+        WOLFSSL_MSG("Bad DH_size");
+    else if (wolfSSL_BN_bn2bin(dh->priv_key, NULL) > (int)privSz)
+        WOLFSSL_MSG("Bad priv internal size");
+    else if (wolfSSL_BN_bn2bin(otherPub, NULL) > (int)pubSz)
+        WOLFSSL_MSG("Bad otherPub size");
+    else {
+        privSz = wolfSSL_BN_bn2bin(dh->priv_key, priv);
+        pubSz  = wolfSSL_BN_bn2bin(otherPub, pub);
+
+        if (privSz <= 0 || pubSz <= 0)
+            WOLFSSL_MSG("Bad BN2bin set");
+        else if (wc_DhAgree((DhKey*)dh->internal, key, &keySz, priv, privSz, pub,
+                                                                     pubSz) < 0)
+            WOLFSSL_MSG("wc_DhAgree failed");
+        else
+            ret = (int)keySz;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(pub,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+#endif /* NO_DH */
+
+
+#ifndef NO_DSA
+static void InitwolfSSL_DSA(WOLFSSL_DSA* dsa)
+{
+    if (dsa) {
+        dsa->p        = NULL;
+        dsa->q        = NULL;
+        dsa->g        = NULL;
+        dsa->pub_key  = NULL;
+        dsa->priv_key = NULL;
+        dsa->internal = NULL;
+        dsa->inSet    = 0;
+        dsa->exSet    = 0;
+    }
+}
+
+
+WOLFSSL_DSA* wolfSSL_DSA_new(void)
+{
+    WOLFSSL_DSA* external;
+    DsaKey*     key;
+
+    WOLFSSL_MSG("wolfSSL_DSA_new");
+
+    key = (DsaKey*) XMALLOC(sizeof(DsaKey), NULL, DYNAMIC_TYPE_DSA);
+    if (key == NULL) {
+        WOLFSSL_MSG("wolfSSL_DSA_new malloc DsaKey failure");
+        return NULL;
+    }
+
+    external = (WOLFSSL_DSA*) XMALLOC(sizeof(WOLFSSL_DSA), NULL,
+                                    DYNAMIC_TYPE_DSA);
+    if (external == NULL) {
+        WOLFSSL_MSG("wolfSSL_DSA_new malloc WOLFSSL_DSA failure");
+        XFREE(key, NULL, DYNAMIC_TYPE_DSA);
+        return NULL;
+    }
+
+    InitwolfSSL_DSA(external);
+    InitDsaKey(key);
+    external->internal = key;
+
+    return external;
+}
+
+
+void wolfSSL_DSA_free(WOLFSSL_DSA* dsa)
+{
+    WOLFSSL_MSG("wolfSSL_DSA_free");
+
+    if (dsa) {
+        if (dsa->internal) {
+            FreeDsaKey((DsaKey*)dsa->internal);
+            XFREE(dsa->internal, NULL, DYNAMIC_TYPE_DSA);
+            dsa->internal = NULL;
+        }
+        wolfSSL_BN_free(dsa->priv_key);
+        wolfSSL_BN_free(dsa->pub_key);
+        wolfSSL_BN_free(dsa->g);
+        wolfSSL_BN_free(dsa->q);
+        wolfSSL_BN_free(dsa->p);
+        InitwolfSSL_DSA(dsa);  /* set back to NULLs for safety */
+
+        XFREE(dsa, NULL, DYNAMIC_TYPE_DSA);
+    }
+}
+
+
+int wolfSSL_DSA_generate_key(WOLFSSL_DSA* dsa)
+{
+    (void)dsa;
+
+    WOLFSSL_MSG("wolfSSL_DSA_generate_key");
+
+    return 0;  /* key gen not needed by server */
+}
+
+
+int wolfSSL_DSA_generate_parameters_ex(WOLFSSL_DSA* dsa, int bits,
+               unsigned char* seed, int seedLen, int* counterRet,
+               unsigned long* hRet, void* cb)
+{
+    (void)dsa;
+    (void)bits;
+    (void)seed;
+    (void)seedLen;
+    (void)counterRet;
+    (void)hRet;
+    (void)cb;
+
+    WOLFSSL_MSG("wolfSSL_DSA_generate_parameters_ex");
+
+    return 0;  /* key gen not needed by server */
+}
+#endif /* NO_DSA */
+
+#ifndef NO_RSA
+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;
+    }
+    external->internal = key;
+
+    return external;
+}
+
+
+void wolfSSL_RSA_free(WOLFSSL_RSA* rsa)
+{
+    WOLFSSL_MSG("wolfSSL_RSA_free");
+
+    if (rsa) {
+        if (rsa->internal) {
+            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);
+        wolfSSL_BN_free(rsa->dmp1);
+        wolfSSL_BN_free(rsa->q);
+        wolfSSL_BN_free(rsa->p);
+        wolfSSL_BN_free(rsa->d);
+        wolfSSL_BN_free(rsa->e);
+        wolfSSL_BN_free(rsa->n);
+        InitwolfSSL_Rsa(rsa);  /* set back to NULLs for safety */
+
+        XFREE(rsa, NULL, DYNAMIC_TYPE_RSA);
+    }
+}
+#endif /* NO_RSA */
+
+
+#if !defined(NO_RSA) || !defined(NO_DSA)
+static int SetIndividualExternal(WOLFSSL_BIGNUM** bn, mp_int* mpi)
+{
+    WOLFSSL_MSG("Entering SetIndividualExternal");
+
+    if (mpi == NULL) {
+        WOLFSSL_MSG("mpi NULL error");
+        return SSL_FATAL_ERROR;
+    }
+
+    if (*bn == NULL) {
+        *bn = wolfSSL_BN_new();
+        if (*bn == NULL) {
+            WOLFSSL_MSG("SetIndividualExternal alloc failed");
+            return SSL_FATAL_ERROR;
+        }
+    }
+
+    if (mp_copy(mpi, (mp_int*)((*bn)->internal)) != MP_OKAY) {
+        WOLFSSL_MSG("mp_copy error");
+        return SSL_FATAL_ERROR;
+    }
+
+    return 0;
+}
+#endif /* !NO_RSA && !NO_DSA */
+
+
+#ifndef NO_DSA
+static int SetDsaExternal(WOLFSSL_DSA* dsa)
+{
+    DsaKey* key;
+    WOLFSSL_MSG("Entering SetDsaExternal");
+
+    if (dsa == NULL || dsa->internal == NULL) {
+        WOLFSSL_MSG("dsa key NULL error");
+        return SSL_FATAL_ERROR;
+    }
+
+    key = (DsaKey*)dsa->internal;
+
+    if (SetIndividualExternal(&dsa->p, &key->p) < 0) {
+        WOLFSSL_MSG("dsa p key error");
+        return SSL_FATAL_ERROR;
+    }
+
+    if (SetIndividualExternal(&dsa->q, &key->q) < 0) {
+        WOLFSSL_MSG("dsa q key error");
+        return SSL_FATAL_ERROR;
+    }
+
+    if (SetIndividualExternal(&dsa->g, &key->g) < 0) {
+        WOLFSSL_MSG("dsa g key error");
+        return SSL_FATAL_ERROR;
+    }
+
+    if (SetIndividualExternal(&dsa->pub_key, &key->y) < 0) {
+        WOLFSSL_MSG("dsa y key error");
+        return SSL_FATAL_ERROR;
+    }
+
+    if (SetIndividualExternal(&dsa->priv_key, &key->x) < 0) {
+        WOLFSSL_MSG("dsa x key error");
+        return SSL_FATAL_ERROR;
+    }
+
+    dsa->exSet = 1;
+
+    return 0;
+}
+#endif /* NO_DSA */
+
+
+#ifndef NO_RSA
+static int SetRsaExternal(WOLFSSL_RSA* rsa)
+{
+    RsaKey* key;
+    WOLFSSL_MSG("Entering SetRsaExternal");
+
+    if (rsa == NULL || rsa->internal == NULL) {
+        WOLFSSL_MSG("rsa key NULL error");
+        return SSL_FATAL_ERROR;
+    }
+
+    key = (RsaKey*)rsa->internal;
+
+    if (SetIndividualExternal(&rsa->n, &key->n) < 0) {
+        WOLFSSL_MSG("rsa n key error");
+        return SSL_FATAL_ERROR;
+    }
+
+    if (SetIndividualExternal(&rsa->e, &key->e) < 0) {
+        WOLFSSL_MSG("rsa e key error");
+        return SSL_FATAL_ERROR;
+    }
+
+    if (SetIndividualExternal(&rsa->d, &key->d) < 0) {
+        WOLFSSL_MSG("rsa d key error");
+        return SSL_FATAL_ERROR;
+    }
+
+    if (SetIndividualExternal(&rsa->p, &key->p) < 0) {
+        WOLFSSL_MSG("rsa p key error");
+        return SSL_FATAL_ERROR;
+    }
+
+    if (SetIndividualExternal(&rsa->q, &key->q) < 0) {
+        WOLFSSL_MSG("rsa q key error");
+        return SSL_FATAL_ERROR;
+    }
+
+    if (SetIndividualExternal(&rsa->dmp1, &key->dP) < 0) {
+        WOLFSSL_MSG("rsa dP key error");
+        return SSL_FATAL_ERROR;
+    }
+
+    if (SetIndividualExternal(&rsa->dmq1, &key->dQ) < 0) {
+        WOLFSSL_MSG("rsa dQ key error");
+        return SSL_FATAL_ERROR;
+    }
+
+    if (SetIndividualExternal(&rsa->iqmp, &key->u) < 0) {
+        WOLFSSL_MSG("rsa u key error");
+        return SSL_FATAL_ERROR;
+    }
+
+    rsa->exSet = 1;
+
+    return 0;
+}
+
+
+/* SSL_SUCCESS on ok */
+int wolfSSL_RSA_generate_key_ex(WOLFSSL_RSA* rsa, int bits, WOLFSSL_BIGNUM* bn,
+                               void* cb)
+{
+    int ret = SSL_FATAL_ERROR;
+
+    WOLFSSL_MSG("wolfSSL_RSA_generate_key_ex");
+
+    (void)rsa;
+    (void)bits;
+    (void)cb;
+    (void)bn;
+
+#ifdef WOLFSSL_KEY_GEN
+    {
+    #ifdef WOLFSSL_SMALL_STACK
+        RNG* rng = NULL;
+    #else
+        RNG  rng[1];
+    #endif
+
+    #ifdef WOLFSSL_SMALL_STACK
+        rng = (RNG*)XMALLOC(sizeof(RNG), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (rng == NULL)
+            return SSL_FATAL_ERROR;
+    #endif
+
+        if (wc_InitRng(rng) < 0)
+            WOLFSSL_MSG("RNG init failed");
+        else if (wc_MakeRsaKey((RsaKey*)rsa->internal, bits, 65537, rng) < 0)
+            WOLFSSL_MSG("wc_MakeRsaKey failed");
+        else if (SetRsaExternal(rsa) < 0)
+            WOLFSSL_MSG("SetRsaExternal failed");
+        else {
+            rsa->inSet = 1;
+            ret = SSL_SUCCESS;
+        }
+
+        wc_FreeRng(rng);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(rng, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+    }
+#else
+    WOLFSSL_MSG("No Key Gen built in");
+#endif
+    return ret;
+}
+
+
+/* SSL_SUCCESS on ok */
+int wolfSSL_RSA_blinding_on(WOLFSSL_RSA* rsa, WOLFSSL_BN_CTX* bn)
+{
+    (void)rsa;
+    (void)bn;
+
+    WOLFSSL_MSG("wolfSSL_RSA_blinding_on");
+
+    return SSL_SUCCESS;  /* on by default */
+}
+
+
+int wolfSSL_RSA_public_encrypt(int len, unsigned char* fr,
+                            unsigned char* to, WOLFSSL_RSA* rsa, int padding)
+{
+    (void)len;
+    (void)fr;
+    (void)to;
+    (void)rsa;
+    (void)padding;
+
+    WOLFSSL_MSG("wolfSSL_RSA_public_encrypt");
+
+    return SSL_FATAL_ERROR;
+}
+
+
+int wolfSSL_RSA_private_decrypt(int len, unsigned char* fr,
+                            unsigned char* to, WOLFSSL_RSA* rsa, int padding)
+{
+    (void)len;
+    (void)fr;
+    (void)to;
+    (void)rsa;
+    (void)padding;
+
+    WOLFSSL_MSG("wolfSSL_RSA_private_decrypt");
+
+    return SSL_FATAL_ERROR;
+}
+
+
+int wolfSSL_RSA_size(const WOLFSSL_RSA* rsa)
+{
+    WOLFSSL_MSG("wolfSSL_RSA_size");
+
+    if (rsa == NULL)
+        return 0;
+
+    return wolfSSL_BN_num_bytes(rsa->n);
+}
+#endif /* NO_RSA */
+
+
+#ifndef NO_DSA
+/* return SSL_SUCCESS on success, < 0 otherwise */
+int wolfSSL_DSA_do_sign(const unsigned char* d, unsigned char* sigRet,
+                       WOLFSSL_DSA* dsa)
+{
+    int    ret = SSL_FATAL_ERROR;
+    int    initTmpRng = 0;
+    RNG*   rng = NULL;
+#ifdef WOLFSSL_SMALL_STACK
+    RNG*   tmpRNG = NULL;
+#else
+    RNG    tmpRNG[1];
+#endif
+
+    WOLFSSL_MSG("wolfSSL_DSA_do_sign");
+
+    if (d == NULL || sigRet == NULL || dsa == NULL)
+        WOLFSSL_MSG("Bad function arguments");
+    else if (dsa->inSet == 0)
+        WOLFSSL_MSG("No DSA internal set");
+    else {
+    #ifdef WOLFSSL_SMALL_STACK
+        tmpRNG = (RNG*)XMALLOC(sizeof(RNG), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (tmpRNG == NULL)
+            return SSL_FATAL_ERROR;
+    #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 (DsaSign(d, sigRet, (DsaKey*)dsa->internal, rng) < 0)
+                WOLFSSL_MSG("DsaSign failed");
+            else
+                ret = SSL_SUCCESS;
+        }
+
+        if (initTmpRng)
+            wc_FreeRng(tmpRNG);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+    }
+
+    return ret;
+}
+#endif /* NO_DSA */
+
+
+#ifndef NO_RSA
+/* 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)
+{
+    word32 outLen;    
+    word32 signSz;
+    int    initTmpRng = 0;
+    RNG*   rng        = NULL;
+    int    ret        = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    RNG*   tmpRNG     = NULL;
+    byte*  encodedSig = NULL;
+#else
+    RNG    tmpRNG[1];
+    byte   encodedSig[MAX_ENCODED_SIG_SZ];
+#endif
+
+    WOLFSSL_MSG("wolfSSL_RSA_sign");
+
+    if (m == NULL || sigRet == NULL || sigLen == NULL || rsa == NULL)
+        WOLFSSL_MSG("Bad function arguments");
+    else if (rsa->inSet == 0)
+        WOLFSSL_MSG("No RSA internal set");
+    else if (type != NID_md5 && type != NID_sha1)
+        WOLFSSL_MSG("Bad md type");
+    else {
+        outLen = (word32)wolfSSL_BN_num_bytes(rsa->n);
+
+    #ifdef WOLFSSL_SMALL_STACK
+        tmpRNG = (RNG*)XMALLOC(sizeof(RNG), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (tmpRNG == NULL)
+            return 0;
+
+        encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        if (encodedSig == NULL) {
+            XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            return 0;
+        }
+    #endif
+
+        if (outLen == 0)
+            WOLFSSL_MSG("Bad RSA size");
+        else 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) {
+        type = (type == NID_md5) ? MD5h : SHAh;
+
+        signSz = wc_EncodeSignature(encodedSig, m, mLen, type);
+        if (signSz == 0) {
+            WOLFSSL_MSG("Bad Encode Signature");
+        }
+        else {
+            *sigLen = wc_RsaSSL_Sign(encodedSig, signSz, sigRet, outLen,
+                                  (RsaKey*)rsa->internal, rng);
+            if (*sigLen <= 0)
+                WOLFSSL_MSG("Bad Rsa Sign");
+            else
+                ret = SSL_SUCCESS;
+        }
+
+    }
+
+    if (initTmpRng)
+        wc_FreeRng(tmpRNG);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(tmpRNG,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    WOLFSSL_MSG("wolfSSL_RSA_sign success");
+    return ret;
+}
+
+
+int wolfSSL_RSA_public_decrypt(int flen, unsigned char* from,
+                          unsigned char* to, WOLFSSL_RSA* rsa, int padding)
+{
+    (void)flen;
+    (void)from;
+    (void)to;
+    (void)rsa;
+    (void)padding;
+
+    WOLFSSL_MSG("wolfSSL_RSA_public_decrypt");
+
+    return SSL_FATAL_ERROR;
+}
+
+
+/* generate p-1 and q-1, SSL_SUCCESS on ok */
+int wolfSSL_RSA_GenAdd(WOLFSSL_RSA* rsa)
+{
+    int    err;
+    mp_int tmp;
+
+    WOLFSSL_MSG("wolfSSL_RsaGenAdd");
+
+    if (rsa == NULL || rsa->p == NULL || rsa->q == NULL || rsa->d == NULL ||
+                       rsa->dmp1 == NULL || rsa->dmq1 == NULL) {
+        WOLFSSL_MSG("rsa no init error");
+        return SSL_FATAL_ERROR;
+    }
+
+    if (mp_init(&tmp) != MP_OKAY) {
+        WOLFSSL_MSG("mp_init error");
+        return SSL_FATAL_ERROR;
+    }
+
+    err = mp_sub_d((mp_int*)rsa->p->internal, 1, &tmp);
+    if (err != MP_OKAY) {
+        WOLFSSL_MSG("mp_sub_d error");
+    }
+    else
+        err = mp_mod((mp_int*)rsa->d->internal, &tmp,
+                     (mp_int*)rsa->dmp1->internal);
+
+    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,
+                     (mp_int*)rsa->dmq1->internal);
+
+    mp_clear(&tmp);
+
+    if (err == MP_OKAY)
+        return SSL_SUCCESS;
+    else
+        return SSL_FATAL_ERROR;
+}
+#endif /* NO_RSA */
+
+
+void wolfSSL_HMAC_Init(WOLFSSL_HMAC_CTX* ctx, const void* key, int keylen,
+                  const EVP_MD* type)
+{
+    WOLFSSL_MSG("wolfSSL_HMAC_Init");
+
+    if (ctx == NULL) {
+        WOLFSSL_MSG("no ctx on init");
+        return;
+    }
+
+    if (type) {
+        WOLFSSL_MSG("init has type");
+
+        if (XSTRNCMP(type, "MD5", 3) == 0) {
+            WOLFSSL_MSG("md5 hmac");
+            ctx->type = MD5;
+        }
+        else if (XSTRNCMP(type, "SHA256", 6) == 0) {
+            WOLFSSL_MSG("sha256 hmac");
+            ctx->type = SHA256;
+        }
+
+        /* has to be last since would pick or 256, 384, or 512 too */
+        else if (XSTRNCMP(type, "SHA", 3) == 0) {
+            WOLFSSL_MSG("sha hmac");
+            ctx->type = SHA;
+        }
+        else {
+            WOLFSSL_MSG("bad init type");
+        }
+    }
+
+    if (key && keylen) {
+        WOLFSSL_MSG("keying hmac");
+        wc_HmacSetKey(&ctx->hmac, ctx->type, (const byte*)key, (word32)keylen);
+        /* OpenSSL compat, no error */
+    }
+}
+
+
+void wolfSSL_HMAC_Update(WOLFSSL_HMAC_CTX* ctx, const unsigned char* data,
+                    int len)
+{
+    WOLFSSL_MSG("wolfSSL_HMAC_Update");
+
+    if (ctx && 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,
+                   unsigned int* len)
+{
+    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 MD5:
+                    *len = MD5_DIGEST_SIZE;
+                    break;
+
+                case SHA:
+                    *len = SHA_DIGEST_SIZE;
+                    break;
+
+                case SHA256:
+                    *len = SHA256_DIGEST_SIZE;
+                    break;
+
+                default:
+                    WOLFSSL_MSG("bad hmac type");
+            }
+        }
+    }
+}
+
+
+void wolfSSL_HMAC_cleanup(WOLFSSL_HMAC_CTX* ctx)
+{
+    (void)ctx;
+
+    WOLFSSL_MSG("wolfSSL_HMAC_cleanup");
+}
+
+
+const WOLFSSL_EVP_MD* wolfSSL_EVP_get_digestbynid(int id)
+{
+    WOLFSSL_MSG("wolfSSL_get_digestbynid");
+
+    switch(id) {
+#ifndef NO_MD5
+        case NID_md5:
+            return wolfSSL_EVP_md5();
+#endif
+#ifndef NO_SHA
+        case NID_sha1:
+            return wolfSSL_EVP_sha1();
+#endif
+        default:
+            WOLFSSL_MSG("Bad digest id value");
+    }
+
+    return NULL;
+}
+
+
+WOLFSSL_RSA* wolfSSL_EVP_PKEY_get1_RSA(WOLFSSL_EVP_PKEY* key)
+{
+    (void)key;
+    WOLFSSL_MSG("wolfSSL_EVP_PKEY_get1_RSA");
+
+    return NULL;
+}
+
+
+WOLFSSL_DSA* wolfSSL_EVP_PKEY_get1_DSA(WOLFSSL_EVP_PKEY* key)
+{
+    (void)key;
+    WOLFSSL_MSG("wolfSSL_EVP_PKEY_get1_DSA");
+
+    return NULL;
+}
+
+
+void* wolfSSL_EVP_X_STATE(const WOLFSSL_EVP_CIPHER_CTX* ctx)
+{
+    WOLFSSL_MSG("wolfSSL_EVP_X_STATE");
+
+    if (ctx) {
+        switch (ctx->cipherType) {
+            case ARC4_TYPE:
+                WOLFSSL_MSG("returning arc4 state");
+                return (void*)&ctx->cipher.arc4.x;
+
+            default:
+                WOLFSSL_MSG("bad x state type");
+                return 0;
+        }
+    }
+
+    return NULL;
+}
+
+
+int wolfSSL_EVP_X_STATE_LEN(const WOLFSSL_EVP_CIPHER_CTX* ctx)
+{
+    WOLFSSL_MSG("wolfSSL_EVP_X_STATE_LEN");
+
+    if (ctx) {
+        switch (ctx->cipherType) {
+            case ARC4_TYPE:
+                WOLFSSL_MSG("returning arc4 state size");
+                return sizeof(Arc4);
+
+            default:
+                WOLFSSL_MSG("bad x state type");
+                return 0;
+        }
+    }
+
+    return 0;
+}
+
+
+#ifndef NO_DES3
+
+void wolfSSL_3des_iv(WOLFSSL_EVP_CIPHER_CTX* ctx, int doset,
+                            unsigned char* iv, int len)
+{
+    (void)len;
+
+    WOLFSSL_MSG("wolfSSL_3des_iv");
+
+    if (ctx == NULL || iv == NULL) {
+        WOLFSSL_MSG("Bad function argument");
+        return;
+    }
+
+    if (doset)
+        wc_Des3_SetIV(&ctx->cipher.des3, iv);  /* OpenSSL compat, no ret */
+    else
+        memcpy(iv, &ctx->cipher.des3.reg, DES_BLOCK_SIZE);
+}
+
+#endif /* NO_DES3 */
+
+
+#ifndef NO_AES
+
+void wolfSSL_aes_ctr_iv(WOLFSSL_EVP_CIPHER_CTX* ctx, int doset,
+                      unsigned char* iv, int len)
+{
+    (void)len;
+
+    WOLFSSL_MSG("wolfSSL_aes_ctr_iv");
+
+    if (ctx == NULL || iv == NULL) {
+        WOLFSSL_MSG("Bad function argument");
+        return;
+    }
+
+    if (doset)
+        wc_AesSetIV(&ctx->cipher.aes, iv);  /* OpenSSL compat, no ret */
+    else
+        memcpy(iv, &ctx->cipher.aes.reg, AES_BLOCK_SIZE);
+}
+
+#endif /* NO_AES */
+
+
+const WOLFSSL_EVP_MD* wolfSSL_EVP_ripemd160(void)
+{
+    WOLFSSL_MSG("wolfSSL_ripemd160");
+
+    return NULL;
+}
+
+
+int wolfSSL_EVP_MD_size(const WOLFSSL_EVP_MD* type)
+{
+    WOLFSSL_MSG("wolfSSL_EVP_MD_size");
+
+    if (type == NULL) {
+        WOLFSSL_MSG("No md type arg");
+        return BAD_FUNC_ARG;
+    }
+
+    if (XSTRNCMP(type, "SHA256", 6) == 0) {
+        return SHA256_DIGEST_SIZE;
+    }
+#ifndef NO_MD5
+    else if (XSTRNCMP(type, "MD5", 3) == 0) {
+        return MD5_DIGEST_SIZE;
+    }
+#endif
+#ifdef WOLFSSL_SHA384
+    else if (XSTRNCMP(type, "SHA384", 6) == 0) {
+        return SHA384_DIGEST_SIZE;
+    }
+#endif
+#ifdef WOLFSSL_SHA512
+    else if (XSTRNCMP(type, "SHA512", 6) == 0) {
+        return SHA512_DIGEST_SIZE;
+    }
+#endif
+#ifndef NO_SHA
+    /* has to be last since would pick or 256, 384, or 512 too */
+    else if (XSTRNCMP(type, "SHA", 3) == 0) {
+        return SHA_DIGEST_SIZE;
+    }
+#endif
+
+    return BAD_FUNC_ARG;
+}
+
+
+int wolfSSL_EVP_CIPHER_CTX_iv_length(const WOLFSSL_EVP_CIPHER_CTX* ctx)
+{
+    WOLFSSL_MSG("wolfSSL_EVP_CIPHER_CTX_iv_length");
+
+    switch (ctx->cipherType) {
+
+        case AES_128_CBC_TYPE :
+        case AES_192_CBC_TYPE :
+        case AES_256_CBC_TYPE :
+            WOLFSSL_MSG("AES CBC");
+            return AES_BLOCK_SIZE;
+
+#ifdef WOLFSSL_AES_COUNTER
+        case AES_128_CTR_TYPE :
+        case AES_192_CTR_TYPE :
+        case AES_256_CTR_TYPE :
+            WOLFSSL_MSG("AES CTR");
+            return AES_BLOCK_SIZE;
+#endif
+
+        case DES_CBC_TYPE :
+            WOLFSSL_MSG("DES CBC");
+            return DES_BLOCK_SIZE;
+
+        case DES_EDE3_CBC_TYPE :
+            WOLFSSL_MSG("DES EDE3 CBC");
+            return DES_BLOCK_SIZE;
+
+        case ARC4_TYPE :
+            WOLFSSL_MSG("ARC4");
+            return 0;
+
+        case NULL_CIPHER_TYPE :
+            WOLFSSL_MSG("NULL");
+            return 0;
+
+        default: {
+            WOLFSSL_MSG("bad type");
+        }
+    }
+    return 0;
+}
+
+
+void wolfSSL_OPENSSL_free(void* p)
+{
+    WOLFSSL_MSG("wolfSSL_OPENSSL_free");
+
+    XFREE(p, NULL, 0);
+}
+
+
+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");
+
+    return SSL_FATAL_ERROR;
+}
+
+
+
+int wolfSSL_PEM_write_bio_DSAPrivateKey(WOLFSSL_BIO* bio, DSA* 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_DSAPrivateKey");
+
+    return SSL_FATAL_ERROR;
+}
+
+
+
+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");
+
+    return NULL;
+}
+
+
+
+#ifndef NO_RSA
+/* Load RSA from Der, SSL_SUCCESS on success < 0 on error */
+int wolfSSL_RSA_LoadDer(WOLFSSL_RSA* rsa, const unsigned char* der,  int derSz)
+{
+    word32 idx = 0;
+    int    ret;
+
+    WOLFSSL_ENTER("wolfSSL_RSA_LoadDer");
+
+    if (rsa == NULL || rsa->internal == NULL || der == NULL || derSz <= 0) {
+        WOLFSSL_MSG("Bad function arguments");
+        return BAD_FUNC_ARG;
+    }
+
+    ret = wc_RsaPrivateKeyDecode(der, &idx, (RsaKey*)rsa->internal, derSz);
+    if (ret < 0) {
+        WOLFSSL_MSG("RsaPrivateKeyDecode failed");
+        return ret;
+    }
+
+    if (SetRsaExternal(rsa) < 0) {
+        WOLFSSL_MSG("SetRsaExternal failed");
+        return SSL_FATAL_ERROR;
+    }
+
+    rsa->inSet = 1;
+
+    return SSL_SUCCESS;
+}
+#endif /* NO_RSA */
+
+
+#ifndef NO_DSA
+/* Load DSA from Der, SSL_SUCCESS on success < 0 on error */
+int wolfSSL_DSA_LoadDer(WOLFSSL_DSA* dsa, const unsigned char* der,  int derSz)
+{
+    word32 idx = 0;
+    int    ret;
+
+    WOLFSSL_ENTER("wolfSSL_DSA_LoadDer");
+
+    if (dsa == NULL || dsa->internal == NULL || der == NULL || derSz <= 0) {
+        WOLFSSL_MSG("Bad function arguments");
+        return BAD_FUNC_ARG;
+    }
+
+    ret = DsaPrivateKeyDecode(der, &idx, (DsaKey*)dsa->internal, derSz);
+    if (ret < 0) {
+        WOLFSSL_MSG("DsaPrivateKeyDecode failed");
+        return ret;
+    }
+
+    if (SetDsaExternal(dsa) < 0) {
+        WOLFSSL_MSG("SetDsaExternal failed");
+        return SSL_FATAL_ERROR;
+    }
+
+    dsa->inSet = 1;
+
+    return SSL_SUCCESS;
+}
+#endif /* NO_DSA */
+
+
+
+
+#endif /* OPENSSL_EXTRA */
+
+
+#ifdef SESSION_CERTS
+
+
+/* Get peer's certificate chain */
+WOLFSSL_X509_CHAIN* wolfSSL_get_peer_chain(WOLFSSL* ssl)
+{
+    WOLFSSL_ENTER("wolfSSL_get_peer_chain");
+    if (ssl)
+        return &ssl->session.chain;
+
+    return 0;
+}
+
+
+/* Get peer's certificate chain total count */
+int wolfSSL_get_chain_count(WOLFSSL_X509_CHAIN* chain)
+{
+    WOLFSSL_ENTER("wolfSSL_get_chain_count");
+    if (chain)
+        return chain->count;
+
+    return 0;
+}
+
+
+/* Get peer's ASN.1 DER ceritifcate at index (idx) length in bytes */
+int wolfSSL_get_chain_length(WOLFSSL_X509_CHAIN* chain, int idx)
+{
+    WOLFSSL_ENTER("wolfSSL_get_chain_length");
+    if (chain)
+        return chain->certs[idx].length;
+
+    return 0;
+}
+
+
+/* Get peer's ASN.1 DER ceritifcate at index (idx) */
+byte* wolfSSL_get_chain_cert(WOLFSSL_X509_CHAIN* chain, int idx)
+{
+    WOLFSSL_ENTER("wolfSSL_get_chain_cert");
+    if (chain)
+        return chain->certs[idx].buffer;
+
+    return 0;
+}
+
+
+/* Get peer's wolfSSL X509 ceritifcate at index (idx) */
+WOLFSSL_X509* wolfSSL_get_chain_X509(WOLFSSL_X509_CHAIN* chain, int idx)
+{
+    int          ret;
+    WOLFSSL_X509* x509 = NULL;
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCert* cert = NULL;
+#else
+    DecodedCert  cert[1];
+#endif
+
+    WOLFSSL_ENTER("wolfSSL_get_chain_X509");
+    if (chain != NULL) {
+    #ifdef WOLFSSL_SMALL_STACK
+        cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        if (cert != NULL)
+    #endif
+        {
+            InitDecodedCert(cert, chain->certs[idx].buffer,
+                                  chain->certs[idx].length, NULL);
+
+            if ((ret = ParseCertRelative(cert, CERT_TYPE, 0, NULL)) != 0)
+                WOLFSSL_MSG("Failed to parse cert");
+            else {
+                x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL,
+                                                             DYNAMIC_TYPE_X509);
+                if (x509 == NULL) {
+                    WOLFSSL_MSG("Failed alloc X509");
+                }
+                else {
+                    InitX509(x509, 1);
+
+                    if ((ret = CopyDecodedToX509(x509, cert)) != 0) {
+                        WOLFSSL_MSG("Failed to copy decoded");
+                        XFREE(x509, NULL, DYNAMIC_TYPE_X509);
+                        x509 = NULL;
+                    }
+                }
+            }
+
+            FreeDecodedCert(cert);
+        #ifdef WOLFSSL_SMALL_STACK
+            XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        #endif
+        }
+    }
+
+    return x509;
+}
+
+
+/* Get peer's PEM ceritifcate at index (idx), output to buffer if inLen big
+   enough else return error (-1), output length is in *outLen
+   SSL_SUCCESS on ok */
+int  wolfSSL_get_chain_cert_pem(WOLFSSL_X509_CHAIN* chain, int idx,
+                               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;
+    int i;
+    int err;
+
+    WOLFSSL_ENTER("wolfSSL_get_chain_cert_pem");
+    if (!chain || !outLen || !buf)
+        return BAD_FUNC_ARG;
+
+    /* don't even try if inLen too short */
+    if (inLen < headerLen + footerLen + chain->certs[idx].length)
+        return BAD_FUNC_ARG;
+
+    /* header */
+    XMEMCPY(buf, header, headerLen);
+    i = headerLen;
+
+    /* body */
+    *outLen = inLen;  /* input to Base64_Encode */
+    if ( (err = Base64_Encode(chain->certs[idx].buffer,
+                       chain->certs[idx].length, buf + i, (word32*)outLen)) < 0)
+        return err;
+    i += *outLen;
+
+    /* footer */
+    if ( (i + footerLen) > inLen)
+        return BAD_FUNC_ARG;
+    XMEMCPY(buf + i, footer, footerLen);
+    *outLen += headerLen + footerLen;
+
+    return SSL_SUCCESS;
+}
+
+
+/* get session ID */
+const byte* wolfSSL_get_sessionID(const WOLFSSL_SESSION* session)
+{
+    WOLFSSL_ENTER("wolfSSL_get_sessionID");
+    if (session)
+        return session->sessionID;
+
+    return NULL;
+}
+
+
+#endif /* SESSION_CERTS */
+
+#ifdef HAVE_FUZZER
+void wolfSSL_SetFuzzerCb(WOLFSSL* ssl, CallbackFuzzer cbf, void* fCtx)
+{
+    if (ssl) {
+        ssl->fuzzerCb  = cbf;
+        ssl->fuzzerCtx = fCtx;
+    }
+}
+#endif
+
+#ifndef NO_CERTS
+#ifdef  HAVE_PK_CALLBACKS
+
+#ifdef HAVE_ECC
+
+void  wolfSSL_CTX_SetEccSignCb(WOLFSSL_CTX* ctx, CallbackEccSign cb)
+{
+    if (ctx)
+        ctx->EccSignCb = cb;
+}
+
+
+void  wolfSSL_SetEccSignCtx(WOLFSSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->EccSignCtx = ctx;
+}
+
+
+void* wolfSSL_GetEccSignCtx(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->EccSignCtx;
+
+    return NULL;
+}
+
+
+void  wolfSSL_CTX_SetEccVerifyCb(WOLFSSL_CTX* ctx, CallbackEccVerify cb)
+{
+    if (ctx)
+        ctx->EccVerifyCb = cb;
+}
+
+
+void  wolfSSL_SetEccVerifyCtx(WOLFSSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->EccVerifyCtx = ctx;
+}
+
+
+void* wolfSSL_GetEccVerifyCtx(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->EccVerifyCtx;
+
+    return NULL;
+}
+
+#endif /* HAVE_ECC */
+
+#ifndef NO_RSA
+
+void  wolfSSL_CTX_SetRsaSignCb(WOLFSSL_CTX* ctx, CallbackRsaSign cb)
+{
+    if (ctx)
+        ctx->RsaSignCb = cb;
+}
+
+
+void  wolfSSL_SetRsaSignCtx(WOLFSSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->RsaSignCtx = ctx;
+}
+
+
+void* wolfSSL_GetRsaSignCtx(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->RsaSignCtx;
+
+    return NULL;
+}
+
+
+void  wolfSSL_CTX_SetRsaVerifyCb(WOLFSSL_CTX* ctx, CallbackRsaVerify cb)
+{
+    if (ctx)
+        ctx->RsaVerifyCb = cb;
+}
+
+
+void  wolfSSL_SetRsaVerifyCtx(WOLFSSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->RsaVerifyCtx = ctx;
+}
+
+
+void* wolfSSL_GetRsaVerifyCtx(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->RsaVerifyCtx;
+
+    return NULL;
+}
+
+void  wolfSSL_CTX_SetRsaEncCb(WOLFSSL_CTX* ctx, CallbackRsaEnc cb)
+{
+    if (ctx)
+        ctx->RsaEncCb = cb;
+}
+
+
+void  wolfSSL_SetRsaEncCtx(WOLFSSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->RsaEncCtx = ctx;
+}
+
+
+void* wolfSSL_GetRsaEncCtx(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->RsaEncCtx;
+
+    return NULL;
+}
+
+void  wolfSSL_CTX_SetRsaDecCb(WOLFSSL_CTX* ctx, CallbackRsaDec cb)
+{
+    if (ctx)
+        ctx->RsaDecCb = cb;
+}
+
+
+void  wolfSSL_SetRsaDecCtx(WOLFSSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->RsaDecCtx = ctx;
+}
+
+
+void* wolfSSL_GetRsaDecCtx(WOLFSSL* ssl)
+{
+    if (ssl)
+        return ssl->RsaDecCtx;
+
+    return NULL;
+}
+
+
+#endif /* NO_RSA */
+
+#endif /* HAVE_PK_CALLBACKS */
+#endif /* NO_CERTS */
+
+
+#ifdef WOLFSSL_HAVE_WOLFSCEP
+    /* Used by autoconf to see if wolfSCEP is available */
+    void wolfSSL_wolfSCEP(void) {}
+#endif
+
+
+#ifdef WOLFSSL_HAVE_CERT_SERVICE
+    /* Used by autoconf to see if cert service is available */
+    void wolfSSL_cert_service(void) {}
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tls.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,2447 @@
+/* tls.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#include <wolfssl/ssl.h>
+#include <wolfssl/internal.h>
+#include <wolfssl/error-ssl.h>
+#include <wolfssl/wolfcrypt/hmac.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+
+
+#ifndef NO_TLS
+
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* WOLFSSL_HAVE_MIN */
+
+
+#ifdef WOLFSSL_SHA384
+    #define P_HASH_MAX_SIZE SHA384_DIGEST_SIZE
+#else
+    #define P_HASH_MAX_SIZE SHA256_DIGEST_SIZE
+#endif
+
+/* compute p_hash for MD5, SHA-1, SHA-256, or SHA-384 for TLSv1 PRF */
+static int p_hash(byte* result, word32 resLen, const byte* secret,
+                   word32 secLen, const byte* seed, word32 seedLen, int hash)
+{
+    word32 len = P_HASH_MAX_SIZE;
+    word32 times;
+    word32 lastLen;
+    word32 lastTime;
+    word32 i;
+    word32 idx = 0;
+    int    ret = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    byte*  previous;
+    byte*  current;
+    Hmac*  hmac;
+#else
+    byte   previous[P_HASH_MAX_SIZE];  /* max size */
+    byte   current[P_HASH_MAX_SIZE];   /* max size */
+    Hmac   hmac[1];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    previous = (byte*)XMALLOC(P_HASH_MAX_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    current  = (byte*)XMALLOC(P_HASH_MAX_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    hmac     = (Hmac*)XMALLOC(sizeof(Hmac),    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    if (previous == NULL || current == NULL || hmac == NULL) {
+        if (previous) XFREE(previous, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (current)  XFREE(current,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (hmac)     XFREE(hmac,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+        return MEMORY_E;
+    }
+#endif
+
+    switch (hash) {
+        #ifndef NO_MD5
+            case md5_mac:
+                hash = MD5;
+                len  = MD5_DIGEST_SIZE;
+            break;
+        #endif
+
+        #ifndef NO_SHA256
+            case sha256_mac:
+                hash = SHA256;
+                len  = SHA256_DIGEST_SIZE;
+            break;
+        #endif
+
+        #ifdef WOLFSSL_SHA384
+            case sha384_mac:
+                hash = SHA384;
+                len  = SHA384_DIGEST_SIZE;
+            break;
+        #endif
+
+        #ifndef NO_SHA
+            case sha_mac:
+            default:
+                hash = SHA;
+                len  = SHA_DIGEST_SIZE;
+            break;
+        #endif
+    }
+
+    times   = resLen / len;
+    lastLen = resLen % len;
+
+    if (lastLen)
+        times += 1;
+
+    lastTime = times - 1;
+
+    if ((ret = wc_HmacSetKey(hmac, hash, secret, secLen)) == 0) {
+        if ((ret = wc_HmacUpdate(hmac, seed, seedLen)) == 0) { /* A0 = seed */
+            if ((ret = wc_HmacFinal(hmac, previous)) == 0) {   /* A1 */
+                for (i = 0; i < times; i++) {
+                    ret = wc_HmacUpdate(hmac, previous, len);
+                    if (ret != 0)
+                        break;
+                    ret = wc_HmacUpdate(hmac, seed, seedLen);
+                    if (ret != 0)
+                        break;
+                    ret = wc_HmacFinal(hmac, current);
+                    if (ret != 0)
+                        break;
+
+                    if ((i == lastTime) && lastLen)
+                        XMEMCPY(&result[idx], current,
+                                                 min(lastLen, P_HASH_MAX_SIZE));
+                    else {
+                        XMEMCPY(&result[idx], current, len);
+                        idx += len;
+                        ret = wc_HmacUpdate(hmac, previous, len);
+                        if (ret != 0)
+                            break;
+                        ret = wc_HmacFinal(hmac, previous);
+                        if (ret != 0)
+                            break;
+                    }
+                }
+            }
+        }
+    }
+
+    ForceZero(previous,  P_HASH_MAX_SIZE);
+    ForceZero(current,   P_HASH_MAX_SIZE);
+    ForceZero(hmac,      sizeof(Hmac));
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(previous, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(current,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(hmac,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+#undef P_HASH_MAX_SIZE
+
+
+#ifndef NO_OLD_TLS
+
+/* calculate XOR for TLSv1 PRF */
+static INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha)
+{
+    word32 i;
+
+    for (i = 0; i < digLen; i++)
+        digest[i] = md5[i] ^ sha[i];
+}
+
+
+/* compute TLSv1 PRF (pseudo random function using HMAC) */
+static int doPRF(byte* digest, word32 digLen, const byte* secret,word32 secLen,
+                 const byte* label, word32 labLen, const byte* seed,
+                 word32 seedLen)
+{
+    int    ret  = 0;
+    word32 half = (secLen + 1) / 2;
+
+#ifdef WOLFSSL_SMALL_STACK
+    byte* md5_half;
+    byte* sha_half;
+    byte* labelSeed;
+    byte* md5_result;
+    byte* sha_result;
+#else
+    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)
+        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,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    sha_half   = (byte*)XMALLOC(MAX_PRF_HALF,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    labelSeed  = (byte*)XMALLOC(MAX_PRF_LABSEED, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    md5_result = (byte*)XMALLOC(MAX_PRF_DIG,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    sha_result = (byte*)XMALLOC(MAX_PRF_DIG,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    if (md5_half == NULL || sha_half == NULL || labelSeed == NULL ||
+                                     md5_result == NULL || sha_result == NULL) {
+        if (md5_half)   XFREE(md5_half,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (sha_half)   XFREE(sha_half,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (labelSeed)  XFREE(labelSeed,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (md5_result) XFREE(md5_result, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (sha_result) XFREE(sha_result, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+        return MEMORY_E;
+    }
+#endif
+
+    XMEMSET(md5_result, 0, digLen);
+    XMEMSET(sha_result, 0, digLen);
+
+    XMEMCPY(md5_half, secret, half);
+    XMEMCPY(sha_half, secret + half - secLen % 2, half);
+
+    XMEMCPY(labelSeed, label, labLen);
+    XMEMCPY(labelSeed + labLen, seed, seedLen);
+
+    if ((ret = p_hash(md5_result, digLen, md5_half, half, labelSeed,
+                                             labLen + seedLen, md5_mac)) == 0) {
+        if ((ret = p_hash(sha_result, digLen, sha_half, half, labelSeed,
+                                             labLen + seedLen, sha_mac)) == 0) {
+            get_xor(digest, digLen, md5_result, sha_result);
+        }
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(md5_half,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(sha_half,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(labelSeed,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(md5_result, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(sha_result, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+#endif
+
+
+/* Wrapper to call straight thru to p_hash in TSL 1.2 cases to remove stack
+   use */
+static int PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen,
+            const byte* label, word32 labLen, const byte* seed, word32 seedLen,
+            int useAtLeastSha256, int hash_type)
+{
+    int ret = 0;
+
+    if (useAtLeastSha256) {
+#ifdef WOLFSSL_SMALL_STACK
+        byte* labelSeed;
+#else
+        byte labelSeed[MAX_PRF_LABSEED]; /* labLen + seedLen is real size */
+#endif
+
+        if (labLen + seedLen > MAX_PRF_LABSEED)
+            return BUFFER_E;
+
+#ifdef WOLFSSL_SMALL_STACK
+        labelSeed = (byte*)XMALLOC(MAX_PRF_LABSEED, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        if (labelSeed == NULL)
+           return MEMORY_E;
+#endif
+
+        XMEMCPY(labelSeed, label, labLen);
+        XMEMCPY(labelSeed + labLen, seed, seedLen);
+
+        /* If a cipher suite wants an algorithm better than sha256, it
+         * should use better. */
+        if (hash_type < sha256_mac)
+            hash_type = sha256_mac;
+        ret = p_hash(digest, digLen, secret, secLen, labelSeed,
+                     labLen + seedLen, hash_type);
+
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(labelSeed, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+    }
+#ifndef NO_OLD_TLS
+    else {
+        ret = doPRF(digest, digLen, secret, secLen, label, labLen, seed,
+                    seedLen);
+    }
+#endif
+
+    return ret;
+}
+
+
+#ifdef WOLFSSL_SHA384
+    #define HSHASH_SZ SHA384_DIGEST_SIZE
+#else
+    #define HSHASH_SZ FINISHED_SZ
+#endif
+
+
+int BuildTlsFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender)
+{
+    const byte* side;
+    byte        handshake_hash[HSHASH_SZ];
+    word32      hashSz = FINISHED_SZ;
+
+#ifndef NO_OLD_TLS
+    wc_Md5GetHash(&ssl->hsHashes->hashMd5, handshake_hash);
+    wc_ShaGetHash(&ssl->hsHashes->hashSha, &handshake_hash[MD5_DIGEST_SIZE]);
+#endif
+
+    if (IsAtLeastTLSv1_2(ssl)) {
+#ifndef NO_SHA256
+        if (ssl->specs.mac_algorithm <= sha256_mac) {
+            int ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256,handshake_hash);
+
+            if (ret != 0)
+                return ret;
+
+            hashSz = SHA256_DIGEST_SIZE;
+        }
+#endif
+#ifdef WOLFSSL_SHA384
+        if (ssl->specs.mac_algorithm == sha384_mac) {
+            int ret = wc_Sha384Final(&ssl->hsHashes->hashSha384,handshake_hash);
+
+            if (ret != 0)
+                return ret;
+
+            hashSz = SHA384_DIGEST_SIZE;
+        }
+#endif
+    }
+
+    if ( XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0)
+        side = tls_client;
+    else
+        side = tls_server;
+
+    return PRF((byte*)hashes, TLS_FINISHED_SZ, ssl->arrays->masterSecret,
+               SECRET_LEN, side, FINISHED_LABEL_SZ, handshake_hash, hashSz,
+               IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
+}
+
+
+#ifndef NO_OLD_TLS
+
+ProtocolVersion MakeTLSv1(void)
+{
+    ProtocolVersion pv;
+    pv.major = SSLv3_MAJOR;
+    pv.minor = TLSv1_MINOR;
+
+    return pv;
+}
+
+
+ProtocolVersion MakeTLSv1_1(void)
+{
+    ProtocolVersion pv;
+    pv.major = SSLv3_MAJOR;
+    pv.minor = TLSv1_1_MINOR;
+
+    return pv;
+}
+
+#endif
+
+
+ProtocolVersion MakeTLSv1_2(void)
+{
+    ProtocolVersion pv;
+    pv.major = SSLv3_MAJOR;
+    pv.minor = TLSv1_2_MINOR;
+
+    return pv;
+}
+
+
+static const byte master_label[MASTER_LABEL_SZ + 1] = "master secret";
+static const byte key_label   [KEY_LABEL_SZ + 1]    = "key expansion";
+
+
+/* External facing wrapper so user can call as well, 0 on success */
+int wolfSSL_DeriveTlsKeys(byte* key_data, word32 keyLen,
+                         const byte* ms, word32 msLen,
+                         const byte* sr, const byte* cr,
+                         int tls1_2, int hash_type)
+{
+    byte  seed[SEED_LEN];
+
+    XMEMCPY(seed,           sr, RAN_LEN);
+    XMEMCPY(seed + RAN_LEN, cr, RAN_LEN);
+
+    return PRF(key_data, keyLen, ms, msLen, key_label, KEY_LABEL_SZ,
+               seed, SEED_LEN, tls1_2, hash_type);
+}
+
+
+int DeriveTlsKeys(WOLFSSL* ssl)
+{
+    int   ret;
+    int   length = 2 * ssl->specs.hash_size +
+                   2 * ssl->specs.key_size  +
+                   2 * ssl->specs.iv_size;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* key_data;
+#else
+    byte  key_data[MAX_PRF_DIG];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    key_data = (byte*)XMALLOC(MAX_PRF_DIG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (key_data == NULL) {
+        return MEMORY_E;
+    }
+#endif
+
+    ret = wolfSSL_DeriveTlsKeys(key_data, length,
+                           ssl->arrays->masterSecret, SECRET_LEN,
+                           ssl->arrays->serverRandom, ssl->arrays->clientRandom,
+                           IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
+    if (ret == 0)
+        ret = StoreKeys(ssl, key_data);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(key_data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+/* External facing wrapper so user can call as well, 0 on success */
+int wolfSSL_MakeTlsMasterSecret(byte* ms, word32 msLen,
+                               const byte* pms, word32 pmsLen,
+                               const byte* cr, const byte* sr,
+                               int tls1_2, int hash_type)
+{
+    byte  seed[SEED_LEN];
+
+    XMEMCPY(seed,           cr, RAN_LEN);
+    XMEMCPY(seed + RAN_LEN, sr, RAN_LEN);
+
+    return PRF(ms, msLen, pms, pmsLen, master_label, MASTER_LABEL_SZ,
+               seed, SEED_LEN, tls1_2, hash_type);
+}
+
+
+int MakeTlsMasterSecret(WOLFSSL* ssl)
+{
+    int   ret;
+
+    ret = wolfSSL_MakeTlsMasterSecret(ssl->arrays->masterSecret, SECRET_LEN,
+              ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz,
+              ssl->arrays->clientRandom, ssl->arrays->serverRandom,
+              IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
+
+    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
+
+        ret = DeriveTlsKeys(ssl);
+    }
+
+    return ret;
+}
+
+
+/* Used by EAP-TLS and EAP-TTLS to derive keying material from
+ * the master_secret. */
+int wolfSSL_make_eap_keys(WOLFSSL* ssl, void* msk, unsigned int len,
+                                                              const char* label)
+{
+    int   ret;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* seed;
+#else
+    byte  seed[SEED_LEN];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    seed = (byte*)XMALLOC(SEED_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (seed == NULL)
+        return MEMORY_E;
+#endif
+
+    /*
+     * As per RFC-5281, the order of the client and server randoms is reversed
+     * from that used by the TLS protocol to derive keys.
+     */
+    XMEMCPY(seed,           ssl->arrays->clientRandom, RAN_LEN);
+    XMEMCPY(seed + RAN_LEN, ssl->arrays->serverRandom, RAN_LEN);
+
+    ret = PRF((byte*)msk, len, ssl->arrays->masterSecret, SECRET_LEN,
+              (const byte *)label, (word32)strlen(label), seed, SEED_LEN,
+              IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(seed, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+/*** next for static INLINE s copied internal.c ***/
+
+/* convert 16 bit integer to opaque */
+static INLINE void c16toa(word16 u16, byte* c)
+{
+    c[0] = (u16 >> 8) & 0xff;
+    c[1] =  u16 & 0xff;
+}
+
+#ifdef HAVE_TLS_EXTENSIONS
+/* convert opaque to 16 bit integer */
+static INLINE void ato16(const byte* c, word16* u16)
+{
+    *u16 = (c[0] << 8) | (c[1]);
+}
+
+#ifdef HAVE_SNI
+/* 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];
+}
+#endif
+#endif
+
+/* 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 INLINE word32 GetSEQIncrement(WOLFSSL* ssl, int verify)
+{
+#ifdef WOLFSSL_DTLS
+    if (ssl->options.dtls) {
+        if (verify)
+            return ssl->keys.dtls_state.curSeq; /* explicit from peer */
+        else
+            return ssl->keys.dtls_sequence_number - 1; /* already incremented */
+    }
+#endif
+    if (verify)
+        return ssl->keys.peer_sequence_number++;
+    else
+        return ssl->keys.sequence_number++;
+}
+
+
+#ifdef WOLFSSL_DTLS
+
+static INLINE word32 GetEpoch(WOLFSSL* ssl, int verify)
+{
+    if (verify)
+        return ssl->keys.dtls_state.curEpoch;
+    else
+        return ssl->keys.dtls_epoch;
+}
+
+#endif /* WOLFSSL_DTLS */
+
+
+/*** end copy ***/
+
+
+/* return HMAC digest type in wolfSSL format */
+int wolfSSL_GetHmacType(WOLFSSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    switch (ssl->specs.mac_algorithm) {
+        #ifndef NO_MD5
+        case md5_mac:
+        {
+            return MD5;
+        }
+        #endif
+        #ifndef NO_SHA256
+        case sha256_mac:
+        {
+            return SHA256;
+        }
+        #endif
+        #ifdef WOLFSSL_SHA384
+        case sha384_mac:
+        {
+            return SHA384;
+        }
+
+        #endif
+        #ifndef NO_SHA
+        case sha_mac:
+        {
+            return SHA;
+        }
+        #endif
+        #ifdef HAVE_BLAKE2
+        case blake2b_mac:
+        {
+            return BLAKE2B_ID;
+        }
+        #endif
+        default:
+        {
+            return SSL_FATAL_ERROR;
+        }
+    }
+}
+
+
+int wolfSSL_SetTlsHmacInner(WOLFSSL* ssl, byte* inner, word32 sz, int content,
+                           int verify)
+{
+    if (ssl == NULL || inner == NULL)
+        return BAD_FUNC_ARG;
+
+    XMEMSET(inner, 0, WOLFSSL_TLS_HMAC_INNER_SZ);
+
+#ifdef WOLFSSL_DTLS
+    if (ssl->options.dtls)
+        c16toa((word16)GetEpoch(ssl, verify), inner);
+#endif
+    c32toa(GetSEQIncrement(ssl, verify), &inner[sizeof(word32)]);
+    inner[SEQ_SZ] = (byte)content;
+    inner[SEQ_SZ + ENUM_LEN]            = ssl->version.major;
+    inner[SEQ_SZ + ENUM_LEN + ENUM_LEN] = ssl->version.minor;
+    c16toa((word16)sz, inner + SEQ_SZ + ENUM_LEN + VERSION_SZ);
+
+    return 0;
+}
+
+
+/* TLS type HMAC */
+int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
+              int content, int verify)
+{
+    Hmac hmac;
+    int  ret;
+    byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ];
+
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+#ifdef HAVE_FUZZER
+    if (ssl->fuzzerCb)
+        ssl->fuzzerCb(ssl, in, sz, FUZZ_HMAC, ssl->fuzzerCtx);
+#endif
+
+    wolfSSL_SetTlsHmacInner(ssl, myInner, sz, content, verify);
+
+    ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl),
+                     wolfSSL_GetMacSecret(ssl, verify), ssl->specs.hash_size);
+    if (ret != 0)
+        return ret;
+    ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner));
+    if (ret != 0)
+        return ret;
+    ret = wc_HmacUpdate(&hmac, in, sz);                                /* content */
+    if (ret != 0)
+        return ret;
+    ret = wc_HmacFinal(&hmac, digest);
+    if (ret != 0)
+        return ret;
+
+    return 0;
+}
+
+#ifdef HAVE_TLS_EXTENSIONS
+
+
+/** Supports up to 64 flags. Update as needed. */
+#define SEMAPHORE_SIZE 8
+
+
+static INLINE word16 TLSX_ToSemaphore(word16 type)
+{
+    switch (type) {
+        case SECURE_RENEGOTIATION:
+            return 63;
+
+        default:
+            if (type > 62) {
+                /* This message SHOULD only happens during the adding of
+                   new TLS extensions in which its IANA number overflows
+                   the current semaphore's range, or if its number already
+                   is assigned to be used by another extension.
+                   Use this check value for the new extension and decrement
+                   the check value by one. */
+                WOLFSSL_MSG("### TLSX semaphore colision or overflow detected!");
+            }
+    }
+
+    return type;
+}
+
+
+#define IS_OFF(semaphore, light) \
+    ((semaphore)[(light) / 8] ^  (byte) (0x01 << ((light) % 8)))
+
+
+#define TURN_ON(semaphore, light) \
+    ((semaphore)[(light) / 8] |= (byte) (0x01 << ((light) % 8)))
+
+
+static int TLSX_Push(TLSX** list, TLSX_Type type, void* data)
+{
+    TLSX* extension;
+
+    extension = (TLSX*)XMALLOC(sizeof(TLSX), 0, DYNAMIC_TYPE_TLSX);
+    if (extension == NULL)
+        return MEMORY_E;
+
+    extension->type = type;
+    extension->data = data;
+    extension->resp = 0;
+    extension->next = *list;
+    *list = extension;
+
+    /* remove duplicated extensions, there should be only one of each type. */
+    do {
+        if (extension->next && extension->next->type == type) {
+            TLSX *next = extension->next;
+
+            extension->next = next->next;
+            next->next = NULL;
+
+            TLSX_FreeAll(next);
+
+            /* there is no way to occur more than */
+            /* two extensions of the same type.   */
+            break;
+        }
+    } while ((extension = extension->next));
+
+    return 0;
+}
+
+
+#ifndef NO_WOLFSSL_SERVER
+
+void TLSX_SetResponse(WOLFSSL* ssl, TLSX_Type type);
+
+void TLSX_SetResponse(WOLFSSL* ssl, TLSX_Type type)
+{
+    TLSX *ext = TLSX_Find(ssl->extensions, type);
+
+    if (ext)
+        ext->resp = 1;
+}
+
+#endif
+
+/* SNI - Server Name Indication */
+
+#ifdef HAVE_SNI
+
+static void TLSX_SNI_Free(SNI* sni)
+{
+    if (sni) {
+        switch (sni->type) {
+            case WOLFSSL_SNI_HOST_NAME:
+                XFREE(sni->data.host_name, 0, DYNAMIC_TYPE_TLSX);
+            break;
+        }
+
+        XFREE(sni, 0, DYNAMIC_TYPE_TLSX);
+    }
+}
+
+static void TLSX_SNI_FreeAll(SNI* list)
+{
+    SNI* sni;
+
+    while ((sni = list)) {
+        list = sni->next;
+        TLSX_SNI_Free(sni);
+    }
+}
+
+static int TLSX_SNI_Append(SNI** list, byte type, const void* data, word16 size)
+{
+    SNI* sni;
+
+    if (list == NULL)
+        return BAD_FUNC_ARG;
+
+    if ((sni = XMALLOC(sizeof(SNI), 0, DYNAMIC_TYPE_TLSX)) == NULL)
+        return MEMORY_E;
+
+    switch (type) {
+        case WOLFSSL_SNI_HOST_NAME: {
+            sni->data.host_name = XMALLOC(size + 1, 0, DYNAMIC_TYPE_TLSX);
+
+            if (sni->data.host_name) {
+                XSTRNCPY(sni->data.host_name, (const char*)data, size);
+                sni->data.host_name[size] = 0;
+            } else {
+                XFREE(sni, 0, DYNAMIC_TYPE_TLSX);
+                return MEMORY_E;
+            }
+        }
+        break;
+
+        default: /* invalid type */
+            XFREE(sni, 0, DYNAMIC_TYPE_TLSX);
+            return BAD_FUNC_ARG;
+    }
+
+    sni->type = type;
+    sni->next = *list;
+
+#ifndef NO_WOLFSSL_SERVER
+    sni->options = 0;
+    sni->status  = WOLFSSL_SNI_NO_MATCH;
+#endif
+
+    *list = sni;
+
+    return 0;
+}
+
+static word16 TLSX_SNI_GetSize(SNI* list)
+{
+    SNI* sni;
+    word16 length = OPAQUE16_LEN; /* list length */
+
+    while ((sni = list)) {
+        list = sni->next;
+
+        length += ENUM_LEN + OPAQUE16_LEN; /* sni type + sni length */
+
+        switch (sni->type) {
+            case WOLFSSL_SNI_HOST_NAME:
+                length += XSTRLEN((char*)sni->data.host_name);
+            break;
+        }
+    }
+
+    return length;
+}
+
+static word16 TLSX_SNI_Write(SNI* list, byte* output)
+{
+    SNI* sni;
+    word16 length = 0;
+    word16 offset = OPAQUE16_LEN; /* list length offset */
+
+    while ((sni = list)) {
+        list = sni->next;
+
+        output[offset++] = sni->type; /* sni type */
+
+        switch (sni->type) {
+            case WOLFSSL_SNI_HOST_NAME:
+                length = XSTRLEN((char*)sni->data.host_name);
+
+                c16toa(length, output + offset); /* sni length */
+                offset += OPAQUE16_LEN;
+
+                XMEMCPY(output + offset, sni->data.host_name, length);
+
+                offset += length;
+            break;
+        }
+    }
+
+    c16toa(offset - OPAQUE16_LEN, output); /* writing list length */
+
+    return offset;
+}
+
+static SNI* TLSX_SNI_Find(SNI *list, byte type)
+{
+    SNI *sni = list;
+
+    while (sni && sni->type != type)
+        sni = sni->next;
+
+    return sni;
+}
+
+#ifndef NO_WOLFSSL_SERVER
+static void TLSX_SNI_SetStatus(TLSX* extensions, byte type, byte status)
+{
+    TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
+    SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+
+    if (sni) {
+        sni->status = status;
+        WOLFSSL_MSG("SNI did match!");
+    }
+}
+
+byte TLSX_SNI_Status(TLSX* extensions, byte type)
+{
+    TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
+    SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+
+    if (sni)
+        return sni->status;
+
+    return 0;
+}
+#endif
+
+static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
+                                                                 byte isRequest)
+{
+#ifndef NO_WOLFSSL_SERVER
+    word16 size = 0;
+    word16 offset = 0;
+#endif
+
+    TLSX *extension = TLSX_Find(ssl->extensions, SERVER_NAME_INDICATION);
+
+    if (!extension)
+        extension = TLSX_Find(ssl->ctx->extensions, SERVER_NAME_INDICATION);
+
+    if (!extension || !extension->data)
+        return isRequest ? 0 : BUFFER_ERROR; /* not using SNI OR unexpected
+                                                SNI response from server. */
+
+    if (!isRequest)
+        return length ? BUFFER_ERROR : 0; /* SNI response must be empty!
+                                             Nothing else to do. */
+
+#ifndef NO_WOLFSSL_SERVER
+
+    if (OPAQUE16_LEN > length)
+        return BUFFER_ERROR;
+
+    ato16(input, &size);
+    offset += OPAQUE16_LEN;
+
+    /* validating sni list length */
+    if (length != OPAQUE16_LEN + size)
+        return BUFFER_ERROR;
+
+    for (size = 0; offset < length; offset += size) {
+        SNI *sni;
+        byte type = input[offset++];
+
+        if (offset + OPAQUE16_LEN > length)
+            return BUFFER_ERROR;
+
+        ato16(input + offset, &size);
+        offset += OPAQUE16_LEN;
+
+        if (offset + size > length)
+            return BUFFER_ERROR;
+
+        if (!(sni = TLSX_SNI_Find((SNI*)extension->data, type))) {
+            continue; /* not using this SNI type */
+        }
+
+        switch(type) {
+            case WOLFSSL_SNI_HOST_NAME: {
+                byte matched = (XSTRLEN(sni->data.host_name) == size)
+                            && (XSTRNCMP(sni->data.host_name,
+                                       (const char*)input + offset, size) == 0);
+
+                if (matched || sni->options & WOLFSSL_SNI_ANSWER_ON_MISMATCH) {
+                    int r = TLSX_UseSNI(&ssl->extensions,
+                                                    type, input + offset, size);
+
+                    if (r != SSL_SUCCESS) return r; /* throw error */
+
+                    TLSX_SNI_SetStatus(ssl->extensions, type,
+                      matched ? WOLFSSL_SNI_REAL_MATCH : WOLFSSL_SNI_FAKE_MATCH);
+
+                } else if (!(sni->options & WOLFSSL_SNI_CONTINUE_ON_MISMATCH)) {
+                    SendAlert(ssl, alert_fatal, unrecognized_name);
+
+                    return UNKNOWN_SNI_HOST_NAME_E;
+                }
+                break;
+            }
+        }
+
+        TLSX_SetResponse(ssl, SERVER_NAME_INDICATION);
+    }
+
+#endif
+
+    return 0;
+}
+
+int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size)
+{
+    TLSX* extension = TLSX_Find(*extensions, SERVER_NAME_INDICATION);
+    SNI*  sni       = NULL;
+    int   ret       = 0;
+
+    if (extensions == NULL || data == NULL)
+        return BAD_FUNC_ARG;
+
+    if ((ret = TLSX_SNI_Append(&sni, type, data, size)) != 0)
+        return ret;
+
+    if (!extension) {
+        if ((ret = TLSX_Push(extensions, SERVER_NAME_INDICATION, (void*)sni))
+                                                                         != 0) {
+            TLSX_SNI_Free(sni);
+            return ret;
+        }
+    }
+    else {
+        /* push new SNI object to extension data. */
+        sni->next = (SNI*)extension->data;
+        extension->data = (void*)sni;
+
+        /* look for another server name of the same type to remove */
+        do {
+            if (sni->next && sni->next->type == type) {
+                SNI *next = sni->next;
+
+                sni->next = next->next;
+                TLSX_SNI_Free(next);
+
+                break;
+            }
+        } while ((sni = sni->next));
+    }
+
+    return SSL_SUCCESS;
+}
+
+#ifndef NO_WOLFSSL_SERVER
+word16 TLSX_SNI_GetRequest(TLSX* extensions, byte type, void** data)
+{
+    TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
+    SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+
+    if (sni && sni->status != WOLFSSL_SNI_NO_MATCH) {
+        switch (sni->type) {
+            case WOLFSSL_SNI_HOST_NAME:
+                *data = sni->data.host_name;
+                return XSTRLEN(*data);
+        }
+    }
+
+    return 0;
+}
+
+void TLSX_SNI_SetOptions(TLSX* extensions, byte type, byte options)
+{
+    TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
+    SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+
+    if (sni)
+        sni->options = options;
+}
+
+int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
+                           byte type, byte* sni, word32* inOutSz)
+{
+    word32 offset = 0;
+    word32 len32  = 0;
+    word16 len16  = 0;
+
+    if (helloSz < RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + CLIENT_HELLO_FIRST)
+        return INCOMPLETE_DATA;
+
+    /* TLS record header */
+    if ((enum ContentType) clientHello[offset++] != handshake)
+        return BUFFER_ERROR;
+
+    if (clientHello[offset++] != SSLv3_MAJOR)
+        return BUFFER_ERROR;
+
+    if (clientHello[offset++] < TLSv1_MINOR)
+        return SNI_UNSUPPORTED;
+
+    ato16(clientHello + offset, &len16);
+    offset += OPAQUE16_LEN;
+
+    if (offset + len16 > helloSz)
+        return INCOMPLETE_DATA;
+
+    /* Handshake header */
+    if ((enum HandShakeType) clientHello[offset] != client_hello)
+        return BUFFER_ERROR;
+
+    c24to32(clientHello + offset + 1, &len32);
+    offset += HANDSHAKE_HEADER_SZ;
+
+    if (offset + len32 > helloSz)
+        return BUFFER_ERROR;
+
+    /* client hello */
+    offset += VERSION_SZ + RAN_LEN; /* version, random */
+
+    if (helloSz < offset + clientHello[offset])
+        return BUFFER_ERROR;
+
+    offset += ENUM_LEN + clientHello[offset]; /* skip session id */
+
+    /* cypher suites */
+    if (helloSz < offset + OPAQUE16_LEN)
+        return BUFFER_ERROR;
+
+    ato16(clientHello + offset, &len16);
+    offset += OPAQUE16_LEN;
+
+    if (helloSz < offset + len16)
+        return BUFFER_ERROR;
+
+    offset += len16; /* skip cypher suites */
+
+    /* compression methods */
+    if (helloSz < offset + 1)
+        return BUFFER_ERROR;
+
+    if (helloSz < offset + clientHello[offset])
+        return BUFFER_ERROR;
+
+    offset += ENUM_LEN + clientHello[offset]; /* skip compression methods */
+
+    /* extensions */
+    if (helloSz < offset + OPAQUE16_LEN)
+        return 0; /* no extensions in client hello. */
+
+    ato16(clientHello + offset, &len16);
+    offset += OPAQUE16_LEN;
+
+    if (helloSz < offset + len16)
+        return BUFFER_ERROR;
+
+    while (len16 >= OPAQUE16_LEN + OPAQUE16_LEN) {
+        word16 extType;
+        word16 extLen;
+
+        ato16(clientHello + offset, &extType);
+        offset += OPAQUE16_LEN;
+
+        ato16(clientHello + offset, &extLen);
+        offset += OPAQUE16_LEN;
+
+        if (helloSz < offset + extLen)
+            return BUFFER_ERROR;
+
+        if (extType != SERVER_NAME_INDICATION) {
+            offset += extLen; /* skip extension */
+        } else {
+            word16 listLen;
+
+            ato16(clientHello + offset, &listLen);
+            offset += OPAQUE16_LEN;
+
+            if (helloSz < offset + listLen)
+                return BUFFER_ERROR;
+
+            while (listLen > ENUM_LEN + OPAQUE16_LEN) {
+                byte   sniType = clientHello[offset++];
+                word16 sniLen;
+
+                ato16(clientHello + offset, &sniLen);
+                offset += OPAQUE16_LEN;
+
+                if (helloSz < offset + sniLen)
+                    return BUFFER_ERROR;
+
+                if (sniType != type) {
+                    offset  += sniLen;
+                    listLen -= min(ENUM_LEN + OPAQUE16_LEN + sniLen, listLen);
+                    continue;
+                }
+
+                *inOutSz = min(sniLen, *inOutSz);
+                XMEMCPY(sni, clientHello + offset, *inOutSz);
+
+                return SSL_SUCCESS;
+            }
+        }
+
+        len16 -= min(2 * OPAQUE16_LEN + extLen, len16);
+    }
+
+    return len16 ? BUFFER_ERROR : 0;
+}
+
+#endif
+
+#define SNI_FREE_ALL TLSX_SNI_FreeAll
+#define SNI_GET_SIZE TLSX_SNI_GetSize
+#define SNI_WRITE    TLSX_SNI_Write
+#define SNI_PARSE    TLSX_SNI_Parse
+
+#else
+
+#define SNI_FREE_ALL(list)
+#define SNI_GET_SIZE(list)    0
+#define SNI_WRITE(a, b)       0
+#define SNI_PARSE(a, b, c, d) 0
+
+#endif /* HAVE_SNI */
+
+#ifdef HAVE_MAX_FRAGMENT
+
+static word16 TLSX_MFL_Write(byte* data, byte* output)
+{
+    output[0] = data[0];
+
+    return ENUM_LEN;
+}
+
+static int TLSX_MFL_Parse(WOLFSSL* ssl, byte* input, word16 length,
+                                                                 byte isRequest)
+{
+    if (length != ENUM_LEN)
+        return BUFFER_ERROR;
+
+    switch (*input) {
+        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:
+            SendAlert(ssl, alert_fatal, illegal_parameter);
+
+            return UNKNOWN_MAX_FRAG_LEN_E;
+    }
+
+#ifndef NO_WOLFSSL_SERVER
+    if (isRequest) {
+        int r = TLSX_UseMaxFragment(&ssl->extensions, *input);
+
+        if (r != SSL_SUCCESS) return r; /* throw error */
+
+        TLSX_SetResponse(ssl, MAX_FRAGMENT_LENGTH);
+    }
+#endif
+
+    return 0;
+}
+
+int TLSX_UseMaxFragment(TLSX** extensions, byte mfl)
+{
+    byte* data = NULL;
+    int   ret  = 0;
+
+    if (extensions == NULL)
+        return BAD_FUNC_ARG;
+
+    if (mfl < WOLFSSL_MFL_2_9 || WOLFSSL_MFL_2_13 < mfl)
+        return BAD_FUNC_ARG;
+
+    if ((data = XMALLOC(ENUM_LEN, 0, DYNAMIC_TYPE_TLSX)) == NULL)
+        return MEMORY_E;
+
+    data[0] = mfl;
+
+    /* push new MFL extension. */
+    if ((ret = TLSX_Push(extensions, MAX_FRAGMENT_LENGTH, data)) != 0) {
+        XFREE(data, 0, DYNAMIC_TYPE_TLSX);
+        return ret;
+    }
+
+    return SSL_SUCCESS;
+}
+
+
+#define MFL_FREE_ALL(data) XFREE(data, 0, DYNAMIC_TYPE_TLSX)
+#define MFL_GET_SIZE(data) ENUM_LEN
+#define MFL_WRITE          TLSX_MFL_Write
+#define MFL_PARSE          TLSX_MFL_Parse
+
+#else
+
+#define MFL_FREE_ALL(a)
+#define MFL_GET_SIZE(a)       0
+#define MFL_WRITE(a, b)       0
+#define MFL_PARSE(a, b, c, d) 0
+
+#endif /* HAVE_MAX_FRAGMENT */
+
+#ifdef HAVE_TRUNCATED_HMAC
+
+static int TLSX_THM_Parse(WOLFSSL* ssl, byte* input, word16 length,
+                                                                 byte isRequest)
+{
+    if (length != 0 || input == NULL)
+        return BUFFER_ERROR;
+
+#ifndef NO_WOLFSSL_SERVER
+    if (isRequest) {
+        int r = TLSX_UseTruncatedHMAC(&ssl->extensions);
+
+        if (r != SSL_SUCCESS) return r; /* throw error */
+
+        TLSX_SetResponse(ssl, TRUNCATED_HMAC);
+    }
+#endif
+
+    ssl->truncated_hmac = 1;
+
+    return 0;
+}
+
+int TLSX_UseTruncatedHMAC(TLSX** extensions)
+{
+    int ret = 0;
+
+    if (extensions == NULL)
+        return BAD_FUNC_ARG;
+
+    if ((ret = TLSX_Push(extensions, TRUNCATED_HMAC, NULL)) != 0)
+        return ret;
+
+    return SSL_SUCCESS;
+}
+
+#define THM_PARSE TLSX_THM_Parse
+
+#else
+
+#define THM_PARSE(a, b, c, d) 0
+
+#endif /* HAVE_TRUNCATED_HMAC */
+
+#ifdef HAVE_SUPPORTED_CURVES
+
+#ifndef HAVE_ECC
+#error Elliptic Curves Extension requires Elliptic Curve Cryptography. \
+       Use --enable-ecc in the configure script or define HAVE_ECC.
+#endif
+
+static void TLSX_EllipticCurve_FreeAll(EllipticCurve* list)
+{
+    EllipticCurve* curve;
+
+    while ((curve = list)) {
+        list = curve->next;
+        XFREE(curve, 0, DYNAMIC_TYPE_TLSX);
+    }
+}
+
+static int TLSX_EllipticCurve_Append(EllipticCurve** list, word16 name)
+{
+    EllipticCurve* curve;
+
+    if (list == NULL)
+        return BAD_FUNC_ARG;
+
+    if ((curve = XMALLOC(sizeof(EllipticCurve), 0, DYNAMIC_TYPE_TLSX)) == NULL)
+        return MEMORY_E;
+
+    curve->name = name;
+    curve->next = *list;
+
+    *list = curve;
+
+    return 0;
+}
+
+#ifndef NO_WOLFSSL_CLIENT
+
+static void TLSX_EllipticCurve_ValidateRequest(WOLFSSL* ssl, byte* semaphore)
+{
+    int i;
+
+    for (i = 0; i < ssl->suites->suiteSz; i+= 2)
+        if (ssl->suites->suites[i] == ECC_BYTE)
+            return;
+
+    /* No elliptic curve suite found */
+    TURN_ON(semaphore, TLSX_ToSemaphore(ELLIPTIC_CURVES));
+}
+
+static word16 TLSX_EllipticCurve_GetSize(EllipticCurve* list)
+{
+    EllipticCurve* curve;
+    word16 length = OPAQUE16_LEN; /* list length */
+
+    while ((curve = list)) {
+        list = curve->next;
+        length += OPAQUE16_LEN; /* curve length */
+    }
+
+    return length;
+}
+
+static word16 TLSX_EllipticCurve_WriteR(EllipticCurve* curve, byte* output);
+static word16 TLSX_EllipticCurve_WriteR(EllipticCurve* curve, byte* output)
+{
+    word16 offset = 0;
+
+    if (!curve)
+        return offset;
+
+    offset = TLSX_EllipticCurve_WriteR(curve->next, output);
+    c16toa(curve->name, output + offset);
+
+    return OPAQUE16_LEN + offset;
+}
+
+static word16 TLSX_EllipticCurve_Write(EllipticCurve* list, byte* output)
+{
+    word16 length = TLSX_EllipticCurve_WriteR(list, output + OPAQUE16_LEN);
+
+    c16toa(length, output); /* writing list length */
+
+    return OPAQUE16_LEN + length;
+}
+
+#endif /* NO_WOLFSSL_CLIENT */
+#ifndef NO_WOLFSSL_SERVER
+
+static int TLSX_EllipticCurve_Parse(WOLFSSL* ssl, byte* input, word16 length,
+                                                                 byte isRequest)
+{
+    word16 offset;
+    word16 name;
+    int r;
+
+    (void) isRequest; /* shut up compiler! */
+
+    if (OPAQUE16_LEN > length || length % OPAQUE16_LEN)
+        return BUFFER_ERROR;
+
+    ato16(input, &offset);
+
+    /* validating curve list length */
+    if (length != OPAQUE16_LEN + offset)
+        return BUFFER_ERROR;
+
+    while (offset) {
+        ato16(input + offset, &name);
+        offset -= OPAQUE16_LEN;
+
+        r = TLSX_UseSupportedCurve(&ssl->extensions, name);
+
+        if (r != SSL_SUCCESS) return r; /* throw error */
+    }
+
+    return 0;
+}
+
+int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) {
+    TLSX*          extension = (first == ECC_BYTE)
+                             ? TLSX_Find(ssl->extensions, ELLIPTIC_CURVES)
+                             : NULL;
+    EllipticCurve* curve     = NULL;
+    word32         oid       = 0;
+    word16         octets    = 0; /* acording to 'ecc_set_type ecc_sets[];' */
+    int            sig       = 0; /* valitade signature */
+    int            key       = 0; /* validate key       */
+
+    (void)oid;
+    (void)octets;
+
+    if (!extension)
+        return 1; /* no suite restriction */
+
+    for (curve = extension->data; curve && !(sig && key); curve = curve->next) {
+
+        switch (curve->name) {
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC160)
+            case WOLFSSL_ECC_SECP160R1: oid = ECC_160R1; octets = 20; break;
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC192)
+            case WOLFSSL_ECC_SECP192R1: oid = ECC_192R1; octets = 24; break;
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC224)
+            case WOLFSSL_ECC_SECP224R1: oid = ECC_224R1; octets = 28; break;
+#endif
+#if defined(HAVE_ALL_CURVES) || !defined(NO_ECC256)
+            case WOLFSSL_ECC_SECP256R1: oid = ECC_256R1; octets = 32; break;
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC384)
+            case WOLFSSL_ECC_SECP384R1: oid = ECC_384R1; octets = 48; break;
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC521)
+            case WOLFSSL_ECC_SECP521R1: oid = ECC_521R1; octets = 66; break;
+#endif
+            default: continue; /* unsupported curve */
+        }
+
+        switch (second) {
+#ifndef NO_DSA
+            /* ECDHE_ECDSA */
+            case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+            case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+            case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+            case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+            case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+            case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+            case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+            case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+            case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+                sig |= ssl->pkCurveOID == oid;
+                key |= ssl->eccTempKeySz == octets;
+            break;
+
+            /* ECDH_ECDSA */
+            case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+            case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+            case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+            case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+            case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+            case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+            case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+                sig |= ssl->pkCurveOID == oid;
+                key |= ssl->pkCurveOID == oid;
+            break;
+#endif
+#ifndef NO_RSA
+            /* ECDHE_RSA */
+            case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+            case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+            case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+            case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+            case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+            case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+            case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+                sig = 1;
+                key |= ssl->eccTempKeySz == octets;
+            break;
+
+            /* ECDH_RSA */
+            case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+            case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+            case TLS_ECDH_RSA_WITH_RC4_128_SHA:
+            case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+            case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+            case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+            case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+            case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+                sig = 1;
+                key |= ssl->pkCurveOID == oid;
+            break;
+#endif
+            default:
+                sig = 1;
+                key = 1;
+            break;
+        }
+    }
+
+    return sig && key;
+}
+
+#endif /* NO_WOLFSSL_SERVER */
+
+int TLSX_UseSupportedCurve(TLSX** extensions, word16 name)
+{
+    TLSX*          extension = TLSX_Find(*extensions, ELLIPTIC_CURVES);
+    EllipticCurve* curve     = NULL;
+    int            ret       = 0;
+
+    if (extensions == NULL)
+        return BAD_FUNC_ARG;
+
+    if ((ret = TLSX_EllipticCurve_Append(&curve, name)) != 0)
+        return ret;
+
+    if (!extension) {
+        if ((ret = TLSX_Push(extensions, ELLIPTIC_CURVES, curve)) != 0) {
+            XFREE(curve, 0, DYNAMIC_TYPE_TLSX);
+            return ret;
+        }
+    }
+    else {
+        /* push new EllipticCurve object to extension data. */
+        curve->next = (EllipticCurve*)extension->data;
+        extension->data = (void*)curve;
+
+        /* look for another curve of the same name to remove (replacement) */
+        do {
+            if (curve->next && curve->next->name == name) {
+                EllipticCurve *next = curve->next;
+
+                curve->next = next->next;
+                XFREE(next, 0, DYNAMIC_TYPE_TLSX);
+
+                break;
+            }
+        } while ((curve = curve->next));
+    }
+
+    return SSL_SUCCESS;
+}
+
+#define EC_FREE_ALL         TLSX_EllipticCurve_FreeAll
+#define EC_VALIDATE_REQUEST TLSX_EllipticCurve_ValidateRequest
+
+#ifndef NO_WOLFSSL_CLIENT
+#define EC_GET_SIZE TLSX_EllipticCurve_GetSize
+#define EC_WRITE    TLSX_EllipticCurve_Write
+#else
+#define EC_GET_SIZE(list)         0
+#define EC_WRITE(a, b)            0
+#endif
+
+#ifndef NO_WOLFSSL_SERVER
+#define EC_PARSE TLSX_EllipticCurve_Parse
+#else
+#define EC_PARSE(a, b, c, d)      0
+#endif
+
+#else
+
+#define EC_FREE_ALL(list)
+#define EC_GET_SIZE(list)         0
+#define EC_WRITE(a, b)            0
+#define EC_PARSE(a, b, c, d)      0
+#define EC_VALIDATE_REQUEST(a, b)
+
+#endif /* HAVE_SUPPORTED_CURVES */
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+
+static byte TLSX_SecureRenegotiation_GetSize(SecureRenegotiation* data,
+                                                                  int isRequest)
+{
+    byte length = OPAQUE8_LEN; /* empty info length */
+
+    if (data->enabled) {
+        /* client sends client_verify_data only */
+        length += TLS_FINISHED_SZ;
+
+        /* server also sends server_verify_data */
+        if (!isRequest)
+            length += TLS_FINISHED_SZ;
+    }
+
+    return length;
+}
+
+static word16 TLSX_SecureRenegotiation_Write(SecureRenegotiation* data,
+                                                    byte* output, int isRequest)
+{
+    word16 offset = OPAQUE8_LEN; /* RenegotiationInfo length */
+
+    if (data->enabled) {
+        /* client sends client_verify_data only */
+        XMEMCPY(output + offset, data->client_verify_data, TLS_FINISHED_SZ);
+        offset += TLS_FINISHED_SZ;
+
+        /* server also sends server_verify_data */
+        if (!isRequest) {
+            XMEMCPY(output + offset, data->server_verify_data, TLS_FINISHED_SZ);
+            offset += TLS_FINISHED_SZ;
+        }
+    }
+
+    output[0] = offset - 1;  /* info length - self */
+
+    return offset;
+}
+
+static int TLSX_SecureRenegotiation_Parse(WOLFSSL* ssl, byte* input,
+                                                  word16 length, byte isRequest)
+{
+    int ret = SECURE_RENEGOTIATION_E;
+
+    if (length >= OPAQUE8_LEN) {
+        if (ssl->secure_renegotiation == NULL) {
+        #ifndef NO_WOLFSSL_SERVER
+            if (isRequest && *input == 0) {
+                ret = 0;  /* don't reply, user didn't enable */
+            }
+        #endif
+        }
+        else if (isRequest) {
+        #ifndef NO_WOLFSSL_SERVER
+            if (*input == TLS_FINISHED_SZ) {
+                /* TODO compare client_verify_data */
+                ret = 0;
+            }
+        #endif
+        }
+        else {
+        #ifndef NO_WOLFSSL_CLIENT
+            if (!ssl->secure_renegotiation->enabled) {
+                if (*input == 0) {
+                    ssl->secure_renegotiation->enabled = 1;
+                    ret = 0;
+                }
+            }
+            else if (*input == 2 * TLS_FINISHED_SZ) {
+                /* TODO compare client_verify_data and server_verify_data */
+                ret = 0;
+            }
+        #endif
+        }
+    }
+
+    if (ret != 0) {
+        /* TODO: turn on fatal error at ssl level too */
+        SendAlert(ssl, alert_fatal, handshake_failure);
+    }
+
+    return ret;
+}
+
+int TLSX_UseSecureRenegotiation(TLSX** extensions)
+{
+    int ret = 0;
+    SecureRenegotiation* data = NULL;
+
+    data = (SecureRenegotiation*)XMALLOC(sizeof(SecureRenegotiation), NULL,
+                                                             DYNAMIC_TYPE_TLSX);
+    if (data == NULL)
+        return MEMORY_E;
+
+    XMEMSET(data, 0, sizeof(SecureRenegotiation));
+
+    ret = TLSX_Push(extensions, SECURE_RENEGOTIATION, data);
+    if (ret != 0) {
+        XFREE(data, 0, DYNAMIC_TYPE_TLSX);
+        return ret;
+    }
+
+    return SSL_SUCCESS;
+}
+
+
+#define SCR_FREE_ALL(data) XFREE(data, NULL, DYNAMIC_TYPE_TLSX)
+#define SCR_GET_SIZE       TLSX_SecureRenegotiation_GetSize
+#define SCR_WRITE          TLSX_SecureRenegotiation_Write
+#define SCR_PARSE          TLSX_SecureRenegotiation_Parse
+
+#else
+
+#define SCR_FREE_ALL(a)
+#define SCR_GET_SIZE(a, b)    0
+#define SCR_WRITE(a, b, c)    0
+#define SCR_PARSE(a, b, c, d) 0
+
+#endif /* HAVE_SECURE_RENEGOTIATION */
+
+#ifdef HAVE_SESSION_TICKET
+
+static void TLSX_SessionTicket_ValidateRequest(WOLFSSL* ssl)
+{
+    TLSX*          extension = TLSX_Find(ssl->extensions, SESSION_TICKET);
+    SessionTicket* ticket    = extension ? extension->data : NULL;
+
+    if (ticket) {
+        /* TODO validate ticket timeout here! */
+        if (ticket->lifetime == 0xfffffff) {
+            /* send empty ticket on timeout */
+            TLSX_UseSessionTicket(&ssl->extensions, NULL);
+        }
+    }
+}
+
+
+static word16 TLSX_SessionTicket_GetSize(SessionTicket* ticket, int isRequest)
+{
+    (void)isRequest;
+    return ticket ? ticket->size : 0;
+}
+
+static word16 TLSX_SessionTicket_Write(SessionTicket* ticket, byte* output,
+                                                                  int isRequest)
+{
+    word16 offset = 0; /* empty ticket */
+
+    if (isRequest && ticket) {
+        XMEMCPY(output + offset, ticket->data, ticket->size);
+        offset += ticket->size;
+    }
+
+    return offset;
+}
+
+
+static int TLSX_SessionTicket_Parse(WOLFSSL* ssl, byte* input, word16 length,
+                                                                 byte isRequest)
+{
+    int ret = 0;
+
+    if (!isRequest) {
+        /* client side */
+        if (length != 0)
+            return BUFFER_ERROR;
+
+        ssl->expect_session_ticket = 1;
+    }
+#ifndef NO_WOLFSSL_SERVER
+    else {
+        /* server side */
+        if (ssl->ctx->ticketEncCb == NULL) {
+            WOLFSSL_MSG("Client sent session ticket, server has no callback");
+            return 0;
+        }
+
+        if (length == 0) {
+            /* blank ticket */
+            ret = TLSX_UseSessionTicket(&ssl->extensions, NULL);
+            if (ret == SSL_SUCCESS) {
+                ret = 0;
+                TLSX_SetResponse(ssl, SESSION_TICKET);  /* send blank ticket */
+                ssl->options.createTicket = 1;  /* will send ticket msg */
+                ssl->options.useTicket    = 1;
+            }
+        } else {
+            /* got actual ticket from client */
+            ret = DoClientTicket(ssl, input, length);
+            if (ret == WOLFSSL_TICKET_RET_OK) {    /* use ticket to resume */
+                WOLFSSL_MSG("Using exisitng client ticket");
+                ssl->options.useTicket = 1;
+                ssl->options.resuming  = 1;
+            } else if (ret == WOLFSSL_TICKET_RET_CREATE) {
+                WOLFSSL_MSG("Using existing client ticket, creating new one");
+                ret = TLSX_UseSessionTicket(&ssl->extensions, NULL);
+                if (ret == SSL_SUCCESS) {
+                    ret = 0;
+                    TLSX_SetResponse(ssl, SESSION_TICKET);
+                                                    /* send blank ticket */
+                    ssl->options.createTicket = 1;  /* will send ticket msg */
+                    ssl->options.useTicket    = 1;
+                    ssl->options.resuming     = 1;
+                }
+            } else if (ret == WOLFSSL_TICKET_RET_REJECT) {
+                WOLFSSL_MSG("Process client ticket rejected, not using");
+                ret = 0;  /* not fatal */
+            } else if (ret == WOLFSSL_TICKET_RET_FATAL || ret < 0) {
+                WOLFSSL_MSG("Process client ticket fatal error, not using");
+            }
+        }
+    }
+#endif /* NO_WOLFSSL_SERVER */
+
+    return ret;
+}
+
+WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime,
+                                                       byte* data, word16 size)
+{
+    SessionTicket* ticket = (SessionTicket*)XMALLOC(sizeof(SessionTicket),
+                                                       NULL, DYNAMIC_TYPE_TLSX);
+    if (ticket) {
+        ticket->data = (byte*)XMALLOC(size, NULL, DYNAMIC_TYPE_TLSX);
+        if (ticket->data == NULL) {
+            XFREE(ticket, NULL, DYNAMIC_TYPE_TLSX);
+            return NULL;
+        }
+
+        XMEMCPY(ticket->data, data, size);
+        ticket->size     = size;
+        ticket->lifetime = lifetime;
+    }
+
+    return ticket;
+}
+WOLFSSL_LOCAL void TLSX_SessionTicket_Free(SessionTicket* ticket)
+{
+    if (ticket) {
+        XFREE(ticket->data, NULL, DYNAMIC_TYPE_TLSX);
+        XFREE(ticket,       NULL, DYNAMIC_TYPE_TLSX);
+    }
+}
+
+int TLSX_UseSessionTicket(TLSX** extensions, SessionTicket* ticket)
+{
+    int ret = 0;
+
+    if (extensions == NULL)
+        return BAD_FUNC_ARG;
+
+    /* If the ticket is NULL, the client will request a new ticket from the
+       server. Otherwise, the client will use it in the next client hello. */
+    if ((ret = TLSX_Push(extensions, SESSION_TICKET, (void*)ticket)) != 0)
+        return ret;
+
+    return SSL_SUCCESS;
+}
+
+#define STK_VALIDATE_REQUEST TLSX_SessionTicket_ValidateRequest
+#define STK_GET_SIZE         TLSX_SessionTicket_GetSize
+#define STK_WRITE            TLSX_SessionTicket_Write
+#define STK_PARSE            TLSX_SessionTicket_Parse
+
+#else
+
+#define STK_VALIDATE_REQUEST(a)
+#define STK_GET_SIZE(a, b)      0
+#define STK_WRITE(a, b, c)      0
+#define STK_PARSE(a, b, c, d)   0
+
+#endif /* HAVE_SESSION_TICKET */
+
+
+TLSX* TLSX_Find(TLSX* list, TLSX_Type type)
+{
+    TLSX* extension = list;
+
+    while (extension && extension->type != type)
+        extension = extension->next;
+
+    return extension;
+}
+
+void TLSX_FreeAll(TLSX* list)
+{
+    TLSX* extension;
+
+    while ((extension = list)) {
+        list = extension->next;
+
+        switch (extension->type) {
+            case SERVER_NAME_INDICATION:
+                SNI_FREE_ALL((SNI*)extension->data);
+                break;
+
+            case MAX_FRAGMENT_LENGTH:
+                MFL_FREE_ALL(extension->data);
+                break;
+
+            case TRUNCATED_HMAC:
+                /* Nothing to do. */
+                break;
+
+            case ELLIPTIC_CURVES:
+                EC_FREE_ALL(extension->data);
+                break;
+
+            case SECURE_RENEGOTIATION:
+                SCR_FREE_ALL(extension->data);
+                break;
+
+            case SESSION_TICKET:
+                /* Nothing to do. */
+                break;
+        }
+
+        XFREE(extension, 0, DYNAMIC_TYPE_TLSX);
+    }
+}
+
+int TLSX_SupportExtensions(WOLFSSL* ssl) {
+    return ssl && (IsTLS(ssl) || ssl->version.major == DTLS_MAJOR);
+}
+
+static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest)
+{
+    TLSX* extension;
+    word16 length = 0;
+
+    while ((extension = list)) {
+        list = extension->next;
+
+        if (!isRequest && !extension->resp)
+            continue; /* skip! */
+
+        if (!IS_OFF(semaphore, TLSX_ToSemaphore(extension->type)))
+            continue; /* skip! */
+
+        /* type + data length */
+        length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
+
+        switch (extension->type) {
+            case SERVER_NAME_INDICATION:
+                if (isRequest)
+                    length += SNI_GET_SIZE(extension->data);
+                break;
+            case MAX_FRAGMENT_LENGTH:
+                length += MFL_GET_SIZE(extension->data);
+                break;
+
+            case TRUNCATED_HMAC:
+                /* empty extension. */
+                break;
+
+            case ELLIPTIC_CURVES:
+                length += EC_GET_SIZE(extension->data);
+                break;
+
+            case SECURE_RENEGOTIATION:
+                length += SCR_GET_SIZE(extension->data, isRequest);
+                break;
+
+            case SESSION_TICKET:
+                length += STK_GET_SIZE(extension->data, isRequest);
+                break;
+        }
+
+        TURN_ON(semaphore, TLSX_ToSemaphore(extension->type));
+    }
+
+    return length;
+}
+
+static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
+                                                                 byte isRequest)
+{
+    TLSX* extension;
+    word16 offset = 0;
+    word16 length_offset = 0;
+
+    while ((extension = list)) {
+        list = extension->next;
+
+        if (!isRequest && !extension->resp)
+            continue; /* skip! */
+
+        if (!IS_OFF(semaphore, TLSX_ToSemaphore(extension->type)))
+            continue; /* skip! */
+
+        /* extension type */
+        c16toa(extension->type, output + offset);
+        offset += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
+        length_offset = offset;
+
+        /* extension data should be written internally */
+        switch (extension->type) {
+            case SERVER_NAME_INDICATION:
+                if (isRequest)
+                    offset += SNI_WRITE(extension->data, output + offset);
+                break;
+
+            case MAX_FRAGMENT_LENGTH:
+                offset += MFL_WRITE(extension->data, output + offset);
+                break;
+
+            case TRUNCATED_HMAC:
+                /* empty extension. */
+                break;
+
+            case ELLIPTIC_CURVES:
+                offset += EC_WRITE(extension->data, output + offset);
+                break;
+
+            case SECURE_RENEGOTIATION:
+                offset += SCR_WRITE(extension->data, output + offset,
+                                                                     isRequest);
+                break;
+
+            case SESSION_TICKET:
+                offset += STK_WRITE(extension->data, output + offset,
+                                                                     isRequest);
+                break;
+        }
+
+        /* writing extension data length */
+        c16toa(offset - length_offset, output + length_offset - OPAQUE16_LEN);
+
+        TURN_ON(semaphore, TLSX_ToSemaphore(extension->type));
+    }
+
+    return offset;
+}
+
+#ifndef NO_WOLFSSL_CLIENT
+
+word16 TLSX_GetRequestSize(WOLFSSL* ssl)
+{
+    word16 length = 0;
+
+    if (TLSX_SupportExtensions(ssl)) {
+        byte semaphore[SEMAPHORE_SIZE] = {0};
+
+        EC_VALIDATE_REQUEST(ssl, semaphore);
+        STK_VALIDATE_REQUEST(ssl);
+
+        if (ssl->extensions)
+            length += TLSX_GetSize(ssl->extensions, semaphore, 1);
+
+        if (ssl->ctx && ssl->ctx->extensions)
+            length += TLSX_GetSize(ssl->ctx->extensions, semaphore, 1);
+
+        if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz)
+            length += ssl->suites->hashSigAlgoSz + HELLO_EXT_LEN;
+    }
+
+    if (length)
+        length += OPAQUE16_LEN; /* for total length storage */
+
+    return length;
+}
+
+word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output)
+{
+    word16 offset = 0;
+
+    if (TLSX_SupportExtensions(ssl) && output) {
+        byte semaphore[SEMAPHORE_SIZE] = {0};
+
+        offset += OPAQUE16_LEN; /* extensions length */
+
+        EC_VALIDATE_REQUEST(ssl, semaphore);
+
+        if (ssl->extensions)
+            offset += TLSX_Write(ssl->extensions, output + offset,
+                                                                  semaphore, 1);
+
+        if (ssl->ctx && ssl->ctx->extensions)
+            offset += TLSX_Write(ssl->ctx->extensions, output + offset,
+                                                                  semaphore, 1);
+
+        if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz)
+        {
+            int i;
+            /* extension type */
+            c16toa(HELLO_EXT_SIG_ALGO, output + offset);
+            offset += HELLO_EXT_TYPE_SZ;
+
+            /* extension data length */
+            c16toa(OPAQUE16_LEN + ssl->suites->hashSigAlgoSz, output + offset);
+            offset += OPAQUE16_LEN;
+
+            /* sig algos length */
+            c16toa(ssl->suites->hashSigAlgoSz, output + offset);
+            offset += OPAQUE16_LEN;
+
+            /* sig algos */
+            for (i = 0; i < ssl->suites->hashSigAlgoSz; i++, offset++)
+                output[offset] = ssl->suites->hashSigAlgo[i];
+        }
+
+        if (offset > OPAQUE16_LEN)
+            c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
+    }
+
+    return offset;
+}
+
+#endif /* NO_WOLFSSL_CLIENT */
+
+#ifndef NO_WOLFSSL_SERVER
+
+word16 TLSX_GetResponseSize(WOLFSSL* ssl)
+{
+    word16 length = 0;
+    byte semaphore[SEMAPHORE_SIZE] = {0};
+
+    if (TLSX_SupportExtensions(ssl))
+        length += TLSX_GetSize(ssl->extensions, semaphore, 0);
+
+    /* All the response data is set at the ssl object only, so no ctx here. */
+
+    if (length)
+        length += OPAQUE16_LEN; /* for total length storage */
+
+    return length;
+}
+
+word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output)
+{
+    word16 offset = 0;
+
+    if (TLSX_SupportExtensions(ssl) && output) {
+        byte semaphore[SEMAPHORE_SIZE] = {0};
+
+        offset += OPAQUE16_LEN; /* extensions length */
+
+        offset += TLSX_Write(ssl->extensions, output + offset, semaphore, 0);
+
+        if (offset > OPAQUE16_LEN)
+            c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
+    }
+
+    return offset;
+}
+
+#endif /* NO_WOLFSSL_SERVER */
+
+int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
+                                                                 Suites *suites)
+{
+    int ret = 0;
+    word16 offset = 0;
+
+    if (!ssl || !input || (isRequest && !suites))
+        return BAD_FUNC_ARG;
+
+    while (ret == 0 && offset < length) {
+        word16 type;
+        word16 size;
+
+        if (length - offset < HELLO_EXT_TYPE_SZ + OPAQUE16_LEN)
+            return BUFFER_ERROR;
+
+        ato16(input + offset, &type);
+        offset += HELLO_EXT_TYPE_SZ;
+
+        ato16(input + offset, &size);
+        offset += OPAQUE16_LEN;
+
+        if (offset + size > length)
+            return BUFFER_ERROR;
+
+        switch (type) {
+            case SERVER_NAME_INDICATION:
+                WOLFSSL_MSG("SNI extension received");
+
+                ret = SNI_PARSE(ssl, input + offset, size, isRequest);
+                break;
+
+            case MAX_FRAGMENT_LENGTH:
+                WOLFSSL_MSG("Max Fragment Length extension received");
+
+                ret = MFL_PARSE(ssl, input + offset, size, isRequest);
+                break;
+
+            case TRUNCATED_HMAC:
+                WOLFSSL_MSG("Truncated HMAC extension received");
+
+                ret = THM_PARSE(ssl, input + offset, size, isRequest);
+                break;
+
+            case ELLIPTIC_CURVES:
+                WOLFSSL_MSG("Elliptic Curves extension received");
+
+                ret = EC_PARSE(ssl, input + offset, size, isRequest);
+                break;
+
+            case SECURE_RENEGOTIATION:
+                WOLFSSL_MSG("Secure Renegotiation extension received");
+
+                ret = SCR_PARSE(ssl, input + offset, size, isRequest);
+                break;
+
+            case SESSION_TICKET:
+                WOLFSSL_MSG("Session Ticket extension received");
+
+                ret = STK_PARSE(ssl, input + offset, size, isRequest);
+                break;
+
+            case HELLO_EXT_SIG_ALGO:
+                if (isRequest) {
+                    /* do not mess with offset inside the switch! */
+                    if (IsAtLeastTLSv1_2(ssl)) {
+                        ato16(input + offset, &suites->hashSigAlgoSz);
+
+                        if (suites->hashSigAlgoSz > size - OPAQUE16_LEN)
+                            return BUFFER_ERROR;
+
+                        XMEMCPY(suites->hashSigAlgo,
+                                input + offset + OPAQUE16_LEN,
+                                min(suites->hashSigAlgoSz,
+                                                        HELLO_EXT_SIGALGO_MAX));
+                    }
+                } else {
+                    WOLFSSL_MSG("Servers MUST NOT send SIG ALGO extension.");
+                }
+
+                break;
+        }
+
+        /* offset should be updated here! */
+        offset += size;
+    }
+
+    return ret;
+}
+
+/* undefining semaphore macros */
+#undef IS_OFF
+#undef TURN_ON
+#undef SEMAPHORE_SIZE
+
+#endif
+
+
+#ifndef NO_WOLFSSL_CLIENT
+
+#ifndef NO_OLD_TLS
+
+    WOLFSSL_METHOD* wolfTLSv1_client_method(void)
+    {
+        WOLFSSL_METHOD* method =
+                             (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
+                                                      DYNAMIC_TYPE_METHOD);
+        if (method)
+            InitSSL_Method(method, MakeTLSv1());
+        return method;
+    }
+
+
+    WOLFSSL_METHOD* wolfTLSv1_1_client_method(void)
+    {
+        WOLFSSL_METHOD* method =
+                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+        if (method)
+            InitSSL_Method(method, MakeTLSv1_1());
+        return method;
+    }
+
+#endif /* !NO_OLD_TLS */
+
+#ifndef NO_SHA256   /* can't use without SHA256 */
+
+    WOLFSSL_METHOD* wolfTLSv1_2_client_method(void)
+    {
+        WOLFSSL_METHOD* method =
+                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+        if (method)
+            InitSSL_Method(method, MakeTLSv1_2());
+        return method;
+    }
+
+#endif
+
+
+    WOLFSSL_METHOD* wolfSSLv23_client_method(void)
+    {
+        WOLFSSL_METHOD* method =
+                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+        if (method) {
+#ifndef NO_SHA256         /* 1.2 requires SHA256 */
+            InitSSL_Method(method, MakeTLSv1_2());
+#else
+            InitSSL_Method(method, MakeTLSv1_1());
+#endif
+#ifndef NO_OLD_TLS
+            method->downgrade = 1;
+#endif
+        }
+        return method;
+    }
+
+
+#endif /* NO_WOLFSSL_CLIENT */
+
+
+
+#ifndef NO_WOLFSSL_SERVER
+
+#ifndef NO_OLD_TLS
+
+    WOLFSSL_METHOD* wolfTLSv1_server_method(void)
+    {
+        WOLFSSL_METHOD* method =
+                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeTLSv1());
+            method->side = WOLFSSL_SERVER_END;
+        }
+        return method;
+    }
+
+
+    WOLFSSL_METHOD* wolfTLSv1_1_server_method(void)
+    {
+        WOLFSSL_METHOD* method =
+                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeTLSv1_1());
+            method->side = WOLFSSL_SERVER_END;
+        }
+        return method;
+    }
+
+#endif /* !NO_OLD_TLS */
+
+#ifndef NO_SHA256   /* can't use without SHA256 */
+
+    WOLFSSL_METHOD* wolfTLSv1_2_server_method(void)
+    {
+        WOLFSSL_METHOD* method =
+                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeTLSv1_2());
+            method->side = WOLFSSL_SERVER_END;
+        }
+        return method;
+    }
+
+#endif
+
+
+    WOLFSSL_METHOD* wolfSSLv23_server_method(void)
+    {
+        WOLFSSL_METHOD* method =
+                              (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+        if (method) {
+#ifndef NO_SHA256         /* 1.2 requires SHA256 */
+            InitSSL_Method(method, MakeTLSv1_2());
+#else
+            InitSSL_Method(method, MakeTLSv1_1());
+#endif
+            method->side      = WOLFSSL_SERVER_END;
+#ifndef NO_OLD_TLS
+            method->downgrade = 1;
+#endif /* !NO_OLD_TLS */
+        }
+        return method;
+    }
+
+
+
+#endif /* NO_WOLFSSL_SERVER */
+#endif /* NO_TLS */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/user_settings.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,15 @@
+    #define MBED
+    //#define SINGLE_THREADED
+    #define WOLFSSL_USER_IO
+    #define NO_FILESYSTEM
+    #define NO_WRITEV
+    #define NO_DEV_RANDOM
+    #define NO_SHA512
+    #define NO_DH
+    #define NO_DSA
+    #define NO_HC128
+    #define HAVE_ECC
+    #define NO_SESSION_CACHE
+    #define WOLFSSL_CMSIS_RTOS
+    #define IGNORE_KEY_EXTENSIONS
+    #define DEBUG_WOLFSSL
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/aes.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,3898 @@
+/* aes.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifndef NO_AES
+
+#include <wolfssl/wolfcrypt/aes.h>
+
+#ifdef HAVE_FIPS
+int wc_AesSetKey(Aes* aes, const byte* key, word32 len, const byte* iv,
+                          int dir)
+{
+    return AesSetKey_fips(aes, key, len, iv, dir);
+}
+
+
+int wc_AesSetIV(Aes* aes, const byte* iv)
+{
+    return AesSetIV_fips(aes, iv);
+}
+
+
+int wc_AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+{
+    return AesCbcEncrypt_fips(aes, out, in, sz);
+}
+
+
+int wc_AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+{
+    return AesCbcDecrypt_fips(aes, out, in, sz);
+}
+
+
+int wc_AesCbcDecryptWithKey(byte* out, const byte* in, word32 inSz,
+                                 const byte* key, word32 keySz, const byte* iv)
+{
+    return AesCbcDecryptWithKey(out, in, inSz, key, keySz, iv);
+}
+
+
+/* AES-CTR */
+#ifdef WOLFSSL_AES_COUNTER
+void wc_AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+{
+    AesCtrEncrypt(aes, out, in, sz);
+}
+#endif
+
+/* AES-DIRECT */
+#if defined(WOLFSSL_AES_DIRECT)
+void wc_AesEncryptDirect(Aes* aes, byte* out, const byte* in)
+{
+    AesEncryptDirect(aes, out, in);
+}
+
+
+void wc_AesDecryptDirect(Aes* aes, byte* out, const byte* in)
+{
+    AesDecryptDirect(aes, out, in);
+}
+
+
+int wc_AesSetKeyDirect(Aes* aes, const byte* key, word32 len,
+                                const byte* iv, int dir)
+{
+    return AesSetKeyDirect(aes, key, len, iv, dir);
+}
+#endif
+
+
+#ifdef HAVE_AESGCM
+int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len)
+{
+    return AesGcmSetKey_fips(aes, key, len);
+}
+
+
+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)
+{
+    return AesGcmEncrypt_fips(aes, out, in, sz, iv, ivSz, authTag, authTagSz,
+                              authIn, authInSz);
+}
+
+
+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)
+{
+    return AesGcmDecrypt_fips(aes, out, in, sz, iv, ivSz, authTag, authTagSz,
+                              authIn, authInSz);
+}
+
+
+int wc_GmacSetKey(Gmac* gmac, const byte* key, word32 len)
+{
+    return GmacSetKey(gmac, key, len);
+}
+
+
+int wc_GmacUpdate(Gmac* gmac, const byte* iv, word32 ivSz,
+                              const byte* authIn, word32 authInSz,
+                              byte* authTag, word32 authTagSz)
+{
+    return GmacUpdate(gmac, iv, ivSz, authIn, authInSz,
+                      authTag, authTagSz);
+}
+
+#endif /* HAVE_AESGCM */
+#ifdef HAVE_AESCCM
+void wc_AesCcmSetKey(Aes* aes, const byte* key, word32 keySz)
+{
+    AesCcmSetKey(aes, key, keySz);
+}
+
+
+void wc_AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
+                              const byte* nonce, word32 nonceSz,
+                              byte* authTag, word32 authTagSz,
+                              const byte* authIn, word32 authInSz)
+{
+    AesCcmEncrypt(aes, out, in, inSz, nonce, nonceSz, authTag, authTagSz,
+                  authIn, authInSz);
+}
+
+
+int  wc_AesCcmDecrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
+                              const byte* nonce, word32 nonceSz,
+                              const byte* authTag, word32 authTagSz,
+                              const byte* authIn, word32 authInSz)
+{
+    return AesCcmDecrypt(aes, out, in, inSz, nonce, nonceSz, authTag, authTagSz,
+                         authIn, authInSz);
+}
+#endif /* HAVE_AESCCM */
+
+#ifdef HAVE_CAVIUM
+int  wc_AesInitCavium(Aes* aes, int i)
+{
+    return AesInitCavium(aes, i);
+}
+
+
+void wc_AesFreeCavium(Aes* aes)
+{
+    AesFreeCavium(aes);
+}
+#endif
+#else /* HAVE_FIPS */
+
+#ifdef WOLFSSL_TI_CRYPT
+#include <wolfcrypt/src/port/ti/ti-aes.c>
+#else
+
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/logging.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+#ifdef DEBUG_AESNI
+    #include <stdio.h>
+#endif
+
+
+#ifdef _MSC_VER
+    /* 4127 warning constant while(1)  */
+    #pragma warning(disable: 4127)
+#endif
+
+
+#if defined(STM32F2_CRYPTO)
+     /* STM32F2 hardware AES support for CBC, CTR modes through the STM32F2
+      * Standard Peripheral Library. Documentation located in STM32F2xx
+      * Standard Peripheral Library document (See note in README).
+      * NOTE: no support for AES-GCM/CCM/Direct */
+    #include "stm32f2xx.h"
+    #include "stm32f2xx_cryp.h"
+#elif defined(HAVE_COLDFIRE_SEC)
+    /* Freescale Coldfire SEC support for CBC mode.
+     * NOTE: no support for AES-CTR/GCM/CCM/Direct */
+    #include <wolfssl/wolfcrypt/types.h>
+    #include "sec.h"
+    #include "mcf5475_sec.h"
+    #include "mcf5475_siu.h"
+#elif defined(FREESCALE_MMCAU)
+    /* Freescale mmCAU hardware AES support for Direct, CBC, CCM, GCM modes
+     * through the CAU/mmCAU library. Documentation located in
+     * ColdFire/ColdFire+ CAU and Kinetis mmCAU Software Library User
+     * Guide (See note in README).
+     * NOTE: no support for AES-CTR */
+    #include "cau_api.h"
+#elif defined(WOLFSSL_PIC32MZ_CRYPT)
+    /* NOTE: no support for AES-CCM/Direct */
+    #define DEBUG_WOLFSSL
+    #include "wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h"
+#elif defined(HAVE_CAVIUM)
+    #include <wolfssl/wolfcrypt/logging.h>
+    #include "cavium_common.h"
+
+    /* still leave SW crypto available */
+    #define NEED_AES_TABLES
+
+    static int  wc_AesCaviumSetKey(Aes* aes, const byte* key, word32 length,
+                                const byte* iv);
+    static int  wc_AesCaviumCbcEncrypt(Aes* aes, byte* out, const byte* in,
+                                    word32 length);
+    static int  wc_AesCaviumCbcDecrypt(Aes* aes, byte* out, const byte* in,
+                                    word32 length);
+#else
+    /* using CTaoCrypt software AES implementation */
+    #define NEED_AES_TABLES
+#endif /* STM32F2_CRYPTO */
+
+
+#ifdef NEED_AES_TABLES
+
+static const word32 rcon[] = {
+    0x01000000, 0x02000000, 0x04000000, 0x08000000,
+    0x10000000, 0x20000000, 0x40000000, 0x80000000,
+    0x1B000000, 0x36000000,
+    /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+static const word32 Te[5][256] = {
+{
+    0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+    0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+    0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+    0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+    0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+    0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+    0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+    0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+    0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+    0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+    0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+    0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+    0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+    0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+    0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+    0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+    0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+    0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+    0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+    0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+    0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+    0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+    0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+    0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+    0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+    0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+    0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+    0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+    0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+    0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+    0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+    0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+    0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+    0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+    0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+    0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+    0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+    0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+    0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+    0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+    0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+    0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+    0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+    0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+    0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+    0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+    0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+    0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+    0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+    0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+    0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+    0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+    0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+    0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+    0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+    0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+    0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+    0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+    0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+    0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+    0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+    0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+    0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+    0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+},
+{
+    0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+    0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+    0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+    0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+    0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+    0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+    0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+    0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+    0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+    0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+    0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+    0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+    0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+    0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+    0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+    0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+    0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+    0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+    0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+    0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+    0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+    0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+    0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+    0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+    0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+    0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+    0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+    0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+    0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+    0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+    0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+    0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+    0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+    0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+    0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+    0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+    0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+    0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+    0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+    0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+    0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+    0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+    0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+    0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+    0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+    0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+    0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+    0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+    0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+    0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+    0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+    0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+    0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+    0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+    0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+    0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+    0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+    0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+    0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+    0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+    0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+    0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+    0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+    0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+},
+{
+    0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+    0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+    0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+    0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+    0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+    0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+    0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+    0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+    0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+    0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+    0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+    0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+    0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+    0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+    0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+    0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+    0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+    0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+    0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+    0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+    0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+    0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+    0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+    0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+    0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+    0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+    0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+    0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+    0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+    0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+    0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+    0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+    0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+    0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+    0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+    0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+    0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+    0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+    0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+    0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+    0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+    0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+    0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+    0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+    0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+    0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+    0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+    0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+    0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+    0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+    0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+    0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+    0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+    0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+    0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+    0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+    0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+    0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+    0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+    0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+    0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+    0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+    0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+    0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+},
+{
+    0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+    0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+    0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+    0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+    0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+    0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+    0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+    0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+    0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+    0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+    0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+    0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+    0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+    0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+    0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+    0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+    0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+    0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+    0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+    0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+    0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+    0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+    0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+    0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+    0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+    0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+    0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+    0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+    0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+    0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+    0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+    0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+    0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+    0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+    0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+    0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+    0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+    0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+    0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+    0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+    0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+    0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+    0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+    0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+    0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+    0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+    0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+    0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+    0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+    0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+    0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+    0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+    0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+    0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+    0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+    0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+    0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+    0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+    0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+    0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+    0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+    0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+    0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+    0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+},
+{
+    0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
+    0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
+    0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
+    0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
+    0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
+    0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
+    0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
+    0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
+    0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
+    0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
+    0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
+    0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
+    0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
+    0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
+    0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
+    0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
+    0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
+    0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
+    0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
+    0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
+    0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
+    0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
+    0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
+    0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
+    0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
+    0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
+    0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
+    0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
+    0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
+    0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
+    0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
+    0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
+    0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
+    0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
+    0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
+    0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
+    0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
+    0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
+    0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
+    0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
+    0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
+    0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
+    0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
+    0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
+    0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
+    0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
+    0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
+    0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
+    0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
+    0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
+    0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
+    0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
+    0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
+    0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
+    0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
+    0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
+    0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
+    0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
+    0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
+    0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
+    0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
+    0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
+    0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
+    0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
+}
+};
+
+static const word32 Td[5][256] = {
+{
+    0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+    0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+    0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+    0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+    0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+    0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+    0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+    0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+    0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+    0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+    0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+    0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+    0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+    0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+    0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+    0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+    0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+    0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+    0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+    0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+    0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+    0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+    0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+    0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+    0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+    0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+    0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+    0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+    0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+    0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+    0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+    0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+    0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+    0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+    0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+    0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+    0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+    0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+    0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+    0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+    0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+    0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+    0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+    0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+    0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+    0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+    0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+    0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+    0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+    0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+    0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+    0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+    0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+    0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+    0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+    0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+    0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+    0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+    0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+    0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+    0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+    0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+    0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+    0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+},
+{
+    0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+    0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+    0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+    0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+    0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+    0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+    0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+    0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+    0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+    0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+    0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+    0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+    0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+    0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+    0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+    0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+    0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+    0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+    0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+    0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+    0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+    0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+    0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+    0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+    0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+    0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+    0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+    0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+    0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+    0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+    0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+    0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+    0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+    0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+    0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+    0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+    0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+    0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+    0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+    0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+    0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+    0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+    0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+    0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+    0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+    0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+    0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+    0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+    0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+    0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+    0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+    0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+    0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+    0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+    0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+    0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+    0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+    0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+    0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+    0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+    0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+    0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+    0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+    0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+},
+{
+    0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+    0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+    0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+    0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+    0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+    0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+    0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+    0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+    0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+    0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+    0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+    0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+    0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+    0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+    0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+    0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+    0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+    0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+    0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+    0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+
+    0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+    0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+    0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+    0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+    0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+    0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+    0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+    0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+    0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+    0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+    0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+    0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+    0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+    0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+    0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+    0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+    0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+    0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+    0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+    0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+    0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+    0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+    0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+    0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+    0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+    0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+    0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+    0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+    0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+    0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+    0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+    0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+    0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+    0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+    0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+    0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+    0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+    0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+    0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+    0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+    0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+    0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+    0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+    0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+},
+{
+    0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+    0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+    0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+    0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+    0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+    0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+    0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+    0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+    0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+    0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+    0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+    0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+    0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+    0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+    0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+    0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+    0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+    0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+    0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+    0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+    0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+    0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+    0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+    0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+    0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+    0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+    0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+    0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+    0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+    0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+    0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+    0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+    0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+    0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+    0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+    0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+    0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+    0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+    0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+    0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+    0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+    0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+    0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+    0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+    0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+    0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+    0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+    0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+    0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+    0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+    0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+    0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+    0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+    0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+    0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+    0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+    0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+    0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+    0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+    0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+    0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+    0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+    0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+    0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+},
+{
+    0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
+    0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
+    0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
+    0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
+    0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
+    0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
+    0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
+    0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
+    0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
+    0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
+    0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
+    0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
+    0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
+    0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
+    0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
+    0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
+    0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
+    0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
+    0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
+    0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
+    0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
+    0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
+    0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
+    0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
+    0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
+    0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
+    0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
+    0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
+    0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
+    0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
+    0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
+    0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
+    0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
+    0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
+    0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
+    0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
+    0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
+    0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
+    0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
+    0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
+    0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
+    0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
+    0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
+    0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
+    0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
+    0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
+    0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
+    0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
+    0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
+    0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
+    0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
+    0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
+    0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
+    0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
+    0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
+    0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
+    0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
+    0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
+    0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
+    0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
+    0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
+    0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
+    0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
+    0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
+}
+};
+
+#define GETBYTE(x, y) (word32)((byte)((x) >> (8 * (y))))
+
+#ifdef WOLFSSL_AESNI
+
+/* Each platform needs to query info type 1 from cpuid to see if aesni is
+ * supported. Also, let's setup a macro for proper linkage w/o ABI conflicts
+ */
+
+#ifndef _MSC_VER
+
+    #define cpuid(reg, func)\
+        __asm__ __volatile__ ("cpuid":\
+             "=a" (reg[0]), "=b" (reg[1]), "=c" (reg[2]), "=d" (reg[3]) :\
+             "a" (func));
+
+    #define XASM_LINK(f) asm(f)
+#else
+
+    #include <intrin.h>
+    #define cpuid(a,b) __cpuid((int*)a,b)
+
+    #define XASM_LINK(f)
+
+#endif /* _MSC_VER */
+
+
+static int Check_CPU_support_AES(void)
+{
+    unsigned int reg[4];  /* put a,b,c,d into 0,1,2,3 */
+    cpuid(reg, 1);        /* query info 1 */
+
+    if (reg[2] & 0x2000000)
+        return 1;
+
+    return 0;
+}
+
+static int checkAESNI = 0;
+static int haveAESNI  = 0;
+
+
+/* tell C compiler these are asm functions in case any mix up of ABI underscore
+   prefix between clang/gcc/llvm etc */
+void AES_CBC_encrypt(const unsigned char* in, unsigned char* out,
+                     unsigned char* ivec, unsigned long length,
+                     const unsigned char* KS, int nr)
+                     XASM_LINK("AES_CBC_encrypt");
+
+
+void AES_CBC_decrypt(const unsigned char* in, unsigned char* out,
+                     unsigned char* ivec, unsigned long length,
+                     const unsigned char* KS, int nr)
+                     XASM_LINK("AES_CBC_decrypt");
+
+void AES_ECB_encrypt(const unsigned char* in, unsigned char* out,
+                     unsigned long length, const unsigned char* KS, int nr)
+                     XASM_LINK("AES_ECB_encrypt");
+
+
+void AES_ECB_decrypt(const unsigned char* in, unsigned char* out,
+                     unsigned long length, const unsigned char* KS, int nr)
+                     XASM_LINK("AES_ECB_decrypt");
+
+void AES_128_Key_Expansion(const unsigned char* userkey,
+                           unsigned char* key_schedule)
+                           XASM_LINK("AES_128_Key_Expansion");
+
+void AES_192_Key_Expansion(const unsigned char* userkey,
+                           unsigned char* key_schedule)
+                           XASM_LINK("AES_192_Key_Expansion");
+
+void AES_256_Key_Expansion(const unsigned char* userkey,
+                           unsigned char* key_schedule)
+                           XASM_LINK("AES_256_Key_Expansion");
+
+
+static int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
+                               Aes* aes)
+{
+    if (!userKey || !aes)
+        return BAD_FUNC_ARG;
+
+    if (bits == 128) {
+       AES_128_Key_Expansion (userKey,(byte*)aes->key); aes->rounds = 10;
+       return 0;
+    }
+    else if (bits == 192) {
+       AES_192_Key_Expansion (userKey,(byte*)aes->key); aes->rounds = 12;
+       return 0;
+    }
+    else if (bits == 256) {
+       AES_256_Key_Expansion (userKey,(byte*)aes->key); aes->rounds = 14;
+       return 0;
+    }
+    return BAD_FUNC_ARG;
+}
+
+
+static int AES_set_decrypt_key(const unsigned char* userKey, const int bits,
+                               Aes* aes)
+{
+    int nr;
+    Aes temp_key;
+    __m128i *Key_Schedule = (__m128i*)aes->key;
+    __m128i *Temp_Key_Schedule = (__m128i*)temp_key.key;
+
+    if (!userKey || !aes)
+        return BAD_FUNC_ARG;
+
+    if (AES_set_encrypt_key(userKey,bits,&temp_key) == BAD_FUNC_ARG)
+        return BAD_FUNC_ARG;
+
+    nr = temp_key.rounds;
+    aes->rounds = nr;
+
+    Key_Schedule[nr] = Temp_Key_Schedule[0];
+    Key_Schedule[nr-1] = _mm_aesimc_si128(Temp_Key_Schedule[1]);
+    Key_Schedule[nr-2] = _mm_aesimc_si128(Temp_Key_Schedule[2]);
+    Key_Schedule[nr-3] = _mm_aesimc_si128(Temp_Key_Schedule[3]);
+    Key_Schedule[nr-4] = _mm_aesimc_si128(Temp_Key_Schedule[4]);
+    Key_Schedule[nr-5] = _mm_aesimc_si128(Temp_Key_Schedule[5]);
+    Key_Schedule[nr-6] = _mm_aesimc_si128(Temp_Key_Schedule[6]);
+    Key_Schedule[nr-7] = _mm_aesimc_si128(Temp_Key_Schedule[7]);
+    Key_Schedule[nr-8] = _mm_aesimc_si128(Temp_Key_Schedule[8]);
+    Key_Schedule[nr-9] = _mm_aesimc_si128(Temp_Key_Schedule[9]);
+
+    if(nr>10) {
+        Key_Schedule[nr-10] = _mm_aesimc_si128(Temp_Key_Schedule[10]);
+        Key_Schedule[nr-11] = _mm_aesimc_si128(Temp_Key_Schedule[11]);
+    }
+
+    if(nr>12) {
+        Key_Schedule[nr-12] = _mm_aesimc_si128(Temp_Key_Schedule[12]);
+        Key_Schedule[nr-13] = _mm_aesimc_si128(Temp_Key_Schedule[13]);
+    }
+
+    Key_Schedule[0] = Temp_Key_Schedule[nr];
+
+    return 0;
+}
+
+
+
+#endif /* WOLFSSL_AESNI */
+
+
+static void wc_AesEncrypt(Aes* aes, const byte* inBlock, byte* outBlock)
+{
+    word32 s0, s1, s2, s3;
+    word32 t0, t1, t2, t3;
+    word32 r = aes->rounds >> 1;
+
+    const word32* rk = aes->key;
+    if (r > 7 || r == 0) {
+        WOLFSSL_MSG("AesEncrypt encountered improper key, set it up");
+        return;  /* stop instead of segfaulting, set up your keys! */
+    }
+#ifdef WOLFSSL_AESNI
+    if (haveAESNI && aes->use_aesni) {
+        #ifdef DEBUG_AESNI
+            printf("about to aes encrypt\n");
+            printf("in  = %p\n", inBlock);
+            printf("out = %p\n", outBlock);
+            printf("aes->key = %p\n", aes->key);
+            printf("aes->rounds = %d\n", aes->rounds);
+            printf("sz = %d\n", AES_BLOCK_SIZE);
+        #endif
+
+        /* check alignment, decrypt doesn't need alignment */
+        if ((wolfssl_word)inBlock % 16) {
+        #ifndef NO_WOLFSSL_ALLOC_ALIGN
+            byte* tmp = (byte*)XMALLOC(AES_BLOCK_SIZE, NULL,
+                                                      DYNAMIC_TYPE_TMP_BUFFER);
+            if (tmp == NULL) return;
+
+            XMEMCPY(tmp, inBlock, AES_BLOCK_SIZE);
+            AES_ECB_encrypt(tmp, tmp, AES_BLOCK_SIZE, (byte*)aes->key,
+                            aes->rounds);
+            XMEMCPY(outBlock, tmp, AES_BLOCK_SIZE);
+            XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            return;
+        #else
+            WOLFSSL_MSG("AES-ECB encrypt with bad alignment");
+            return;
+        #endif
+        }
+
+        AES_ECB_encrypt(inBlock, outBlock, AES_BLOCK_SIZE, (byte*)aes->key,
+                        aes->rounds);
+
+        return;
+    }
+    else {
+        #ifdef DEBUG_AESNI
+            printf("Skipping AES-NI\n");
+        #endif
+    }
+#endif
+
+    /*
+     * map byte array block to cipher state
+     * and add initial round key:
+     */
+    XMEMCPY(&s0, inBlock,                  sizeof(s0));
+    XMEMCPY(&s1, inBlock + sizeof(s0),     sizeof(s1));
+    XMEMCPY(&s2, inBlock + 2 * sizeof(s0), sizeof(s2));
+    XMEMCPY(&s3, inBlock + 3 * sizeof(s0), sizeof(s3));
+
+    #ifdef LITTLE_ENDIAN_ORDER
+        s0 = ByteReverseWord32(s0);
+        s1 = ByteReverseWord32(s1);
+        s2 = ByteReverseWord32(s2);
+        s3 = ByteReverseWord32(s3);
+    #endif
+
+    s0 ^= rk[0];
+    s1 ^= rk[1];
+    s2 ^= rk[2];
+    s3 ^= rk[3];
+
+    /*
+     * Nr - 1 full rounds:
+     */
+
+    for (;;) {
+        t0 =
+            Te[0][GETBYTE(s0, 3)]  ^
+            Te[1][GETBYTE(s1, 2)]  ^
+            Te[2][GETBYTE(s2, 1)]  ^
+            Te[3][GETBYTE(s3, 0)]  ^
+            rk[4];
+        t1 =
+            Te[0][GETBYTE(s1, 3)]  ^
+            Te[1][GETBYTE(s2, 2)]  ^
+            Te[2][GETBYTE(s3, 1)]  ^
+            Te[3][GETBYTE(s0, 0)]  ^
+            rk[5];
+        t2 =
+            Te[0][GETBYTE(s2, 3)] ^
+            Te[1][GETBYTE(s3, 2)]  ^
+            Te[2][GETBYTE(s0, 1)]  ^
+            Te[3][GETBYTE(s1, 0)]  ^
+            rk[6];
+        t3 =
+            Te[0][GETBYTE(s3, 3)] ^
+            Te[1][GETBYTE(s0, 2)]  ^
+            Te[2][GETBYTE(s1, 1)]  ^
+            Te[3][GETBYTE(s2, 0)]  ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Te[0][GETBYTE(t0, 3)] ^
+            Te[1][GETBYTE(t1, 2)] ^
+            Te[2][GETBYTE(t2, 1)] ^
+            Te[3][GETBYTE(t3, 0)] ^
+            rk[0];
+        s1 =
+            Te[0][GETBYTE(t1, 3)] ^
+            Te[1][GETBYTE(t2, 2)] ^
+            Te[2][GETBYTE(t3, 1)] ^
+            Te[3][GETBYTE(t0, 0)] ^
+            rk[1];
+        s2 =
+            Te[0][GETBYTE(t2, 3)] ^
+            Te[1][GETBYTE(t3, 2)] ^
+            Te[2][GETBYTE(t0, 1)] ^
+            Te[3][GETBYTE(t1, 0)] ^
+            rk[2];
+        s3 =
+            Te[0][GETBYTE(t3, 3)] ^
+            Te[1][GETBYTE(t0, 2)] ^
+            Te[2][GETBYTE(t1, 1)] ^
+            Te[3][GETBYTE(t2, 0)] ^
+            rk[3];
+    }
+
+    /*
+     * apply last round and
+     * map cipher state to byte array block:
+     */
+
+    s0 =
+        (Te[4][GETBYTE(t0, 3)] & 0xff000000) ^
+        (Te[4][GETBYTE(t1, 2)] & 0x00ff0000) ^
+        (Te[4][GETBYTE(t2, 1)] & 0x0000ff00) ^
+        (Te[4][GETBYTE(t3, 0)] & 0x000000ff) ^
+        rk[0];
+    s1 =
+        (Te[4][GETBYTE(t1, 3)] & 0xff000000) ^
+        (Te[4][GETBYTE(t2, 2)] & 0x00ff0000) ^
+        (Te[4][GETBYTE(t3, 1)] & 0x0000ff00) ^
+        (Te[4][GETBYTE(t0, 0)] & 0x000000ff) ^
+        rk[1];
+    s2 =
+        (Te[4][GETBYTE(t2, 3)] & 0xff000000) ^
+        (Te[4][GETBYTE(t3, 2)] & 0x00ff0000) ^
+        (Te[4][GETBYTE(t0, 1)] & 0x0000ff00) ^
+        (Te[4][GETBYTE(t1, 0)] & 0x000000ff) ^
+        rk[2];
+    s3 =
+        (Te[4][GETBYTE(t3, 3)] & 0xff000000) ^
+        (Te[4][GETBYTE(t0, 2)] & 0x00ff0000) ^
+        (Te[4][GETBYTE(t1, 1)] & 0x0000ff00) ^
+        (Te[4][GETBYTE(t2, 0)] & 0x000000ff) ^
+        rk[3];
+
+    /* write out */
+    #ifdef LITTLE_ENDIAN_ORDER
+        s0 = ByteReverseWord32(s0);
+        s1 = ByteReverseWord32(s1);
+        s2 = ByteReverseWord32(s2);
+        s3 = ByteReverseWord32(s3);
+    #endif
+
+    XMEMCPY(outBlock,                  &s0, sizeof(s0));
+    XMEMCPY(outBlock + sizeof(s0),     &s1, sizeof(s1));
+    XMEMCPY(outBlock + 2 * sizeof(s0), &s2, sizeof(s2));
+    XMEMCPY(outBlock + 3 * sizeof(s0), &s3, sizeof(s3));
+}
+
+static void wc_AesDecrypt(Aes* aes, const byte* inBlock, byte* outBlock)
+{
+    word32 s0, s1, s2, s3;
+    word32 t0, t1, t2, t3;
+    word32 r = aes->rounds >> 1;
+
+    const word32* rk = aes->key;
+    if (r > 7 || r == 0) {
+        WOLFSSL_MSG("AesDecrypt encountered improper key, set it up");
+        return;  /* stop instead of segfaulting, set up your keys! */
+    }
+#ifdef WOLFSSL_AESNI
+    if (haveAESNI && aes->use_aesni) {
+        #ifdef DEBUG_AESNI
+            printf("about to aes decrypt\n");
+            printf("in  = %p\n", inBlock);
+            printf("out = %p\n", outBlock);
+            printf("aes->key = %p\n", aes->key);
+            printf("aes->rounds = %d\n", aes->rounds);
+            printf("sz = %d\n", AES_BLOCK_SIZE);
+        #endif
+
+        /* if input and output same will overwrite input iv */
+        XMEMCPY(aes->tmp, inBlock, AES_BLOCK_SIZE);
+        AES_ECB_decrypt(inBlock, outBlock, AES_BLOCK_SIZE, (byte*)aes->key,
+                        aes->rounds);
+        return;
+    }
+    else {
+        #ifdef DEBUG_AESNI
+            printf("Skipping AES-NI\n");
+        #endif
+    }
+#endif
+
+    /*
+     * map byte array block to cipher state
+     * and add initial round key:
+     */
+    XMEMCPY(&s0, inBlock,                  sizeof(s0));
+    XMEMCPY(&s1, inBlock + sizeof(s0),     sizeof(s1));
+    XMEMCPY(&s2, inBlock + 2 * sizeof(s0), sizeof(s2));
+    XMEMCPY(&s3, inBlock + 3 * sizeof(s0), sizeof(s3));
+
+    #ifdef LITTLE_ENDIAN_ORDER
+        s0 = ByteReverseWord32(s0);
+        s1 = ByteReverseWord32(s1);
+        s2 = ByteReverseWord32(s2);
+        s3 = ByteReverseWord32(s3);
+    #endif
+
+    s0 ^= rk[0];
+    s1 ^= rk[1];
+    s2 ^= rk[2];
+    s3 ^= rk[3];
+
+    /*
+     * Nr - 1 full rounds:
+     */
+
+    for (;;) {
+        t0 =
+            Td[0][GETBYTE(s0, 3)] ^
+            Td[1][GETBYTE(s3, 2)] ^
+            Td[2][GETBYTE(s2, 1)] ^
+            Td[3][GETBYTE(s1, 0)] ^
+            rk[4];
+        t1 =
+            Td[0][GETBYTE(s1, 3)] ^
+            Td[1][GETBYTE(s0, 2)] ^
+            Td[2][GETBYTE(s3, 1)] ^
+            Td[3][GETBYTE(s2, 0)] ^
+            rk[5];
+        t2 =
+            Td[0][GETBYTE(s2, 3)] ^
+            Td[1][GETBYTE(s1, 2)] ^
+            Td[2][GETBYTE(s0, 1)] ^
+            Td[3][GETBYTE(s3, 0)] ^
+            rk[6];
+        t3 =
+            Td[0][GETBYTE(s3, 3)] ^
+            Td[1][GETBYTE(s2, 2)] ^
+            Td[2][GETBYTE(s1, 1)] ^
+            Td[3][GETBYTE(s0, 0)] ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Td[0][GETBYTE(t0, 3)] ^
+            Td[1][GETBYTE(t3, 2)] ^
+            Td[2][GETBYTE(t2, 1)] ^
+            Td[3][GETBYTE(t1, 0)] ^
+            rk[0];
+        s1 =
+            Td[0][GETBYTE(t1, 3)] ^
+            Td[1][GETBYTE(t0, 2)] ^
+            Td[2][GETBYTE(t3, 1)] ^
+            Td[3][GETBYTE(t2, 0)] ^
+            rk[1];
+        s2 =
+            Td[0][GETBYTE(t2, 3)] ^
+            Td[1][GETBYTE(t1, 2)] ^
+            Td[2][GETBYTE(t0, 1)] ^
+            Td[3][GETBYTE(t3, 0)] ^
+            rk[2];
+        s3 =
+            Td[0][GETBYTE(t3, 3)] ^
+            Td[1][GETBYTE(t2, 2)] ^
+            Td[2][GETBYTE(t1, 1)] ^
+            Td[3][GETBYTE(t0, 0)] ^
+            rk[3];
+    }
+    /*
+     * apply last round and
+     * map cipher state to byte array block:
+     */
+    s0 =
+        (Td[4][GETBYTE(t0, 3)] & 0xff000000) ^
+        (Td[4][GETBYTE(t3, 2)] & 0x00ff0000) ^
+        (Td[4][GETBYTE(t2, 1)] & 0x0000ff00) ^
+        (Td[4][GETBYTE(t1, 0)] & 0x000000ff) ^
+        rk[0];
+    s1 =
+        (Td[4][GETBYTE(t1, 3)] & 0xff000000) ^
+        (Td[4][GETBYTE(t0, 2)] & 0x00ff0000) ^
+        (Td[4][GETBYTE(t3, 1)] & 0x0000ff00) ^
+        (Td[4][GETBYTE(t2, 0)] & 0x000000ff) ^
+        rk[1];
+    s2 =
+        (Td[4][GETBYTE(t2, 3)] & 0xff000000) ^
+        (Td[4][GETBYTE(t1, 2)] & 0x00ff0000) ^
+        (Td[4][GETBYTE(t0, 1)] & 0x0000ff00) ^
+        (Td[4][GETBYTE(t3, 0)] & 0x000000ff) ^
+        rk[2];
+    s3 =
+        (Td[4][GETBYTE(t3, 3)] & 0xff000000) ^
+        (Td[4][GETBYTE(t2, 2)] & 0x00ff0000) ^
+        (Td[4][GETBYTE(t1, 1)] & 0x0000ff00) ^
+        (Td[4][GETBYTE(t0, 0)] & 0x000000ff) ^
+        rk[3];
+
+    /* write out */
+    #ifdef LITTLE_ENDIAN_ORDER
+        s0 = ByteReverseWord32(s0);
+        s1 = ByteReverseWord32(s1);
+        s2 = ByteReverseWord32(s2);
+        s3 = ByteReverseWord32(s3);
+    #endif
+
+    XMEMCPY(outBlock,                  &s0, sizeof(s0));
+    XMEMCPY(outBlock + sizeof(s0),     &s1, sizeof(s1));
+    XMEMCPY(outBlock + 2 * sizeof(s0), &s2, sizeof(s2));
+    XMEMCPY(outBlock + 3 * sizeof(s0), &s3, sizeof(s3));
+}
+
+#endif /* NEED_AES_TABLES */
+
+
+/* wc_AesSetKey */
+#ifdef STM32F2_CRYPTO
+    int wc_AesSetKey(Aes* aes, const byte* userKey, word32 keylen, const byte* iv,
+                  int dir)
+    {
+        word32 *rk = aes->key;
+
+        if (!((keylen == 16) || (keylen == 24) || (keylen == 32)))
+            return BAD_FUNC_ARG;
+
+        aes->rounds = keylen/4 + 6;
+        XMEMCPY(rk, userKey, keylen);
+        ByteReverseWords(rk, rk, keylen);
+
+        return wc_AesSetIV(aes, iv);
+    }
+
+    int wc_AesSetKeyDirect(Aes* aes, const byte* userKey, word32 keylen,
+                        const byte* iv, int dir)
+    {
+        return wc_AesSetKey(aes, userKey, keylen, iv, dir);
+    }
+
+#elif defined(HAVE_COLDFIRE_SEC)
+    #if defined (HAVE_THREADX)
+        #include "memory_pools.h"
+        extern TX_BYTE_POOL mp_ncached;  /* Non Cached memory pool */
+    #endif
+
+    #define AES_BUFFER_SIZE (AES_BLOCK_SIZE * 64)
+    static unsigned char *AESBuffIn = NULL;
+    static unsigned char *AESBuffOut = NULL;
+    static byte *secReg;
+    static byte *secKey;
+    static volatile SECdescriptorType *secDesc;
+
+    static wolfSSL_Mutex Mutex_AesSEC;
+
+    #define SEC_DESC_AES_CBC_ENCRYPT 0x60300010
+    #define SEC_DESC_AES_CBC_DECRYPT 0x60200010
+
+    extern volatile unsigned char __MBAR[];
+
+    int wc_AesSetKey(Aes* aes, const byte* userKey, word32 keylen, const byte* iv,
+                  int dir)
+    {
+        if (AESBuffIn == NULL) {
+            #if defined (HAVE_THREADX)
+			    int s1, s2, s3, s4, s5 ;
+                s5 = tx_byte_allocate(&mp_ncached,(void *)&secDesc,
+                                      sizeof(SECdescriptorType), TX_NO_WAIT);
+                s1 = tx_byte_allocate(&mp_ncached, (void *)&AESBuffIn,
+                                      AES_BUFFER_SIZE, TX_NO_WAIT);
+                s2 = tx_byte_allocate(&mp_ncached, (void *)&AESBuffOut,
+                                      AES_BUFFER_SIZE, TX_NO_WAIT);
+                s3 = tx_byte_allocate(&mp_ncached, (void *)&secKey,
+                                      AES_BLOCK_SIZE*2, TX_NO_WAIT);
+                s4 = tx_byte_allocate(&mp_ncached, (void *)&secReg,
+                                      AES_BLOCK_SIZE, TX_NO_WAIT);
+
+                if(s1 || s2 || s3 || s4 || s5)
+                    return BAD_FUNC_ARG;
+            #else
+                #warning "Allocate non-Cache buffers"
+            #endif
+
+            InitMutex(&Mutex_AesSEC);
+        }
+
+        if (!((keylen == 16) || (keylen == 24) || (keylen == 32)))
+            return BAD_FUNC_ARG;
+
+        if (aes == NULL)
+            return BAD_FUNC_ARG;
+
+        aes->rounds = keylen/4 + 6;
+        XMEMCPY(aes->key, userKey, keylen);
+
+        if (iv)
+            XMEMCPY(aes->reg, iv, AES_BLOCK_SIZE);
+
+        return 0;
+    }
+#elif defined(FREESCALE_MMCAU)
+    int wc_AesSetKey(Aes* aes, const byte* userKey, word32 keylen, const byte* iv,
+                  int dir)
+    {
+        byte *rk = (byte*)aes->key;
+
+        if (!((keylen == 16) || (keylen == 24) || (keylen == 32)))
+            return BAD_FUNC_ARG;
+
+        if (rk == NULL)
+            return BAD_FUNC_ARG;
+
+        aes->rounds = keylen/4 + 6;
+        cau_aes_set_key(userKey, keylen*8, rk);
+
+        return wc_AesSetIV(aes, iv);
+    }
+
+    int wc_AesSetKeyDirect(Aes* aes, const byte* userKey, word32 keylen,
+                        const byte* iv, int dir)
+    {
+        return wc_AesSetKey(aes, userKey, keylen, iv, dir);
+    }
+#else
+    static int wc_AesSetKeyLocal(Aes* aes, const byte* userKey, word32 keylen,
+                const byte* iv, int dir)
+    {
+        word32 temp, *rk = aes->key;
+        unsigned int i = 0;
+
+        #ifdef WOLFSSL_AESNI
+            aes->use_aesni = 0;
+        #endif /* WOLFSSL_AESNI */
+        #ifdef WOLFSSL_AES_COUNTER
+            aes->left = 0;
+        #endif /* WOLFSSL_AES_COUNTER */
+
+        aes->rounds = keylen/4 + 6;
+
+        XMEMCPY(rk, userKey, keylen);
+        #ifdef LITTLE_ENDIAN_ORDER
+            ByteReverseWords(rk, rk, keylen);
+        #endif
+
+        #ifdef WOLFSSL_PIC32MZ_CRYPT
+        {
+            word32 *akey1 = aes->key_ce;
+            word32 *areg = aes->iv_ce ;
+            aes->keylen = keylen ;
+            XMEMCPY(akey1, userKey, keylen);
+            if (iv)
+                XMEMCPY(areg, iv, AES_BLOCK_SIZE);
+            else
+                XMEMSET(areg,  0, AES_BLOCK_SIZE);
+        }
+        #endif
+
+        switch(keylen)
+        {
+        case 16:
+            while (1)
+            {
+                temp  = rk[3];
+                rk[4] = rk[0] ^
+                    (Te[4][GETBYTE(temp, 2)] & 0xff000000) ^
+                    (Te[4][GETBYTE(temp, 1)] & 0x00ff0000) ^
+                    (Te[4][GETBYTE(temp, 0)] & 0x0000ff00) ^
+                    (Te[4][GETBYTE(temp, 3)] & 0x000000ff) ^
+                    rcon[i];
+                rk[5] = rk[1] ^ rk[4];
+                rk[6] = rk[2] ^ rk[5];
+                rk[7] = rk[3] ^ rk[6];
+                if (++i == 10)
+                    break;
+                rk += 4;
+            }
+            break;
+
+        case 24:
+            /* for (;;) here triggers a bug in VC60 SP4 w/ Pro Pack */
+            while (1)
+            {
+                temp = rk[ 5];
+                rk[ 6] = rk[ 0] ^
+                    (Te[4][GETBYTE(temp, 2)] & 0xff000000) ^
+                    (Te[4][GETBYTE(temp, 1)] & 0x00ff0000) ^
+                    (Te[4][GETBYTE(temp, 0)] & 0x0000ff00) ^
+                    (Te[4][GETBYTE(temp, 3)] & 0x000000ff) ^
+                    rcon[i];
+                rk[ 7] = rk[ 1] ^ rk[ 6];
+                rk[ 8] = rk[ 2] ^ rk[ 7];
+                rk[ 9] = rk[ 3] ^ rk[ 8];
+                if (++i == 8)
+                    break;
+                rk[10] = rk[ 4] ^ rk[ 9];
+                rk[11] = rk[ 5] ^ rk[10];
+                rk += 6;
+            }
+            break;
+
+        case 32:
+            while (1)
+            {
+                temp = rk[ 7];
+                rk[ 8] = rk[ 0] ^
+                    (Te[4][GETBYTE(temp, 2)] & 0xff000000) ^
+                    (Te[4][GETBYTE(temp, 1)] & 0x00ff0000) ^
+                    (Te[4][GETBYTE(temp, 0)] & 0x0000ff00) ^
+                    (Te[4][GETBYTE(temp, 3)] & 0x000000ff) ^
+                    rcon[i];
+                rk[ 9] = rk[ 1] ^ rk[ 8];
+                rk[10] = rk[ 2] ^ rk[ 9];
+                rk[11] = rk[ 3] ^ rk[10];
+                if (++i == 7)
+                    break;
+                temp = rk[11];
+                rk[12] = rk[ 4] ^
+                    (Te[4][GETBYTE(temp, 3)] & 0xff000000) ^
+                    (Te[4][GETBYTE(temp, 2)] & 0x00ff0000) ^
+                    (Te[4][GETBYTE(temp, 1)] & 0x0000ff00) ^
+                    (Te[4][GETBYTE(temp, 0)] & 0x000000ff);
+                rk[13] = rk[ 5] ^ rk[12];
+                rk[14] = rk[ 6] ^ rk[13];
+                rk[15] = rk[ 7] ^ rk[14];
+
+                rk += 8;
+            }
+            break;
+
+        default:
+            return BAD_FUNC_ARG;
+        }
+
+        if (dir == AES_DECRYPTION)
+        {
+            unsigned int j;
+            rk = aes->key;
+
+            /* invert the order of the round keys: */
+            for (i = 0, j = 4* aes->rounds; i < j; i += 4, j -= 4) {
+                temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
+                temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+                temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+                temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+            }
+            /* apply the inverse MixColumn transform to all round keys but the
+               first and the last: */
+            for (i = 1; i < aes->rounds; i++) {
+                rk += 4;
+                rk[0] =
+                    Td[0][Te[4][GETBYTE(rk[0], 3)] & 0xff] ^
+                    Td[1][Te[4][GETBYTE(rk[0], 2)] & 0xff] ^
+                    Td[2][Te[4][GETBYTE(rk[0], 1)] & 0xff] ^
+                    Td[3][Te[4][GETBYTE(rk[0], 0)] & 0xff];
+                rk[1] =
+                    Td[0][Te[4][GETBYTE(rk[1], 3)] & 0xff] ^
+                    Td[1][Te[4][GETBYTE(rk[1], 2)] & 0xff] ^
+                    Td[2][Te[4][GETBYTE(rk[1], 1)] & 0xff] ^
+                    Td[3][Te[4][GETBYTE(rk[1], 0)] & 0xff];
+                rk[2] =
+                    Td[0][Te[4][GETBYTE(rk[2], 3)] & 0xff] ^
+                    Td[1][Te[4][GETBYTE(rk[2], 2)] & 0xff] ^
+                    Td[2][Te[4][GETBYTE(rk[2], 1)] & 0xff] ^
+                    Td[3][Te[4][GETBYTE(rk[2], 0)] & 0xff];
+                rk[3] =
+                    Td[0][Te[4][GETBYTE(rk[3], 3)] & 0xff] ^
+                    Td[1][Te[4][GETBYTE(rk[3], 2)] & 0xff] ^
+                    Td[2][Te[4][GETBYTE(rk[3], 1)] & 0xff] ^
+                    Td[3][Te[4][GETBYTE(rk[3], 0)] & 0xff];
+            }
+        }
+
+        return wc_AesSetIV(aes, iv);
+    }
+
+    int wc_AesSetKey(Aes* aes, const byte* userKey, word32 keylen, const byte* iv,
+                  int dir)
+    {
+
+        if (!((keylen == 16) || (keylen == 24) || (keylen == 32)))
+            return BAD_FUNC_ARG;
+
+        #ifdef HAVE_CAVIUM
+        if (aes->magic == WOLFSSL_AES_CAVIUM_MAGIC)
+            return wc_AesCaviumSetKey(aes, userKey, keylen, iv);
+        #endif
+
+        #ifdef WOLFSSL_AESNI
+        if (checkAESNI == 0) {
+            haveAESNI  = Check_CPU_support_AES();
+            checkAESNI = 1;
+        }
+        if (haveAESNI) {
+            aes->use_aesni = 1;
+            if (iv)
+                XMEMCPY(aes->reg, iv, AES_BLOCK_SIZE);
+            if (dir == AES_ENCRYPTION)
+                return AES_set_encrypt_key(userKey, keylen * 8, aes);
+            else
+                return AES_set_decrypt_key(userKey, keylen * 8, aes);
+        }
+        #endif /* WOLFSSL_AESNI */
+
+        return wc_AesSetKeyLocal(aes, userKey, keylen, iv, dir);
+    }
+
+    #if defined(WOLFSSL_AES_DIRECT) || defined(WOLFSSL_AES_COUNTER)
+
+    /* AES-CTR and AES-DIRECT need to use this for key setup, no aesni yet */
+    int wc_AesSetKeyDirect(Aes* aes, const byte* userKey, word32 keylen,
+                        const byte* iv, int dir)
+    {
+        return wc_AesSetKeyLocal(aes, userKey, keylen, iv, dir);
+    }
+
+    #endif /* WOLFSSL_AES_DIRECT || WOLFSSL_AES_COUNTER */
+#endif /* STM32F2_CRYPTO, wc_AesSetKey block */
+
+
+/* wc_AesSetIV is shared between software and hardware */
+int wc_AesSetIV(Aes* aes, const byte* iv)
+{
+    if (aes == NULL)
+        return BAD_FUNC_ARG;
+
+    if (iv)
+        XMEMCPY(aes->reg, iv, AES_BLOCK_SIZE);
+    else
+        XMEMSET(aes->reg,  0, AES_BLOCK_SIZE);
+
+    return 0;
+}
+
+
+int wc_AesCbcDecryptWithKey(byte* out, const byte* in, word32 inSz,
+                                  const byte* key, word32 keySz, const byte* iv)
+{
+    int  ret = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    Aes* aes = NULL;
+#else
+    Aes  aes[1];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    aes = (Aes*)XMALLOC(sizeof(Aes), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (aes == NULL)
+        return MEMORY_E;
+#endif
+
+    ret = wc_AesSetKey(aes, key, keySz, iv, AES_DECRYPTION);
+    if (ret == 0)
+        ret = wc_AesCbcDecrypt(aes, out, in, inSz); 
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(aes, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+/* AES-DIRECT */
+#if defined(WOLFSSL_AES_DIRECT)
+    #if defined(FREESCALE_MMCAU)
+
+        /* Allow direct access to one block encrypt */
+        void wc_AesEncryptDirect(Aes* aes, byte* out, const byte* in)
+        {
+            byte* key;
+            key = (byte*)aes->key;
+
+            return cau_aes_encrypt(in, key, aes->rounds, out);
+        }
+
+        /* Allow direct access to one block decrypt */
+        void wc_AesDecryptDirect(Aes* aes, byte* out, const byte* in)
+        {
+            byte* key;
+            key = (byte*)aes->key;
+
+            return cau_aes_decrypt(in, key, aes->rounds, out);
+        }
+
+    #elif defined(STM32F2_CRYPTO)
+        #error "STM32F2 crypto doesn't yet support AES direct"
+
+    #elif defined(HAVE_COLDFIRE_SEC)
+        #error "Coldfire SEC doesn't yet support AES direct"
+
+    #elif defined(WOLFSSL_PIC32MZ_CRYPT)
+        #error "PIC32MZ doesn't yet support AES direct"
+
+    #else
+        /* Allow direct access to one block encrypt */
+        void wc_AesEncryptDirect(Aes* aes, byte* out, const byte* in)
+        {
+            wc_AesEncrypt(aes, in, out);
+        }
+
+        /* Allow direct access to one block decrypt */
+        void wc_AesDecryptDirect(Aes* aes, byte* out, const byte* in)
+        {
+            wc_AesDecrypt(aes, in, out);
+        }
+
+    #endif /* FREESCALE_MMCAU, AES direct block */
+#endif /* WOLFSSL_AES_DIRECT */
+
+
+/* AES-CBC */
+#ifdef STM32F2_CRYPTO
+    int wc_AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+    {
+        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);
+
+        /* 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 iv */
+        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);
+
+        /* enable crypto processor */
+        CRYP_Cmd(ENABLE);
+
+        while (sz > 0)
+        {
+            /* flush IN/OUT FIFOs */
+            CRYP_FIFOFlush();
+
+            CRYP_DataIn(*(uint32_t*)&in[0]);
+            CRYP_DataIn(*(uint32_t*)&in[4]);
+            CRYP_DataIn(*(uint32_t*)&in[8]);
+            CRYP_DataIn(*(uint32_t*)&in[12]);
+
+            /* wait until the complete message has been processed */
+            while(CRYP_GetFlagStatus(CRYP_FLAG_BUSY) != RESET) {}
+
+            *(uint32_t*)&out[0]  = CRYP_DataOut();
+            *(uint32_t*)&out[4]  = CRYP_DataOut();
+            *(uint32_t*)&out[8]  = CRYP_DataOut();
+            *(uint32_t*)&out[12] = CRYP_DataOut();
+
+            /* store iv for next call */
+            XMEMCPY(aes->reg, out + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+
+            sz  -= 16;
+            in  += 16;
+            out += 16;
+        }
+
+        /* disable crypto processor */
+        CRYP_Cmd(DISABLE);
+
+        return 0;
+    }
+
+    int wc_AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+    {
+        word32 *dec_key, *iv;
+        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);
+
+        /* if input and output same will overwrite input iv */
+        XMEMCPY(aes->tmp, in + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+
+        /* 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  = 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);
+
+        /* enable crypto processor */
+        CRYP_Cmd(ENABLE);
+
+        /* wait until key has been prepared */
+        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 iv */
+        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);
+
+        /* enable crypto processor */
+        CRYP_Cmd(ENABLE);
+
+        while (sz > 0)
+        {
+            /* flush IN/OUT FIFOs */
+            CRYP_FIFOFlush();
+
+            CRYP_DataIn(*(uint32_t*)&in[0]);
+            CRYP_DataIn(*(uint32_t*)&in[4]);
+            CRYP_DataIn(*(uint32_t*)&in[8]);
+            CRYP_DataIn(*(uint32_t*)&in[12]);
+
+            /* wait until the complete message has been processed */
+            while(CRYP_GetFlagStatus(CRYP_FLAG_BUSY) != RESET) {}
+
+            *(uint32_t*)&out[0]  = CRYP_DataOut();
+            *(uint32_t*)&out[4]  = CRYP_DataOut();
+            *(uint32_t*)&out[8]  = CRYP_DataOut();
+            *(uint32_t*)&out[12] = CRYP_DataOut();
+
+            /* store iv for next call */
+            XMEMCPY(aes->reg, aes->tmp, AES_BLOCK_SIZE);
+
+            sz -= 16;
+            in += 16;
+            out += 16;
+        }
+
+        /* disable crypto processor */
+        CRYP_Cmd(DISABLE);
+
+        return 0;
+    }
+
+#elif defined(HAVE_COLDFIRE_SEC)
+    static int wc_AesCbcCrypt(Aes* aes, byte* po, const byte* pi, word32 sz,
+                           word32 descHeader)
+    {
+        #ifdef DEBUG_WOLFSSL
+            int i; int stat1, stat2; int ret;
+	    #endif
+
+        int size;
+        volatile int v;
+
+        if ((pi == NULL) || (po == NULL))
+            return BAD_FUNC_ARG;    /*wrong pointer*/
+
+        LockMutex(&Mutex_AesSEC);
+
+        /* Set descriptor for SEC */
+        secDesc->length1 = 0x0;
+        secDesc->pointer1 = NULL;
+
+        secDesc->length2 = AES_BLOCK_SIZE;
+        secDesc->pointer2 = (byte *)secReg; /* Initial Vector */
+
+        switch(aes->rounds) {
+            case 10: secDesc->length3 = 16 ; break ;
+            case 12: secDesc->length3 = 24 ; break ;
+            case 14: secDesc->length3 = 32 ; break ;
+        }
+        XMEMCPY(secKey, aes->key, secDesc->length3);
+
+        secDesc->pointer3 = (byte *)secKey;
+        secDesc->pointer4 = AESBuffIn;
+        secDesc->pointer5 = AESBuffOut;
+        secDesc->length6 = 0x0;
+        secDesc->pointer6 = NULL;
+        secDesc->length7 = 0x0;
+        secDesc->pointer7 = NULL;
+        secDesc->nextDescriptorPtr = NULL;
+
+        while (sz) {
+            secDesc->header = descHeader;
+            XMEMCPY(secReg, aes->reg, AES_BLOCK_SIZE);
+            if ((sz % AES_BUFFER_SIZE) == sz) {
+                size = sz;
+                sz = 0;
+            } else {
+                size = AES_BUFFER_SIZE;
+                sz -= AES_BUFFER_SIZE;
+            }
+            secDesc->length4 = size;
+            secDesc->length5 = size;
+
+            XMEMCPY(AESBuffIn, pi, size);
+            if(descHeader == SEC_DESC_AES_CBC_DECRYPT) {
+                XMEMCPY((void*)aes->tmp, (void*)&(pi[size-AES_BLOCK_SIZE]),
+                        AES_BLOCK_SIZE);
+            }
+
+            /* Point SEC to the location of the descriptor */
+            MCF_SEC_FR0 = (uint32)secDesc;
+            /* Initialize SEC and wait for encryption to complete */
+            MCF_SEC_CCCR0 = 0x0000001a;
+            /* poll SISR to determine when channel is complete */
+            v=0;
+
+            while ((secDesc->header>> 24) != 0xff) v++;
+
+            #ifdef DEBUG_WOLFSSL
+                ret = MCF_SEC_SISRH;
+                stat1 = MCF_SEC_AESSR;
+                stat2 = MCF_SEC_AESISR;
+                if (ret & 0xe0000000) {
+                    db_printf("Aes_Cbc(i=%d):ISRH=%08x, AESSR=%08x, "
+                              "AESISR=%08x\n", i, ret, stat1, stat2);
+                }
+            #endif
+
+            XMEMCPY(po, AESBuffOut, size);
+
+            if (descHeader == SEC_DESC_AES_CBC_ENCRYPT) {
+                XMEMCPY((void*)aes->reg, (void*)&(po[size-AES_BLOCK_SIZE]),
+                        AES_BLOCK_SIZE);
+            } else {
+                XMEMCPY((void*)aes->reg, (void*)aes->tmp, AES_BLOCK_SIZE);
+            }
+
+            pi += size;
+            po += size;
+        }
+
+        UnLockMutex(&Mutex_AesSEC);
+        return 0;
+    }
+
+    int wc_AesCbcEncrypt(Aes* aes, byte* po, const byte* pi, word32 sz)
+    {
+        return (wc_AesCbcCrypt(aes, po, pi, sz, SEC_DESC_AES_CBC_ENCRYPT));
+    }
+
+    int wc_AesCbcDecrypt(Aes* aes, byte* po, const byte* pi, word32 sz)
+    {
+        return (wc_AesCbcCrypt(aes, po, pi, sz, SEC_DESC_AES_CBC_DECRYPT));
+    }
+
+#elif defined(FREESCALE_MMCAU)
+    int wc_AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+    {
+        int i;
+        int offset = 0;
+        int len = sz;
+
+        byte *iv, *enc_key;
+        byte temp_block[AES_BLOCK_SIZE];
+
+        iv      = (byte*)aes->reg;
+        enc_key = (byte*)aes->key;
+
+        if ((wolfssl_word)out % WOLFSSL_MMCAU_ALIGNMENT) {
+            WOLFSSL_MSG("Bad cau_aes_encrypt alignment");
+            return BAD_ALIGN_E;
+        }
+
+        while (len > 0)
+        {
+            XMEMCPY(temp_block, in + offset, AES_BLOCK_SIZE);
+
+            /* XOR block with IV for CBC */
+            for (i = 0; i < AES_BLOCK_SIZE; i++)
+                temp_block[i] ^= iv[i];
+
+            cau_aes_encrypt(temp_block, enc_key, aes->rounds, out + offset);
+
+            len    -= AES_BLOCK_SIZE;
+            offset += AES_BLOCK_SIZE;
+
+            /* store IV for next block */
+            XMEMCPY(iv, out + offset - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+        }
+
+        return 0;
+    }
+
+    int wc_AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+    {
+        int i;
+        int offset = 0;
+        int len = sz;
+
+        byte* iv, *dec_key;
+        byte temp_block[AES_BLOCK_SIZE];
+
+        iv      = (byte*)aes->reg;
+        dec_key = (byte*)aes->key;
+
+        if ((wolfssl_word)out % WOLFSSL_MMCAU_ALIGNMENT) {
+            WOLFSSL_MSG("Bad cau_aes_decrypt alignment");
+            return BAD_ALIGN_E;
+        }
+
+        while (len > 0)
+        {
+            XMEMCPY(temp_block, in + offset, AES_BLOCK_SIZE);
+
+            cau_aes_decrypt(in + offset, dec_key, aes->rounds, out + offset);
+
+            /* XOR block with IV for CBC */
+            for (i = 0; i < AES_BLOCK_SIZE; i++)
+                (out + offset)[i] ^= iv[i];
+
+            /* store IV for next block */
+            XMEMCPY(iv, temp_block, AES_BLOCK_SIZE);
+
+            len    -= AES_BLOCK_SIZE;
+            offset += AES_BLOCK_SIZE;
+        }
+
+        return 0;
+    }
+
+#elif defined(WOLFSSL_PIC32MZ_CRYPT)
+    /* core hardware crypt engine driver */
+    static void wc_AesCrypt(Aes *aes, byte* out, const byte* in, word32 sz,
+                                            int dir, int algo, int cryptoalgo)
+    {
+        securityAssociation *sa_p ;
+        bufferDescriptor *bd_p ;
+
+        volatile securityAssociation sa __attribute__((aligned (8)));
+        volatile bufferDescriptor bd __attribute__((aligned (8)));
+        volatile int k ;
+
+        /* get uncached address */
+        sa_p = KVA0_TO_KVA1(&sa) ;
+        bd_p = KVA0_TO_KVA1(&bd) ;
+
+        /* Sync cache and physical memory */
+        if(PIC32MZ_IF_RAM(in)) {
+            XMEMCPY((void *)KVA0_TO_KVA1(in), (void *)in, sz);
+        }
+        XMEMSET((void *)KVA0_TO_KVA1(out), 0, sz);
+        /* Set up the Security Association */
+        XMEMSET((byte *)KVA0_TO_KVA1(&sa), 0, sizeof(sa));
+        sa_p->SA_CTRL.ALGO = algo ; /* AES */
+        sa_p->SA_CTRL.LNC = 1;
+        sa_p->SA_CTRL.LOADIV = 1;
+        sa_p->SA_CTRL.FB = 1;
+        sa_p->SA_CTRL.ENCTYPE = dir ; /* Encryption/Decryption */
+        sa_p->SA_CTRL.CRYPTOALGO = cryptoalgo;
+
+        if(cryptoalgo == PIC32_CRYPTOALGO_AES_GCM){
+            switch(aes->keylen) {
+            case 32:
+                sa_p->SA_CTRL.KEYSIZE = PIC32_AES_KEYSIZE_256 ;
+                break ;
+            case 24:
+                sa_p->SA_CTRL.KEYSIZE = PIC32_AES_KEYSIZE_192 ;
+                break ;
+            case 16:
+                sa_p->SA_CTRL.KEYSIZE = PIC32_AES_KEYSIZE_128 ;
+                break ;
+            }
+        } else
+            sa_p->SA_CTRL.KEYSIZE = PIC32_AES_KEYSIZE_128 ;
+
+        ByteReverseWords(
+        (word32 *)KVA0_TO_KVA1(sa.SA_ENCKEY + 8 - aes->keylen/sizeof(word32)),
+                         (word32 *)aes->key_ce, aes->keylen);
+        ByteReverseWords(
+        (word32*)KVA0_TO_KVA1(sa.SA_ENCIV), (word32 *)aes->iv_ce, 16);
+
+        XMEMSET((byte *)KVA0_TO_KVA1(&bd), 0, sizeof(bd));
+        /* Set up the Buffer Descriptor */
+        bd_p->BD_CTRL.BUFLEN = sz;
+        if(cryptoalgo == PIC32_CRYPTOALGO_AES_GCM) {
+            if(sz % 0x10)
+                bd_p->BD_CTRL.BUFLEN = (sz/0x10 + 1) * 0x10 ;
+        }
+        bd_p->BD_CTRL.LIFM = 1;
+        bd_p->BD_CTRL.SA_FETCH_EN = 1;
+        bd_p->BD_CTRL.LAST_BD = 1;
+        bd_p->BD_CTRL.DESC_EN = 1;
+
+        bd_p->SA_ADDR = (unsigned int)KVA_TO_PA(&sa) ;
+        bd_p->SRCADDR = (unsigned int)KVA_TO_PA(in) ;
+        bd_p->DSTADDR = (unsigned int)KVA_TO_PA(out);
+        bd_p->MSGLEN = sz ;
+
+        CECON = 1 << 6;
+        while (CECON);
+
+        /* Run the engine */
+        CEBDPADDR = (unsigned int)KVA_TO_PA(&bd) ;
+        CEINTEN = 0x07;
+        CECON = 0x27;
+
+        WAIT_ENGINE ;
+
+        if((cryptoalgo == PIC32_CRYPTOALGO_CBC) ||
+           (cryptoalgo == PIC32_CRYPTOALGO_TCBC)||
+           (cryptoalgo == PIC32_CRYPTOALGO_RCBC)) {
+            /* set iv for the next call */
+            if(dir == PIC32_ENCRYPTION) {
+                XMEMCPY((void *)aes->iv_ce,
+                        (void*)KVA0_TO_KVA1(out + sz - AES_BLOCK_SIZE),
+                        AES_BLOCK_SIZE) ;
+            } else {
+                ByteReverseWords((word32*)aes->iv_ce,
+                        (word32 *)KVA0_TO_KVA1(in + sz - AES_BLOCK_SIZE),
+                        AES_BLOCK_SIZE);
+            }
+        }
+        XMEMCPY((byte *)out, (byte *)KVA0_TO_KVA1(out), sz) ;
+        ByteReverseWords((word32*)out, (word32 *)out, sz);
+    }
+
+    int wc_AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+    {
+        wc_AesCrypt(aes, out, in, sz, PIC32_ENCRYPTION, PIC32_ALGO_AES,
+                                                      PIC32_CRYPTOALGO_RCBC );
+        return 0 ;
+    }
+
+    int wc_AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+    {
+        wc_AesCrypt(aes, out, in, sz, PIC32_DECRYPTION, PIC32_ALGO_AES,
+                                                      PIC32_CRYPTOALGO_RCBC);
+        return 0 ;
+    }
+
+#else
+    int wc_AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+    {
+        word32 blocks = sz / AES_BLOCK_SIZE;
+
+    #ifdef HAVE_CAVIUM
+        if (aes->magic == WOLFSSL_AES_CAVIUM_MAGIC)
+            return wc_AesCaviumCbcEncrypt(aes, out, in, sz);
+    #endif
+
+    #ifdef WOLFSSL_AESNI
+        if (haveAESNI) {
+            #ifdef DEBUG_AESNI
+                printf("about to aes cbc encrypt\n");
+                printf("in  = %p\n", in);
+                printf("out = %p\n", out);
+                printf("aes->key = %p\n", aes->key);
+                printf("aes->reg = %p\n", aes->reg);
+                printf("aes->rounds = %d\n", aes->rounds);
+                printf("sz = %d\n", sz);
+            #endif
+
+            /* check alignment, decrypt doesn't need alignment */
+            if ((wolfssl_word)in % 16) {
+            #ifndef NO_WOLFSSL_ALLOC_ALIGN
+                byte* tmp = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                WOLFSSL_MSG("AES-CBC encrypt with bad alignment");
+                if (tmp == NULL) return MEMORY_E;
+
+                XMEMCPY(tmp, in, sz);
+                AES_CBC_encrypt(tmp, tmp, (byte*)aes->reg, sz, (byte*)aes->key,
+                            aes->rounds);
+                /* store iv for next call */
+                XMEMCPY(aes->reg, tmp + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+
+                XMEMCPY(out, tmp, sz);
+                XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                return 0;
+            #else
+                return BAD_ALIGN_E;
+            #endif
+            }
+
+            AES_CBC_encrypt(in, out, (byte*)aes->reg, sz, (byte*)aes->key,
+                            aes->rounds);
+            /* store iv for next call */
+            XMEMCPY(aes->reg, out + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+
+            return 0;
+        }
+    #endif
+
+        while (blocks--) {
+            xorbuf((byte*)aes->reg, in, AES_BLOCK_SIZE);
+            wc_AesEncrypt(aes, (byte*)aes->reg, (byte*)aes->reg);
+            XMEMCPY(out, aes->reg, AES_BLOCK_SIZE);
+
+            out += AES_BLOCK_SIZE;
+            in  += AES_BLOCK_SIZE;
+        }
+
+        return 0;
+    }
+
+    int wc_AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+    {
+        word32 blocks = sz / AES_BLOCK_SIZE;
+
+    #ifdef HAVE_CAVIUM
+        if (aes->magic == WOLFSSL_AES_CAVIUM_MAGIC)
+            return wc_AesCaviumCbcDecrypt(aes, out, in, sz);
+    #endif
+
+    #ifdef WOLFSSL_AESNI
+        if (haveAESNI) {
+            #ifdef DEBUG_AESNI
+                printf("about to aes cbc decrypt\n");
+                printf("in  = %p\n", in);
+                printf("out = %p\n", out);
+                printf("aes->key = %p\n", aes->key);
+                printf("aes->reg = %p\n", aes->reg);
+                printf("aes->rounds = %d\n", aes->rounds);
+                printf("sz = %d\n", sz);
+            #endif
+
+            /* if input and output same will overwrite input iv */
+            XMEMCPY(aes->tmp, in + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+            AES_CBC_decrypt(in, out, (byte*)aes->reg, sz, (byte*)aes->key,
+                            aes->rounds);
+            /* store iv for next call */
+            XMEMCPY(aes->reg, aes->tmp, AES_BLOCK_SIZE);
+            return 0;
+        }
+    #endif
+
+        while (blocks--) {
+            XMEMCPY(aes->tmp, in, AES_BLOCK_SIZE);
+            wc_AesDecrypt(aes, (byte*)aes->tmp, out);
+            xorbuf(out, (byte*)aes->reg, AES_BLOCK_SIZE);
+            XMEMCPY(aes->reg, aes->tmp, AES_BLOCK_SIZE);
+
+            out += AES_BLOCK_SIZE;
+            in  += AES_BLOCK_SIZE;
+        }
+
+        return 0;
+    }
+
+#endif /* STM32F2_CRYPTO, AES-CBC block */
+
+/* AES-CTR */
+#ifdef WOLFSSL_AES_COUNTER
+
+    #ifdef STM32F2_CRYPTO
+        void wc_AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+        {
+            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);
+
+            /* 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 iv */
+            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_CTR;
+            AES_CRYP_InitStructure.CRYP_DataType = CRYP_DataType_8b;
+            CRYP_Init(&AES_CRYP_InitStructure);
+
+            /* enable crypto processor */
+            CRYP_Cmd(ENABLE);
+
+            while (sz > 0)
+            {
+                /* flush IN/OUT FIFOs */
+                CRYP_FIFOFlush();
+
+                CRYP_DataIn(*(uint32_t*)&in[0]);
+                CRYP_DataIn(*(uint32_t*)&in[4]);
+                CRYP_DataIn(*(uint32_t*)&in[8]);
+                CRYP_DataIn(*(uint32_t*)&in[12]);
+
+                /* wait until the complete message has been processed */
+                while(CRYP_GetFlagStatus(CRYP_FLAG_BUSY) != RESET) {}
+
+                *(uint32_t*)&out[0]  = CRYP_DataOut();
+                *(uint32_t*)&out[4]  = CRYP_DataOut();
+                *(uint32_t*)&out[8]  = CRYP_DataOut();
+                *(uint32_t*)&out[12] = CRYP_DataOut();
+
+                /* store iv for next call */
+                XMEMCPY(aes->reg, out + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+
+                sz  -= 16;
+                in  += 16;
+                out += 16;
+            }
+
+            /* disable crypto processor */
+            CRYP_Cmd(DISABLE);
+        }
+
+    #elif defined(WOLFSSL_PIC32MZ_CRYPT)
+        void wc_AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+        {
+            int i ;
+            char out_block[AES_BLOCK_SIZE] ;
+            int odd ;
+            int even ;
+            char *tmp ; /* (char *)aes->tmp, for short */
+
+            tmp = (char *)aes->tmp ;
+            if(aes->left) {
+                if((aes->left + sz) >= AES_BLOCK_SIZE){
+                    odd = AES_BLOCK_SIZE - aes->left ;
+                } else {
+                    odd = sz ;
+                }
+                XMEMCPY(tmp+aes->left, in, odd) ;
+                if((odd+aes->left) == AES_BLOCK_SIZE){
+                    wc_AesCrypt(aes, out_block, tmp, AES_BLOCK_SIZE,
+                        PIC32_ENCRYPTION, PIC32_ALGO_AES, PIC32_CRYPTOALGO_RCTR);
+                    XMEMCPY(out, out_block+aes->left, odd) ;
+                    aes->left = 0 ;
+                    XMEMSET(tmp, 0x0, AES_BLOCK_SIZE) ;
+                    /* Increment IV */
+                    for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
+                        if (++((byte *)aes->iv_ce)[i])
+                            break ;
+                    }
+                }
+                in += odd ;
+                out+= odd ;
+                sz -= odd ;
+            }
+            odd = sz % AES_BLOCK_SIZE ;  /* if there is tail flagment */
+            if(sz / AES_BLOCK_SIZE) {
+                even = (sz/AES_BLOCK_SIZE)*AES_BLOCK_SIZE ;
+                wc_AesCrypt(aes, out, in, even, PIC32_ENCRYPTION, PIC32_ALGO_AES,
+                                                        PIC32_CRYPTOALGO_RCTR);
+                out += even ;
+                in  += even ;
+                do {  /* Increment IV */
+                    for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
+                        if (++((byte *)aes->iv_ce)[i])
+                            break ;
+                    }
+                    even -= AES_BLOCK_SIZE ;
+                } while((int)even > 0) ;
+            }
+            if(odd) {
+                XMEMSET(tmp+aes->left, 0x0, AES_BLOCK_SIZE - aes->left) ;
+                XMEMCPY(tmp+aes->left, in, odd) ;
+                wc_AesCrypt(aes, out_block, tmp, AES_BLOCK_SIZE,
+                        PIC32_ENCRYPTION, PIC32_ALGO_AES, PIC32_CRYPTOALGO_RCTR);
+                XMEMCPY(out, out_block+aes->left,odd) ;
+                aes->left += odd ;
+            }
+        }
+
+    #elif defined(HAVE_COLDFIRE_SEC)
+        #error "Coldfire SEC doesn't currently support AES-CTR mode"
+
+    #elif defined(FREESCALE_MMCAU)
+        #error "Freescale mmCAU doesn't currently support AES-CTR mode"
+
+    #else
+        /* Increment AES counter */
+        static INLINE void IncrementAesCounter(byte* inOutCtr)
+        {
+            int i;
+
+            /* in network byte order so start at end and work back */
+            for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
+                if (++inOutCtr[i])  /* we're done unless we overflow */
+                    return;
+            }
+        }
+
+        void wc_AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+        {
+            byte* tmp = (byte*)aes->tmp + AES_BLOCK_SIZE - aes->left;
+
+            /* consume any unused bytes left in aes->tmp */
+            while (aes->left && sz) {
+               *(out++) = *(in++) ^ *(tmp++);
+               aes->left--;
+               sz--;
+            }
+
+            /* do as many block size ops as possible */
+            while (sz >= AES_BLOCK_SIZE) {
+                wc_AesEncrypt(aes, (byte*)aes->reg, out);
+                IncrementAesCounter((byte*)aes->reg);
+                xorbuf(out, in, AES_BLOCK_SIZE);
+
+                out += AES_BLOCK_SIZE;
+                in  += AES_BLOCK_SIZE;
+                sz  -= AES_BLOCK_SIZE;
+                aes->left = 0;
+            }
+
+            /* handle non block size remaining and sotre unused byte count in left */
+            if (sz) {
+                wc_AesEncrypt(aes, (byte*)aes->reg, (byte*)aes->tmp);
+                IncrementAesCounter((byte*)aes->reg);
+
+                aes->left = AES_BLOCK_SIZE;
+                tmp = (byte*)aes->tmp;
+
+                while (sz--) {
+                    *(out++) = *(in++) ^ *(tmp++);
+                    aes->left--;
+                }
+            }
+        }
+
+    #endif /* STM32F2_CRYPTO, AES-CTR block */
+
+#endif /* WOLFSSL_AES_COUNTER */
+
+#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.
+ */
+
+#ifdef STM32F2_CRYPTO
+    #error "STM32F2 crypto doesn't currently support AES-GCM mode"
+
+#elif defined(HAVE_COLDFIRE_SEC)
+    #error "Coldfire SEC doesn't currently support AES-GCM mode"
+
+#endif
+
+enum {
+    CTR_SZ = 4
+};
+
+
+static INLINE void InitGcmCounter(byte* inOutCtr)
+{
+    inOutCtr[AES_BLOCK_SIZE - 4] = 0;
+    inOutCtr[AES_BLOCK_SIZE - 3] = 0;
+    inOutCtr[AES_BLOCK_SIZE - 2] = 0;
+    inOutCtr[AES_BLOCK_SIZE - 1] = 1;
+}
+
+
+static INLINE void IncrementGcmCounter(byte* inOutCtr)
+{
+    int i;
+
+    /* in network byte order so start at end and work back */
+    for (i = AES_BLOCK_SIZE - 1; i >= AES_BLOCK_SIZE - CTR_SZ; i--) {
+        if (++inOutCtr[i])  /* we're done unless we overflow */
+            return;
+    }
+}
+
+
+#if defined(GCM_SMALL) || defined(GCM_TABLE)
+
+static INLINE void FlattenSzInBits(byte* buf, word32 sz)
+{
+    /* Multiply the sz by 8 */
+    word32 szHi = (sz >> (8*sizeof(sz) - 3));
+    sz <<= 3;
+
+    /* copy over the words of the sz into the destination buffer */
+    buf[0] = (szHi >> 24) & 0xff;
+    buf[1] = (szHi >> 16) & 0xff;
+    buf[2] = (szHi >>  8) & 0xff;
+    buf[3] = szHi & 0xff;
+    buf[4] = (sz >> 24) & 0xff;
+    buf[5] = (sz >> 16) & 0xff;
+    buf[6] = (sz >>  8) & 0xff;
+    buf[7] = sz & 0xff;
+}
+
+
+static INLINE void RIGHTSHIFTX(byte* x)
+{
+    int i;
+    int carryOut = 0;
+    int carryIn = 0;
+    int borrow = x[15] & 0x01;
+
+    for (i = 0; i < AES_BLOCK_SIZE; i++) {
+        carryOut = x[i] & 0x01;
+        x[i] = (x[i] >> 1) | (carryIn ? 0x80 : 0);
+        carryIn = carryOut;
+    }
+    if (borrow) x[0] ^= 0xE1;
+}
+
+#endif /* defined(GCM_SMALL) || defined(GCM_TABLE) */
+
+
+#ifdef GCM_TABLE
+
+static void GenerateM0(Aes* aes)
+{
+    int i, j;
+    byte (*m)[AES_BLOCK_SIZE] = aes->M0;
+
+    XMEMCPY(m[128], aes->H, AES_BLOCK_SIZE);
+
+    for (i = 64; i > 0; i /= 2) {
+        XMEMCPY(m[i], m[i*2], AES_BLOCK_SIZE);
+        RIGHTSHIFTX(m[i]);
+    }
+
+    for (i = 2; i < 256; i *= 2) {
+        for (j = 1; j < i; j++) {
+            XMEMCPY(m[i+j], m[i], AES_BLOCK_SIZE);
+            xorbuf(m[i+j], m[j], AES_BLOCK_SIZE);
+        }
+    }
+
+    XMEMSET(m[0], 0, AES_BLOCK_SIZE);
+}
+
+#endif /* GCM_TABLE */
+
+
+int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len)
+{
+    int  ret;
+    byte iv[AES_BLOCK_SIZE];
+
+    #ifdef FREESCALE_MMCAU
+        byte* rk = (byte*)aes->key;
+    #endif
+
+    if (!((len == 16) || (len == 24) || (len == 32)))
+        return BAD_FUNC_ARG;
+
+    XMEMSET(iv, 0, AES_BLOCK_SIZE);
+    ret = wc_AesSetKey(aes, key, len, iv, AES_ENCRYPTION);
+
+    if (ret == 0) {
+    #ifdef FREESCALE_MMCAU
+        cau_aes_encrypt(iv, rk, aes->rounds, aes->H);
+    #else
+        wc_AesEncrypt(aes, iv, aes->H);
+    #endif
+    #ifdef GCM_TABLE
+        GenerateM0(aes);
+    #endif /* GCM_TABLE */
+    }
+
+    return ret;
+}
+
+
+#if defined(GCM_SMALL)
+
+static void GMULT(byte* X, byte* Y)
+{
+    byte Z[AES_BLOCK_SIZE];
+    byte V[AES_BLOCK_SIZE];
+    int i, j;
+
+    XMEMSET(Z, 0, AES_BLOCK_SIZE);
+    XMEMCPY(V, X, AES_BLOCK_SIZE);
+    for (i = 0; i < AES_BLOCK_SIZE; i++)
+    {
+        byte y = Y[i];
+        for (j = 0; j < 8; j++)
+        {
+            if (y & 0x80) {
+                xorbuf(Z, V, AES_BLOCK_SIZE);
+            }
+
+            RIGHTSHIFTX(V);
+            y = y << 1;
+        }
+    }
+    XMEMCPY(X, Z, AES_BLOCK_SIZE);
+}
+
+
+static void GHASH(Aes* aes, const byte* a, word32 aSz,
+                                const byte* c, word32 cSz, byte* s, word32 sSz)
+{
+    byte x[AES_BLOCK_SIZE];
+    byte scratch[AES_BLOCK_SIZE];
+    word32 blocks, partial;
+    byte* h = aes->H;
+
+    XMEMSET(x, 0, AES_BLOCK_SIZE);
+
+    /* Hash in A, the Additional Authentication Data */
+    if (aSz != 0 && a != NULL) {
+        blocks = aSz / AES_BLOCK_SIZE;
+        partial = aSz % AES_BLOCK_SIZE;
+        while (blocks--) {
+            xorbuf(x, a, AES_BLOCK_SIZE);
+            GMULT(x, h);
+            a += AES_BLOCK_SIZE;
+        }
+        if (partial != 0) {
+            XMEMSET(scratch, 0, AES_BLOCK_SIZE);
+            XMEMCPY(scratch, a, partial);
+            xorbuf(x, scratch, AES_BLOCK_SIZE);
+            GMULT(x, h);
+        }
+    }
+
+    /* Hash in C, the Ciphertext */
+    if (cSz != 0 && c != NULL) {
+        blocks = cSz / AES_BLOCK_SIZE;
+        partial = cSz % AES_BLOCK_SIZE;
+        while (blocks--) {
+            xorbuf(x, c, AES_BLOCK_SIZE);
+            GMULT(x, h);
+            c += AES_BLOCK_SIZE;
+        }
+        if (partial != 0) {
+            XMEMSET(scratch, 0, AES_BLOCK_SIZE);
+            XMEMCPY(scratch, c, partial);
+            xorbuf(x, scratch, AES_BLOCK_SIZE);
+            GMULT(x, h);
+        }
+    }
+
+    /* Hash in the lengths of A and C in bits */
+    FlattenSzInBits(&scratch[0], aSz);
+    FlattenSzInBits(&scratch[8], cSz);
+    xorbuf(x, scratch, AES_BLOCK_SIZE);
+    GMULT(x, h);
+
+    /* Copy the result into s. */
+    XMEMCPY(s, x, sSz);
+}
+
+/* end GCM_SMALL */
+#elif defined(GCM_TABLE)
+
+static const byte R[256][2] = {
+    {0x00, 0x00}, {0x01, 0xc2}, {0x03, 0x84}, {0x02, 0x46},
+    {0x07, 0x08}, {0x06, 0xca}, {0x04, 0x8c}, {0x05, 0x4e},
+    {0x0e, 0x10}, {0x0f, 0xd2}, {0x0d, 0x94}, {0x0c, 0x56},
+    {0x09, 0x18}, {0x08, 0xda}, {0x0a, 0x9c}, {0x0b, 0x5e},
+    {0x1c, 0x20}, {0x1d, 0xe2}, {0x1f, 0xa4}, {0x1e, 0x66},
+    {0x1b, 0x28}, {0x1a, 0xea}, {0x18, 0xac}, {0x19, 0x6e},
+    {0x12, 0x30}, {0x13, 0xf2}, {0x11, 0xb4}, {0x10, 0x76},
+    {0x15, 0x38}, {0x14, 0xfa}, {0x16, 0xbc}, {0x17, 0x7e},
+    {0x38, 0x40}, {0x39, 0x82}, {0x3b, 0xc4}, {0x3a, 0x06},
+    {0x3f, 0x48}, {0x3e, 0x8a}, {0x3c, 0xcc}, {0x3d, 0x0e},
+    {0x36, 0x50}, {0x37, 0x92}, {0x35, 0xd4}, {0x34, 0x16},
+    {0x31, 0x58}, {0x30, 0x9a}, {0x32, 0xdc}, {0x33, 0x1e},
+    {0x24, 0x60}, {0x25, 0xa2}, {0x27, 0xe4}, {0x26, 0x26},
+    {0x23, 0x68}, {0x22, 0xaa}, {0x20, 0xec}, {0x21, 0x2e},
+    {0x2a, 0x70}, {0x2b, 0xb2}, {0x29, 0xf4}, {0x28, 0x36},
+    {0x2d, 0x78}, {0x2c, 0xba}, {0x2e, 0xfc}, {0x2f, 0x3e},
+    {0x70, 0x80}, {0x71, 0x42}, {0x73, 0x04}, {0x72, 0xc6},
+    {0x77, 0x88}, {0x76, 0x4a}, {0x74, 0x0c}, {0x75, 0xce},
+    {0x7e, 0x90}, {0x7f, 0x52}, {0x7d, 0x14}, {0x7c, 0xd6},
+    {0x79, 0x98}, {0x78, 0x5a}, {0x7a, 0x1c}, {0x7b, 0xde},
+    {0x6c, 0xa0}, {0x6d, 0x62}, {0x6f, 0x24}, {0x6e, 0xe6},
+    {0x6b, 0xa8}, {0x6a, 0x6a}, {0x68, 0x2c}, {0x69, 0xee},
+    {0x62, 0xb0}, {0x63, 0x72}, {0x61, 0x34}, {0x60, 0xf6},
+    {0x65, 0xb8}, {0x64, 0x7a}, {0x66, 0x3c}, {0x67, 0xfe},
+    {0x48, 0xc0}, {0x49, 0x02}, {0x4b, 0x44}, {0x4a, 0x86},
+    {0x4f, 0xc8}, {0x4e, 0x0a}, {0x4c, 0x4c}, {0x4d, 0x8e},
+    {0x46, 0xd0}, {0x47, 0x12}, {0x45, 0x54}, {0x44, 0x96},
+    {0x41, 0xd8}, {0x40, 0x1a}, {0x42, 0x5c}, {0x43, 0x9e},
+    {0x54, 0xe0}, {0x55, 0x22}, {0x57, 0x64}, {0x56, 0xa6},
+    {0x53, 0xe8}, {0x52, 0x2a}, {0x50, 0x6c}, {0x51, 0xae},
+    {0x5a, 0xf0}, {0x5b, 0x32}, {0x59, 0x74}, {0x58, 0xb6},
+    {0x5d, 0xf8}, {0x5c, 0x3a}, {0x5e, 0x7c}, {0x5f, 0xbe},
+    {0xe1, 0x00}, {0xe0, 0xc2}, {0xe2, 0x84}, {0xe3, 0x46},
+    {0xe6, 0x08}, {0xe7, 0xca}, {0xe5, 0x8c}, {0xe4, 0x4e},
+    {0xef, 0x10}, {0xee, 0xd2}, {0xec, 0x94}, {0xed, 0x56},
+    {0xe8, 0x18}, {0xe9, 0xda}, {0xeb, 0x9c}, {0xea, 0x5e},
+    {0xfd, 0x20}, {0xfc, 0xe2}, {0xfe, 0xa4}, {0xff, 0x66},
+    {0xfa, 0x28}, {0xfb, 0xea}, {0xf9, 0xac}, {0xf8, 0x6e},
+    {0xf3, 0x30}, {0xf2, 0xf2}, {0xf0, 0xb4}, {0xf1, 0x76},
+    {0xf4, 0x38}, {0xf5, 0xfa}, {0xf7, 0xbc}, {0xf6, 0x7e},
+    {0xd9, 0x40}, {0xd8, 0x82}, {0xda, 0xc4}, {0xdb, 0x06},
+    {0xde, 0x48}, {0xdf, 0x8a}, {0xdd, 0xcc}, {0xdc, 0x0e},
+    {0xd7, 0x50}, {0xd6, 0x92}, {0xd4, 0xd4}, {0xd5, 0x16},
+    {0xd0, 0x58}, {0xd1, 0x9a}, {0xd3, 0xdc}, {0xd2, 0x1e},
+    {0xc5, 0x60}, {0xc4, 0xa2}, {0xc6, 0xe4}, {0xc7, 0x26},
+    {0xc2, 0x68}, {0xc3, 0xaa}, {0xc1, 0xec}, {0xc0, 0x2e},
+    {0xcb, 0x70}, {0xca, 0xb2}, {0xc8, 0xf4}, {0xc9, 0x36},
+    {0xcc, 0x78}, {0xcd, 0xba}, {0xcf, 0xfc}, {0xce, 0x3e},
+    {0x91, 0x80}, {0x90, 0x42}, {0x92, 0x04}, {0x93, 0xc6},
+    {0x96, 0x88}, {0x97, 0x4a}, {0x95, 0x0c}, {0x94, 0xce},
+    {0x9f, 0x90}, {0x9e, 0x52}, {0x9c, 0x14}, {0x9d, 0xd6},
+    {0x98, 0x98}, {0x99, 0x5a}, {0x9b, 0x1c}, {0x9a, 0xde},
+    {0x8d, 0xa0}, {0x8c, 0x62}, {0x8e, 0x24}, {0x8f, 0xe6},
+    {0x8a, 0xa8}, {0x8b, 0x6a}, {0x89, 0x2c}, {0x88, 0xee},
+    {0x83, 0xb0}, {0x82, 0x72}, {0x80, 0x34}, {0x81, 0xf6},
+    {0x84, 0xb8}, {0x85, 0x7a}, {0x87, 0x3c}, {0x86, 0xfe},
+    {0xa9, 0xc0}, {0xa8, 0x02}, {0xaa, 0x44}, {0xab, 0x86},
+    {0xae, 0xc8}, {0xaf, 0x0a}, {0xad, 0x4c}, {0xac, 0x8e},
+    {0xa7, 0xd0}, {0xa6, 0x12}, {0xa4, 0x54}, {0xa5, 0x96},
+    {0xa0, 0xd8}, {0xa1, 0x1a}, {0xa3, 0x5c}, {0xa2, 0x9e},
+    {0xb5, 0xe0}, {0xb4, 0x22}, {0xb6, 0x64}, {0xb7, 0xa6},
+    {0xb2, 0xe8}, {0xb3, 0x2a}, {0xb1, 0x6c}, {0xb0, 0xae},
+    {0xbb, 0xf0}, {0xba, 0x32}, {0xb8, 0x74}, {0xb9, 0xb6},
+    {0xbc, 0xf8}, {0xbd, 0x3a}, {0xbf, 0x7c}, {0xbe, 0xbe} };
+
+
+static void GMULT(byte *x, byte m[256][AES_BLOCK_SIZE])
+{
+    int i, j;
+    byte Z[AES_BLOCK_SIZE];
+    byte a;
+
+    XMEMSET(Z, 0, sizeof(Z));
+
+    for (i = 15; i > 0; i--) {
+        xorbuf(Z, m[x[i]], AES_BLOCK_SIZE);
+        a = Z[15];
+
+        for (j = 15; j > 0; j--) {
+            Z[j] = Z[j-1];
+        }
+
+        Z[0] = R[a][0];
+        Z[1] ^= R[a][1];
+    }
+    xorbuf(Z, m[x[0]], AES_BLOCK_SIZE);
+
+    XMEMCPY(x, Z, AES_BLOCK_SIZE);
+}
+
+
+static void GHASH(Aes* aes, const byte* a, word32 aSz,
+                                const byte* c, word32 cSz, byte* s, word32 sSz)
+{
+    byte x[AES_BLOCK_SIZE];
+    byte scratch[AES_BLOCK_SIZE];
+    word32 blocks, partial;
+
+    XMEMSET(x, 0, AES_BLOCK_SIZE);
+
+    /* Hash in A, the Additional Authentication Data */
+    if (aSz != 0 && a != NULL) {
+        blocks = aSz / AES_BLOCK_SIZE;
+        partial = aSz % AES_BLOCK_SIZE;
+        while (blocks--) {
+            xorbuf(x, a, AES_BLOCK_SIZE);
+            GMULT(x, aes->M0);
+            a += AES_BLOCK_SIZE;
+        }
+        if (partial != 0) {
+            XMEMSET(scratch, 0, AES_BLOCK_SIZE);
+            XMEMCPY(scratch, a, partial);
+            xorbuf(x, scratch, AES_BLOCK_SIZE);
+            GMULT(x, aes->M0);
+        }
+    }
+
+    /* Hash in C, the Ciphertext */
+    if (cSz != 0 && c != NULL) {
+        blocks = cSz / AES_BLOCK_SIZE;
+        partial = cSz % AES_BLOCK_SIZE;
+        while (blocks--) {
+            xorbuf(x, c, AES_BLOCK_SIZE);
+            GMULT(x, aes->M0);
+            c += AES_BLOCK_SIZE;
+        }
+        if (partial != 0) {
+            XMEMSET(scratch, 0, AES_BLOCK_SIZE);
+            XMEMCPY(scratch, c, partial);
+            xorbuf(x, scratch, AES_BLOCK_SIZE);
+            GMULT(x, aes->M0);
+        }
+    }
+
+    /* Hash in the lengths of A and C in bits */
+    FlattenSzInBits(&scratch[0], aSz);
+    FlattenSzInBits(&scratch[8], cSz);
+    xorbuf(x, scratch, AES_BLOCK_SIZE);
+    GMULT(x, aes->M0);
+
+    /* Copy the result into s. */
+    XMEMCPY(s, x, sSz);
+}
+
+/* end GCM_TABLE */
+#elif defined(WORD64_AVAILABLE) && !defined(GCM_WORD32)
+
+static void GMULT(word64* X, word64* Y)
+{
+    word64 Z[2] = {0,0};
+    word64 V[2] ; 
+    int i, j;
+    V[0] = X[0] ;  V[1] = X[1] ;
+
+    for (i = 0; i < 2; i++)
+    {
+        word64 y = Y[i];
+        for (j = 0; j < 64; j++)
+        {
+            if (y & 0x8000000000000000ULL) {
+                Z[0] ^= V[0];
+                Z[1] ^= V[1];
+            }
+
+            if (V[1] & 0x0000000000000001) {
+                V[1] >>= 1;
+                V[1] |= ((V[0] & 0x0000000000000001) ? 0x8000000000000000ULL : 0);
+                V[0] >>= 1;
+                V[0] ^= 0xE100000000000000ULL;
+            }
+            else {
+                V[1] >>= 1;
+                V[1] |= ((V[0] & 0x0000000000000001) ? 0x8000000000000000ULL : 0);
+                V[0] >>= 1;
+            }
+            y <<= 1;
+        }
+    }
+    X[0] = Z[0];
+    X[1] = Z[1];
+}
+
+
+static void GHASH(Aes* aes, const byte* a, word32 aSz,
+                                const byte* c, word32 cSz, byte* s, word32 sSz)
+{
+    word64 x[2] = {0,0};
+    word32 blocks, partial;
+    word64 bigH[2];
+
+    XMEMCPY(bigH, aes->H, AES_BLOCK_SIZE);
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords64(bigH, bigH, AES_BLOCK_SIZE); 
+    #endif
+
+    /* Hash in A, the Additional Authentication Data */
+    if (aSz != 0 && a != NULL) {
+        word64 bigA[2];
+        blocks = aSz / AES_BLOCK_SIZE;
+        partial = aSz % AES_BLOCK_SIZE;
+        while (blocks--) {
+            XMEMCPY(bigA, a, AES_BLOCK_SIZE);
+            #ifdef LITTLE_ENDIAN_ORDER
+                ByteReverseWords64(bigA, bigA, AES_BLOCK_SIZE);
+            #endif
+            x[0] ^= bigA[0];
+            x[1] ^= bigA[1];
+            GMULT(x, bigH);
+            a += AES_BLOCK_SIZE;
+        }
+        if (partial != 0) {
+            XMEMSET(bigA, 0, AES_BLOCK_SIZE);
+            XMEMCPY(bigA, a, partial);
+            #ifdef LITTLE_ENDIAN_ORDER
+                ByteReverseWords64(bigA, bigA, AES_BLOCK_SIZE);
+            #endif
+            x[0] ^= bigA[0];
+            x[1] ^= bigA[1];
+            GMULT(x, bigH);
+        }
+    }
+
+    /* Hash in C, the Ciphertext */
+    if (cSz != 0 && c != NULL) {
+        word64 bigC[2];
+        blocks = cSz / AES_BLOCK_SIZE;
+        partial = cSz % AES_BLOCK_SIZE;
+        while (blocks--) {
+            XMEMCPY(bigC, c, AES_BLOCK_SIZE);
+            #ifdef LITTLE_ENDIAN_ORDER
+                ByteReverseWords64(bigC, bigC, AES_BLOCK_SIZE);
+            #endif
+            x[0] ^= bigC[0];
+            x[1] ^= bigC[1];
+            GMULT(x, bigH);
+            c += AES_BLOCK_SIZE;
+        }
+        if (partial != 0) {
+            XMEMSET(bigC, 0, AES_BLOCK_SIZE);
+            XMEMCPY(bigC, c, partial);
+            #ifdef LITTLE_ENDIAN_ORDER
+                ByteReverseWords64(bigC, bigC, AES_BLOCK_SIZE);
+            #endif
+            x[0] ^= bigC[0];
+            x[1] ^= bigC[1];
+            GMULT(x, bigH);
+        }
+    }
+
+    /* Hash in the lengths in bits of A and C */
+    {
+        word64 len[2] ; 
+        len[0] = aSz ; len[1] = cSz;
+
+        /* Lengths are in bytes. Convert to bits. */
+        len[0] *= 8;
+        len[1] *= 8;
+
+        x[0] ^= len[0];
+        x[1] ^= len[1];
+        GMULT(x, bigH);
+    }
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords64(x, x, AES_BLOCK_SIZE);
+    #endif
+    XMEMCPY(s, x, sSz);
+}
+
+/* end defined(WORD64_AVAILABLE) && !defined(GCM_WORD32) */
+#else /* GCM_WORD32 */
+
+static void GMULT(word32* X, word32* Y)
+{
+    word32 Z[4] = {0,0,0,0};
+    word32 V[4] ;
+    int i, j;
+
+    V[0] = X[0];  V[1] = X[1]; V[2] =  X[2]; V[3] =  X[3];
+
+    for (i = 0; i < 4; i++)
+    {
+        word32 y = Y[i];
+        for (j = 0; j < 32; j++)
+        {
+            if (y & 0x80000000) {
+                Z[0] ^= V[0];
+                Z[1] ^= V[1];
+                Z[2] ^= V[2];
+                Z[3] ^= V[3];
+            }
+
+            if (V[3] & 0x00000001) {
+                V[3] >>= 1;
+                V[3] |= ((V[2] & 0x00000001) ? 0x80000000 : 0);
+                V[2] >>= 1;
+                V[2] |= ((V[1] & 0x00000001) ? 0x80000000 : 0);
+                V[1] >>= 1;
+                V[1] |= ((V[0] & 0x00000001) ? 0x80000000 : 0);
+                V[0] >>= 1;
+                V[0] ^= 0xE1000000;
+            } else {
+                V[3] >>= 1;
+                V[3] |= ((V[2] & 0x00000001) ? 0x80000000 : 0);
+                V[2] >>= 1;
+                V[2] |= ((V[1] & 0x00000001) ? 0x80000000 : 0);
+                V[1] >>= 1;
+                V[1] |= ((V[0] & 0x00000001) ? 0x80000000 : 0);
+                V[0] >>= 1;
+            }
+            y <<= 1;
+        }
+    }
+    X[0] = Z[0];
+    X[1] = Z[1];
+    X[2] = Z[2];
+    X[3] = Z[3];
+}
+
+
+static void GHASH(Aes* aes, const byte* a, word32 aSz,
+                                const byte* c, word32 cSz, byte* s, word32 sSz)
+{
+    word32 x[4] = {0,0,0,0};
+    word32 blocks, partial;
+    word32 bigH[4];
+
+    XMEMCPY(bigH, aes->H, AES_BLOCK_SIZE);
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords(bigH, bigH, AES_BLOCK_SIZE);
+    #endif
+
+    /* Hash in A, the Additional Authentication Data */
+    if (aSz != 0 && a != NULL) {
+        word32 bigA[4];
+        blocks = aSz / AES_BLOCK_SIZE;
+        partial = aSz % AES_BLOCK_SIZE;
+        while (blocks--) {
+            XMEMCPY(bigA, a, AES_BLOCK_SIZE);
+            #ifdef LITTLE_ENDIAN_ORDER
+                ByteReverseWords(bigA, bigA, AES_BLOCK_SIZE);
+            #endif
+            x[0] ^= bigA[0];
+            x[1] ^= bigA[1];
+            x[2] ^= bigA[2];
+            x[3] ^= bigA[3];
+            GMULT(x, bigH);
+            a += AES_BLOCK_SIZE;
+        }
+        if (partial != 0) {
+            XMEMSET(bigA, 0, AES_BLOCK_SIZE);
+            XMEMCPY(bigA, a, partial);
+            #ifdef LITTLE_ENDIAN_ORDER
+                ByteReverseWords(bigA, bigA, AES_BLOCK_SIZE);
+            #endif
+            x[0] ^= bigA[0];
+            x[1] ^= bigA[1];
+            x[2] ^= bigA[2];
+            x[3] ^= bigA[3];
+            GMULT(x, bigH);
+        }
+    }
+
+    /* Hash in C, the Ciphertext */
+    if (cSz != 0 && c != NULL) {
+        word32 bigC[4];
+        blocks = cSz / AES_BLOCK_SIZE;
+        partial = cSz % AES_BLOCK_SIZE;
+        while (blocks--) {
+            XMEMCPY(bigC, c, AES_BLOCK_SIZE);
+            #ifdef LITTLE_ENDIAN_ORDER
+                ByteReverseWords(bigC, bigC, AES_BLOCK_SIZE);
+            #endif
+            x[0] ^= bigC[0];
+            x[1] ^= bigC[1];
+            x[2] ^= bigC[2];
+            x[3] ^= bigC[3];
+            GMULT(x, bigH);
+            c += AES_BLOCK_SIZE;
+        }
+        if (partial != 0) {
+            XMEMSET(bigC, 0, AES_BLOCK_SIZE);
+            XMEMCPY(bigC, c, partial);
+            #ifdef LITTLE_ENDIAN_ORDER
+                ByteReverseWords(bigC, bigC, AES_BLOCK_SIZE);
+            #endif
+            x[0] ^= bigC[0];
+            x[1] ^= bigC[1];
+            x[2] ^= bigC[2];
+            x[3] ^= bigC[3];
+            GMULT(x, bigH);
+        }
+    }
+
+    /* Hash in the lengths in bits of A and C */
+    {
+        word32 len[4];
+
+        /* Lengths are in bytes. Convert to bits. */
+        len[0] = (aSz >> (8*sizeof(aSz) - 3));
+        len[1] = aSz << 3;
+        len[2] = (cSz >> (8*sizeof(cSz) - 3));
+        len[3] = cSz << 3;
+
+        x[0] ^= len[0];
+        x[1] ^= len[1];
+        x[2] ^= len[2];
+        x[3] ^= len[3];
+        GMULT(x, bigH);
+    }
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords(x, x, AES_BLOCK_SIZE);
+    #endif
+    XMEMCPY(s, x, sSz);
+}
+
+#endif /* end GCM_WORD32 */
+
+
+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)
+{
+    word32 blocks = sz / AES_BLOCK_SIZE;
+    word32 partial = sz % AES_BLOCK_SIZE;
+    const byte* p = in;
+    byte* c = out;
+    byte counter[AES_BLOCK_SIZE];
+    byte *ctr ;
+    byte scratch[AES_BLOCK_SIZE];
+
+#ifdef FREESCALE_MMCAU
+    byte* key = (byte*)aes->key;
+#endif
+
+    WOLFSSL_ENTER("AesGcmEncrypt");
+
+#ifdef WOLFSSL_PIC32MZ_CRYPT
+    ctr = (char *)aes->iv_ce ;
+#else
+    ctr = counter ;
+#endif
+
+    XMEMSET(ctr, 0, AES_BLOCK_SIZE);
+    XMEMCPY(ctr, iv, ivSz);
+    InitGcmCounter(ctr);
+
+#ifdef WOLFSSL_PIC32MZ_CRYPT
+    if(blocks)
+        wc_AesCrypt(aes, out, in, blocks*AES_BLOCK_SIZE,
+             PIC32_ENCRYPTION, PIC32_ALGO_AES, PIC32_CRYPTOALGO_AES_GCM );
+#endif
+    while (blocks--) {
+        IncrementGcmCounter(ctr);
+        #ifndef WOLFSSL_PIC32MZ_CRYPT
+            #ifdef FREESCALE_MMCAU
+                cau_aes_encrypt(ctr, key, aes->rounds, scratch);
+            #else
+                wc_AesEncrypt(aes, ctr, scratch);
+            #endif
+        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);
+        #ifdef FREESCALE_MMCAU
+            cau_aes_encrypt(ctr, key, aes->rounds, scratch);
+        #else
+            wc_AesEncrypt(aes, ctr, scratch);
+        #endif
+        xorbuf(scratch, p, partial);
+        XMEMCPY(c, scratch, partial);
+
+    }
+
+    GHASH(aes, authIn, authInSz, out, sz, authTag, authTagSz);
+    InitGcmCounter(ctr);
+    #ifdef FREESCALE_MMCAU
+        cau_aes_encrypt(ctr, key, aes->rounds, scratch);
+    #else
+        wc_AesEncrypt(aes, ctr, scratch);
+    #endif
+    xorbuf(authTag, scratch, authTagSz);
+
+    return 0;
+}
+
+
+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)
+{
+    word32 blocks = sz / AES_BLOCK_SIZE;
+    word32 partial = sz % AES_BLOCK_SIZE;
+    const byte* c = in;
+    byte* p = out;
+    byte counter[AES_BLOCK_SIZE];
+    byte *ctr ;
+    byte scratch[AES_BLOCK_SIZE];
+
+#ifdef FREESCALE_MMCAU
+    byte* key = (byte*)aes->key;
+#endif
+
+    WOLFSSL_ENTER("AesGcmDecrypt");
+
+#ifdef WOLFSSL_PIC32MZ_CRYPT
+    ctr = (char *)aes->iv_ce ;
+#else
+    ctr = counter ;
+#endif
+
+    XMEMSET(ctr, 0, AES_BLOCK_SIZE);
+    XMEMCPY(ctr, iv, ivSz);
+    InitGcmCounter(ctr);
+
+    /* Calculate the authTag again using the received auth data and the
+     * cipher text. */
+    {
+        byte Tprime[AES_BLOCK_SIZE];
+        byte EKY0[AES_BLOCK_SIZE];
+
+        GHASH(aes, authIn, authInSz, in, sz, Tprime, sizeof(Tprime));
+        #ifdef FREESCALE_MMCAU
+            cau_aes_encrypt(ctr, key, aes->rounds, EKY0);
+        #else
+            wc_AesEncrypt(aes, ctr, EKY0);
+        #endif
+        xorbuf(Tprime, EKY0, sizeof(Tprime));
+
+        if (ConstantCompare(authTag, Tprime, authTagSz) != 0) {
+            return AES_GCM_AUTH_E;
+        }
+    }
+
+#ifdef WOLFSSL_PIC32MZ_CRYPT
+    if(blocks)
+        wc_AesCrypt(aes, out, in, blocks*AES_BLOCK_SIZE,
+             PIC32_DECRYPTION, PIC32_ALGO_AES, PIC32_CRYPTOALGO_AES_GCM );
+#endif
+
+    while (blocks--) {
+        IncrementGcmCounter(ctr);
+        #ifndef WOLFSSL_PIC32MZ_CRYPT
+            #ifdef FREESCALE_MMCAU
+                cau_aes_encrypt(ctr, key, aes->rounds, scratch);
+            #else
+                wc_AesEncrypt(aes, ctr, scratch);
+            #endif
+        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);
+        #ifdef FREESCALE_MMCAU
+            cau_aes_encrypt(ctr, key, aes->rounds, scratch);
+        #else
+            wc_AesEncrypt(aes, ctr, scratch);
+        #endif
+        xorbuf(scratch, c, partial);
+        XMEMCPY(p, scratch, partial);
+    }
+    return 0;
+}
+
+
+
+WOLFSSL_API int wc_GmacSetKey(Gmac* gmac, const byte* key, word32 len)
+{
+    return wc_AesGcmSetKey(&gmac->aes, key, len);
+}
+
+
+WOLFSSL_API int wc_GmacUpdate(Gmac* gmac, const byte* iv, word32 ivSz,
+                              const byte* authIn, word32 authInSz,
+                              byte* authTag, word32 authTagSz)
+{
+    return wc_AesGcmEncrypt(&gmac->aes, NULL, NULL, 0, iv, ivSz,
+                                         authTag, authTagSz, authIn, authInSz);
+}
+
+#endif /* HAVE_AESGCM */
+
+
+#ifdef HAVE_AESCCM
+
+#ifdef STM32F2_CRYPTO
+    #error "STM32F2 crypto doesn't currently support AES-CCM mode"
+
+#elif defined(HAVE_COLDFIRE_SEC)
+    #error "Coldfire SEC doesn't currently support AES-CCM mode"
+
+#elif defined(WOLFSSL_PIC32MZ_CRYPT)
+    #error "PIC32MZ doesn't currently support AES-CCM mode"
+
+#endif
+
+void wc_AesCcmSetKey(Aes* aes, const byte* key, word32 keySz)
+{
+    byte nonce[AES_BLOCK_SIZE];
+
+    if (!((keySz == 16) || (keySz == 24) || (keySz == 32)))
+        return;
+
+    XMEMSET(nonce, 0, sizeof(nonce));
+    wc_AesSetKey(aes, key, keySz, nonce, AES_ENCRYPTION);
+}
+
+
+static void roll_x(Aes* aes, const byte* in, word32 inSz, byte* out)
+{
+    #ifdef FREESCALE_MMCAU
+        byte* key = (byte*)aes->key;
+    #endif
+
+    /* process the bulk of the data */
+    while (inSz >= AES_BLOCK_SIZE) {
+        xorbuf(out, in, AES_BLOCK_SIZE);
+        in += AES_BLOCK_SIZE;
+        inSz -= AES_BLOCK_SIZE;
+
+        #ifdef FREESCALE_MMCAU
+            cau_aes_encrypt(out, key, aes->rounds, out);
+        #else
+            wc_AesEncrypt(aes, out, out);
+        #endif
+    }
+
+    /* process remainder of the data */
+    if (inSz > 0) {
+        xorbuf(out, in, inSz);
+        #ifdef FREESCALE_MMCAU
+            cau_aes_encrypt(out, key, aes->rounds, out);
+        #else
+            wc_AesEncrypt(aes, out, out);
+        #endif
+    }
+}
+
+
+static void roll_auth(Aes* aes, const byte* in, word32 inSz, byte* out)
+{
+    word32 authLenSz;
+    word32 remainder;
+
+    #ifdef FREESCALE_MMCAU
+        byte* key = (byte*)aes->key;
+    #endif
+
+    /* encode the length in */
+    if (inSz <= 0xFEFF) {
+        authLenSz = 2;
+        out[0] ^= ((inSz & 0xFF00) >> 8);
+        out[1] ^=  (inSz & 0x00FF);
+    }
+    else if (inSz <= 0xFFFFFFFF) {
+        authLenSz = 6;
+        out[0] ^= 0xFF; out[1] ^= 0xFE;
+        out[2] ^= ((inSz & 0xFF000000) >> 24);
+        out[3] ^= ((inSz & 0x00FF0000) >> 16);
+        out[4] ^= ((inSz & 0x0000FF00) >>  8);
+        out[5] ^=  (inSz & 0x000000FF);
+    }
+    /* Note, the protocol handles auth data up to 2^64, but we are
+     * using 32-bit sizes right now, so the bigger data isn't handled
+     * else if (inSz <= 0xFFFFFFFFFFFFFFFF) {} */
+    else
+        return;
+
+    /* start fill out the rest of the first block */
+    remainder = AES_BLOCK_SIZE - authLenSz;
+    if (inSz >= remainder) {
+        /* plenty of bulk data to fill the remainder of this block */
+        xorbuf(out + authLenSz, in, remainder);
+        inSz -= remainder;
+        in += remainder;
+    }
+    else {
+        /* not enough bulk data, copy what is available, and pad zero */
+        xorbuf(out + authLenSz, in, inSz);
+        inSz = 0;
+    }
+    #ifdef FREESCALE_MMCAU
+        cau_aes_encrypt(out, key, aes->rounds, out);
+    #else
+        wc_AesEncrypt(aes, out, out);
+    #endif
+
+    if (inSz > 0)
+        roll_x(aes, in, inSz, out);
+}
+
+
+static INLINE void AesCcmCtrInc(byte* B, word32 lenSz)
+{
+    word32 i;
+
+    for (i = 0; i < lenSz; i++) {
+        if (++B[AES_BLOCK_SIZE - 1 - i] != 0) return;
+    }
+}
+
+
+void wc_AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
+                   const byte* nonce, word32 nonceSz,
+                   byte* authTag, word32 authTagSz,
+                   const byte* authIn, word32 authInSz)
+{
+    byte A[AES_BLOCK_SIZE];
+    byte B[AES_BLOCK_SIZE];
+    byte lenSz;
+    word32 i;
+
+    #ifdef FREESCALE_MMCAU
+        byte* key = (byte*)aes->key;
+    #endif
+
+    XMEMCPY(B+1, nonce, nonceSz);
+    lenSz = AES_BLOCK_SIZE - 1 - (byte)nonceSz;
+    B[0] = (authInSz > 0 ? 64 : 0)
+         + (8 * (((byte)authTagSz - 2) / 2))
+         + (lenSz - 1);
+    for (i = 0; i < lenSz; i++)
+        B[AES_BLOCK_SIZE - 1 - i] = (inSz >> (8 * i)) & 0xFF;
+
+    #ifdef FREESCALE_MMCAU
+        cau_aes_encrypt(B, key, aes->rounds, A);
+    #else
+        wc_AesEncrypt(aes, B, A);
+    #endif
+    if (authInSz > 0)
+        roll_auth(aes, authIn, authInSz, A);
+    if (inSz > 0)
+        roll_x(aes, in, inSz, A);
+    XMEMCPY(authTag, A, authTagSz);
+
+    B[0] = lenSz - 1;
+    for (i = 0; i < lenSz; i++)
+        B[AES_BLOCK_SIZE - 1 - i] = 0;
+    #ifdef FREESCALE_MMCAU
+        cau_aes_encrypt(B, key, aes->rounds, A);
+    #else
+        wc_AesEncrypt(aes, B, A);
+    #endif
+    xorbuf(authTag, A, authTagSz);
+
+    B[15] = 1;
+    while (inSz >= AES_BLOCK_SIZE) {
+        #ifdef FREESCALE_MMCAU
+            cau_aes_encrypt(B, key, aes->rounds, A);
+        #else
+            wc_AesEncrypt(aes, B, A);
+        #endif
+        xorbuf(A, in, AES_BLOCK_SIZE);
+        XMEMCPY(out, A, AES_BLOCK_SIZE);
+
+        AesCcmCtrInc(B, lenSz);
+        inSz -= AES_BLOCK_SIZE;
+        in += AES_BLOCK_SIZE;
+        out += AES_BLOCK_SIZE;
+    }
+    if (inSz > 0) {
+        #ifdef FREESCALE_MMCAU
+            cau_aes_encrypt(B, key, aes->rounds, A);
+        #else
+            wc_AesEncrypt(aes, B, A);
+        #endif
+        xorbuf(A, in, inSz);
+        XMEMCPY(out, A, inSz);
+    }
+
+    ForceZero(A, AES_BLOCK_SIZE);
+    ForceZero(B, AES_BLOCK_SIZE);
+}
+
+
+int  wc_AesCcmDecrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
+                   const byte* nonce, word32 nonceSz,
+                   const byte* authTag, word32 authTagSz,
+                   const byte* authIn, word32 authInSz)
+{
+    byte A[AES_BLOCK_SIZE];
+    byte B[AES_BLOCK_SIZE];
+    byte* o;
+    byte lenSz;
+    word32 i, oSz;
+    int result = 0;
+
+    #ifdef FREESCALE_MMCAU
+        byte* key = (byte*)aes->key;
+    #endif
+
+    o = out;
+    oSz = inSz;
+    XMEMCPY(B+1, nonce, nonceSz);
+    lenSz = AES_BLOCK_SIZE - 1 - (byte)nonceSz;
+
+    B[0] = lenSz - 1;
+    for (i = 0; i < lenSz; i++)
+        B[AES_BLOCK_SIZE - 1 - i] = 0;
+    B[15] = 1;
+
+    while (oSz >= AES_BLOCK_SIZE) {
+        #ifdef FREESCALE_MMCAU
+            cau_aes_encrypt(B, key, aes->rounds, A);
+        #else
+            wc_AesEncrypt(aes, B, A);
+        #endif
+        xorbuf(A, in, AES_BLOCK_SIZE);
+        XMEMCPY(o, A, AES_BLOCK_SIZE);
+
+        AesCcmCtrInc(B, lenSz);
+        oSz -= AES_BLOCK_SIZE;
+        in += AES_BLOCK_SIZE;
+        o += AES_BLOCK_SIZE;
+    }
+    if (inSz > 0) {
+        #ifdef FREESCALE_MMCAU
+            cau_aes_encrypt(B, key, aes->rounds, A);
+        #else
+            wc_AesEncrypt(aes, B, A);
+        #endif
+        xorbuf(A, in, oSz);
+        XMEMCPY(o, A, oSz);
+    }
+
+    for (i = 0; i < lenSz; i++)
+        B[AES_BLOCK_SIZE - 1 - i] = 0;
+    #ifdef FREESCALE_MMCAU
+        cau_aes_encrypt(B, key, aes->rounds, A);
+    #else
+        wc_AesEncrypt(aes, B, A);
+    #endif
+
+    o = out;
+    oSz = inSz;
+
+    B[0] = (authInSz > 0 ? 64 : 0)
+         + (8 * (((byte)authTagSz - 2) / 2))
+         + (lenSz - 1);
+    for (i = 0; i < lenSz; i++)
+        B[AES_BLOCK_SIZE - 1 - i] = (inSz >> (8 * i)) & 0xFF;
+
+    #ifdef FREESCALE_MMCAU
+        cau_aes_encrypt(B, key, aes->rounds, A);
+    #else
+        wc_AesEncrypt(aes, B, A);
+    #endif
+    if (authInSz > 0)
+        roll_auth(aes, authIn, authInSz, A);
+    if (inSz > 0)
+        roll_x(aes, o, oSz, A);
+
+    B[0] = lenSz - 1;
+    for (i = 0; i < lenSz; i++)
+        B[AES_BLOCK_SIZE - 1 - i] = 0;
+    #ifdef FREESCALE_MMCAU
+        cau_aes_encrypt(B, key, aes->rounds, B);
+    #else
+        wc_AesEncrypt(aes, B, B);
+    #endif
+    xorbuf(A, B, authTagSz);
+
+    if (ConstantCompare(A, authTag, authTagSz) != 0) {
+        /* If the authTag check fails, don't keep the decrypted data.
+         * Unfortunately, you need the decrypted data to calculate the
+         * check value. */
+        XMEMSET(out, 0, inSz);
+        result = AES_CCM_AUTH_E;
+    }
+
+    ForceZero(A, AES_BLOCK_SIZE);
+    ForceZero(B, AES_BLOCK_SIZE);
+    o = NULL;
+
+    return result;
+}
+
+#endif /* HAVE_AESCCM */
+
+
+#ifdef HAVE_CAVIUM
+
+#include <wolfssl/ctaocrypt/logging.h>
+#include "cavium_common.h"
+
+/* Initiliaze Aes for use with Nitrox device */
+int wc_AesInitCavium(Aes* aes, int devId)
+{
+    if (aes == NULL)
+        return -1;
+
+    if (CspAllocContext(CONTEXT_SSL, &aes->contextHandle, devId) != 0)
+        return -1;
+
+    aes->devId = devId;
+    aes->magic = WOLFSSL_AES_CAVIUM_MAGIC;
+
+    return 0;
+}
+
+
+/* Free Aes from use with Nitrox device */
+void wc_AesFreeCavium(Aes* aes)
+{
+    if (aes == NULL)
+        return;
+
+    if (aes->magic != WOLFSSL_AES_CAVIUM_MAGIC)
+        return;
+
+    CspFreeContext(CONTEXT_SSL, aes->contextHandle, aes->devId);
+    aes->magic = 0;
+}
+
+
+static int wc_AesCaviumSetKey(Aes* aes, const byte* key, word32 length,
+                           const byte* iv)
+{
+    if (aes == NULL)
+        return -1;
+
+    XMEMCPY(aes->key, key, length);   /* key still holds key, iv still in reg */
+    if (length == 16)
+        aes->type = AES_128;
+    else if (length == 24)
+        aes->type = AES_192;
+    else if (length == 32)
+        aes->type = AES_256;
+
+    return wc_AesSetIV(aes, iv);
+}
+
+
+static int AesCaviumCbcEncrypt(Aes* aes, byte* out, const byte* in,
+                               word32 length)
+{
+    wolfssl_word offset = 0;
+    word32 requestId;
+
+    while (length > WOLFSSL_MAX_16BIT) {
+        word16 slen = (word16)WOLFSSL_MAX_16BIT;
+        if (CspEncryptAes(CAVIUM_BLOCKING, aes->contextHandle, CAVIUM_NO_UPDATE,
+                          aes->type, slen, (byte*)in + offset, out + offset,
+                          (byte*)aes->reg, (byte*)aes->key, &requestId,
+                          aes->devId) != 0) {
+            WOLFSSL_MSG("Bad Cavium Aes Encrypt");
+            return -1;
+        }
+        length -= WOLFSSL_MAX_16BIT;
+        offset += WOLFSSL_MAX_16BIT;
+        XMEMCPY(aes->reg, out + offset - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+    }
+    if (length) {
+        word16 slen = (word16)length;
+        if (CspEncryptAes(CAVIUM_BLOCKING, aes->contextHandle, CAVIUM_NO_UPDATE,
+                          aes->type, slen, (byte*)in + offset, out + offset,
+                          (byte*)aes->reg, (byte*)aes->key, &requestId,
+                          aes->devId) != 0) {
+            WOLFSSL_MSG("Bad Cavium Aes Encrypt");
+            return -1;
+        }
+        XMEMCPY(aes->reg, out + offset+length - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+    }
+    return 0;
+}
+
+static int AesCaviumCbcDecrypt(Aes* aes, byte* out, const byte* in,
+                               word32 length)
+{
+    word32 requestId;
+    wolfssl_word offset = 0;
+
+    while (length > WOLFSSL_MAX_16BIT) {
+        word16 slen = (word16)WOLFSSL_MAX_16BIT;
+        XMEMCPY(aes->tmp, in + offset + slen - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+        if (CspDecryptAes(CAVIUM_BLOCKING, aes->contextHandle, CAVIUM_NO_UPDATE,
+                          aes->type, slen, (byte*)in + offset, out + offset,
+                          (byte*)aes->reg, (byte*)aes->key, &requestId,
+                          aes->devId) != 0) {
+            WOLFSSL_MSG("Bad Cavium Aes Decrypt");
+            return -1;
+        }
+        length -= WOLFSSL_MAX_16BIT;
+        offset += WOLFSSL_MAX_16BIT;
+        XMEMCPY(aes->reg, aes->tmp, AES_BLOCK_SIZE);
+    }
+    if (length) {
+        word16 slen = (word16)length;
+        XMEMCPY(aes->tmp, in + offset + slen - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+        if (CspDecryptAes(CAVIUM_BLOCKING, aes->contextHandle, CAVIUM_NO_UPDATE,
+                          aes->type, slen, (byte*)in + offset, out + offset,
+                          (byte*)aes->reg, (byte*)aes->key, &requestId,
+                          aes->devId) != 0) {
+            WOLFSSL_MSG("Bad Cavium Aes Decrypt");
+            return -1;
+        }
+        XMEMCPY(aes->reg, aes->tmp, AES_BLOCK_SIZE);
+    }
+    return 0;
+}
+
+#endif /* HAVE_CAVIUM */
+
+#endif /* WOLFSSL_TI_CRYPT */
+
+#endif /* HAVE_FIPS */
+
+#endif /* NO_AES */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/arc4.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,179 @@
+/* arc4.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifndef NO_RC4
+
+#include <wolfssl/wolfcrypt/arc4.h>
+
+#ifdef HAVE_CAVIUM
+    static void wc_Arc4CaviumSetKey(Arc4* arc4, const byte* key, word32 length);
+    static void wc_Arc4CaviumProcess(Arc4* arc4, byte* out, const byte* in,
+                                  word32 length);
+#endif
+
+
+void wc_Arc4SetKey(Arc4* arc4, const byte* key, word32 length)
+{
+    word32 i;
+    word32 keyIndex = 0, stateIndex = 0;
+
+#ifdef HAVE_CAVIUM
+    if (arc4->magic == WOLFSSL_ARC4_CAVIUM_MAGIC)
+        return wc_Arc4CaviumSetKey(arc4, key, length);
+#endif
+
+    arc4->x = 1;
+    arc4->y = 0;
+
+    for (i = 0; i < ARC4_STATE_SIZE; i++)
+        arc4->state[i] = (byte)i;
+
+    for (i = 0; i < ARC4_STATE_SIZE; i++) {
+        word32 a = arc4->state[i];
+        stateIndex += key[keyIndex] + a;
+        stateIndex &= 0xFF;
+        arc4->state[i] = arc4->state[stateIndex];
+        arc4->state[stateIndex] = (byte)a;
+
+        if (++keyIndex >= length)
+            keyIndex = 0;
+    }
+}
+
+
+static INLINE byte MakeByte(word32* x, word32* y, byte* s)
+{
+    word32 a = s[*x], b;
+    *y = (*y+a) & 0xff;
+
+    b = s[*y];
+    s[*x] = (byte)b;
+    s[*y] = (byte)a;
+    *x = (*x+1) & 0xff;
+
+    return s[(a+b) & 0xff];
+}
+
+
+void wc_Arc4Process(Arc4* arc4, byte* out, const byte* in, word32 length)
+{
+    word32 x;
+    word32 y;
+
+#ifdef HAVE_CAVIUM
+    if (arc4->magic == WOLFSSL_ARC4_CAVIUM_MAGIC)
+        return wc_Arc4CaviumProcess(arc4, out, in, length);
+#endif
+
+    x = arc4->x;
+    y = arc4->y;
+
+    while(length--)
+        *out++ = *in++ ^ MakeByte(&x, &y, arc4->state);
+
+    arc4->x = (byte)x;
+    arc4->y = (byte)y;
+}
+
+
+#ifdef HAVE_CAVIUM
+
+#include <wolfssl/wolfcrypt/logging.h>
+#include "cavium_common.h"
+
+/* Initiliaze Arc4 for use with Nitrox device */
+int wc_Arc4InitCavium(Arc4* arc4, int devId)
+{
+    if (arc4 == NULL)
+        return -1;
+
+    if (CspAllocContext(CONTEXT_SSL, &arc4->contextHandle, devId) != 0)
+        return -1;
+
+    arc4->devId = devId;
+    arc4->magic = WOLFSSL_ARC4_CAVIUM_MAGIC;
+
+    return 0;
+}
+
+
+/* Free Arc4 from use with Nitrox device */
+void wc_Arc4FreeCavium(Arc4* arc4)
+{
+    if (arc4 == NULL)
+        return;
+
+    if (arc4->magic != WOLFSSL_ARC4_CAVIUM_MAGIC)
+        return;
+
+    CspFreeContext(CONTEXT_SSL, arc4->contextHandle, arc4->devId);
+    arc4->magic = 0;
+}
+
+
+static void wc_Arc4CaviumSetKey(Arc4* arc4, const byte* key, word32 length)
+{
+    word32 requestId;
+
+    if (CspInitializeRc4(CAVIUM_BLOCKING, arc4->contextHandle, length,
+                         (byte*)key, &requestId, arc4->devId) != 0) {
+        WOLFSSL_MSG("Bad Cavium Arc4 Init");
+    }
+}
+
+
+static void wc_Arc4CaviumProcess(Arc4* arc4, byte* out, const byte* in,
+                              word32 length)
+{
+    wolfssl_word offset = 0;
+    word32 requestId;
+
+    while (length > WOLFSSL_MAX_16BIT) {
+        word16 slen = (word16)WOLFSSL_MAX_16BIT;
+        if (CspEncryptRc4(CAVIUM_BLOCKING, arc4->contextHandle,CAVIUM_UPDATE,
+                          slen, (byte*)in + offset, out + offset, &requestId,
+                          arc4->devId) != 0) {
+            WOLFSSL_MSG("Bad Cavium Arc4 Encrypt");
+        }
+        length -= WOLFSSL_MAX_16BIT;
+        offset += WOLFSSL_MAX_16BIT;
+    }
+    if (length) {
+        word16 slen = (word16)length;
+        if (CspEncryptRc4(CAVIUM_BLOCKING, arc4->contextHandle,CAVIUM_UPDATE,
+                          slen, (byte*)in + offset, out + offset, &requestId,
+                          arc4->devId) != 0) {
+            WOLFSSL_MSG("Bad Cavium Arc4 Encrypt");
+        }
+    }
+}
+
+#endif /* HAVE_CAVIUM */
+
+#endif /* NO_RC4 */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/asm.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,1619 @@
+/* asm.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+/*
+ * Based on public domain TomsFastMath 0.10 by Tom St Denis, tomstdenis@iahu.ca,
+ * http://math.libtomcrypt.com
+ */
+
+
+/******************************************************************/
+/* fp_montgomery_reduce.c asm or generic */
+
+
+/* Each platform needs to query info type 1 from cpuid to see if aesni is
+ * supported. Also, let's setup a macro for proper linkage w/o ABI conflicts
+ */
+
+#if defined(HAVE_INTEL_MULX)
+#ifndef _MSC_VER
+    #define cpuid(reg, leaf, sub)\
+            __asm__ __volatile__ ("cpuid":\
+             "=a" (reg[0]), "=b" (reg[1]), "=c" (reg[2]), "=d" (reg[3]) :\
+             "a" (leaf), "c"(sub));
+
+    #define XASM_LINK(f) asm(f)
+#else
+
+    #include <intrin.h>
+    #define cpuid(a,b) __cpuid((int*)a,b)
+
+    #define XASM_LINK(f)
+
+#endif /* _MSC_VER */
+
+#define EAX 0
+#define EBX 1
+#define ECX 2 
+#define EDX 3
+    
+#define CPUID_AVX1   0x1
+#define CPUID_AVX2   0x2
+#define CPUID_RDRAND 0x4
+#define CPUID_RDSEED 0x8
+#define CPUID_BMI2   0x10   /* MULX, RORX */
+#define CPUID_ADX    0x20   /* ADCX, ADOX */
+
+#define IS_INTEL_AVX1       (cpuid_flags&CPUID_AVX1)
+#define IS_INTEL_AVX2       (cpuid_flags&CPUID_AVX2)
+#define IS_INTEL_BMI2       (cpuid_flags&CPUID_BMI2)
+#define IS_INTEL_ADX        (cpuid_flags&CPUID_ADX)
+#define IS_INTEL_RDRAND     (cpuid_flags&CPUID_RDRAND)
+#define IS_INTEL_RDSEED     (cpuid_flags&CPUID_RDSEED)
+#define SET_FLAGS         
+
+static word32 cpuid_check = 0 ;
+static word32 cpuid_flags = 0 ;
+
+static word32 cpuid_flag(word32 leaf, word32 sub, word32 num, word32 bit) {
+    int got_intel_cpu=0;
+    unsigned int reg[5]; 
+    
+    reg[4] = '\0' ;
+    cpuid(reg, 0, 0);  
+    if(memcmp((char *)&(reg[EBX]), "Genu", 4) == 0 &&  
+                memcmp((char *)&(reg[EDX]), "ineI", 4) == 0 &&  
+                memcmp((char *)&(reg[ECX]), "ntel", 4) == 0) {  
+        got_intel_cpu = 1;  
+    }    
+    if (got_intel_cpu) {
+        cpuid(reg, leaf, sub);
+        return((reg[num]>>bit)&0x1) ;
+    }
+    return 0 ;
+}
+
+INLINE static int set_cpuid_flags(void) {  
+    if(cpuid_check == 0) {
+        if(cpuid_flag(7, 0, EBX, 8)){  cpuid_flags |= CPUID_BMI2 ; }
+        if(cpuid_flag(7, 0, EBX,19)){  cpuid_flags |= CPUID_ADX  ; }
+		cpuid_check = 1 ;
+		return 0 ;
+    }
+    return 1 ;
+}
+
+#define RETURN return
+#define IF_HAVE_INTEL_MULX(func, ret)    \
+   if(cpuid_check==0)set_cpuid_flags() ; \
+   if(IS_INTEL_BMI2 && IS_INTEL_ADX){  func;  ret ;  }
+
+#else
+    #define IF_HAVE_INTEL_MULX(func, ret)
+#endif
+
+#if defined(TFM_X86) && !defined(TFM_SSE2) 
+/* x86-32 code */
+
+#define MONT_START 
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                                          \
+__asm__(                                                      \
+   "movl %5,%%eax \n\t"                                   \
+   "mull %4       \n\t"                                   \
+   "addl %1,%%eax \n\t"                                   \
+   "adcl $0,%%edx \n\t"                                   \
+   "addl %%eax,%0 \n\t"                                   \
+   "adcl $0,%%edx \n\t"                                   \
+   "movl %%edx,%1 \n\t"                                   \
+:"=g"(_c[LO]), "=r"(cy)                                   \
+:"0"(_c[LO]), "1"(cy), "g"(mu), "g"(*tmpm++)              \
+: "%eax", "%edx", "cc")
+
+#define PROPCARRY                           \
+__asm__(                                        \
+   "addl   %1,%0    \n\t"                   \
+   "setb   %%al     \n\t"                   \
+   "movzbl %%al,%1 \n\t"                    \
+:"=g"(_c[LO]), "=r"(cy)                     \
+:"0"(_c[LO]), "1"(cy)                       \
+: "%eax", "cc")
+
+/******************************************************************/
+#elif defined(TFM_X86_64)
+/* x86-64 code */
+
+#define MONT_START 
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp;
+
+#define INNERMUL                                          \
+__asm__(                                                      \
+   "movq %5,%%rax \n\t"                                   \
+   "mulq %4       \n\t"                                   \
+   "addq %1,%%rax \n\t"                                   \
+   "adcq $0,%%rdx \n\t"                                   \
+   "addq %%rax,%0 \n\t"                                   \
+   "adcq $0,%%rdx \n\t"                                   \
+   "movq %%rdx,%1 \n\t"                                   \
+:"=g"(_c[LO]), "=r"(cy)                                   \
+:"0"(_c[LO]), "1"(cy), "r"(mu), "r"(*tmpm++)              \
+: "%rax", "%rdx", "cc")
+
+#if defined(HAVE_INTEL_MULX)
+#define MULX_INIT(a0, c0, cy)\
+    __asm__ volatile(                                     \
+             "xorq  %%r10, %%r10\n\t"                     \
+             "movq  %1,%%rdx\n\t"                         \
+             "addq  %2, %0\n\t"       /* c0+=cy; Set CF, OF */ \
+             "adoxq %%r10, %%r10\n\t" /* Reset   OF */    \
+             :"+m"(c0):"r"(a0),"r"(cy):"%r8","%r9", "%r10","%r11","%r12","%rdx") ; \
+
+#define MULX_INNERMUL_R1(c0, c1, pre, rdx)\
+   {                                                      \
+    __asm__  volatile (                                   \
+         "movq  %3, %%rdx\n\t"                            \
+         "mulx  %%r11,%%r9, %%r8 \n\t"                    \
+         "movq  %2, %%r12\n\t"                            \
+         "adoxq  %%r9,%0     \n\t"                        \
+         "adcxq  %%r8,%1     \n\t"                        \
+         :"+r"(c0),"+r"(c1):"m"(pre),"r"(rdx):"%r8","%r9", "%r10", "%r11","%r12","%rdx"    \
+    ); }
+    
+
+#define MULX_INNERMUL_R2(c0, c1, pre, rdx)\
+   {                                                      \
+    __asm__  volatile (                                   \
+         "movq  %3, %%rdx\n\t"                            \
+         "mulx  %%r12,%%r9, %%r8 \n\t"                    \
+         "movq  %2, %%r11\n\t"                            \
+         "adoxq  %%r9,%0     \n\t"                        \
+         "adcxq  %%r8,%1     \n\t"                        \
+         :"+r"(c0),"+r"(c1):"m"(pre),"r"(rdx):"%r8","%r9", "%r10", "%r11","%r12","%rdx"    \
+    ); }
+
+#define MULX_LOAD_R1(val)\
+    __asm__  volatile (                                   \
+        "movq %0, %%r11\n\t"\
+        ::"m"(val):"%r8","%r9", "%r10", "%r11","%r12","%rdx"\
+) ;
+
+#define MULX_INNERMUL_LAST(c0, c1, rdx)\
+   {                                                      \
+    __asm__  volatile (                                   \
+         "movq   %2, %%rdx\n\t"                           \
+         "mulx   %%r12,%%r9, %%r8 \n\t"                   \
+         "movq   $0, %%r10      \n\t"                     \
+         "adoxq  %%r10, %%r9   \n\t"                      \
+         "adcq   $0,%%r8       \n\t"                      \
+         "addq   %%r9,%0       \n\t"                      \
+         "adcq   $0,%%r8       \n\t"                      \
+         "movq   %%r8,%1       \n\t"                      \
+         :"+m"(c0),"=m"(c1):"r"(rdx):"%r8","%r9","%r10", "%r11", "%r12","%rdx"\
+    ); }
+
+#define MULX_INNERMUL8(x,y,z,cy)\
+{       word64 rdx = y ;\
+        MULX_LOAD_R1(x[0]) ;\
+        MULX_INIT(y, _c0, cy) ; /* rdx=y; z0+=cy; */ \
+        MULX_INNERMUL_R1(_c0, _c1, x[1], rdx) ;\
+        MULX_INNERMUL_R2(_c1, _c2, x[2], rdx) ;\
+        MULX_INNERMUL_R1(_c2, _c3, x[3], rdx) ;\
+        MULX_INNERMUL_R2(_c3, _c4, x[4], rdx) ;\
+        MULX_INNERMUL_R1(_c4, _c5, x[5], rdx) ;\
+        MULX_INNERMUL_R2(_c5, _c6, x[6], rdx) ;\
+        MULX_INNERMUL_R1(_c6, _c7, x[7], rdx) ;\
+        MULX_INNERMUL_LAST(_c7, cy, rdx) ;\
+}
+#define INNERMUL8_MULX \
+{\
+    MULX_INNERMUL8(tmpm, mu, _c, cy);\
+}
+#endif
+
+#define INNERMUL8 \
+ __asm__(                  \
+ "movq 0(%5),%%rax    \n\t"  \
+ "movq 0(%2),%%r10    \n\t"  \
+ "movq 0x8(%5),%%r11  \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq 0x8(%2),%%r10  \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0(%0)    \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+ "movq %%r11,%%rax    \n\t"  \
+ "movq 0x10(%5),%%r11 \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq 0x10(%2),%%r10 \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0x8(%0)  \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+ "movq %%r11,%%rax    \n\t"  \
+ "movq 0x18(%5),%%r11 \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq 0x18(%2),%%r10 \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0x10(%0) \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+ "movq %%r11,%%rax    \n\t"  \
+ "movq 0x20(%5),%%r11 \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq 0x20(%2),%%r10 \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0x18(%0) \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+ "movq %%r11,%%rax    \n\t"  \
+ "movq 0x28(%5),%%r11 \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq 0x28(%2),%%r10 \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0x20(%0) \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+ "movq %%r11,%%rax    \n\t"  \
+ "movq 0x30(%5),%%r11 \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq 0x30(%2),%%r10 \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0x28(%0) \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+ "movq %%r11,%%rax    \n\t"  \
+ "movq 0x38(%5),%%r11 \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq 0x38(%2),%%r10 \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0x30(%0) \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+ "movq %%r11,%%rax    \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0x38(%0) \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+:"=r"(_c), "=r"(cy)                    \
+: "0"(_c),  "1"(cy), "g"(mu), "r"(tmpm)\
+: "%rax", "%rdx", "%r10", "%r11", "cc")\
+
+#define PROPCARRY                           \
+__asm__(                                        \
+   "addq   %1,%0    \n\t"                   \
+   "setb   %%al     \n\t"                   \
+   "movzbq %%al,%1 \n\t"                    \
+:"=g"(_c[LO]), "=r"(cy)                     \
+:"0"(_c[LO]), "1"(cy)                       \
+: "%rax", "cc")
+
+/******************************************************************/
+#elif defined(TFM_SSE2)  
+/* SSE2 code (assumes 32-bit fp_digits) */
+/* XMM register assignments:
+ * xmm0  *tmpm++, then Mu * (*tmpm++)
+ * xmm1  c[x], then Mu
+ * xmm2  mp
+ * xmm3  cy
+ * xmm4  _c[LO]
+ */
+
+#define MONT_START \
+   __asm__("movd %0,%%mm2"::"g"(mp))
+
+#define MONT_FINI \
+   __asm__("emms")
+
+#define LOOP_START          \
+__asm__(                        \
+"movd %0,%%mm1        \n\t" \
+"pxor %%mm3,%%mm3     \n\t" \
+"pmuludq %%mm2,%%mm1  \n\t" \
+:: "g"(c[x]))
+
+/* pmuludq on mmx registers does a 32x32->64 multiply. */
+#define INNERMUL               \
+__asm__(                           \
+   "movd %1,%%mm4        \n\t" \
+   "movd %2,%%mm0        \n\t" \
+   "paddq %%mm4,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm0  \n\t" \
+   "paddq %%mm0,%%mm3    \n\t" \
+   "movd %%mm3,%0        \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+:"=g"(_c[LO]) : "0"(_c[LO]), "g"(*tmpm++) );
+
+#define INNERMUL8 \
+__asm__(                           \
+   "movd 0(%1),%%mm4     \n\t" \
+   "movd 0(%2),%%mm0     \n\t" \
+   "paddq %%mm4,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm0  \n\t" \
+   "movd 4(%2),%%mm5     \n\t" \
+   "paddq %%mm0,%%mm3    \n\t" \
+   "movd 4(%1),%%mm6     \n\t" \
+   "movd %%mm3,0(%0)     \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+\
+   "paddq %%mm6,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm5  \n\t" \
+   "movd 8(%2),%%mm6     \n\t" \
+   "paddq %%mm5,%%mm3    \n\t" \
+   "movd 8(%1),%%mm7     \n\t" \
+   "movd %%mm3,4(%0)     \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+\
+   "paddq %%mm7,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm6  \n\t" \
+   "movd 12(%2),%%mm7    \n\t" \
+   "paddq %%mm6,%%mm3    \n\t" \
+   "movd 12(%1),%%mm5     \n\t" \
+   "movd %%mm3,8(%0)     \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+\
+   "paddq %%mm5,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm7  \n\t" \
+   "movd 16(%2),%%mm5    \n\t" \
+   "paddq %%mm7,%%mm3    \n\t" \
+   "movd 16(%1),%%mm6    \n\t" \
+   "movd %%mm3,12(%0)    \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+\
+   "paddq %%mm6,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm5  \n\t" \
+   "movd 20(%2),%%mm6    \n\t" \
+   "paddq %%mm5,%%mm3    \n\t" \
+   "movd 20(%1),%%mm7    \n\t" \
+   "movd %%mm3,16(%0)    \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+\
+   "paddq %%mm7,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm6  \n\t" \
+   "movd 24(%2),%%mm7    \n\t" \
+   "paddq %%mm6,%%mm3    \n\t" \
+   "movd 24(%1),%%mm5     \n\t" \
+   "movd %%mm3,20(%0)    \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+\
+   "paddq %%mm5,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm7  \n\t" \
+   "movd 28(%2),%%mm5    \n\t" \
+   "paddq %%mm7,%%mm3    \n\t" \
+   "movd 28(%1),%%mm6    \n\t" \
+   "movd %%mm3,24(%0)    \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+\
+   "paddq %%mm6,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm5  \n\t" \
+   "paddq %%mm5,%%mm3    \n\t" \
+   "movd %%mm3,28(%0)    \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+:"=r"(_c) : "0"(_c), "r"(tmpm) );
+
+/* TAO switched tmpm from "g" to "r" after gcc tried to index the indexed stack
+   pointer */
+
+#define LOOP_END \
+__asm__( "movd %%mm3,%0  \n" :"=r"(cy))
+
+#define PROPCARRY                           \
+__asm__(                                        \
+   "addl   %1,%0    \n\t"                   \
+   "setb   %%al     \n\t"                   \
+   "movzbl %%al,%1 \n\t"                    \
+:"=g"(_c[LO]), "=r"(cy)                     \
+:"0"(_c[LO]), "1"(cy)                       \
+: "%eax", "cc")
+
+/******************************************************************/
+#elif defined(TFM_ARM)
+   /* ARMv4 code */
+
+#define MONT_START 
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+
+#ifdef __thumb__
+
+#define INNERMUL                    \
+__asm__(                                \
+    " LDR    r0,%1            \n\t" \
+    " ADDS   r0,r0,%0         \n\t" \
+    " ITE    CS               \n\t" \
+    " MOVCS  %0,#1            \n\t" \
+    " MOVCC  %0,#0            \n\t" \
+    " UMLAL  r0,%0,%3,%4      \n\t" \
+    " STR    r0,%1            \n\t" \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(*tmpm++),"m"(_c[0]):"r0","cc");
+
+#define PROPCARRY                  \
+__asm__(                               \
+    " LDR   r0,%1            \n\t" \
+    " ADDS  r0,r0,%0         \n\t" \
+    " STR   r0,%1            \n\t" \
+    " ITE   CS               \n\t" \
+    " MOVCS %0,#1            \n\t" \
+    " MOVCC %0,#0            \n\t" \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"m"(_c[0]):"r0","cc");
+
+
+/* TAO thumb mode uses ite (if then else) to detect carry directly
+ * fixed unmatched constraint warning by changing 1 to m  */
+
+#else  /* __thumb__ */
+
+#define INNERMUL                    \
+__asm__(                                \
+    " LDR    r0,%1            \n\t" \
+    " ADDS   r0,r0,%0         \n\t" \
+    " MOVCS  %0,#1            \n\t" \
+    " MOVCC  %0,#0            \n\t" \
+    " UMLAL  r0,%0,%3,%4      \n\t" \
+    " STR    r0,%1            \n\t" \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(*tmpm++),"1"(_c[0]):"r0","cc");
+
+#define PROPCARRY                  \
+__asm__(                               \
+    " LDR   r0,%1            \n\t" \
+    " ADDS  r0,r0,%0         \n\t" \
+    " STR   r0,%1            \n\t" \
+    " MOVCS %0,#1            \n\t" \
+    " MOVCC %0,#0            \n\t" \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"r0","cc");
+
+#endif /* __thumb__ */
+
+#elif defined(TFM_PPC32)
+
+/* PPC32 */
+#define MONT_START 
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                     \
+__asm__(                                 \
+   " mullw    16,%3,%4       \n\t"   \
+   " mulhwu   17,%3,%4       \n\t"   \
+   " addc     16,16,%0       \n\t"   \
+   " addze    17,17          \n\t"   \
+   " lwz      18,%1          \n\t"   \
+   " addc     16,16,18       \n\t"   \
+   " addze    %0,17          \n\t"   \
+   " stw      16,%1          \n\t"   \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(tmpm[0]),"1"(_c[0]):"16", "17", "18","cc"); ++tmpm;
+
+#define PROPCARRY                    \
+__asm__(                                 \
+   " lwz      16,%1         \n\t"    \
+   " addc     16,16,%0      \n\t"    \
+   " stw      16,%1         \n\t"    \
+   " xor      %0,%0,%0      \n\t"    \
+   " addze    %0,%0         \n\t"    \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"16","cc");
+
+#elif defined(TFM_PPC64)
+
+/* PPC64 */
+#define MONT_START 
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                     \
+__asm__(                                 \
+   " mulld    16,%3,%4       \n\t"   \
+   " mulhdu   17,%3,%4       \n\t"   \
+   " addc     16,16,%0       \n\t"   \
+   " addze    17,17          \n\t"   \
+   " ldx      18,0,%1        \n\t"   \
+   " addc     16,16,18       \n\t"   \
+   " addze    %0,17          \n\t"   \
+   " sdx      16,0,%1        \n\t"   \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(tmpm[0]),"1"(_c[0]):"16", "17", "18","cc"); ++tmpm;
+
+#define PROPCARRY                    \
+__asm__(                                 \
+   " ldx      16,0,%1       \n\t"    \
+   " addc     16,16,%0      \n\t"    \
+   " sdx      16,0,%1       \n\t"    \
+   " xor      %0,%0,%0      \n\t"    \
+   " addze    %0,%0         \n\t"    \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"16","cc");
+
+/******************************************************************/
+
+#elif defined(TFM_AVR32)
+
+/* AVR32 */
+#define MONT_START 
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                    \
+__asm__(                                \
+    " ld.w   r2,%1            \n\t" \
+    " add    r2,%0            \n\t" \
+    " eor    r3,r3            \n\t" \
+    " acr    r3               \n\t" \
+    " macu.d r2,%3,%4         \n\t" \
+    " st.w   %1,r2            \n\t" \
+    " mov    %0,r3            \n\t" \
+:"=r"(cy),"=r"(_c):"0"(cy),"r"(mu),"r"(*tmpm++),"1"(_c):"r2","r3");
+
+#define PROPCARRY                    \
+__asm__(                                 \
+   " ld.w     r2,%1         \n\t"    \
+   " add      r2,%0         \n\t"    \
+   " st.w     %1,r2         \n\t"    \
+   " eor      %0,%0         \n\t"    \
+   " acr      %0            \n\t"    \
+:"=r"(cy),"=r"(&_c[0]):"0"(cy),"1"(&_c[0]):"r2","cc");
+
+#else
+
+/* ISO C code */
+#define MONT_START 
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                                      \
+   do { fp_word t;                                    \
+   t  = ((fp_word)_c[0] + (fp_word)cy) +              \
+                (((fp_word)mu) * ((fp_word)*tmpm++)); \
+   _c[0] = (fp_digit)t;                               \
+   cy = (fp_digit)(t >> DIGIT_BIT);                   \
+   } while (0)
+
+#define PROPCARRY \
+   do { fp_digit t = _c[0] += cy; cy = (t < cy); } while (0)
+
+#endif
+/******************************************************************/
+
+
+#define LO  0
+/* end fp_montogomery_reduce.c asm */
+
+
+/* start fp_sqr_comba.c asm */
+#if defined(TFM_X86)
+
+/* x86-32 optimized */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+#define SQRADD(i, j)                                      \
+__asm__(                                            \
+     "movl  %6,%%eax     \n\t"                            \
+     "mull  %%eax        \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i) :"%eax","%edx","cc");
+
+#define SQRADD2(i, j)                                     \
+__asm__(                                            \
+     "movl  %6,%%eax     \n\t"                            \
+     "mull  %7           \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","%edx", "cc");
+
+#define SQRADDSC(i, j)                                    \
+__asm__(                                                     \
+     "movl  %3,%%eax     \n\t"                            \
+     "mull  %4           \n\t"                            \
+     "movl  %%eax,%0     \n\t"                            \
+     "movl  %%edx,%1     \n\t"                            \
+     "xorl  %2,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "g"(i), "g"(j) :"%eax","%edx","cc");
+
+/* TAO removed sc0,1,2 as input to remove warning so %6,%7 become %3,%4 */
+
+#define SQRADDAC(i, j)                                    \
+__asm__(                                                     \
+     "movl  %6,%%eax     \n\t"                            \
+     "mull  %7           \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%eax","%edx","cc");
+
+#define SQRADDDB                                          \
+__asm__(                                                     \
+     "addl %6,%0         \n\t"                            \
+     "adcl %7,%1         \n\t"                            \
+     "adcl %8,%2         \n\t"                            \
+     "addl %6,%0         \n\t"                            \
+     "adcl %7,%1         \n\t"                            \
+     "adcl %8,%2         \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(sc0), "r"(sc1), "r"(sc2) : "cc");
+
+#elif defined(TFM_X86_64)
+/* x86-64 optimized */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+#define SQRADD(i, j)                                      \
+__asm__(                                                     \
+     "movq  %6,%%rax     \n\t"                            \
+     "mulq  %%rax        \n\t"                            \
+     "addq  %%rax,%0     \n\t"                            \
+     "adcq  %%rdx,%1     \n\t"                            \
+     "adcq  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "g"(i) :"%rax","%rdx","cc");
+
+#define SQRADD2(i, j)                                     \
+__asm__(                                                     \
+     "movq  %6,%%rax     \n\t"                            \
+     "mulq  %7           \n\t"                            \
+     "addq  %%rax,%0     \n\t"                            \
+     "adcq  %%rdx,%1     \n\t"                            \
+     "adcq  $0,%2        \n\t"                            \
+     "addq  %%rax,%0     \n\t"                            \
+     "adcq  %%rdx,%1     \n\t"                            \
+     "adcq  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "g"(i), "g"(j)  :"%rax","%rdx","cc");
+
+#define SQRADDSC(i, j)                                    \
+__asm__(                                                     \
+     "movq  %3,%%rax     \n\t"                            \
+     "mulq  %4           \n\t"                            \
+     "movq  %%rax,%0     \n\t"                            \
+     "movq  %%rdx,%1     \n\t"                            \
+     "xorq  %2,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "g"(i), "g"(j) :"%rax","%rdx","cc");
+
+/* TAO removed sc0,1,2 as input to remove warning so %6,%7 become %3,%4 */
+
+#define SQRADDAC(i, j)                                                         \
+__asm__(                                                     \
+     "movq  %6,%%rax     \n\t"                            \
+     "mulq  %7           \n\t"                            \
+     "addq  %%rax,%0     \n\t"                            \
+     "adcq  %%rdx,%1     \n\t"                            \
+     "adcq  $0,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%rax","%rdx","cc");
+
+#define SQRADDDB                                          \
+__asm__(                                                     \
+     "addq %6,%0         \n\t"                            \
+     "adcq %7,%1         \n\t"                            \
+     "adcq %8,%2         \n\t"                            \
+     "addq %6,%0         \n\t"                            \
+     "adcq %7,%1         \n\t"                            \
+     "adcq %8,%2         \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(sc0), "r"(sc1), "r"(sc2) : "cc");
+
+#elif defined(TFM_SSE2)
+
+/* SSE2 Optimized */
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI \
+   __asm__("emms");
+
+#define SQRADD(i, j)                                      \
+__asm__(                                            \
+     "movd  %6,%%mm0     \n\t"                            \
+     "pmuludq %%mm0,%%mm0\n\t"                            \
+     "movd  %%mm0,%%eax  \n\t"                            \
+     "psrlq $32,%%mm0    \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "movd  %%mm0,%%eax  \n\t"                            \
+     "adcl  %%eax,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i) :"%eax","cc");
+
+#define SQRADD2(i, j)                                     \
+__asm__(                                            \
+     "movd  %6,%%mm0     \n\t"                            \
+     "movd  %7,%%mm1     \n\t"                            \
+     "pmuludq %%mm1,%%mm0\n\t"                            \
+     "movd  %%mm0,%%eax  \n\t"                            \
+     "psrlq $32,%%mm0    \n\t"                            \
+     "movd  %%mm0,%%edx  \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","%edx","cc");
+
+#define SQRADDSC(i, j)                                                         \
+__asm__(                                            \
+     "movd  %3,%%mm0     \n\t"                            \
+     "movd  %4,%%mm1     \n\t"                            \
+     "pmuludq %%mm1,%%mm0\n\t"                            \
+     "movd  %%mm0,%0     \n\t"                            \
+     "psrlq $32,%%mm0    \n\t"                            \
+     "movd  %%mm0,%1     \n\t"                            \
+     "xorl  %2,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "m"(i), "m"(j));
+
+/* TAO removed sc0,1,2 as input to remove warning so %6,%7 become %3,%4 */
+
+#define SQRADDAC(i, j)                                                         \
+__asm__(                                            \
+     "movd  %6,%%mm0     \n\t"                            \
+     "movd  %7,%%mm1     \n\t"                            \
+     "pmuludq %%mm1,%%mm0\n\t"                            \
+     "movd  %%mm0,%%eax  \n\t"                            \
+     "psrlq $32,%%mm0    \n\t"                            \
+     "movd  %%mm0,%%edx  \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "m"(i), "m"(j)  :"%eax","%edx","cc");
+
+#define SQRADDDB                                          \
+__asm__(                                                     \
+     "addl %6,%0         \n\t"                            \
+     "adcl %7,%1         \n\t"                            \
+     "adcl %8,%2         \n\t"                            \
+     "addl %6,%0         \n\t"                            \
+     "adcl %7,%1         \n\t"                            \
+     "adcl %8,%2         \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(sc0), "r"(sc1), "r"(sc2) : "cc");
+
+#elif defined(TFM_ARM)
+
+/* ARM code */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)                                             \
+__asm__(                                                             \
+"  UMULL  r0,r1,%6,%6              \n\t"                         \
+"  ADDS   %0,%0,r0                 \n\t"                         \
+"  ADCS   %1,%1,r1                 \n\t"                         \
+"  ADC    %2,%2,#0                 \n\t"                         \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i) : "r0", "r1", "cc");
+	
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)                                            \
+__asm__(                                                             \
+"  UMULL  r0,r1,%6,%7              \n\t"                         \
+"  ADDS   %0,%0,r0                 \n\t"                         \
+"  ADCS   %1,%1,r1                 \n\t"                         \
+"  ADC    %2,%2,#0                 \n\t"                         \
+"  ADDS   %0,%0,r0                 \n\t"                         \
+"  ADCS   %1,%1,r1                 \n\t"                         \
+"  ADC    %2,%2,#0                 \n\t"                         \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "cc");
+
+#define SQRADDSC(i, j)                                           \
+__asm__(                                                             \
+"  UMULL  %0,%1,%3,%4              \n\t"                         \
+"  SUB    %2,%2,%2                 \n\t"                         \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2) : "r"(i), "r"(j) : "cc");
+
+/* TAO removed sc0,1,2 as input to remove warning so %6,%7 become %3,%4 */
+
+#define SQRADDAC(i, j)                                           \
+__asm__(                                                             \
+"  UMULL  r0,r1,%6,%7              \n\t"                         \
+"  ADDS   %0,%0,r0                 \n\t"                         \
+"  ADCS   %1,%1,r1                 \n\t"                         \
+"  ADC    %2,%2,#0                 \n\t"                         \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2) : "0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j) : "r0", "r1", "cc");
+
+#define SQRADDDB                                                 \
+__asm__(                                                             \
+"  ADDS  %0,%0,%3                     \n\t"                      \
+"  ADCS  %1,%1,%4                     \n\t"                      \
+"  ADC   %2,%2,%5                     \n\t"                      \
+"  ADDS  %0,%0,%3                     \n\t"                      \
+"  ADCS  %1,%1,%4                     \n\t"                      \
+"  ADC   %2,%2,%5                     \n\t"                      \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "cc");
+
+#elif defined(TFM_PPC32)
+
+/* PPC32 */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)             \
+__asm__(                             \
+   " mullw  16,%6,%6       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhwu 16,%6,%6       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i):"16","cc");
+
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)            \
+__asm__(                             \
+   " mullw  16,%6,%7       \n\t" \
+   " mulhwu 17,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " adde   %1,%1,17       \n\t" \
+   " addze  %2,%2          \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " adde   %1,%1,17       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"16", "17","cc");
+
+#define SQRADDSC(i, j)            \
+__asm__(                              \
+   " mullw  %0,%6,%7        \n\t" \
+   " mulhwu %1,%6,%7        \n\t" \
+   " xor    %2,%2,%2        \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i),"r"(j) : "cc");
+
+#define SQRADDAC(i, j)           \
+__asm__(                             \
+   " mullw  16,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhwu 16,%6,%7       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j):"16", "cc");
+
+#define SQRADDDB                  \
+__asm__(                              \
+   " addc   %0,%0,%3        \n\t" \
+   " adde   %1,%1,%4        \n\t" \
+   " adde   %2,%2,%5        \n\t" \
+   " addc   %0,%0,%3        \n\t" \
+   " adde   %1,%1,%4        \n\t" \
+   " adde   %2,%2,%5        \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "cc");
+
+#elif defined(TFM_PPC64)
+/* PPC64 */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)             \
+__asm__(                             \
+   " mulld  16,%6,%6       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhdu 16,%6,%6       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i):"16","cc");
+
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)            \
+__asm__(                             \
+   " mulld  16,%6,%7       \n\t" \
+   " mulhdu 17,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " adde   %1,%1,17       \n\t" \
+   " addze  %2,%2          \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " adde   %1,%1,17       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"16", "17","cc");
+
+#define SQRADDSC(i, j)            \
+__asm__(                              \
+   " mulld  %0,%6,%7        \n\t" \
+   " mulhdu %1,%6,%7        \n\t" \
+   " xor    %2,%2,%2        \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i),"r"(j) : "cc");
+
+#define SQRADDAC(i, j)           \
+__asm__(                             \
+   " mulld  16,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhdu 16,%6,%7       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j):"16", "cc");
+
+#define SQRADDDB                  \
+__asm__(                              \
+   " addc   %0,%0,%3        \n\t" \
+   " adde   %1,%1,%4        \n\t" \
+   " adde   %2,%2,%5        \n\t" \
+   " addc   %0,%0,%3        \n\t" \
+   " adde   %1,%1,%4        \n\t" \
+   " adde   %2,%2,%5        \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "cc");
+
+
+#elif defined(TFM_AVR32)
+
+/* AVR32 */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)             \
+__asm__(                             \
+   " mulu.d r2,%6,%6       \n\t" \
+   " add    %0,%0,r2       \n\t" \
+   " adc    %1,%1,r3       \n\t" \
+   " acr    %2             \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i):"r2","r3");
+
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)            \
+__asm__(                             \
+   " mulu.d r2,%6,%7       \n\t" \
+   " add    %0,%0,r2       \n\t" \
+   " adc    %1,%1,r3       \n\t" \
+   " acr    %2,            \n\t" \
+   " add    %0,%0,r2       \n\t" \
+   " adc    %1,%1,r3       \n\t" \
+   " acr    %2,            \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"r2", "r3");
+
+#define SQRADDSC(i, j)            \
+__asm__(                              \
+   " mulu.d r2,%6,%7        \n\t" \
+   " mov    %0,r2           \n\t" \
+   " mov    %1,r3           \n\t" \
+   " eor    %2,%2           \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i),"r"(j) : "r2", "r3");
+
+#define SQRADDAC(i, j)           \
+__asm__(                             \
+   " mulu.d r2,%6,%7       \n\t" \
+   " add    %0,%0,r2       \n\t" \
+   " adc    %1,%1,r3       \n\t" \
+   " acr    %2             \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j):"r2", "r3");
+
+#define SQRADDDB                  \
+__asm__(                              \
+   " add    %0,%0,%3        \n\t" \
+   " adc    %1,%1,%4        \n\t" \
+   " adc    %2,%2,%5        \n\t" \
+   " add    %0,%0,%3        \n\t" \
+   " adc    %1,%1,%4        \n\t" \
+   " adc    %2,%2,%5        \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "cc");
+
+
+#else
+
+#define TFM_ISO
+
+/* ISO C portable code */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)                                 \
+   do { fp_word t;                                   \
+   t = c0 + ((fp_word)i) * ((fp_word)j);  c0 = (fp_digit)t;    \
+   t = c1 + (t >> DIGIT_BIT);             c1 = (fp_digit)t;    \
+                                          c2 +=(fp_digit) (t >> DIGIT_BIT); \
+   } while (0);
+  
+
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)                                                 \
+   do { fp_word t;                                                    \
+   t  = ((fp_word)i) * ((fp_word)j);                                  \
+   tt = (fp_word)c0 + t;                 c0 = (fp_digit)tt;           \
+   tt = (fp_word)c1 + (tt >> DIGIT_BIT); c1 = (fp_digit)tt;           \
+                                         c2 +=(fp_digit)( tt >> DIGIT_BIT);    \
+   tt = (fp_word)c0 + t;                 c0 = (fp_digit)tt;                    \
+   tt = (fp_word)c1 + (tt >> DIGIT_BIT); c1 = (fp_digit)tt;            \
+                                         c2 +=(fp_digit) (tt >> DIGIT_BIT);    \
+   } while (0);
+
+#define SQRADDSC(i, j)                                                         \
+   do { fp_word t;                                                             \
+      t =  ((fp_word)i) * ((fp_word)j);                                        \
+      sc0 = (fp_digit)t; sc1 = (t >> DIGIT_BIT); sc2 = 0;                      \
+   } while (0);
+
+#define SQRADDAC(i, j)                                                         \
+   do { fp_word t;                                                             \
+   t = sc0 + ((fp_word)i) * ((fp_word)j);  sc0 =  (fp_digit)t;                 \
+   t = sc1 + (t >> DIGIT_BIT);             sc1 =  (fp_digit)t;                 \
+                                           sc2 += (fp_digit)(t >> DIGIT_BIT);  \
+   } while (0);
+
+#define SQRADDDB                                                               \
+   do { fp_word t;                                                             \
+   t = ((fp_word)sc0) + ((fp_word)sc0) + c0; c0 = (fp_digit)t;                 \
+   t = ((fp_word)sc1) + ((fp_word)sc1) + c1 + (t >> DIGIT_BIT);                \
+                                             c1 = (fp_digit)t;                 \
+   c2 = c2 + (fp_digit)(((fp_word)sc2) + ((fp_word)sc2) + (t >> DIGIT_BIT));   \
+   } while (0);
+
+#endif
+
+#ifdef TFM_SMALL_SET
+    #include "fp_sqr_comba_small_set.i"
+#endif
+
+#if defined(TFM_SQR3)
+    #include "fp_sqr_comba_3.i"
+#endif
+#if defined(TFM_SQR4)
+    #include "fp_sqr_comba_4.i"
+#endif
+#if defined(TFM_SQR6)
+    #include "fp_sqr_comba_6.i"
+#endif
+#if defined(TFM_SQR7)
+    #include "fp_sqr_comba_7.i"
+#endif
+#if defined(TFM_SQR8)
+    #include "fp_sqr_comba_8.i"
+#endif
+#if defined(TFM_SQR9)
+    #include "fp_sqr_comba_9.i"
+#endif
+#if defined(TFM_SQR12)
+    #include "fp_sqr_comba_12.i"
+#endif
+#if defined(TFM_SQR17)
+    #include "fp_sqr_comba_17.i"
+#endif
+#if defined(TFM_SQR20)
+    #include "fp_sqr_comba_20.i"
+#endif
+#if defined(TFM_SQR24)
+    #include "fp_sqr_comba_24.i"
+#endif
+#if defined(TFM_SQR28)
+    #include "fp_sqr_comba_28.i"
+#endif
+#if defined(TFM_SQR32)
+    #include "fp_sqr_comba_32.i"
+#endif
+#if defined(TFM_SQR48)
+    #include "fp_sqr_comba_48.i"
+#endif
+#if defined(TFM_SQR64)
+    #include "fp_sqr_comba_64.i"
+#endif
+/* end fp_sqr_comba.c asm */
+
+/* start fp_mul_comba.c asm */
+/* these are the combas.  Worship them. */
+#if defined(TFM_X86)
+/* Generic x86 optimized code */
+
+/* anything you need at the start */
+#define COMBA_START
+
+/* clear the chaining variables */
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+/* forward the carry to the next digit */
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+/* store the first sum */
+#define COMBA_STORE(x) \
+   x = c0;
+
+/* store the second sum [carry] */
+#define COMBA_STORE2(x) \
+   x = c1;
+
+/* anything you need at the end */
+#define COMBA_FINI
+
+/* this should multiply i and j  */
+#define MULADD(i, j)                                      \
+__asm__(                                                      \
+     "movl  %6,%%eax     \n\t"                            \
+     "mull  %7           \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","%edx","cc");
+
+#elif defined(TFM_X86_64)
+/* x86-64 optimized */
+
+/* anything you need at the start */
+#define COMBA_START
+
+/* clear the chaining variables */
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+/* forward the carry to the next digit */
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+/* store the first sum */
+#define COMBA_STORE(x) \
+   x = c0;
+
+/* store the second sum [carry] */
+#define COMBA_STORE2(x) \
+   x = c1;
+
+/* anything you need at the end */
+#define COMBA_FINI
+
+/* this should multiply i and j  */
+#define MULADD(i, j)                                      \
+__asm__  (                                                    \
+     "movq  %6,%%rax     \n\t"                            \
+     "mulq  %7           \n\t"                            \
+     "addq  %%rax,%0     \n\t"                            \
+     "adcq  %%rdx,%1     \n\t"                            \
+     "adcq  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "g"(i), "g"(j)  :"%rax","%rdx","cc");
+
+
+#if defined(HAVE_INTEL_MULX)
+#define MULADD_MULX(b0, c0, c1, rdx)\
+    __asm__  volatile (                                   \
+         "movq   %3, %%rdx\n\t"                           \
+         "mulx  %2,%%r9, %%r8 \n\t"                       \
+         "adoxq  %%r9,%0     \n\t"                        \
+         "adcxq  %%r8,%1     \n\t"                        \
+         :"+r"(c0),"+r"(c1):"r"(b0), "r"(rdx):"%r8","%r9","%r10","%rdx"\
+    )
+
+
+#define MULADD_MULX_ADD_CARRY(c0, c1)\
+    __asm__ volatile(\
+    "mov $0, %%r10\n\t"\
+    "movq %1, %%r8\n\t"\
+    "adox %%r10, %0\n\t"\
+    "adcx %%r10, %1\n\t"\
+    :"+r"(c0),"+r"(c1)::"%r8","%r9","%r10","%rdx") ;
+
+#define MULADD_SET_A(a0)\
+    __asm__ volatile("add $0, %%r8\n\t"                   \
+             "movq  %0,%%rdx\n\t"                         \
+             ::"r"(a0):"%r8","%r9","%r10","%rdx") ;
+
+#define MULADD_BODY(a,b,c)\
+    {   word64 rdx = a->dp[ix] ;      \
+        cp = &(c->dp[iz]) ;           \
+        c0 = cp[0] ; c1 = cp[1];      \
+        MULADD_SET_A(rdx) ;           \
+        MULADD_MULX(b0, c0, c1, rdx) ;\
+        cp[0]=c0; c0=cp[2];           \
+        MULADD_MULX(b1, c1, c0, rdx) ;\
+        cp[1]=c1; c1=cp[3];           \
+        MULADD_MULX(b2, c0, c1, rdx) ;\
+        cp[2]=c0; c0=cp[4];           \
+        MULADD_MULX(b3, c1, c0, rdx) ;\
+        cp[3]=c1; c1=cp[5];           \
+        MULADD_MULX_ADD_CARRY(c0, c1);\
+        cp[4]=c0; cp[5]=c1;           \
+    }
+
+#define TFM_INTEL_MUL_COMBA(a, b, c)\
+  for(ix=0; ix<pa; ix++)c->dp[ix]=0 ; \
+  for(iy=0; (iy<b->used); iy+=4) {    \
+    fp_digit *bp ;                    \
+    bp = &(b->dp[iy+0]) ;             \
+    fp_digit b0 = bp[0] , b1= bp[1],  \
+             b2= bp[2], b3= bp[3];    \
+    ix=0, iz=iy;                      \
+    while(ix<a->used) {               \
+        fp_digit c0, c1;              \
+        fp_digit *cp ;                \
+        MULADD_BODY(a,b,c);           \
+        ix++ ; iz++ ;                 \
+    }                                 \
+};
+#endif
+
+#elif defined(TFM_SSE2)
+/* use SSE2 optimizations */
+
+/* anything you need at the start */
+#define COMBA_START
+
+/* clear the chaining variables */
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+/* forward the carry to the next digit */
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+/* store the first sum */
+#define COMBA_STORE(x) \
+   x = c0;
+
+/* store the second sum [carry] */
+#define COMBA_STORE2(x) \
+   x = c1;
+
+/* anything you need at the end */
+#define COMBA_FINI \
+   __asm__("emms");
+
+/* this should multiply i and j  */
+#define MULADD(i, j)                                     \
+__asm__(                                                     \
+    "movd  %6,%%mm0     \n\t"                            \
+    "movd  %7,%%mm1     \n\t"                            \
+    "pmuludq %%mm1,%%mm0\n\t"                            \
+    "movd  %%mm0,%%eax  \n\t"                            \
+    "psrlq $32,%%mm0    \n\t"                            \
+    "addl  %%eax,%0     \n\t"                            \
+    "movd  %%mm0,%%eax  \n\t"                            \
+    "adcl  %%eax,%1     \n\t"                            \
+    "adcl  $0,%2        \n\t"                            \
+    :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","cc");
+
+#elif defined(TFM_ARM)
+/* ARM code */
+
+#define COMBA_START 
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI
+
+#define MULADD(i, j)                                          \
+__asm__(                                                          \
+"  UMULL  r0,r1,%6,%7           \n\t"                         \
+"  ADDS   %0,%0,r0              \n\t"                         \
+"  ADCS   %1,%1,r1              \n\t"                         \
+"  ADC    %2,%2,#0              \n\t"                         \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "cc");
+
+#elif defined(TFM_PPC32)
+/* For 32-bit PPC */
+
+#define COMBA_START
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI 
+   
+/* untested: will mulhwu change the flags?  Docs say no */
+#define MULADD(i, j)              \
+__asm__(                              \
+   " mullw  16,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhwu 16,%6,%7       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"16");
+
+#elif defined(TFM_PPC64)
+/* For 64-bit PPC */
+
+#define COMBA_START
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI 
+   
+/* untested: will mulhwu change the flags?  Docs say no */
+#define MULADD(i, j)              \
+____asm__(                              \
+   " mulld  16,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhdu 16,%6,%7       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"16");
+
+#elif defined(TFM_AVR32)
+
+/* ISO C code */
+
+#define COMBA_START
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI 
+   
+#define MULADD(i, j)             \
+____asm__(                             \
+   " mulu.d r2,%6,%7        \n\t"\
+   " add    %0,r2           \n\t"\
+   " adc    %1,%1,r3        \n\t"\
+   " acr    %2              \n\t"\
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"r2","r3");
+
+#else
+/* ISO C code */
+
+#define COMBA_START
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI 
+   
+#define MULADD(i, j)                                                                                                                                  \
+   do { fp_word t;                                                    \
+   t = (fp_word)c0 + ((fp_word)i) * ((fp_word)j); c0 = (fp_digit)t;   \
+   t = (fp_word)c1 + (t >> DIGIT_BIT);                                \
+   c1 = (fp_digit)t; c2 += (fp_digit)(t >> DIGIT_BIT);                \
+   } while (0);
+
+#endif
+
+
+#ifdef TFM_SMALL_SET
+    #include "fp_mul_comba_small_set.i"
+#endif
+
+#if defined(TFM_MUL3)
+    #include "fp_mul_comba_3.i"
+#endif
+#if defined(TFM_MUL4)
+    #include "fp_mul_comba_4.i"
+#endif
+#if defined(TFM_MUL6)
+    #include "fp_mul_comba_6.i"
+#endif
+#if defined(TFM_MUL7)
+    #include "fp_mul_comba_7.i"
+#endif
+#if defined(TFM_MUL8)
+    #include "fp_mul_comba_8.i"
+#endif
+#if defined(TFM_MUL9)
+    #include "fp_mul_comba_9.i"
+#endif
+#if defined(TFM_MUL12)
+    #include "fp_mul_comba_12.i"
+#endif
+#if defined(TFM_MUL17)
+    #include "fp_mul_comba_17.i"
+#endif
+#if defined(TFM_MUL20)
+    #include "fp_mul_comba_20.i"
+#endif
+#if defined(TFM_MUL24)
+    #include "fp_mul_comba_24.i"
+#endif
+#if defined(TFM_MUL28)
+    #include "fp_mul_comba_28.i"
+#endif
+#if defined(TFM_MUL32)
+    #include "fp_mul_comba_32.i"
+#endif
+#if defined(TFM_MUL48)
+    #include "fp_mul_comba_48.i"
+#endif
+#if defined(TFM_MUL64)
+    #include "fp_mul_comba_64.i"
+#endif
+
+/* end fp_mul_comba.c asm */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/asn.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,7796 @@
+/* asn.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#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>
+#include <wolfssl/wolfcrypt/coding.h>
+#include <wolfssl/wolfcrypt/md2.h>
+#include <wolfssl/wolfcrypt/hmac.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/pwdbased.h>
+#include <wolfssl/wolfcrypt/des3.h>
+#include <wolfssl/wolfcrypt/logging.h>
+
+#include <wolfssl/wolfcrypt/random.h>
+
+
+#ifndef NO_RC4
+    #include <wolfssl/wolfcrypt/arc4.h>
+#endif
+
+#ifdef HAVE_NTRU
+    #include "ntru_crypto.h"
+#endif
+
+#if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384)
+    #include <wolfssl/wolfcrypt/sha512.h>
+#endif
+
+#ifndef NO_SHA256
+    #include <wolfssl/wolfcrypt/sha256.h>
+#endif
+
+#ifdef HAVE_ECC
+    #include <wolfssl/wolfcrypt/ecc.h>
+#endif
+
+#ifdef WOLFSSL_DEBUG_ENCODING
+    #ifdef FREESCALE_MQX
+        #include <fio.h>
+    #else
+        #include <stdio.h>
+    #endif
+#endif
+
+#ifdef _MSC_VER
+    /* 4996 warning to use MS extensions e.g., strcpy_s instead of XSTRNCPY */
+    #pragma warning(disable: 4996)
+#endif
+
+
+#ifndef TRUE
+    #define TRUE  1
+#endif
+#ifndef FALSE
+    #define FALSE 0
+#endif
+
+
+#ifdef HAVE_RTP_SYS
+    /* uses parital <time.h> structures */
+    #define XTIME(tl)  (0)
+    #define XGMTIME(c, t) my_gmtime((c))
+    #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t))
+#elif defined(MICRIUM)
+    #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+        #define XVALIDATE_DATE(d,f,t) NetSecure_ValidateDateHandler((d),(f),(t))
+    #else
+        #define XVALIDATE_DATE(d, f, t) (0)
+    #endif
+    #define NO_TIME_H
+    /* since Micrium not defining XTIME or XGMTIME, CERT_GEN not available */
+#elif defined(MICROCHIP_TCPIP_V5) || defined(MICROCHIP_TCPIP)
+    #include <time.h>
+    #define XTIME(t1) pic32_time((t1))
+    #define XGMTIME(c, t) gmtime((c))
+    #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t))
+#elif defined(FREESCALE_MQX)
+    #define XTIME(t1)  mqx_time((t1))
+    #define XGMTIME(c, t) mqx_gmtime((c), (t))
+    #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t))
+#elif defined(WOLFSSL_MDK_ARM)
+    #if defined(WOLFSSL_MDK5)
+        #include "cmsis_os.h"
+    #else
+        #include <rtl.h>
+    #endif
+    #undef RNG
+    #include "wolfssl_MDK_ARM.h"
+    #undef RNG
+    #define RNG wolfSSL_RNG /*for avoiding name conflict in "stm32f2xx.h" */
+    #define XTIME(tl)  (0)
+    #define XGMTIME(c, t) wolfssl_MDK_gmtime((c))
+    #define XVALIDATE_DATE(d, f, t)  ValidateDate((d), (f), (t))
+#elif defined(USER_TIME)
+    /* user time, and gmtime compatible functions, there is a gmtime 
+       implementation here that WINCE uses, so really just need some ticks
+       since the EPOCH 
+    */
+
+    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 */
+    };
+    typedef long time_t;
+
+    /* forward declaration */
+    struct tm* gmtime(const time_t* timer);
+    extern time_t XTIME(time_t * timer);
+
+    #define XGMTIME(c, t) gmtime((c))
+    #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t))
+
+    #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)
+    /* user would like to override time() and gmtime() functionality */
+
+    #ifndef HAVE_TIME_T_TYPE
+        typedef long time_t;
+    #endif
+    extern time_t XTIME(time_t * timer);
+
+    #ifndef HAVE_TM_TYPE
+        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
+    extern struct tm* XGMTIME(const time_t* timer, struct tm* tmp);
+
+    #ifndef HAVE_VALIDATE_DATE
+        #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t))
+    #endif
+#else
+    /* default */
+    /* uses complete <time.h> facility */
+    #include <time.h>
+    #define XTIME(tl)     time((tl))
+    #define XGMTIME(c, t) gmtime((c))
+    #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t))
+#endif
+
+
+#ifdef _WIN32_WCE
+/* no time() or gmtime() even though in time.h header?? */
+
+#include <windows.h>
+
+
+time_t 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( _WIN32_WCE ) || defined( USER_TIME )
+
+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 /* _WIN32_WCE  || USER_TIME */
+
+
+#ifdef HAVE_RTP_SYS
+
+#define YEAR0          1900
+
+struct tm* my_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 */
+
+
+#ifdef FREESCALE_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;
+}
+
+/* CodeWarrior GCC toolchain only has gmtime_r(), no gmtime() */
+struct tm* mqx_gmtime(const time_t* clock, struct tm* tmpTime)
+{
+    return gmtime_r(clock, tmpTime);
+}
+
+#endif /* FREESCALE_MQX */
+
+#ifdef 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 */
+
+static INLINE word32 btoi(byte b)
+{
+    return b - 0x30;
+}
+
+
+/* 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(MICRIUM)
+
+CPU_INT32S NetSecure_ValidateDateHandler(CPU_INT08U *date, CPU_INT08U format,
+                                         CPU_INT08U dateType)
+{
+    CPU_BOOLEAN  rtn_code;
+    CPU_INT32S   i;
+    CPU_INT32S   val;    
+    CPU_INT16U   year;
+    CPU_INT08U   month;
+    CPU_INT16U   day;
+    CPU_INT08U   hour;
+    CPU_INT08U   min;
+    CPU_INT08U   sec;
+
+    i    = 0;
+    year = 0u;
+
+    if (format == ASN_UTC_TIME) {
+        if (btoi(date[0]) >= 5)
+            year = 1900;
+        else
+            year = 2000;
+    }
+    else  { /* format == GENERALIZED_TIME */
+        year += btoi(date[i++]) * 1000;
+        year += btoi(date[i++]) * 100;
+    }    
+
+    val = year;
+    GetTime(&val, date, &i);
+    year = (CPU_INT16U)val;
+
+    val = 0;
+    GetTime(&val, date, &i);   
+    month = (CPU_INT08U)val;   
+
+    val = 0;
+    GetTime(&val, date, &i);  
+    day = (CPU_INT16U)val;
+
+    val = 0;
+    GetTime(&val, date, &i);  
+    hour = (CPU_INT08U)val;
+
+    val = 0;
+    GetTime(&val, date, &i);  
+    min = (CPU_INT08U)val;
+
+    val = 0;
+    GetTime(&val, date, &i);  
+    sec = (CPU_INT08U)val;
+
+    return NetSecure_ValidateDate(year, month, day, hour, min, sec, dateType); 
+}
+
+#endif /* MICRIUM */
+
+
+WOLFSSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len,
+                           word32 maxIdx)
+{
+    int     length = 0;
+    word32  i = *inOutIdx;
+    byte    b;
+
+    *len = 0;    /* default length */
+
+    if ( (i+1) > maxIdx) {   /* for first read */
+        WOLFSSL_MSG("GetLength bad index on input");
+        return BUFFER_E;
+    }
+
+    b = input[i++];
+    if (b >= ASN_LONG_LENGTH) {        
+        word32 bytes = b & 0x7F;
+
+        if ( (i+bytes) > maxIdx) {   /* for reading bytes */
+            WOLFSSL_MSG("GetLength bad long length");
+            return BUFFER_E;
+        }
+
+        while (bytes--) {
+            b = input[i++];
+            length = (length << 8) | b;
+        }
+    }
+    else
+        length = b;
+    
+    if ( (i+length) > maxIdx) {   /* for user of length */
+        WOLFSSL_MSG("GetLength value exceeds buffer length");
+        return BUFFER_E;
+    }
+
+    *inOutIdx = i;
+    if (length > 0)
+        *len = length;
+
+    return length;
+}
+
+
+WOLFSSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len,
+                           word32 maxIdx)
+{
+    int    length = -1;
+    word32 idx    = *inOutIdx;
+
+    if (input[idx++] != (ASN_SEQUENCE | ASN_CONSTRUCTED) ||
+            GetLength(input, &idx, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    *len      = length;
+    *inOutIdx = idx;
+
+    return length;
+}
+
+
+WOLFSSL_LOCAL int GetSet(const byte* input, word32* inOutIdx, int* len,
+                        word32 maxIdx)
+{
+    int    length = -1;
+    word32 idx    = *inOutIdx;
+
+    if (input[idx++] != (ASN_SET | ASN_CONSTRUCTED) ||
+            GetLength(input, &idx, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    *len      = length;
+    *inOutIdx = idx;
+
+    return length;
+}
+
+
+/* winodws header clash for WinCE using GetVersion */
+WOLFSSL_LOCAL int GetMyVersion(const byte* input, word32* inOutIdx, int* version)
+{
+    word32 idx = *inOutIdx;
+
+    WOLFSSL_ENTER("GetMyVersion");
+
+    if (input[idx++] != ASN_INTEGER)
+        return ASN_PARSE_E;
+
+    if (input[idx++] != 0x01)
+        return ASN_VERSION_E;
+
+    *version  = input[idx++];
+    *inOutIdx = idx;
+
+    return *version;
+}
+
+
+#ifndef NO_PWDBASED
+/* Get small count integer, 32 bits or less */
+static int GetShortInt(const byte* input, word32* inOutIdx, int* number)
+{
+    word32 idx = *inOutIdx;
+    word32 len;
+
+    *number = 0;
+
+    if (input[idx++] != ASN_INTEGER)
+        return ASN_PARSE_E;
+
+    len = input[idx++];
+    if (len > 4)
+        return ASN_PARSE_E;
+
+    while (len--) {
+        *number  = *number << 8 | input[idx++];
+    }
+
+    *inOutIdx = idx;
+
+    return *number;
+}
+#endif /* !NO_PWDBASED */
+
+
+/* May not have one, not an error */
+static int GetExplicitVersion(const byte* input, word32* inOutIdx, int* version)
+{
+    word32 idx = *inOutIdx;
+
+    WOLFSSL_ENTER("GetExplicitVersion");
+    if (input[idx++] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) {
+        *inOutIdx = ++idx;  /* eat header */
+        return GetMyVersion(input, inOutIdx, version);
+    }
+
+    /* go back as is */
+    *version = 0;
+
+    return 0;
+}
+
+
+WOLFSSL_LOCAL int GetInt(mp_int* mpi, const byte* input, word32* inOutIdx,
+                  word32 maxIdx)
+{
+    word32 i = *inOutIdx;
+    byte   b = input[i++];
+    int    length;
+
+    if (b != ASN_INTEGER)
+        return ASN_PARSE_E;
+
+    if (GetLength(input, &i, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    if ( (b = input[i++]) == 0x00)
+        length--;
+    else
+        i--;
+
+    if (mp_init(mpi) != MP_OKAY)
+        return MP_INIT_E;
+
+    if (mp_read_unsigned_bin(mpi, (byte*)input + i, length) != 0) {
+        mp_clear(mpi);
+        return ASN_GETINT_E;
+    }
+
+    *inOutIdx = i + length;
+    return 0;
+}
+
+
+static int GetObjectId(const byte* input, word32* inOutIdx, word32* oid,
+                     word32 maxIdx)
+{
+    int    length;
+    word32 i = *inOutIdx;
+    byte   b;
+    *oid = 0;
+    
+    b = input[i++];
+    if (b != ASN_OBJECT_ID) 
+        return ASN_OBJECT_ID_E;
+    
+    if (GetLength(input, &i, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+    
+    while(length--)
+        *oid += input[i++];
+    /* just sum it up for now */
+    
+    *inOutIdx = i;
+    
+    return 0;
+}
+
+
+WOLFSSL_LOCAL int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid,
+                     word32 maxIdx)
+{
+    int    length;
+    word32 i = *inOutIdx;
+    byte   b;
+    *oid = 0;
+   
+    WOLFSSL_ENTER("GetAlgoId");
+
+    if (GetSequence(input, &i, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+    
+    b = input[i++];
+    if (b != ASN_OBJECT_ID) 
+        return ASN_OBJECT_ID_E;
+    
+    if (GetLength(input, &i, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+    
+    while(length--) {
+        /* odd HC08 compiler behavior here when input[i++] */
+        *oid += input[i];
+        i++;
+    }
+    /* just sum it up for now */
+    
+    /* could have NULL tag and 0 terminator, but may not */
+    b = input[i++];
+    
+    if (b == ASN_TAG_NULL) {
+        b = input[i++];
+        if (b != 0)
+            return ASN_EXPECT_0_E;
+    }
+    else
+    /* go back, didn't have it */
+        i--;
+    
+    *inOutIdx = i;
+    
+    return 0;
+}
+
+#ifndef NO_RSA
+
+
+#ifdef HAVE_CAVIUM
+
+static int GetCaviumInt(byte** buff, word16* buffSz, const byte* input,
+                        word32* inOutIdx, word32 maxIdx, void* heap)
+{
+    word32 i = *inOutIdx;
+    byte   b = input[i++];
+    int    length;
+
+    if (b != ASN_INTEGER)
+        return ASN_PARSE_E;
+
+    if (GetLength(input, &i, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    if ( (b = input[i++]) == 0x00)
+        length--;
+    else
+        i--;
+
+    *buffSz = (word16)length;
+    *buff   = XMALLOC(*buffSz, heap, DYNAMIC_TYPE_CAVIUM_RSA);
+    if (*buff == NULL)
+        return MEMORY_E;
+
+    XMEMCPY(*buff, input + i, *buffSz);
+
+    *inOutIdx = i + length;
+    return 0;
+}
+
+static int CaviumRsaPrivateKeyDecode(const byte* input, word32* inOutIdx,
+                                     RsaKey* key, word32 inSz)
+{
+    int   version, length;
+    void* h = key->heap;
+
+    if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetMyVersion(input, inOutIdx, &version) < 0)
+        return ASN_PARSE_E;
+
+    key->type = RSA_PRIVATE;
+
+    if (GetCaviumInt(&key->c_n,  &key->c_nSz,   input, inOutIdx, inSz, h) < 0 ||
+        GetCaviumInt(&key->c_e,  &key->c_eSz,   input, inOutIdx, inSz, h) < 0 ||
+        GetCaviumInt(&key->c_d,  &key->c_dSz,   input, inOutIdx, inSz, h) < 0 ||
+        GetCaviumInt(&key->c_p,  &key->c_pSz,   input, inOutIdx, inSz, h) < 0 ||
+        GetCaviumInt(&key->c_q,  &key->c_qSz,   input, inOutIdx, inSz, h) < 0 ||
+        GetCaviumInt(&key->c_dP, &key->c_dP_Sz, input, inOutIdx, inSz, h) < 0 ||
+        GetCaviumInt(&key->c_dQ, &key->c_dQ_Sz, input, inOutIdx, inSz, h) < 0 ||
+        GetCaviumInt(&key->c_u,  &key->c_uSz,   input, inOutIdx, inSz, h) < 0 )
+            return ASN_RSA_KEY_E;
+
+    return 0;
+}
+
+
+#endif /* HAVE_CAVIUM */
+
+int wc_RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
+                        word32 inSz)
+{
+    int    version, length;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == WOLFSSL_RSA_CAVIUM_MAGIC)
+        return CaviumRsaPrivateKeyDecode(input, inOutIdx, key, inSz);
+#endif
+
+    if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetMyVersion(input, inOutIdx, &version) < 0)
+        return ASN_PARSE_E;
+
+    key->type = RSA_PRIVATE;
+
+    if (GetInt(&key->n,  input, inOutIdx, inSz) < 0 ||
+        GetInt(&key->e,  input, inOutIdx, inSz) < 0 ||
+        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->dQ, input, inOutIdx, inSz) < 0 ||
+        GetInt(&key->u,  input, inOutIdx, inSz) < 0 )  return ASN_RSA_KEY_E;
+
+    return 0;
+}
+
+#endif /* NO_RSA */
+
+/* Remove PKCS8 header, move beginning of traditional to beginning of input */
+int ToTraditional(byte* input, word32 sz)
+{
+    word32 inOutIdx = 0, oid;
+    int    version, length;
+
+    if (GetSequence(input, &inOutIdx, &length, sz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetMyVersion(input, &inOutIdx, &version) < 0)
+        return ASN_PARSE_E;
+
+    if (GetAlgoId(input, &inOutIdx, &oid, sz) < 0)
+        return ASN_PARSE_E;
+
+    if (input[inOutIdx] == ASN_OBJECT_ID) {
+        /* pkcs8 ecc uses slightly different format */
+        inOutIdx++;  /* past id */
+        if (GetLength(input, &inOutIdx, &length, sz) < 0)
+            return ASN_PARSE_E;
+        inOutIdx += length;  /* over sub id, key input will verify */
+    }
+
+    if (input[inOutIdx++] != ASN_OCTET_STRING)
+        return ASN_PARSE_E;
+
+    if (GetLength(input, &inOutIdx, &length, sz) < 0)
+        return ASN_PARSE_E;
+
+    XMEMMOVE(input, input + inOutIdx, length);
+
+    return length;
+}
+
+
+#ifndef NO_PWDBASED
+
+/* 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)
+{
+    *id      = ALGO_ID_E;
+    *version = PKCS5;   /* default */
+
+    if (first == 1) {
+        switch (second) {
+        case 1:
+            *id = PBE_SHA1_RC4_128;
+            *version = PKCS12;
+            return 0;
+        case 3:
+            *id = PBE_SHA1_DES3;
+            *version = PKCS12;
+            return 0;
+        default:
+            return ALGO_ID_E;
+        }
+    }
+
+    if (first != PKCS5)
+        return ASN_INPUT_E;  /* VERSION ERROR */
+
+    if (second == PBES2) {
+        *version = PKCS5v2;
+        return 0;
+    }
+
+    switch (second) {
+    case 3:                   /* see RFC 2898 for ids */
+        *id = PBE_MD5_DES;
+        return 0;
+    case 10:
+        *id = PBE_SHA1_DES;
+        return 0;
+    default:
+        return ALGO_ID_E;
+
+    }
+}
+
+
+/* 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)
+{
+    switch (oid) {
+    case 69:
+        *id = PBE_SHA1_DES;
+        return 0;
+    case 652:
+        *id = PBE_SHA1_DES3;
+        return 0;
+    default:
+        return ALGO_ID_E;
+
+    }
+}
+
+
+/* Decrypt intput 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
+
+    switch (id) {
+        case PBE_MD5_DES:
+            typeH = MD5;
+            derivedLen = 16;           /* may need iv for v1.5 */
+            decryptionType = DES_TYPE;
+            break;
+
+        case PBE_SHA1_DES:
+            typeH = SHA;
+            derivedLen = 16;           /* may need iv for v1.5 */
+            decryptionType = DES_TYPE;
+            break;
+
+        case PBE_SHA1_DES3:
+            typeH = SHA;
+            derivedLen = 32;           /* may need iv for v1.5 */
+            decryptionType = DES3_TYPE;
+            break;
+
+        case PBE_SHA1_RC4_128:
+            typeH = 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 == PKCS12) {
+        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 == PKCS12)
+                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 == PKCS12)
+                desIv = cbcIv;
+            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;
+}
+
+
+/* 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    first, second, length, version, saltSz, id;
+    int    iterations = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    byte*  salt = NULL;
+    byte*  cbcIv = NULL;
+#else
+    byte   salt[MAX_SALT_SIZE];
+    byte   cbcIv[MAX_IV_SIZE];
+#endif
+    
+    if (GetSequence(input, &inOutIdx, &length, sz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetAlgoId(input, &inOutIdx, &oid, sz) < 0)
+        return ASN_PARSE_E;
+    
+    first  = input[inOutIdx - 2];   /* PKCS version alwyas 2nd to last byte */
+    second = input[inOutIdx - 1];   /* version.algo, algo id last byte */
+
+    if (CheckAlgo(first, second, &id, &version) < 0)
+        return ASN_INPUT_E;  /* Algo ID error */
+
+    if (version == PKCS5v2) {
+
+        if (GetSequence(input, &inOutIdx, &length, sz) < 0)
+            return ASN_PARSE_E;
+
+        if (GetAlgoId(input, &inOutIdx, &oid, sz) < 0)
+            return ASN_PARSE_E;
+
+        if (oid != PBKDF2_OID)
+            return ASN_PARSE_E;
+    }
+
+    if (GetSequence(input, &inOutIdx, &length, sz) < 0)
+        return ASN_PARSE_E;
+
+    if (input[inOutIdx++] != ASN_OCTET_STRING)
+        return ASN_PARSE_E;
+    
+    if (GetLength(input, &inOutIdx, &saltSz, sz) < 0)
+        return ASN_PARSE_E;
+
+    if (saltSz > MAX_SALT_SIZE)
+        return ASN_PARSE_E;
+     
+#ifdef WOLFSSL_SMALL_STACK
+    salt = (byte*)XMALLOC(MAX_SALT_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (salt == NULL)
+        return MEMORY_E;
+#endif
+
+    XMEMCPY(salt, &input[inOutIdx], saltSz);
+    inOutIdx += saltSz;
+
+    if (GetShortInt(input, &inOutIdx, &iterations) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_PARSE_E;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (cbcIv == NULL) {
+        XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    if (version == PKCS5v2) {
+        /* get encryption algo */
+        if (GetAlgoId(input, &inOutIdx, &oid, sz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ASN_PARSE_E;
+        }
+
+        if (CheckAlgoV2(oid, &id) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ASN_PARSE_E;  /* PKCS v2 algo id error */
+        }
+
+        if (input[inOutIdx++] != ASN_OCTET_STRING) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ASN_PARSE_E;
+        }
+    
+        if (GetLength(input, &inOutIdx, &length, sz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ASN_PARSE_E;
+        }
+
+        XMEMCPY(cbcIv, &input[inOutIdx], length);
+        inOutIdx += length;
+    }
+
+    if (input[inOutIdx++] != ASN_OCTET_STRING) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_PARSE_E;
+    }
+
+    if (GetLength(input, &inOutIdx, &length, sz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_PARSE_E;
+    }
+
+    if (DecryptKey(password, passwordSz, salt, saltSz, iterations, id,
+                   input + inOutIdx, length, version, cbcIv) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_INPUT_E;  /* decrypt failure */
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    XMEMMOVE(input, input + inOutIdx, length);
+    return ToTraditional(input, length);
+}
+
+#endif /* NO_PWDBASED */
+
+#ifndef NO_RSA
+
+int wc_RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
+                       word32 inSz)
+{
+    int    length;
+
+    if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+        return ASN_PARSE_E;
+
+    key->type = RSA_PUBLIC;
+
+#if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
+    {
+    byte b = input[*inOutIdx];
+    if (b != ASN_INTEGER) {
+        /* not from decoded cert, will have algo id, skip past */
+        if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+            return ASN_PARSE_E;
+        
+        b = input[(*inOutIdx)++];
+        if (b != ASN_OBJECT_ID) 
+            return ASN_OBJECT_ID_E;
+        
+        if (GetLength(input, inOutIdx, &length, inSz) < 0)
+            return ASN_PARSE_E;
+        
+        *inOutIdx += length;   /* skip past */
+        
+        /* could have NULL tag and 0 terminator, but may not */
+        b = input[(*inOutIdx)++];
+        
+        if (b == ASN_TAG_NULL) {
+            b = input[(*inOutIdx)++];
+            if (b != 0) 
+                return ASN_EXPECT_0_E;
+        }
+        else
+        /* go back, didn't have it */
+            (*inOutIdx)--;
+        
+        /* should have bit tag length and seq next */
+        b = input[(*inOutIdx)++];
+        if (b != ASN_BIT_STRING)
+            return ASN_BITSTR_E;
+        
+        if (GetLength(input, inOutIdx, &length, inSz) < 0)
+            return ASN_PARSE_E;
+        
+        /* could have 0 */
+        b = input[(*inOutIdx)++];
+        if (b != 0)
+            (*inOutIdx)--;
+        
+        if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+            return ASN_PARSE_E;
+    }  /* end if */
+    }  /* openssl var block */
+#endif /* OPENSSL_EXTRA */
+
+    if (GetInt(&key->n,  input, inOutIdx, inSz) < 0 ||
+        GetInt(&key->e,  input, inOutIdx, inSz) < 0 )  return ASN_RSA_KEY_E;
+
+    return 0;
+}
+
+/* import RSA public key elements (n, e) into RsaKey structure (key) */
+int wc_RsaPublicKeyDecodeRaw(const byte* n, word32 nSz, const byte* e,
+                             word32 eSz, RsaKey* key)
+{
+    if (n == NULL || e == NULL || key == NULL)
+        return BAD_FUNC_ARG;
+
+    key->type = RSA_PUBLIC;
+
+    if (mp_init(&key->n) != MP_OKAY)
+        return MP_INIT_E;
+
+    if (mp_read_unsigned_bin(&key->n, n, nSz) != 0) {
+        mp_clear(&key->n);
+        return ASN_GETINT_E;
+    }
+
+    if (mp_init(&key->e) != MP_OKAY) {
+        mp_clear(&key->n);
+        return MP_INIT_E;
+    }
+
+    if (mp_read_unsigned_bin(&key->e, e, eSz) != 0) {
+        mp_clear(&key->n);
+        mp_clear(&key->e);
+        return ASN_GETINT_E;
+    }
+
+    return 0;
+}
+
+#endif
+
+#ifndef NO_DH
+
+int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz)
+{
+    int    length;
+
+    if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetInt(&key->p,  input, inOutIdx, inSz) < 0 ||
+        GetInt(&key->g,  input, inOutIdx, inSz) < 0 )  return ASN_DH_KEY_E;
+
+    return 0;
+}
+
+
+int wc_DhParamsLoad(const byte* input, word32 inSz, byte* p, word32* pInOutSz,
+                 byte* g, word32* gInOutSz)
+{
+    word32 i = 0;
+    byte   b;
+    int    length;
+
+    if (GetSequence(input, &i, &length, inSz) < 0)
+        return ASN_PARSE_E;
+
+    b = input[i++];
+    if (b != ASN_INTEGER)
+        return ASN_PARSE_E;
+
+    if (GetLength(input, &i, &length, inSz) < 0)
+        return ASN_PARSE_E;
+
+    if ( (b = input[i++]) == 0x00)
+        length--;
+    else
+        i--;
+
+    if (length <= (int)*pInOutSz) {
+        XMEMCPY(p, &input[i], length);
+        *pInOutSz = length;
+    }
+    else
+        return BUFFER_E;
+
+    i += length;
+
+    b = input[i++];
+    if (b != ASN_INTEGER)
+        return ASN_PARSE_E;
+
+    if (GetLength(input, &i, &length, inSz) < 0)
+        return ASN_PARSE_E;
+
+    if (length <= (int)*gInOutSz) {
+        XMEMCPY(g, &input[i], length);
+        *gInOutSz = length;
+    }
+    else
+        return BUFFER_E;
+
+    return 0;
+}
+
+#endif /* NO_DH */
+
+
+#ifndef NO_DSA
+
+int DsaPublicKeyDecode(const byte* input, word32* inOutIdx, DsaKey* key,
+                        word32 inSz)
+{
+    int    length;
+
+    if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetInt(&key->p,  input, inOutIdx, inSz) < 0 ||
+        GetInt(&key->q,  input, inOutIdx, inSz) < 0 ||
+        GetInt(&key->g,  input, inOutIdx, inSz) < 0 ||
+        GetInt(&key->y,  input, inOutIdx, inSz) < 0 )  return ASN_DH_KEY_E;
+
+    key->type = DSA_PUBLIC;
+    return 0;
+}
+
+
+int DsaPrivateKeyDecode(const byte* input, word32* inOutIdx, DsaKey* key,
+                        word32 inSz)
+{
+    int    length, version;
+
+    if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetMyVersion(input, inOutIdx, &version) < 0)
+        return ASN_PARSE_E;
+
+    if (GetInt(&key->p,  input, inOutIdx, inSz) < 0 ||
+        GetInt(&key->q,  input, inOutIdx, inSz) < 0 ||
+        GetInt(&key->g,  input, inOutIdx, inSz) < 0 ||
+        GetInt(&key->y,  input, inOutIdx, inSz) < 0 ||
+        GetInt(&key->x,  input, inOutIdx, inSz) < 0 )  return ASN_DH_KEY_E;
+
+    key->type = DSA_PRIVATE;
+    return 0;
+}
+
+#endif /* NO_DSA */
+
+
+void InitDecodedCert(DecodedCert* cert, byte* source, word32 inSz, void* heap)
+{
+    cert->publicKey       = 0;
+    cert->pubKeySize      = 0;
+    cert->pubKeyStored    = 0;
+    cert->version         = 0;
+    cert->signature       = 0;
+    cert->subjectCN       = 0;
+    cert->subjectCNLen    = 0;
+    cert->subjectCNEnc    = CTC_UTF8;
+    cert->subjectCNStored = 0;
+    cert->weOwnAltNames   = 0;
+    cert->altNames        = NULL;
+#ifndef IGNORE_NAME_CONSTRAINTS
+    cert->altEmailNames   = NULL;
+    cert->permittedNames  = NULL;
+    cert->excludedNames   = NULL;
+#endif /* IGNORE_NAME_CONSTRAINTS */
+    cert->issuer[0]       = '\0';
+    cert->subject[0]      = '\0';
+    cert->source          = source;  /* don't own */
+    cert->srcIdx          = 0;
+    cert->maxIdx          = inSz;    /* can't go over this index */
+    cert->heap            = heap;
+    XMEMSET(cert->serial, 0, EXTERNAL_SERIAL_SIZE);
+    cert->serialSz        = 0;
+    cert->extensions      = 0;
+    cert->extensionsSz    = 0;
+    cert->extensionsIdx   = 0;
+    cert->extAuthInfo     = NULL;
+    cert->extAuthInfoSz   = 0;
+    cert->extCrlInfo      = NULL;
+    cert->extCrlInfoSz    = 0;
+    XMEMSET(cert->extSubjKeyId, 0, KEYID_SIZE);
+    cert->extSubjKeyIdSet = 0;
+    XMEMSET(cert->extAuthKeyId, 0, KEYID_SIZE);
+    cert->extAuthKeyIdSet = 0;
+    cert->extKeyUsageSet  = 0;
+    cert->extKeyUsage     = 0;
+    cert->extExtKeyUsageSet = 0;
+    cert->extExtKeyUsage    = 0;
+    cert->isCA            = 0;
+#ifdef HAVE_PKCS7
+    cert->issuerRaw       = NULL;
+    cert->issuerRawLen    = 0;
+#endif
+#ifdef WOLFSSL_CERT_GEN
+    cert->subjectSN       = 0;
+    cert->subjectSNLen    = 0;
+    cert->subjectSNEnc    = CTC_UTF8;
+    cert->subjectC        = 0;
+    cert->subjectCLen     = 0;
+    cert->subjectCEnc     = CTC_PRINTABLE;
+    cert->subjectL        = 0;
+    cert->subjectLLen     = 0;
+    cert->subjectLEnc     = CTC_UTF8;
+    cert->subjectST       = 0;
+    cert->subjectSTLen    = 0;
+    cert->subjectSTEnc    = CTC_UTF8;
+    cert->subjectO        = 0;
+    cert->subjectOLen     = 0;
+    cert->subjectOEnc     = CTC_UTF8;
+    cert->subjectOU       = 0;
+    cert->subjectOULen    = 0;
+    cert->subjectOUEnc    = CTC_UTF8;
+    cert->subjectEmail    = 0;
+    cert->subjectEmailLen = 0;
+#endif /* WOLFSSL_CERT_GEN */
+    cert->beforeDate      = NULL;
+    cert->beforeDateLen   = 0;
+    cert->afterDate       = NULL;
+    cert->afterDateLen    = 0;
+#ifdef OPENSSL_EXTRA
+    XMEMSET(&cert->issuerName, 0, sizeof(DecodedName));
+    XMEMSET(&cert->subjectName, 0, sizeof(DecodedName));
+    cert->extBasicConstSet = 0;
+    cert->extBasicConstCrit = 0;
+    cert->extBasicConstPlSet = 0;
+    cert->pathLength = 0;
+    cert->extSubjAltNameSet = 0;
+    cert->extSubjAltNameCrit = 0;
+    cert->extAuthKeyIdCrit = 0;
+    cert->extSubjKeyIdCrit = 0;
+    cert->extKeyUsageCrit = 0;
+    cert->extExtKeyUsageCrit = 0;
+    cert->extExtKeyUsageSrc = NULL;
+    cert->extExtKeyUsageSz = 0;
+    cert->extExtKeyUsageCount = 0;
+    cert->extAuthKeyIdSrc = NULL;
+    cert->extAuthKeyIdSz = 0;
+    cert->extSubjKeyIdSrc = NULL;
+    cert->extSubjKeyIdSz = 0;
+#endif /* OPENSSL_EXTRA */
+#if defined(OPENSSL_EXTRA) || !defined(IGNORE_NAME_CONSTRAINTS)
+    cert->extNameConstraintSet = 0;
+#endif /* OPENSSL_EXTRA || !IGNORE_NAME_CONSTRAINTS */
+#ifdef HAVE_ECC
+    cert->pkCurveOID = 0;
+#endif /* HAVE_ECC */
+#ifdef WOLFSSL_SEP
+    cert->deviceTypeSz = 0;
+    cert->deviceType = NULL;
+    cert->hwTypeSz = 0;
+    cert->hwType = NULL;
+    cert->hwSerialNumSz = 0;
+    cert->hwSerialNum = NULL;
+    #ifdef OPENSSL_EXTRA
+        cert->extCertPolicySet = 0;
+        cert->extCertPolicyCrit = 0;
+    #endif /* OPENSSL_EXTRA */
+#endif /* WOLFSSL_SEP */
+}
+
+
+void FreeAltNames(DNS_entry* altNames, void* heap)
+{
+    (void)heap;
+
+    while (altNames) {
+        DNS_entry* tmp = altNames->next;
+
+        XFREE(altNames->name, heap, DYNAMIC_TYPE_ALTNAME);
+        XFREE(altNames,       heap, DYNAMIC_TYPE_ALTNAME);
+        altNames = tmp;
+    }
+}
+
+#ifndef IGNORE_NAME_CONSTRAINTS
+
+void FreeNameSubtrees(Base_entry* names, void* heap)
+{
+    (void)heap;
+
+    while (names) {
+        Base_entry* tmp = names->next;
+
+        XFREE(names->name, heap, DYNAMIC_TYPE_ALTNAME);
+        XFREE(names,       heap, DYNAMIC_TYPE_ALTNAME);
+        names = tmp;
+    }
+}
+
+#endif /* IGNORE_NAME_CONSTRAINTS */
+
+void FreeDecodedCert(DecodedCert* cert)
+{
+    if (cert->subjectCNStored == 1)
+        XFREE(cert->subjectCN, cert->heap, DYNAMIC_TYPE_SUBJECT_CN);
+    if (cert->pubKeyStored == 1)
+        XFREE(cert->publicKey, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    if (cert->weOwnAltNames && cert->altNames)
+        FreeAltNames(cert->altNames, cert->heap);
+#ifndef IGNORE_NAME_CONSTRAINTS
+    if (cert->altEmailNames)
+        FreeAltNames(cert->altEmailNames, cert->heap);
+    if (cert->permittedNames)
+        FreeNameSubtrees(cert->permittedNames, cert->heap);
+    if (cert->excludedNames)
+        FreeNameSubtrees(cert->excludedNames, cert->heap);
+#endif /* IGNORE_NAME_CONSTRAINTS */
+#ifdef WOLFSSL_SEP
+    XFREE(cert->deviceType, cert->heap, 0);
+    XFREE(cert->hwType, cert->heap, 0);
+    XFREE(cert->hwSerialNum, cert->heap, 0);
+#endif /* WOLFSSL_SEP */
+#ifdef OPENSSL_EXTRA
+    if (cert->issuerName.fullName != NULL)
+        XFREE(cert->issuerName.fullName, NULL, DYNAMIC_TYPE_X509);
+    if (cert->subjectName.fullName != NULL)
+        XFREE(cert->subjectName.fullName, NULL, DYNAMIC_TYPE_X509);
+#endif /* OPENSSL_EXTRA */
+}
+
+
+static int GetCertHeader(DecodedCert* cert)
+{
+    int ret = 0, len;
+    byte serialTmp[EXTERNAL_SERIAL_SIZE];
+#if defined(WOLFSSL_SMALL_STACK) && defined(USE_FAST_MATH)
+    mp_int* mpi = NULL;
+#else
+    mp_int stack_mpi;
+    mp_int* mpi = &stack_mpi;
+#endif
+
+    if (GetSequence(cert->source, &cert->srcIdx, &len, cert->maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    cert->certBegin = cert->srcIdx;
+
+    if (GetSequence(cert->source, &cert->srcIdx, &len, cert->maxIdx) < 0)
+        return ASN_PARSE_E;
+    cert->sigIndex = len + cert->srcIdx;
+
+    if (GetExplicitVersion(cert->source, &cert->srcIdx, &cert->version) < 0)
+        return ASN_PARSE_E;
+
+#if defined(WOLFSSL_SMALL_STACK) && defined(USE_FAST_MATH)
+    mpi = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (mpi == NULL)
+        return MEMORY_E;
+#endif
+
+    if (GetInt(mpi, cert->source, &cert->srcIdx, cert->maxIdx) < 0) {
+#if defined(WOLFSSL_SMALL_STACK) && defined(USE_FAST_MATH)
+        XFREE(mpi, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_PARSE_E;
+    }
+
+    len = mp_unsigned_bin_size(mpi);
+    if (len < (int)sizeof(serialTmp)) {
+        if ( (ret = mp_to_unsigned_bin(mpi, serialTmp)) == MP_OKAY) {
+            XMEMCPY(cert->serial, serialTmp, len);
+            cert->serialSz = len;
+        }
+    }
+    mp_clear(mpi);
+
+#if defined(WOLFSSL_SMALL_STACK) && defined(USE_FAST_MATH)
+    XFREE(mpi, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+#if !defined(NO_RSA)
+/* Store Rsa Key, may save later, Dsa could use in future */
+static int StoreRsaKey(DecodedCert* cert)
+{
+    int    length;
+    word32 recvd = cert->srcIdx;
+
+    if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0)
+        return ASN_PARSE_E;
+   
+    recvd = cert->srcIdx - recvd;
+    length += recvd;
+
+    while (recvd--)
+       cert->srcIdx--;
+
+    cert->pubKeySize = length;
+    cert->publicKey = cert->source + cert->srcIdx;
+    cert->srcIdx += length;
+
+    return 0;
+}
+#endif
+
+
+#ifdef HAVE_ECC
+
+    /* return 0 on sucess if the ECC curve oid sum is supported */
+    static int CheckCurve(word32 oid)
+    {
+        int ret = 0;
+
+        switch (oid) {
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC160)
+            case ECC_160R1:
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC192)
+            case ECC_192R1:
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC224)
+            case ECC_224R1:
+#endif
+#if defined(HAVE_ALL_CURVES) || !defined(NO_ECC256)
+            case ECC_256R1:
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC384)
+            case ECC_384R1:
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC521)
+            case ECC_521R1:
+#endif
+                break;
+
+            default:
+                ret = ALGO_ID_E;
+        }
+
+        return ret;
+    }
+
+#endif /* HAVE_ECC */
+
+
+static int GetKey(DecodedCert* cert)
+{
+    int length;
+#ifdef HAVE_NTRU
+    int tmpIdx = cert->srcIdx;
+#endif
+
+    if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0)
+        return ASN_PARSE_E;
+   
+    if (GetAlgoId(cert->source, &cert->srcIdx, &cert->keyOID, cert->maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    switch (cert->keyOID) {
+   #ifndef NO_RSA
+        case RSAk:
+        {
+            byte b = cert->source[cert->srcIdx++];
+            if (b != ASN_BIT_STRING)
+                return ASN_BITSTR_E;
+
+            if (GetLength(cert->source,&cert->srcIdx,&length,cert->maxIdx) < 0)
+                return ASN_PARSE_E;
+            b = cert->source[cert->srcIdx++];
+            if (b != 0x00)
+                return ASN_EXPECT_0_E;
+    
+            return StoreRsaKey(cert);
+        }
+
+    #endif /* NO_RSA */
+    #ifdef HAVE_NTRU
+        case NTRUk:
+        {
+            const byte* key = &cert->source[tmpIdx];
+            byte*       next = (byte*)key;
+            word16      keyLen;
+            word32      rc;
+            word32      remaining = cert->maxIdx - cert->srcIdx;
+#ifdef WOLFSSL_SMALL_STACK
+            byte*       keyBlob = NULL;
+#else
+            byte        keyBlob[MAX_NTRU_KEY_SZ];
+#endif
+            rc = ntru_crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey(key,
+                                &keyLen, NULL, &next, &remaining);
+            if (rc != NTRU_OK)
+                return ASN_NTRU_KEY_E;
+            if (keyLen > MAX_NTRU_KEY_SZ)
+                return ASN_NTRU_KEY_E;
+
+#ifdef WOLFSSL_SMALL_STACK
+            keyBlob = (byte*)XMALLOC(MAX_NTRU_KEY_SZ, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            if (keyBlob == NULL)
+                return MEMORY_E;
+#endif
+
+            rc = ntru_crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey(key,
+                                &keyLen, keyBlob, &next, &remaining);
+            if (rc != NTRU_OK) {
+#ifdef WOLFSSL_SMALL_STACK
+                XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+                return ASN_NTRU_KEY_E;
+            }
+
+            if ( (next - key) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+                XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+                return ASN_NTRU_KEY_E;
+            }
+
+            cert->srcIdx = tmpIdx + (int)(next - key);
+
+            cert->publicKey = (byte*) XMALLOC(keyLen, cert->heap,
+                                              DYNAMIC_TYPE_PUBLIC_KEY);
+            if (cert->publicKey == NULL) {
+#ifdef WOLFSSL_SMALL_STACK
+                XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+                return MEMORY_E;
+            }
+            XMEMCPY(cert->publicKey, keyBlob, keyLen);
+            cert->pubKeyStored = 1;
+            cert->pubKeySize   = keyLen;
+
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(keyBlob, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+            return 0;
+        }
+    #endif /* HAVE_NTRU */
+    #ifdef HAVE_ECC
+        case ECDSAk:
+        {
+            int    oidSz = 0;
+            byte   b = cert->source[cert->srcIdx++];
+        
+            if (b != ASN_OBJECT_ID) 
+                return ASN_OBJECT_ID_E;
+
+            if (GetLength(cert->source,&cert->srcIdx,&oidSz,cert->maxIdx) < 0)
+                return ASN_PARSE_E;
+
+            while(oidSz--)
+                cert->pkCurveOID += cert->source[cert->srcIdx++];
+
+            if (CheckCurve(cert->pkCurveOID) < 0)
+                return ECC_CURVE_OID_E;
+
+            /* key header */
+            b = cert->source[cert->srcIdx++];
+            if (b != ASN_BIT_STRING)
+                return ASN_BITSTR_E;
+
+            if (GetLength(cert->source,&cert->srcIdx,&length,cert->maxIdx) < 0)
+                return ASN_PARSE_E;
+            b = cert->source[cert->srcIdx++];
+            if (b != 0x00)
+                return ASN_EXPECT_0_E;
+
+            /* actual key, use length - 1 since ate preceding 0 */
+            length -= 1;
+
+            cert->publicKey = (byte*) XMALLOC(length, cert->heap,
+                                              DYNAMIC_TYPE_PUBLIC_KEY);
+            if (cert->publicKey == NULL)
+                return MEMORY_E;
+            XMEMCPY(cert->publicKey, &cert->source[cert->srcIdx], length);
+            cert->pubKeyStored = 1;
+            cert->pubKeySize   = length;
+
+            cert->srcIdx += length;
+
+            return 0;
+        }
+    #endif /* HAVE_ECC */
+        default:
+            return ASN_UNKNOWN_OID_E;
+    }
+}
+
+
+/* process NAME, either issuer or subject */
+static int GetName(DecodedCert* cert, int nameType)
+{
+    int    length;  /* length of all distinguished names */
+    int    dummy;
+    int    ret;
+    char*  full;
+    byte*  hash;
+    word32 idx;
+    #ifdef OPENSSL_EXTRA
+        DecodedName* dName =
+                  (nameType == ISSUER) ? &cert->issuerName : &cert->subjectName;
+    #endif /* OPENSSL_EXTRA */
+
+    WOLFSSL_MSG("Getting Cert Name");
+
+    if (nameType == ISSUER) {
+        full = cert->issuer;
+        hash = cert->issuerHash;
+    }
+    else {
+        full = cert->subject;
+        hash = cert->subjectHash;
+    }
+
+    if (cert->source[cert->srcIdx] == ASN_OBJECT_ID) {
+        WOLFSSL_MSG("Trying optional prefix...");
+
+        if (GetLength(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0)
+            return ASN_PARSE_E;
+
+        cert->srcIdx += length;
+        WOLFSSL_MSG("Got optional prefix");
+    }
+
+    /* For OCSP, RFC2560 section 4.1.1 states the issuer hash should be
+     * calculated over the entire DER encoding of the Name field, including
+     * the tag and length. */
+    idx = cert->srcIdx;
+    if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0)
+        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
+    if (ret != 0)
+        return ret;
+
+    length += cert->srcIdx;
+    idx = 0;
+
+#ifdef HAVE_PKCS7
+    /* store pointer to raw issuer */
+    if (nameType == ISSUER) {
+        cert->issuerRaw = &cert->source[cert->srcIdx];
+        cert->issuerRawLen = length - cert->srcIdx;
+    }
+#endif
+#ifndef IGNORE_NAME_CONSTRAINTS
+    if (nameType == SUBJECT) {
+        cert->subjectRaw = &cert->source[cert->srcIdx];
+        cert->subjectRawLen = length - cert->srcIdx;
+    }
+#endif
+
+    while (cert->srcIdx < (word32)length) {
+        byte   b;
+        byte   joint[2];
+        byte   tooBig = FALSE;
+        int    oidSz;
+
+        if (GetSet(cert->source, &cert->srcIdx, &dummy, cert->maxIdx) < 0) {
+            WOLFSSL_MSG("Cert name lacks set header, trying sequence");
+        }
+
+        if (GetSequence(cert->source, &cert->srcIdx, &dummy, cert->maxIdx) < 0)
+            return ASN_PARSE_E;
+
+        b = cert->source[cert->srcIdx++];
+        if (b != ASN_OBJECT_ID) 
+            return ASN_OBJECT_ID_E;
+
+        if (GetLength(cert->source, &cert->srcIdx, &oidSz, cert->maxIdx) < 0)
+            return ASN_PARSE_E;
+
+        XMEMCPY(joint, &cert->source[cert->srcIdx], sizeof(joint));
+
+        /* v1 name types */
+        if (joint[0] == 0x55 && joint[1] == 0x04) {
+            byte   id;
+            byte   copy = FALSE;
+            int    strLen;
+
+            cert->srcIdx += 2;
+            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 + 14) > (int)(ASN_NAME_MAX - idx)) {
+                /* include biggest pre fix header too 4 = "/serialNumber=" */
+                WOLFSSL_MSG("ASN Name too big, skipping");
+                tooBig = TRUE;
+            }
+
+            if (id == ASN_COMMON_NAME) {
+                if (nameType == SUBJECT) {
+                    cert->subjectCN = (char *)&cert->source[cert->srcIdx];
+                    cert->subjectCNLen = strLen;
+                    cert->subjectCNEnc = b;
+                }
+
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/CN=", 4);
+                    idx += 4;
+                    copy = TRUE;
+                }
+                #ifdef OPENSSL_EXTRA
+                    dName->cnIdx = cert->srcIdx;
+                    dName->cnLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+            else if (id == ASN_SUR_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/SN=", 4);
+                    idx += 4;
+                    copy = TRUE;
+                }
+                #ifdef WOLFSSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectSN = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectSNLen = strLen;
+                        cert->subjectSNEnc = b;
+                    }
+                #endif /* WOLFSSL_CERT_GEN */
+                #ifdef OPENSSL_EXTRA
+                    dName->snIdx = cert->srcIdx;
+                    dName->snLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+            else if (id == ASN_COUNTRY_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/C=", 3);
+                    idx += 3;
+                    copy = TRUE;
+                }
+                #ifdef WOLFSSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectC = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectCLen = strLen;
+                        cert->subjectCEnc = b;
+                    }
+                #endif /* WOLFSSL_CERT_GEN */
+                #ifdef OPENSSL_EXTRA
+                    dName->cIdx = cert->srcIdx;
+                    dName->cLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+            else if (id == ASN_LOCALITY_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/L=", 3);
+                    idx += 3;
+                    copy = TRUE;
+                }
+                #ifdef WOLFSSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectL = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectLLen = strLen;
+                        cert->subjectLEnc = b;
+                    }
+                #endif /* WOLFSSL_CERT_GEN */
+                #ifdef OPENSSL_EXTRA
+                    dName->lIdx = cert->srcIdx;
+                    dName->lLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+            else if (id == ASN_STATE_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/ST=", 4);
+                    idx += 4;
+                    copy = TRUE;
+                }
+                #ifdef WOLFSSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectST = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectSTLen = strLen;
+                        cert->subjectSTEnc = b;
+                    }
+                #endif /* WOLFSSL_CERT_GEN */
+                #ifdef OPENSSL_EXTRA
+                    dName->stIdx = cert->srcIdx;
+                    dName->stLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+            else if (id == ASN_ORG_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/O=", 3);
+                    idx += 3;
+                    copy = TRUE;
+                }
+                #ifdef WOLFSSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectO = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectOLen = strLen;
+                        cert->subjectOEnc = b;
+                    }
+                #endif /* WOLFSSL_CERT_GEN */
+                #ifdef OPENSSL_EXTRA
+                    dName->oIdx = cert->srcIdx;
+                    dName->oLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+            else if (id == ASN_ORGUNIT_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/OU=", 4);
+                    idx += 4;
+                    copy = TRUE;
+                }
+                #ifdef WOLFSSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectOU = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectOULen = strLen;
+                        cert->subjectOUEnc = b;
+                    }
+                #endif /* WOLFSSL_CERT_GEN */
+                #ifdef OPENSSL_EXTRA
+                    dName->ouIdx = cert->srcIdx;
+                    dName->ouLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+            else if (id == ASN_SERIAL_NUMBER) {
+                if (!tooBig) {
+                   XMEMCPY(&full[idx], "/serialNumber=", 14);
+                   idx += 14;
+                   copy = TRUE;
+                }
+                #ifdef OPENSSL_EXTRA
+                    dName->snIdx = cert->srcIdx;
+                    dName->snLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+
+            if (copy && !tooBig) {
+                XMEMCPY(&full[idx], &cert->source[cert->srcIdx], strLen);
+                idx += strLen;
+            }
+
+            cert->srcIdx += strLen;
+        }
+        else {
+            /* skip */
+            byte email = FALSE;
+            byte uid   = FALSE;
+            int  adv;
+
+            if (joint[0] == 0x2a && joint[1] == 0x86)  /* email id hdr */
+                email = TRUE;
+
+            if (joint[0] == 0x9  && joint[1] == 0x92)  /* uid id hdr */
+                uid = TRUE;
+
+            cert->srcIdx += oidSz + 1;
+
+            if (GetLength(cert->source, &cert->srcIdx, &adv, cert->maxIdx) < 0)
+                return ASN_PARSE_E;
+
+            if (adv > (int)(ASN_NAME_MAX - idx)) {
+                WOLFSSL_MSG("ASN name too big, skipping");
+                tooBig = TRUE;
+            }
+
+            if (email) {
+                if ( (14 + adv) > (int)(ASN_NAME_MAX - idx)) {
+                    WOLFSSL_MSG("ASN name too big, skipping");
+                    tooBig = TRUE;
+                }
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/emailAddress=", 14);
+                    idx += 14;
+                }
+
+                #ifdef WOLFSSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectEmail = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectEmailLen = adv;
+                    }
+                #endif /* WOLFSSL_CERT_GEN */
+                #ifdef OPENSSL_EXTRA
+                    dName->emailIdx = cert->srcIdx;
+                    dName->emailLen = adv;
+                #endif /* OPENSSL_EXTRA */
+                #ifndef IGNORE_NAME_CONSTRAINTS
+                    {
+                        DNS_entry* emailName = NULL;
+
+                        emailName = (DNS_entry*)XMALLOC(sizeof(DNS_entry),
+                                              cert->heap, DYNAMIC_TYPE_ALTNAME);
+                        if (emailName == NULL) {
+                            WOLFSSL_MSG("\tOut of Memory");
+                            return MEMORY_E;
+                        }
+                        emailName->name = (char*)XMALLOC(adv + 1,
+                                              cert->heap, DYNAMIC_TYPE_ALTNAME);
+                        if (emailName->name == NULL) {
+                            WOLFSSL_MSG("\tOut of Memory");
+                            return MEMORY_E;
+                        }
+                        XMEMCPY(emailName->name,
+                                              &cert->source[cert->srcIdx], adv);
+                        emailName->name[adv] = 0;
+
+                        emailName->next = cert->altEmailNames;
+                        cert->altEmailNames = emailName;
+                    }
+                #endif /* IGNORE_NAME_CONSTRAINTS */
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], &cert->source[cert->srcIdx], adv);
+                    idx += adv;
+                }
+            }
+
+            if (uid) {
+                if ( (5 + adv) > (int)(ASN_NAME_MAX - idx)) {
+                    WOLFSSL_MSG("ASN name too big, skipping");
+                    tooBig = TRUE;
+                }
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/UID=", 5);
+                    idx += 5;
+
+                    XMEMCPY(&full[idx], &cert->source[cert->srcIdx], adv);
+                    idx += adv;
+                }
+                #ifdef OPENSSL_EXTRA
+                    dName->uidIdx = cert->srcIdx;
+                    dName->uidLen = adv;
+                #endif /* OPENSSL_EXTRA */
+            }
+
+            cert->srcIdx += adv;
+        }
+    }
+    full[idx++] = 0;
+
+    #ifdef OPENSSL_EXTRA
+    {
+        int totalLen = 0;
+
+        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;
+
+        dName->fullName = (char*)XMALLOC(totalLen + 1, NULL, DYNAMIC_TYPE_X509);
+        if (dName->fullName != NULL) {
+            idx = 0;
+
+            if (dName->cnLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/CN=", 4);
+                idx += 4;
+                XMEMCPY(&dName->fullName[idx],
+                                     &cert->source[dName->cnIdx], dName->cnLen);
+                dName->cnIdx = idx;
+                idx += dName->cnLen;
+            }
+            if (dName->snLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/SN=", 4);
+                idx += 4;
+                XMEMCPY(&dName->fullName[idx],
+                                     &cert->source[dName->snIdx], dName->snLen);
+                dName->snIdx = idx;
+                idx += dName->snLen;
+            }
+            if (dName->cLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/C=", 3);
+                idx += 3;
+                XMEMCPY(&dName->fullName[idx],
+                                       &cert->source[dName->cIdx], dName->cLen);
+                dName->cIdx = idx;
+                idx += dName->cLen;
+            }
+            if (dName->lLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/L=", 3);
+                idx += 3;
+                XMEMCPY(&dName->fullName[idx],
+                                       &cert->source[dName->lIdx], dName->lLen);
+                dName->lIdx = idx;
+                idx += dName->lLen;
+            }
+            if (dName->stLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/ST=", 4);
+                idx += 4;
+                XMEMCPY(&dName->fullName[idx],
+                                     &cert->source[dName->stIdx], dName->stLen);
+                dName->stIdx = idx;
+                idx += dName->stLen;
+            }
+            if (dName->oLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/O=", 3);
+                idx += 3;
+                XMEMCPY(&dName->fullName[idx],
+                                       &cert->source[dName->oIdx], dName->oLen);
+                dName->oIdx = idx;
+                idx += dName->oLen;
+            }
+            if (dName->ouLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/OU=", 4);
+                idx += 4;
+                XMEMCPY(&dName->fullName[idx],
+                                     &cert->source[dName->ouIdx], dName->ouLen);
+                dName->ouIdx = idx;
+                idx += dName->ouLen;
+            }
+            if (dName->emailLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/emailAddress=", 14);
+                idx += 14;
+                XMEMCPY(&dName->fullName[idx],
+                               &cert->source[dName->emailIdx], dName->emailLen);
+                dName->emailIdx = idx;
+                idx += dName->emailLen;
+            }
+            if (dName->uidLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/UID=", 5);
+                idx += 5;
+                XMEMCPY(&dName->fullName[idx],
+                                   &cert->source[dName->uidIdx], dName->uidLen);
+                dName->uidIdx = idx;
+                idx += dName->uidLen;
+            }
+            if (dName->serialLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/serialNumber=", 14);
+                idx += 14;
+                XMEMCPY(&dName->fullName[idx],
+                             &cert->source[dName->serialIdx], dName->serialLen);
+                dName->serialIdx = idx;
+                idx += dName->serialLen;
+            }
+            dName->fullName[idx] = '\0';
+            dName->fullNameLen = totalLen;
+        }
+    }
+    #endif /* OPENSSL_EXTRA */
+
+    return 0;
+}
+
+
+#ifndef NO_TIME_H
+
+/* 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);
+}
+
+
+/* like atoi but only use first byte */
+/* Make sure before and after dates are valid */
+int ValidateDate(const byte* date, byte format, int dateType)
+{
+    time_t ltime;
+    struct tm  certTime;
+    struct tm* localTime;
+    struct tm* tmpTime = NULL;
+    int    i = 0;
+
+#if defined(FREESCALE_MQX) || defined(TIME_OVERRIDES)
+    struct tm tmpTimeStorage;
+    tmpTime = &tmpTimeStorage;
+#else
+    (void)tmpTime;
+#endif
+
+    ltime = XTIME(0);
+    XMEMSET(&certTime, 0, sizeof(certTime));
+
+    if (format == ASN_UTC_TIME) {
+        if (btoi(date[0]) >= 5)
+            certTime.tm_year = 1900;
+        else
+            certTime.tm_year = 2000;
+    }
+    else  { /* format == GENERALIZED_TIME */
+        certTime.tm_year += btoi(date[i++]) * 1000;
+        certTime.tm_year += btoi(date[i++]) * 100;
+    }
+
+    /* adjust tm_year, tm_mon */
+    GetTime((int*)&certTime.tm_year, date, &i); certTime.tm_year -= 1900;
+    GetTime((int*)&certTime.tm_mon,  date, &i); certTime.tm_mon  -= 1;
+    GetTime((int*)&certTime.tm_mday, date, &i);
+    GetTime((int*)&certTime.tm_hour, date, &i);
+    GetTime((int*)&certTime.tm_min,  date, &i);
+    GetTime((int*)&certTime.tm_sec,  date, &i);
+
+        if (date[i] != 'Z') {     /* only Zulu supported for this profile */
+        WOLFSSL_MSG("Only Zulu time supported for this profile");
+        return 0;
+    }
+
+    localTime = XGMTIME(&ltime, tmpTime);
+
+    if (dateType == BEFORE) {
+        if (DateLessThan(localTime, &certTime))
+            return 0;
+    }
+    else
+        if (DateGreaterThan(localTime, &certTime))
+            return 0;
+
+    return 1;
+}
+
+#endif /* NO_TIME_H */
+
+
+static int GetDate(DecodedCert* cert, int dateType)
+{
+    int    length;
+    byte   date[MAX_DATE_SIZE];
+    byte   b;
+    word32 startIdx = 0;
+
+    if (dateType == BEFORE)
+        cert->beforeDate = &cert->source[cert->srcIdx];
+    else
+        cert->afterDate = &cert->source[cert->srcIdx];
+    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;
+
+    if (dateType == BEFORE)
+        cert->beforeDateLen = cert->srcIdx - startIdx;
+    else
+        cert->afterDateLen  = cert->srcIdx - startIdx;
+
+    if (!XVALIDATE_DATE(date, b, dateType)) {
+        if (dateType == BEFORE)
+            return ASN_BEFORE_DATE_E;
+        else
+            return ASN_AFTER_DATE_E;
+    }
+
+    return 0;
+}
+
+
+static int GetValidity(DecodedCert* cert, int verify)
+{
+    int length;
+    int badDate = 0;
+
+    if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    if (GetDate(cert, BEFORE) < 0 && verify)
+        badDate = ASN_BEFORE_DATE_E;           /* continue parsing */
+    
+    if (GetDate(cert, AFTER) < 0 && verify)
+        return ASN_AFTER_DATE_E;
+   
+    if (badDate != 0)
+        return badDate;
+
+    return 0;
+}
+
+
+int DecodeToKey(DecodedCert* cert, int verify)
+{
+    int badDate = 0;
+    int ret;
+
+    if ( (ret = GetCertHeader(cert)) < 0)
+        return ret;
+
+    WOLFSSL_MSG("Got Cert Header");
+
+    if ( (ret = GetAlgoId(cert->source, &cert->srcIdx, &cert->signatureOID,
+                          cert->maxIdx)) < 0)
+        return ret;
+
+    WOLFSSL_MSG("Got Algo ID");
+
+    if ( (ret = GetName(cert, ISSUER)) < 0)
+        return ret;
+
+    if ( (ret = GetValidity(cert, verify)) < 0)
+        badDate = ret;
+
+    if ( (ret = GetName(cert, SUBJECT)) < 0)
+        return ret;
+
+    WOLFSSL_MSG("Got Subject Name");
+
+    if ( (ret = GetKey(cert)) < 0)
+        return ret;
+
+    WOLFSSL_MSG("Got Key");
+
+    if (badDate != 0)
+        return badDate;
+
+    return ret;
+}
+
+
+static int GetSignature(DecodedCert* cert)
+{
+    int    length;
+    byte   b = cert->source[cert->srcIdx++];
+
+    if (b != ASN_BIT_STRING)
+        return ASN_BITSTR_E;
+
+    if (GetLength(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    cert->sigLength = length;
+
+    b = cert->source[cert->srcIdx++];
+    if (b != 0x00)
+        return ASN_EXPECT_0_E;
+
+    cert->sigLength--;
+    cert->signature = &cert->source[cert->srcIdx];
+    cert->srcIdx += cert->sigLength;
+
+    return 0;
+}
+
+
+static word32 SetDigest(const byte* digest, word32 digSz, byte* output)
+{
+    output[0] = ASN_OCTET_STRING;
+    output[1] = (byte)digSz;
+    XMEMCPY(&output[2], digest, digSz);
+
+    return digSz + 2;
+} 
+
+
+static word32 BytePrecision(word32 value)
+{
+    word32 i;
+    for (i = sizeof(value); i; --i)
+        if (value >> ((i - 1) * WOLFSSL_BIT_SIZE))
+            break;
+
+    return i;
+}
+
+
+WOLFSSL_LOCAL word32 SetLength(word32 length, byte* output)
+{
+    word32 i = 0, j;
+
+    if (length < ASN_LONG_LENGTH)
+        output[i++] = (byte)length;
+    else {
+        output[i++] = (byte)(BytePrecision(length) | ASN_LONG_LENGTH);
+      
+        for (j = BytePrecision(length); j; --j) {
+            output[i] = (byte)(length >> ((j - 1) * WOLFSSL_BIT_SIZE));
+            i++;
+        }
+    }
+
+    return i;
+}
+
+
+WOLFSSL_LOCAL word32 SetSequence(word32 len, byte* output)
+{
+    output[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
+    return SetLength(len, output + 1) + 1;
+}
+
+WOLFSSL_LOCAL word32 SetOctetString(word32 len, byte* output)
+{
+    output[0] = ASN_OCTET_STRING;
+    return SetLength(len, output + 1) + 1;
+}
+
+/* Write a set header to output */
+WOLFSSL_LOCAL word32 SetSet(word32 len, byte* output)
+{
+    output[0] = ASN_SET | ASN_CONSTRUCTED;
+    return SetLength(len, output + 1) + 1;
+}
+
+WOLFSSL_LOCAL word32 SetImplicit(byte tag, byte number, word32 len, byte* output)
+{
+
+    output[0] = ((tag == ASN_SEQUENCE || tag == ASN_SET) ? ASN_CONSTRUCTED : 0)
+                    | ASN_CONTEXT_SPECIFIC | number;
+    return SetLength(len, output + 1) + 1;
+}
+
+WOLFSSL_LOCAL word32 SetExplicit(byte number, word32 len, byte* output)
+{
+    output[0] = ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | number;
+    return SetLength(len, output + 1) + 1;
+}
+
+
+#if defined(HAVE_ECC) && (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN))
+
+static word32 SetCurve(ecc_key* key, byte* output)
+{
+
+    /* curve types */
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC192)
+    static const byte ECC_192v1_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d,
+                                             0x03, 0x01, 0x01};
+#endif
+#if defined(HAVE_ALL_CURVES) || !defined(NO_ECC256)
+    static const byte ECC_256v1_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d,
+                                            0x03, 0x01, 0x07};
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC160)
+    static const byte ECC_160r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00,
+                                             0x02};
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC224)
+    static const byte ECC_224r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00,
+                                             0x21};
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC384)
+    static const byte ECC_384r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00,
+                                             0x22};
+#endif
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC521)
+    static const byte ECC_521r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00,
+                                             0x23};
+#endif
+
+    int    oidSz = 0;
+    int    idx = 0;
+    int    lenSz = 0;
+    const  byte* oid = 0;
+
+    output[0] = ASN_OBJECT_ID;
+    idx++;
+
+    switch (key->dp->size) {
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC160)
+        case 20:
+            oidSz = sizeof(ECC_160r1_AlgoID);
+            oid   =        ECC_160r1_AlgoID;
+            break;
+#endif
+
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC192)
+        case 24:
+            oidSz = sizeof(ECC_192v1_AlgoID);
+            oid   =        ECC_192v1_AlgoID;
+            break;
+#endif
+
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC224)
+        case 28:
+            oidSz = sizeof(ECC_224r1_AlgoID);
+            oid   =        ECC_224r1_AlgoID;
+            break;
+#endif
+
+#if defined(HAVE_ALL_CURVES) || !defined(NO_ECC256)
+        case 32:
+            oidSz = sizeof(ECC_256v1_AlgoID);
+            oid   =        ECC_256v1_AlgoID;
+            break;
+#endif
+
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC384)
+        case 48:
+            oidSz = sizeof(ECC_384r1_AlgoID);
+            oid   =        ECC_384r1_AlgoID;
+            break;
+#endif
+
+#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC521)
+        case 66:
+            oidSz = sizeof(ECC_521r1_AlgoID);
+            oid   =        ECC_521r1_AlgoID;
+            break;
+#endif
+
+        default:
+            return ASN_UNKNOWN_OID_E;
+    }
+    lenSz = SetLength(oidSz, output+idx);
+    idx += lenSz;
+
+    XMEMCPY(output+idx, oid, oidSz);
+    idx += oidSz;
+
+    return idx;
+}
+
+#endif /* HAVE_ECC && WOLFSSL_CERT_GEN */
+
+
+WOLFSSL_LOCAL word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz)
+{
+    /* adding TAG_NULL and 0 to end */
+    
+    /* hashTypes */
+    static const byte shaAlgoID[]    = { 0x2b, 0x0e, 0x03, 0x02, 0x1a,
+                                         0x05, 0x00 };
+    static const byte sha256AlgoID[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+                                         0x04, 0x02, 0x01, 0x05, 0x00 };
+    static const byte sha384AlgoID[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+                                         0x04, 0x02, 0x02, 0x05, 0x00 };
+    static const byte sha512AlgoID[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+                                         0x04, 0x02, 0x03, 0x05, 0x00 };
+    static const byte md5AlgoID[]    = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+                                         0x02, 0x05, 0x05, 0x00  };
+    static const byte md2AlgoID[]    = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+                                         0x02, 0x02, 0x05, 0x00};
+
+    /* blkTypes, no NULL tags because IV is there instead */
+    static const byte desCbcAlgoID[]  = { 0x2B, 0x0E, 0x03, 0x02, 0x07 };
+    static const byte des3CbcAlgoID[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                          0x0D, 0x03, 0x07 };
+
+    /* RSA sigTypes */
+    #ifndef NO_RSA
+        static const byte md5wRSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7,
+                                            0x0d, 0x01, 0x01, 0x04, 0x05, 0x00};
+        static const byte shawRSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7,
+                                            0x0d, 0x01, 0x01, 0x05, 0x05, 0x00};
+        static const byte sha256wRSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7,
+                                            0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00};
+        static const byte sha384wRSA_AlgoID[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
+                                            0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00};
+        static const byte sha512wRSA_AlgoID[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
+                                            0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00};
+    #endif /* NO_RSA */
+ 
+    /* ECDSA sigTypes */
+    #ifdef HAVE_ECC 
+        static const byte shawECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d,
+                                                 0x04, 0x01, 0x05, 0x00};
+        static const byte sha256wECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE,0x3d,
+                                                 0x04, 0x03, 0x02, 0x05, 0x00};
+        static const byte sha384wECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE,0x3d,
+                                                 0x04, 0x03, 0x03, 0x05, 0x00};
+        static const byte sha512wECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE,0x3d,
+                                                 0x04, 0x03, 0x04, 0x05, 0x00};
+    #endif /* HAVE_ECC */
+ 
+    /* RSA keyType */
+    #ifndef NO_RSA
+        static const byte RSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+                                            0x01, 0x01, 0x01, 0x05, 0x00};
+    #endif /* NO_RSA */
+
+    #ifdef HAVE_ECC 
+        /* ECC keyType */
+        /* no tags, so set tagSz smaller later */
+        static const byte ECC_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d,
+                                           0x02, 0x01};
+    #endif /* HAVE_ECC */
+
+    int    algoSz = 0;
+    int    tagSz  = 2;   /* tag null and terminator */
+    word32 idSz, seqSz;
+    const  byte* algoName = 0;
+    byte ID_Length[MAX_LENGTH_SZ];
+    byte seqArray[MAX_SEQ_SZ + 1];  /* add object_id to end */
+
+    if (type == hashType) {
+        switch (algoOID) {
+        case SHAh:
+            algoSz = sizeof(shaAlgoID);
+            algoName = shaAlgoID;
+            break;
+
+        case SHA256h:
+            algoSz = sizeof(sha256AlgoID);
+            algoName = sha256AlgoID;
+            break;
+
+        case SHA384h:
+            algoSz = sizeof(sha384AlgoID);
+            algoName = sha384AlgoID;
+            break;
+
+        case SHA512h:
+            algoSz = sizeof(sha512AlgoID);
+            algoName = sha512AlgoID;
+            break;
+
+        case MD2h:
+            algoSz = sizeof(md2AlgoID);
+            algoName = md2AlgoID;
+            break;
+
+        case MD5h:
+            algoSz = sizeof(md5AlgoID);
+            algoName = md5AlgoID;
+            break;
+
+        default:
+            WOLFSSL_MSG("Unknown Hash Algo");
+            return 0;  /* UNKOWN_HASH_E; */
+        }
+    }
+    else if (type == blkType) {
+        switch (algoOID) {
+        case DESb:
+            algoSz = sizeof(desCbcAlgoID);
+            algoName = desCbcAlgoID;
+            tagSz = 0;
+            break;
+        case DES3b:
+            algoSz = sizeof(des3CbcAlgoID);
+            algoName = des3CbcAlgoID;
+            tagSz = 0;
+            break;
+        default:
+            WOLFSSL_MSG("Unknown Block Algo");
+            return 0;
+        }
+    }
+    else if (type == sigType) {    /* sigType */
+        switch (algoOID) {
+        #ifndef NO_RSA
+            case CTC_MD5wRSA:
+                algoSz = sizeof(md5wRSA_AlgoID);
+                algoName = md5wRSA_AlgoID;
+                break;
+
+            case CTC_SHAwRSA:
+                algoSz = sizeof(shawRSA_AlgoID);
+                algoName = shawRSA_AlgoID;
+                break;
+
+            case CTC_SHA256wRSA:
+                algoSz = sizeof(sha256wRSA_AlgoID);
+                algoName = sha256wRSA_AlgoID;
+                break;
+
+            case CTC_SHA384wRSA:
+                algoSz = sizeof(sha384wRSA_AlgoID);
+                algoName = sha384wRSA_AlgoID;
+                break;
+
+            case CTC_SHA512wRSA:
+                algoSz = sizeof(sha512wRSA_AlgoID);
+                algoName = sha512wRSA_AlgoID;
+                break;
+        #endif /* NO_RSA */
+        #ifdef HAVE_ECC 
+            case CTC_SHAwECDSA:
+                algoSz = sizeof(shawECDSA_AlgoID);
+                algoName = shawECDSA_AlgoID;
+                break;
+
+            case CTC_SHA256wECDSA:
+                algoSz = sizeof(sha256wECDSA_AlgoID);
+                algoName = sha256wECDSA_AlgoID;
+                break;
+
+            case CTC_SHA384wECDSA:
+                algoSz = sizeof(sha384wECDSA_AlgoID);
+                algoName = sha384wECDSA_AlgoID;
+                break;
+
+            case CTC_SHA512wECDSA:
+                algoSz = sizeof(sha512wECDSA_AlgoID);
+                algoName = sha512wECDSA_AlgoID;
+                break;
+        #endif /* HAVE_ECC */
+        default:
+            WOLFSSL_MSG("Unknown Signature Algo");
+            return 0;
+        }
+    }
+    else if (type == keyType) {    /* keyType */
+        switch (algoOID) {
+        #ifndef NO_RSA
+            case RSAk:
+                algoSz = sizeof(RSA_AlgoID);
+                algoName = RSA_AlgoID;
+                break;
+        #endif /* NO_RSA */
+        #ifdef HAVE_ECC 
+            case ECDSAk:
+                algoSz = sizeof(ECC_AlgoID);
+                algoName = ECC_AlgoID;
+                tagSz = 0;
+                break;
+        #endif /* HAVE_ECC */
+        default:
+            WOLFSSL_MSG("Unknown Key Algo");
+            return 0;
+        }
+    }
+    else {
+        WOLFSSL_MSG("Unknown Algo type");
+        return 0;
+    }
+
+    idSz  = SetLength(algoSz - tagSz, ID_Length); /* don't include tags */
+    seqSz = SetSequence(idSz + algoSz + 1 + curveSz, seqArray); 
+                 /* +1 for object id, curveID of curveSz follows for ecc */
+    seqArray[seqSz++] = ASN_OBJECT_ID;
+
+    XMEMCPY(output, seqArray, seqSz);
+    XMEMCPY(output + seqSz, ID_Length, idSz);
+    XMEMCPY(output + seqSz + idSz, algoName, algoSz);
+
+    return seqSz + idSz + algoSz;
+
+}
+
+
+word32 wc_EncodeSignature(byte* out, const byte* digest, word32 digSz,
+                          int hashOID)
+{
+    byte digArray[MAX_ENCODED_DIG_SZ];
+    byte algoArray[MAX_ALGO_SZ];
+    byte seqArray[MAX_SEQ_SZ];
+    word32 encDigSz, algoSz, seqSz;
+
+    encDigSz = SetDigest(digest, digSz, digArray);
+    algoSz   = SetAlgoID(hashOID, algoArray, hashType, 0);
+    seqSz    = SetSequence(encDigSz + algoSz, seqArray);
+
+    XMEMCPY(out, seqArray, seqSz);
+    XMEMCPY(out + seqSz, algoArray, algoSz);
+    XMEMCPY(out + seqSz + algoSz, digArray, encDigSz);
+
+    return encDigSz + algoSz + seqSz;
+}
+
+
+int wc_GetCTC_HashOID(int type)
+{
+    switch (type) {
+#ifdef WOLFSSL_MD2
+        case MD2:
+            return MD2h;
+#endif
+#ifndef NO_MD5
+        case MD5:
+            return MD5h;
+#endif
+#ifndef NO_SHA
+        case SHA:
+            return SHAh;
+#endif
+#ifndef NO_SHA256
+        case SHA256:
+            return SHA256h;
+#endif
+#ifdef WOLFSSL_SHA384
+        case SHA384:
+            return SHA384h;
+#endif
+#ifdef WOLFSSL_SHA512
+        case SHA512:
+            return SHA512h;
+#endif
+        default:
+            return 0;
+    };
+}
+
+
+/* return true (1) or false (0) for Confirmation */
+static int ConfirmSignature(const byte* buf, word32 bufSz,
+    const byte* key, word32 keySz, word32 keyOID,
+    const byte* sig, word32 sigSz, word32 sigOID,
+    void* heap)
+{
+    int  typeH = 0, digestSz = 0, ret = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* digest;
+#else
+    byte digest[MAX_DIGEST_SIZE];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    digest = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (digest == NULL)
+        return 0; /* not confirmed */
+#endif
+
+    (void)key;
+    (void)keySz;
+    (void)sig;
+    (void)sigSz;
+    (void)heap;
+
+    switch (sigOID) {
+    #ifndef NO_MD5
+        case CTC_MD5wRSA:
+        if (wc_Md5Hash(buf, bufSz, digest) == 0) {
+            typeH    = MD5h;
+            digestSz = MD5_DIGEST_SIZE;
+        }
+        break;
+    #endif
+    #if defined(WOLFSSL_MD2)
+        case CTC_MD2wRSA:
+        if (wc_Md2Hash(buf, bufSz, digest) == 0) {
+            typeH    = MD2h;
+            digestSz = MD2_DIGEST_SIZE;
+        }
+        break;
+    #endif
+    #ifndef NO_SHA
+        case CTC_SHAwRSA:
+        case CTC_SHAwDSA:
+        case CTC_SHAwECDSA:
+        if (wc_ShaHash(buf, bufSz, digest) == 0) {    
+            typeH    = SHAh;
+            digestSz = SHA_DIGEST_SIZE;                
+        }
+        break;
+    #endif
+    #ifndef NO_SHA256
+        case CTC_SHA256wRSA:
+        case CTC_SHA256wECDSA:
+        if (wc_Sha256Hash(buf, bufSz, digest) == 0) {    
+            typeH    = SHA256h;
+            digestSz = SHA256_DIGEST_SIZE;
+        }
+        break;
+    #endif
+    #ifdef WOLFSSL_SHA512
+        case CTC_SHA512wRSA:
+        case CTC_SHA512wECDSA:
+        if (wc_Sha512Hash(buf, bufSz, digest) == 0) {    
+            typeH    = SHA512h;
+            digestSz = SHA512_DIGEST_SIZE;
+        }
+        break;
+    #endif
+    #ifdef WOLFSSL_SHA384
+        case CTC_SHA384wRSA:
+        case CTC_SHA384wECDSA:
+        if (wc_Sha384Hash(buf, bufSz, digest) == 0) {    
+            typeH    = SHA384h;
+            digestSz = SHA384_DIGEST_SIZE;
+        }            
+        break;
+    #endif
+        default:
+            WOLFSSL_MSG("Verify Signautre has unsupported type");
+    }
+    
+    if (typeH == 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return 0; /* not confirmed */
+    }
+
+    switch (keyOID) {
+    #ifndef NO_RSA
+        case RSAk:
+        {
+            word32 idx = 0;
+            int    encodedSigSz, verifySz;
+            byte*  out;
+#ifdef WOLFSSL_SMALL_STACK
+            RsaKey* pubKey;
+            byte* plain;
+            byte* encodedSig;
+#else
+            RsaKey pubKey[1];
+            byte plain[MAX_ENCODED_SIG_SZ];
+            byte encodedSig[MAX_ENCODED_SIG_SZ];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+            pubKey = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            plain = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            
+            if (pubKey == NULL || plain == NULL || encodedSig == NULL) {
+                WOLFSSL_MSG("Failed to allocate memory at ConfirmSignature");
+                
+                if (pubKey)
+                    XFREE(pubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                if (plain)
+                    XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                if (encodedSig)
+                    XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                
+                break; /* not confirmed */
+            }
+#endif
+
+            if (sigSz > MAX_ENCODED_SIG_SZ) {
+                WOLFSSL_MSG("Verify Signautre is too big");
+            }
+            else if (wc_InitRsaKey(pubKey, heap) != 0) {
+                WOLFSSL_MSG("InitRsaKey failed");
+            }
+            else if (wc_RsaPublicKeyDecode(key, &idx, pubKey, keySz) < 0) {
+                WOLFSSL_MSG("ASN Key decode error RSA");
+            }
+            else {
+                XMEMCPY(plain, sig, sigSz);
+
+                if ((verifySz = wc_RsaSSL_VerifyInline(plain, sigSz, &out,
+                                                                 pubKey)) < 0) {
+                    WOLFSSL_MSG("Rsa SSL verify error");
+                }
+                else {
+                    /* make sure we're right justified */
+                    encodedSigSz =
+                        wc_EncodeSignature(encodedSig, digest, digestSz, typeH);
+                    if (encodedSigSz != verifySz ||
+                                XMEMCMP(out, encodedSig, encodedSigSz) != 0) {
+                        WOLFSSL_MSG("Rsa SSL verify match encode error");
+                    }
+                    else
+                        ret = 1; /* match */
+
+                    #ifdef WOLFSSL_DEBUG_ENCODING
+                    {
+                        int x;
+
+                        printf("wolfssl encodedSig:\n");
+
+                        for (x = 0; x < encodedSigSz; x++) {
+                            printf("%02x ", encodedSig[x]);
+                            if ( (x % 16) == 15)
+                                printf("\n");
+                        }
+
+                        printf("\n");
+                        printf("actual digest:\n");
+
+                        for (x = 0; x < verifySz; x++) {
+                            printf("%02x ", out[x]);
+                            if ( (x % 16) == 15)
+                                printf("\n");
+                        }
+
+                        printf("\n");
+                    }
+                    #endif /* WOLFSSL_DEBUG_ENCODING */
+
+                }
+
+            }
+
+            wc_FreeRsaKey(pubKey);
+
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(pubKey,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(plain,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            break;
+        }
+
+    #endif /* NO_RSA */
+    #ifdef HAVE_ECC
+        case ECDSAk:
+        {
+            int verify = 0;
+#ifdef WOLFSSL_SMALL_STACK
+            ecc_key* pubKey;
+#else
+            ecc_key pubKey[1];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+            pubKey = (ecc_key*)XMALLOC(sizeof(ecc_key), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            if (pubKey == NULL) {
+                WOLFSSL_MSG("Failed to allocate pubKey");
+                break; /* not confirmed */
+            }
+#endif
+
+            if (wc_ecc_init(pubKey) < 0) {
+                WOLFSSL_MSG("Failed to initialize key");
+                break; /* not confirmed */
+            }
+            if (wc_ecc_import_x963(key, keySz, pubKey) < 0) {
+                WOLFSSL_MSG("ASN Key import error ECC");
+            }
+            else {   
+                if (wc_ecc_verify_hash(sig, sigSz, digest, digestSz, &verify,
+                                                                pubKey) != 0) {
+                    WOLFSSL_MSG("ECC verify hash error");
+                }
+                else if (1 != verify) {
+                    WOLFSSL_MSG("ECC Verify didn't match");
+                } else
+                    ret = 1; /* match */
+
+            }
+            wc_ecc_free(pubKey);
+
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(pubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            break;
+        }
+    #endif /* HAVE_ECC */
+        default:
+            WOLFSSL_MSG("Verify Key type unknown");
+    }
+    
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+#ifndef IGNORE_NAME_CONSTRAINTS
+
+static int MatchBaseName(int type, const char* name, int nameSz,
+                                                   const char* base, int baseSz)
+{
+    if (base == NULL || baseSz <= 0 || name == NULL || nameSz <= 0 ||
+            name[0] == '.' || nameSz < baseSz ||
+            (type != ASN_RFC822_TYPE && type != ASN_DNS_TYPE))
+        return 0;
+
+    /* If an email type, handle special cases where the base is only
+     * a domain, or is an email address itself. */
+    if (type == ASN_RFC822_TYPE) {
+        const char* p = NULL;
+        int count = 0;
+
+        if (base[0] != '.') {
+            p = base;
+            count = 0;
+
+            /* find the '@' in the base */
+            while (*p != '@' && count < baseSz) {
+                count++;
+                p++;
+            }
+
+            /* No '@' in base, reset p to NULL */
+            if (count >= baseSz)
+                p = NULL;
+        }
+
+        if (p == NULL) {
+            /* Base isn't an email address, it is a domain name,
+             * wind the name forward one character past its '@'. */
+            p = name;
+            count = 0;
+            while (*p != '@' && count < baseSz) {
+                count++;
+                p++;
+            }
+
+            if (count < baseSz && *p == '@') {
+                name = p + 1;
+                nameSz -= count + 1;
+            }
+        }
+    }
+
+    if ((type == ASN_DNS_TYPE || type == ASN_RFC822_TYPE) && base[0] == '.') {
+        int szAdjust = nameSz - baseSz;
+        name += szAdjust;
+        nameSz -= szAdjust;
+    }
+
+    while (nameSz > 0) {
+        if (XTOLOWER((unsigned char)*name++) != 
+                                               XTOLOWER((unsigned char)*base++))
+            return 0;
+        nameSz--;
+    }
+
+    return 1;
+}
+
+
+static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert)
+{
+    if (signer == NULL || cert == NULL)
+        return 0;
+
+    /* Check against the excluded list */
+    if (signer->excludedNames) {
+        Base_entry* base = signer->excludedNames;
+
+        while (base != NULL) {
+            if (base->type == ASN_DNS_TYPE) {
+                DNS_entry* name = cert->altNames;
+                while (name != NULL) {
+                    if (MatchBaseName(ASN_DNS_TYPE,
+                                          name->name, (int)XSTRLEN(name->name),
+                                          base->name, base->nameSz))
+                        return 0;
+                    name = name->next;
+                }
+            }
+            else if (base->type == ASN_RFC822_TYPE) {
+                DNS_entry* name = cert->altEmailNames;
+                while (name != NULL) {
+                    if (MatchBaseName(ASN_RFC822_TYPE,
+                                          name->name, (int)XSTRLEN(name->name),
+                                          base->name, base->nameSz))
+                        return 0;
+
+                    name = name->next;
+                }
+            }
+            else if (base->type == ASN_DIR_TYPE) {
+                if (cert->subjectRawLen == base->nameSz &&
+                    XMEMCMP(cert->subjectRaw, base->name, base->nameSz) == 0) {
+
+                    return 0;
+                }
+            }
+            base = base->next;
+        }
+    }
+
+    /* Check against the permitted list */
+    if (signer->permittedNames != NULL) {
+        int needDns = 0;
+        int matchDns = 0;
+        int needEmail = 0;
+        int matchEmail = 0;
+        int needDir = 0;
+        int matchDir = 0;
+        Base_entry* base = signer->permittedNames;
+
+        while (base != NULL) {
+            if (base->type == ASN_DNS_TYPE) {
+                DNS_entry* name = cert->altNames;
+
+                if (name != NULL)
+                    needDns = 1;
+
+                while (name != NULL) {
+                    matchDns = MatchBaseName(ASN_DNS_TYPE,
+                                          name->name, (int)XSTRLEN(name->name),
+                                          base->name, base->nameSz);
+                    name = name->next;
+                }
+            }
+            else if (base->type == ASN_RFC822_TYPE) {
+                DNS_entry* name = cert->altEmailNames;
+
+                if (name != NULL)
+                    needEmail = 1;
+
+                while (name != NULL) {
+                    matchEmail = MatchBaseName(ASN_DNS_TYPE,
+                                          name->name, (int)XSTRLEN(name->name),
+                                          base->name, base->nameSz);
+                    name = name->next;
+                }
+            }
+            else if (base->type == ASN_DIR_TYPE) {
+                needDir = 1;
+                if (cert->subjectRaw != NULL &&
+                    cert->subjectRawLen == base->nameSz &&
+                    XMEMCMP(cert->subjectRaw, base->name, base->nameSz) == 0) {
+
+                    matchDir = 1;
+                }
+            }
+            base = base->next;
+        }
+
+        if ((needDns && !matchDns) || (needEmail && !matchEmail) ||
+            (needDir && !matchDir)) {
+
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+#endif /* IGNORE_NAME_CONSTRAINTS */
+
+
+static int DecodeAltNames(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length = 0;
+
+    WOLFSSL_ENTER("DecodeAltNames");
+
+    if (GetSequence(input, &idx, &length, sz) < 0) {
+        WOLFSSL_MSG("\tBad Sequence");
+        return ASN_PARSE_E;
+    }
+
+    cert->weOwnAltNames = 1;
+
+    while (length > 0) {
+        byte       b = input[idx++];
+
+        length--;
+
+        /* Save DNS Type names in the altNames list. */
+        /* Save Other Type names in the cert's OidMap */
+        if (b == (ASN_CONTEXT_SPECIFIC | ASN_DNS_TYPE)) {
+            DNS_entry* dnsEntry;
+            int strLen;
+            word32 lenStartIdx = idx;
+
+            if (GetLength(input, &idx, &strLen, sz) < 0) {
+                WOLFSSL_MSG("\tfail: str length");
+                return ASN_PARSE_E;
+            }
+            length -= (idx - lenStartIdx);
+
+            dnsEntry = (DNS_entry*)XMALLOC(sizeof(DNS_entry), cert->heap,
+                                        DYNAMIC_TYPE_ALTNAME);
+            if (dnsEntry == NULL) {
+                WOLFSSL_MSG("\tOut of Memory");
+                return ASN_PARSE_E;
+            }
+
+            dnsEntry->name = (char*)XMALLOC(strLen + 1, cert->heap,
+                                         DYNAMIC_TYPE_ALTNAME);
+            if (dnsEntry->name == NULL) {
+                WOLFSSL_MSG("\tOut of Memory");
+                XFREE(dnsEntry, cert->heap, DYNAMIC_TYPE_ALTNAME);
+                return ASN_PARSE_E;
+            }
+
+            XMEMCPY(dnsEntry->name, &input[idx], strLen);
+            dnsEntry->name[strLen] = '\0';
+
+            dnsEntry->next = cert->altNames;
+            cert->altNames = dnsEntry;
+
+            length -= strLen;
+            idx    += strLen;
+        }
+#ifndef IGNORE_NAME_CONSTRAINTS
+        else if (b == (ASN_CONTEXT_SPECIFIC | ASN_RFC822_TYPE)) {
+            DNS_entry* emailEntry;
+            int strLen;
+            word32 lenStartIdx = idx;
+
+            if (GetLength(input, &idx, &strLen, sz) < 0) {
+                WOLFSSL_MSG("\tfail: str length");
+                return ASN_PARSE_E;
+            }
+            length -= (idx - lenStartIdx);
+
+            emailEntry = (DNS_entry*)XMALLOC(sizeof(DNS_entry), cert->heap,
+                                        DYNAMIC_TYPE_ALTNAME);
+            if (emailEntry == NULL) {
+                WOLFSSL_MSG("\tOut of Memory");
+                return ASN_PARSE_E;
+            }
+
+            emailEntry->name = (char*)XMALLOC(strLen + 1, cert->heap,
+                                         DYNAMIC_TYPE_ALTNAME);
+            if (emailEntry->name == NULL) {
+                WOLFSSL_MSG("\tOut of Memory");
+                XFREE(emailEntry, cert->heap, DYNAMIC_TYPE_ALTNAME);
+                return ASN_PARSE_E;
+            }
+
+            XMEMCPY(emailEntry->name, &input[idx], strLen);
+            emailEntry->name[strLen] = '\0';
+
+            emailEntry->next = cert->altEmailNames;
+            cert->altEmailNames = emailEntry;
+
+            length -= strLen;
+            idx    += strLen;
+        }
+#endif /* IGNORE_NAME_CONSTRAINTS */
+#ifdef WOLFSSL_SEP
+        else if (b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | ASN_OTHER_TYPE))
+        {
+            int strLen;
+            word32 lenStartIdx = idx;
+            word32 oid = 0;
+
+            if (GetLength(input, &idx, &strLen, sz) < 0) {
+                WOLFSSL_MSG("\tfail: other name length");
+                return ASN_PARSE_E;
+            }
+            /* Consume the rest of this sequence. */
+            length -= (strLen + idx - lenStartIdx);
+
+            if (GetObjectId(input, &idx, &oid, sz) < 0) {
+                WOLFSSL_MSG("\tbad OID");
+                return ASN_PARSE_E;
+            }
+
+            if (oid != HW_NAME_OID) {
+                WOLFSSL_MSG("\tincorrect OID");
+                return ASN_PARSE_E;
+            }
+
+            if (input[idx++] != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) {
+                WOLFSSL_MSG("\twrong type");
+                return ASN_PARSE_E;
+            }
+
+            if (GetLength(input, &idx, &strLen, sz) < 0) {
+                WOLFSSL_MSG("\tfail: str len");
+                return ASN_PARSE_E;
+            }
+
+            if (GetSequence(input, &idx, &strLen, sz) < 0) {
+                WOLFSSL_MSG("\tBad Sequence");
+                return ASN_PARSE_E;
+            }
+
+            if (input[idx++] != ASN_OBJECT_ID) {
+                WOLFSSL_MSG("\texpected OID");
+                return ASN_PARSE_E;
+            }
+
+            if (GetLength(input, &idx, &strLen, sz) < 0) {
+                WOLFSSL_MSG("\tfailed: str len");
+                return ASN_PARSE_E;
+            }
+
+            cert->hwType = (byte*)XMALLOC(strLen, cert->heap, 0);
+            if (cert->hwType == NULL) {
+                WOLFSSL_MSG("\tOut of Memory");
+                return MEMORY_E;
+            }
+
+            XMEMCPY(cert->hwType, &input[idx], strLen);
+            cert->hwTypeSz = strLen;
+            idx += strLen;
+
+            if (input[idx++] != ASN_OCTET_STRING) {
+                WOLFSSL_MSG("\texpected Octet String");
+                return ASN_PARSE_E;
+            }
+
+            if (GetLength(input, &idx, &strLen, sz) < 0) {
+                WOLFSSL_MSG("\tfailed: str len");
+                return ASN_PARSE_E;
+            }
+
+            cert->hwSerialNum = (byte*)XMALLOC(strLen + 1, cert->heap, 0);
+            if (cert->hwSerialNum == NULL) {
+                WOLFSSL_MSG("\tOut of Memory");
+                return MEMORY_E;
+            }
+
+            XMEMCPY(cert->hwSerialNum, &input[idx], strLen);
+            cert->hwSerialNum[strLen] = '\0';
+            cert->hwSerialNumSz = strLen;
+            idx += strLen;
+        }
+#endif /* WOLFSSL_SEP */
+        else {
+            int strLen;
+            word32 lenStartIdx = idx;
+
+            WOLFSSL_MSG("\tUnsupported name type, skipping");
+
+            if (GetLength(input, &idx, &strLen, sz) < 0) {
+                WOLFSSL_MSG("\tfail: unsupported name length");
+                return ASN_PARSE_E;
+            }
+            length -= (strLen + idx - lenStartIdx);
+            idx += strLen;
+        }
+    }
+    return 0;
+}
+
+
+static int DecodeBasicCaConstraint(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length = 0;
+
+    WOLFSSL_ENTER("DecodeBasicCaConstraint");
+    if (GetSequence(input, &idx, &length, sz) < 0) {
+        WOLFSSL_MSG("\tfail: bad SEQUENCE");
+        return ASN_PARSE_E;
+    }
+
+    if (length == 0)
+        return 0;
+
+    /* If the basic ca constraint is false, this extension may be named, but
+     * left empty. So, if the length is 0, just return. */
+
+    if (input[idx++] != ASN_BOOLEAN)
+    {
+        WOLFSSL_MSG("\tfail: constraint not BOOLEAN");
+        return ASN_PARSE_E;
+    }
+
+    if (GetLength(input, &idx, &length, sz) < 0)
+    {
+        WOLFSSL_MSG("\tfail: length");
+        return ASN_PARSE_E;
+    }
+
+    if (input[idx++])
+        cert->isCA = 1;
+
+    #ifdef OPENSSL_EXTRA
+        /* If there isn't any more data, return. */
+        if (idx >= (word32)sz)
+            return 0;
+
+        /* Anything left should be the optional pathlength */
+        if (input[idx++] != ASN_INTEGER) {
+            WOLFSSL_MSG("\tfail: pathlen not INTEGER");
+            return ASN_PARSE_E;
+        }
+
+        if (input[idx++] != 1) {
+            WOLFSSL_MSG("\tfail: pathlen too long");
+            return ASN_PARSE_E;
+        }
+
+        cert->pathLength = input[idx];
+        cert->extBasicConstPlSet = 1;
+    #endif /* OPENSSL_EXTRA */
+
+    return 0;
+}
+
+
+#define CRLDP_FULL_NAME 0
+    /* From RFC3280 SS4.2.1.14, Distribution Point Name*/
+#define GENERALNAME_URI 6
+    /* From RFC3280 SS4.2.1.7, GeneralName */
+
+static int DecodeCrlDist(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length = 0;
+
+    WOLFSSL_ENTER("DecodeCrlDist");
+
+    /* Unwrap the list of Distribution Points*/
+    if (GetSequence(input, &idx, &length, sz) < 0)
+        return ASN_PARSE_E;
+
+    /* Unwrap a single Distribution Point */
+    if (GetSequence(input, &idx, &length, sz) < 0)
+        return ASN_PARSE_E;
+
+    /* The Distribution Point has three explicit optional members
+     *  First check for a DistributionPointName
+     */
+    if (input[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
+    {
+        idx++;
+        if (GetLength(input, &idx, &length, sz) < 0)
+            return ASN_PARSE_E;
+
+        if (input[idx] == 
+                    (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | CRLDP_FULL_NAME))
+        {
+            idx++;
+            if (GetLength(input, &idx, &length, sz) < 0)
+                return ASN_PARSE_E;
+
+            if (input[idx] == (ASN_CONTEXT_SPECIFIC | GENERALNAME_URI))
+            {
+                idx++;
+                if (GetLength(input, &idx, &length, sz) < 0)
+                    return ASN_PARSE_E;
+
+                cert->extCrlInfoSz = length;
+                cert->extCrlInfo = input + idx;
+                idx += length;
+            }
+            else
+                /* This isn't a URI, skip it. */
+                idx += length;
+        }
+        else
+            /* This isn't a FULLNAME, skip it. */
+            idx += length;
+    }
+
+    /* Check for reasonFlags */
+    if (idx < (word32)sz &&
+        input[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1))
+    {
+        idx++;
+        if (GetLength(input, &idx, &length, sz) < 0)
+            return ASN_PARSE_E;
+        idx += length;
+    }
+
+    /* Check for cRLIssuer */
+    if (idx < (word32)sz &&
+        input[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 2))
+    {
+        idx++;
+        if (GetLength(input, &idx, &length, sz) < 0)
+            return ASN_PARSE_E;
+        idx += length;
+    }
+
+    if (idx < (word32)sz)
+    {
+        WOLFSSL_MSG("\tThere are more CRL Distribution Point records, "
+                   "but we only use the first one.");
+    }
+
+    return 0;
+}
+
+
+static int DecodeAuthInfo(byte* input, int sz, DecodedCert* cert)
+/*
+ *  Read the first of the Authority Information Access records. If there are
+ *  any issues, return without saving the record.
+ */
+{
+    word32 idx = 0;
+    int length = 0;
+    byte b;
+    word32 oid;
+
+    WOLFSSL_ENTER("DecodeAuthInfo");
+
+    /* Unwrap the list of AIAs */
+    if (GetSequence(input, &idx, &length, sz) < 0)
+        return ASN_PARSE_E;
+
+    while (idx < (word32)sz) {
+        /* Unwrap a single AIA */
+        if (GetSequence(input, &idx, &length, sz) < 0)
+            return ASN_PARSE_E;
+
+        oid = 0;
+        if (GetObjectId(input, &idx, &oid, sz) < 0)
+            return ASN_PARSE_E;
+
+        /* Only supporting URIs right now. */
+        b = input[idx++];
+        if (GetLength(input, &idx, &length, sz) < 0)
+            return ASN_PARSE_E;
+
+        if (b == (ASN_CONTEXT_SPECIFIC | GENERALNAME_URI) &&
+            oid == AIA_OCSP_OID)
+        {
+            cert->extAuthInfoSz = length;
+            cert->extAuthInfo = input + idx;
+            break;
+        }
+        idx += length;
+    }
+
+    return 0;
+}
+
+
+static int DecodeAuthKeyId(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length = 0, ret = 0;
+
+    WOLFSSL_ENTER("DecodeAuthKeyId");
+
+    if (GetSequence(input, &idx, &length, sz) < 0) {
+        WOLFSSL_MSG("\tfail: should be a SEQUENCE\n");
+        return ASN_PARSE_E;
+    }
+
+    if (input[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) {
+        WOLFSSL_MSG("\tinfo: OPTIONAL item 0, not available\n");
+        return 0;
+    }
+
+    if (GetLength(input, &idx, &length, sz) < 0) {
+        WOLFSSL_MSG("\tfail: extension data length");
+        return ASN_PARSE_E;
+    }
+
+    #ifdef OPENSSL_EXTRA
+        cert->extAuthKeyIdSrc = &input[idx];
+        cert->extAuthKeyIdSz = length;
+    #endif /* OPENSSL_EXTRA */
+
+    if (length == KEYID_SIZE) {
+        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
+    }
+
+    return ret;
+}
+
+
+static int DecodeSubjKeyId(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length = 0, ret = 0;
+
+    WOLFSSL_ENTER("DecodeSubjKeyId");
+
+    if (input[idx++] != ASN_OCTET_STRING) {
+        WOLFSSL_MSG("\tfail: should be an OCTET STRING");
+        return ASN_PARSE_E;
+    }
+
+    if (GetLength(input, &idx, &length, sz) < 0) {
+        WOLFSSL_MSG("\tfail: extension data length");
+        return ASN_PARSE_E;
+    }
+
+    #ifdef OPENSSL_EXTRA
+        cert->extSubjKeyIdSrc = &input[idx];
+        cert->extSubjKeyIdSz = length;
+    #endif /* OPENSSL_EXTRA */
+
+    if (length == SIGNER_DIGEST_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
+    }
+
+    return ret;
+}
+
+
+static int DecodeKeyUsage(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length;
+    byte unusedBits;
+    WOLFSSL_ENTER("DecodeKeyUsage");
+
+    if (input[idx++] != ASN_BIT_STRING) {
+        WOLFSSL_MSG("\tfail: key usage expected bit string");
+        return ASN_PARSE_E;
+    }
+
+    if (GetLength(input, &idx, &length, sz) < 0) {
+        WOLFSSL_MSG("\tfail: key usage bad length");
+        return ASN_PARSE_E;
+    }
+
+    unusedBits = input[idx++];
+    length--;
+
+    if (length == 2) {
+        cert->extKeyUsage = (word16)((input[idx] << 8) | input[idx+1]);
+        cert->extKeyUsage >>= unusedBits;
+    }
+    else if (length == 1)
+        cert->extKeyUsage = (word16)(input[idx] << 1);
+
+    return 0;
+}
+
+
+static int DecodeExtKeyUsage(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0, oid;
+    int length;
+
+    WOLFSSL_ENTER("DecodeExtKeyUsage");
+
+    if (GetSequence(input, &idx, &length, sz) < 0) {
+        WOLFSSL_MSG("\tfail: should be a SEQUENCE");
+        return ASN_PARSE_E;
+    }
+
+    #ifdef OPENSSL_EXTRA
+        cert->extExtKeyUsageSrc = input + idx;
+        cert->extExtKeyUsageSz = length;
+    #endif
+
+    while (idx < (word32)sz) {
+        if (GetObjectId(input, &idx, &oid, sz) < 0)
+            return ASN_PARSE_E;
+
+        switch (oid) {
+            case EKU_ANY_OID:
+                cert->extExtKeyUsage |= EXTKEYUSE_ANY;
+                break;
+            case EKU_SERVER_AUTH_OID:
+                cert->extExtKeyUsage |= EXTKEYUSE_SERVER_AUTH;
+                break;
+            case EKU_CLIENT_AUTH_OID:
+                cert->extExtKeyUsage |= EXTKEYUSE_CLIENT_AUTH;
+                break;
+            case EKU_OCSP_SIGN_OID:
+                cert->extExtKeyUsage |= EXTKEYUSE_OCSP_SIGN;
+                break;
+        }
+
+        #ifdef OPENSSL_EXTRA
+            cert->extExtKeyUsageCount++;
+        #endif
+    }
+
+    return 0;
+}
+
+
+#ifndef IGNORE_NAME_CONSTRAINTS
+static int DecodeSubtree(byte* input, int sz, Base_entry** head, void* heap)
+{
+    word32 idx = 0;
+
+    (void)heap;
+
+    while (idx < (word32)sz) {
+        int seqLength, strLength;
+        word32 nameIdx;
+        byte b;
+
+        if (GetSequence(input, &idx, &seqLength, sz) < 0) {
+            WOLFSSL_MSG("\tfail: should be a SEQUENCE");
+            return ASN_PARSE_E;
+        }
+
+        nameIdx = idx;
+        b = input[nameIdx++];
+        if (GetLength(input, &nameIdx, &strLength, sz) <= 0) {
+            WOLFSSL_MSG("\tinvalid length");
+            return ASN_PARSE_E;
+        }
+
+        if (b == (ASN_CONTEXT_SPECIFIC | ASN_DNS_TYPE) ||
+            b == (ASN_CONTEXT_SPECIFIC | ASN_RFC822_TYPE) ||
+            b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | ASN_DIR_TYPE)) {
+
+            Base_entry* entry = (Base_entry*)XMALLOC(sizeof(Base_entry),
+                                                    heap, DYNAMIC_TYPE_ALTNAME);
+
+            if (entry == NULL) {
+                WOLFSSL_MSG("allocate error");
+                return MEMORY_E;
+            }
+
+            entry->name = (char*)XMALLOC(strLength, heap, DYNAMIC_TYPE_ALTNAME);
+            if (entry->name == NULL) {
+                WOLFSSL_MSG("allocate error");
+                return MEMORY_E;
+            }
+
+            XMEMCPY(entry->name, &input[nameIdx], strLength);
+            entry->nameSz = strLength;
+            entry->type = b & 0x0F;
+
+            entry->next = *head;
+            *head = entry;
+        }
+
+        idx += seqLength;
+    }
+
+    return 0;
+}
+
+
+static int DecodeNameConstraints(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length = 0;
+
+    WOLFSSL_ENTER("DecodeNameConstraints");
+
+    if (GetSequence(input, &idx, &length, sz) < 0) {
+        WOLFSSL_MSG("\tfail: should be a SEQUENCE");
+        return ASN_PARSE_E;
+    }
+
+    while (idx < (word32)sz) {
+        byte b = input[idx++];
+        Base_entry** subtree = NULL;
+
+        if (GetLength(input, &idx, &length, sz) <= 0) {
+            WOLFSSL_MSG("\tinvalid length");
+            return ASN_PARSE_E;
+        }
+
+        if (b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0))
+            subtree = &cert->permittedNames;
+        else if (b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1))
+            subtree = &cert->excludedNames;
+        else {
+            WOLFSSL_MSG("\tinvalid subtree");
+            return ASN_PARSE_E;
+        }
+
+        DecodeSubtree(input + idx, length, subtree, cert->heap);
+
+        idx += length;
+    }
+
+    return 0;
+}
+#endif /* IGNORE_NAME_CONSTRAINTS */
+
+
+#ifdef WOLFSSL_SEP
+    static int DecodeCertPolicy(byte* input, int sz, DecodedCert* cert)
+    {
+        word32 idx = 0;
+        int length = 0;
+
+        WOLFSSL_ENTER("DecodeCertPolicy");
+
+        /* Unwrap certificatePolicies */
+        if (GetSequence(input, &idx, &length, sz) < 0) {
+            WOLFSSL_MSG("\tdeviceType isn't OID");
+            return ASN_PARSE_E;
+        }
+
+        if (GetSequence(input, &idx, &length, sz) < 0) {
+            WOLFSSL_MSG("\tdeviceType isn't OID");
+            return ASN_PARSE_E;
+        }
+
+        if (input[idx++] != ASN_OBJECT_ID) {
+            WOLFSSL_MSG("\tdeviceType isn't OID");
+            return ASN_PARSE_E;
+        }
+
+        if (GetLength(input, &idx, &length, sz) < 0) {
+            WOLFSSL_MSG("\tCouldn't read length of deviceType");
+            return ASN_PARSE_E;
+        }
+
+        if (length > 0) {
+            cert->deviceType = (byte*)XMALLOC(length, cert->heap, 0);
+            if (cert->deviceType == NULL) {
+                WOLFSSL_MSG("\tCouldn't alloc memory for deviceType");
+                return MEMORY_E;
+            }
+            cert->deviceTypeSz = length;
+            XMEMCPY(cert->deviceType, input + idx, length);
+        }
+
+        WOLFSSL_LEAVE("DecodeCertPolicy", 0);
+        return 0;
+    }
+#endif /* WOLFSSL_SEP */
+
+
+static int DecodeCertExtensions(DecodedCert* cert)
+/*
+ *  Processing the Certificate Extensions. This does not modify the current
+ *  index. It is works starting with the recorded extensions pointer.
+ */
+{
+    word32 idx = 0;
+    int sz = cert->extensionsSz;
+    byte* input = cert->extensions;
+    int length;
+    word32 oid;
+    byte critical = 0;
+    byte criticalFail = 0;
+
+    WOLFSSL_ENTER("DecodeCertExtensions");
+
+    if (input == NULL || sz == 0)
+        return BAD_FUNC_ARG;
+
+    if (input[idx++] != ASN_EXTENSIONS)
+        return ASN_PARSE_E;
+
+    if (GetLength(input, &idx, &length, sz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetSequence(input, &idx, &length, sz) < 0)
+        return ASN_PARSE_E;
+    
+    while (idx < (word32)sz) {
+        if (GetSequence(input, &idx, &length, sz) < 0) {
+            WOLFSSL_MSG("\tfail: should be a SEQUENCE");
+            return ASN_PARSE_E;
+        }
+
+        oid = 0;
+        if (GetObjectId(input, &idx, &oid, sz) < 0) {
+            WOLFSSL_MSG("\tfail: OBJECT ID");
+            return ASN_PARSE_E;
+        }
+
+        /* check for critical flag */
+        critical = 0;
+        if (input[idx] == ASN_BOOLEAN) {
+            int boolLength = 0;
+            idx++;
+            if (GetLength(input, &idx, &boolLength, sz) < 0) {
+                WOLFSSL_MSG("\tfail: critical boolean length");
+                return ASN_PARSE_E;
+            }
+            if (input[idx++])
+                critical = 1;
+        }
+
+        /* process the extension based on the OID */
+        if (input[idx++] != ASN_OCTET_STRING) {
+            WOLFSSL_MSG("\tfail: should be an OCTET STRING");
+            return ASN_PARSE_E;
+        }
+
+        if (GetLength(input, &idx, &length, sz) < 0) {
+            WOLFSSL_MSG("\tfail: extension data length");
+            return ASN_PARSE_E;
+        }
+
+        switch (oid) {
+            case BASIC_CA_OID:
+                #ifdef OPENSSL_EXTRA
+                    cert->extBasicConstSet = 1;
+                    cert->extBasicConstCrit = critical;
+                #endif
+                if (DecodeBasicCaConstraint(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            case CRL_DIST_OID:
+                if (DecodeCrlDist(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            case AUTH_INFO_OID:
+                if (DecodeAuthInfo(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            case ALT_NAMES_OID:
+                #ifdef OPENSSL_EXTRA
+                    cert->extSubjAltNameSet = 1;
+                    cert->extSubjAltNameCrit = critical;
+                #endif
+                if (DecodeAltNames(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            case AUTH_KEY_OID:
+                cert->extAuthKeyIdSet = 1;
+                #ifdef OPENSSL_EXTRA
+                    cert->extAuthKeyIdCrit = critical;
+                #endif
+                if (DecodeAuthKeyId(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            case SUBJ_KEY_OID:
+                cert->extSubjKeyIdSet = 1;
+                #ifdef OPENSSL_EXTRA
+                    cert->extSubjKeyIdCrit = critical;
+                #endif
+                if (DecodeSubjKeyId(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            case CERT_POLICY_OID:
+                WOLFSSL_MSG("Certificate Policy extension not supported yet.");
+                #ifdef WOLFSSL_SEP
+                    #ifdef OPENSSL_EXTRA
+                        cert->extCertPolicySet = 1;
+                        cert->extCertPolicyCrit = critical;
+                    #endif
+                    if (DecodeCertPolicy(&input[idx], length, cert) < 0)
+                        return ASN_PARSE_E;
+                #endif
+                break;
+
+            case KEY_USAGE_OID:
+                cert->extKeyUsageSet = 1;
+                #ifdef OPENSSL_EXTRA
+                    cert->extKeyUsageCrit = critical;
+                #endif
+                if (DecodeKeyUsage(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            case EXT_KEY_USAGE_OID:
+                cert->extExtKeyUsageSet = 1;
+                #ifdef OPENSSL_EXTRA
+                    cert->extExtKeyUsageCrit = critical;
+                #endif
+                if (DecodeExtKeyUsage(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            #ifndef IGNORE_NAME_CONSTRAINTS
+            case NAME_CONS_OID:
+                cert->extNameConstraintSet = 1;
+                #ifdef OPENSSL_EXTRA
+                    cert->extNameConstraintCrit = critical;
+                #endif
+                if (DecodeNameConstraints(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+            #endif /* IGNORE_NAME_CONSTRAINTS */
+
+            case INHIBIT_ANY_OID:
+                WOLFSSL_MSG("Inhibit anyPolicy extension not supported yet.");
+                break;
+
+            default:
+                /* While it is a failure to not support critical extensions,
+                 * still parse the certificate ignoring the unsupported
+                 * extention to allow caller to accept it with the verify
+                 * callback. */
+                if (critical)
+                    criticalFail = 1;
+                break;
+        }
+        idx += length;
+    }
+
+    return criticalFail ? ASN_CRIT_EXT_E : 0;
+}
+
+
+int ParseCert(DecodedCert* cert, int type, int verify, void* cm)
+{
+    int   ret;
+    char* ptr;
+
+    ret = ParseCertRelative(cert, type, verify, cm);
+    if (ret < 0)
+        return ret;
+
+    if (cert->subjectCNLen > 0) {
+        ptr = (char*) XMALLOC(cert->subjectCNLen + 1, cert->heap,
+                              DYNAMIC_TYPE_SUBJECT_CN);
+        if (ptr == NULL)
+            return MEMORY_E;
+        XMEMCPY(ptr, cert->subjectCN, cert->subjectCNLen);
+        ptr[cert->subjectCNLen] = '\0';
+        cert->subjectCN = ptr;
+        cert->subjectCNStored = 1;
+    }
+
+    if (cert->keyOID == RSAk &&
+                          cert->publicKey != NULL  && cert->pubKeySize > 0) {
+        ptr = (char*) XMALLOC(cert->pubKeySize, cert->heap,
+                              DYNAMIC_TYPE_PUBLIC_KEY);
+        if (ptr == NULL)
+            return MEMORY_E;
+        XMEMCPY(ptr, cert->publicKey, cert->pubKeySize);
+        cert->publicKey = (byte *)ptr;
+        cert->pubKeyStored = 1;
+    }
+
+    return ret;
+}
+
+
+/* from SSL proper, for locking can't do find here anymore */
+#ifdef __cplusplus
+    extern "C" {
+#endif
+    WOLFSSL_LOCAL Signer* GetCA(void* signers, byte* hash);
+    #ifndef NO_SKID
+        WOLFSSL_LOCAL Signer* GetCAByName(void* signers, byte* hash);
+    #endif
+#ifdef __cplusplus
+    } 
+#endif
+
+
+int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm)
+{
+    word32 confirmOID;
+    int    ret;
+    int    badDate     = 0;
+    int    criticalExt = 0;
+
+    if ((ret = DecodeToKey(cert, verify)) < 0) {
+        if (ret == ASN_BEFORE_DATE_E || ret == ASN_AFTER_DATE_E)
+            badDate = ret;
+        else
+            return ret;
+    }
+
+    WOLFSSL_MSG("Parsed Past Key");
+
+    if (cert->srcIdx < cert->sigIndex) {
+        #ifndef ALLOW_V1_EXTENSIONS
+            if (cert->version < 2) {
+                WOLFSSL_MSG("    v1 and v2 certs not allowed extensions");
+                return ASN_VERSION_E;
+            }
+        #endif
+        /* save extensions */
+        cert->extensions    = &cert->source[cert->srcIdx];
+        cert->extensionsSz  =  cert->sigIndex - cert->srcIdx;
+        cert->extensionsIdx = cert->srcIdx;   /* for potential later use */
+
+        if ((ret = DecodeCertExtensions(cert)) < 0) {
+            if (ret == ASN_CRIT_EXT_E)
+                criticalExt = ret;
+            else
+                return ret;
+        }
+
+        /* advance past extensions */
+        cert->srcIdx =  cert->sigIndex;
+    }
+
+    if ((ret = GetAlgoId(cert->source, &cert->srcIdx, &confirmOID,
+                         cert->maxIdx)) < 0)
+        return ret;
+
+    if ((ret = GetSignature(cert)) < 0)
+        return ret;
+
+    if (confirmOID != cert->signatureOID)
+        return ASN_SIG_OID_E;
+
+    #ifndef NO_SKID
+        if (cert->extSubjKeyIdSet == 0
+                          && cert->publicKey != NULL && cert->pubKeySize > 0) {
+        #ifdef NO_SHA
+            ret = wc_Sha256Hash(cert->publicKey, cert->pubKeySize,
+                                                            cert->extSubjKeyId);
+        #else
+            ret = wc_ShaHash(cert->publicKey, cert->pubKeySize,
+                                                            cert->extSubjKeyId);
+        #endif
+            if (ret != 0)
+                return ret;
+        }
+    #endif
+
+    if (verify && type != CA_TYPE) {
+        Signer* ca = NULL;
+        #ifndef NO_SKID
+            if (cert->extAuthKeyIdSet)
+                ca = GetCA(cm, cert->extAuthKeyId);
+            if (ca == NULL)
+                ca = GetCAByName(cm, cert->issuerHash);
+        #else /* NO_SKID */
+            ca = GetCA(cm, cert->issuerHash);
+        #endif /* NO SKID */
+        WOLFSSL_MSG("About to verify certificate signature");
+ 
+        if (ca) {
+#ifdef HAVE_OCSP
+            /* Need the ca's public key hash for OCSP */
+    #ifdef NO_SHA
+            ret = wc_Sha256Hash(ca->publicKey, ca->pubKeySize,
+                                cert->issuerKeyHash);
+    #else /* NO_SHA */
+            ret = wc_ShaHash(ca->publicKey, ca->pubKeySize,
+                                cert->issuerKeyHash);
+    #endif /* NO_SHA */
+            if (ret != 0)
+                return ret;
+#endif /* HAVE_OCSP */
+            /* try to confirm/verify signature */
+            if (!ConfirmSignature(cert->source + cert->certBegin,
+                        cert->sigIndex - cert->certBegin,
+                    ca->publicKey, ca->pubKeySize, ca->keyOID,
+                    cert->signature, cert->sigLength, cert->signatureOID,
+                    cert->heap)) {
+                WOLFSSL_MSG("Confirm signature failed");
+                return ASN_SIG_CONFIRM_E;
+            }
+#ifndef IGNORE_NAME_CONSTRAINTS
+            /* check that this cert's name is permitted by the signer's
+             * name constraints */
+            if (!ConfirmNameConstraints(ca, cert)) {
+                WOLFSSL_MSG("Confirm name constraint failed");
+                return ASN_NAME_INVALID_E;
+            }
+#endif /* IGNORE_NAME_CONSTRAINTS */
+        }
+        else {
+            /* no signer */
+            WOLFSSL_MSG("No CA signer to verify with");
+            return ASN_NO_SIGNER_E;
+        }
+    }
+
+    if (badDate != 0)
+        return badDate;
+
+    if (criticalExt != 0)
+        return criticalExt;
+
+    return 0;
+}
+
+
+/* Create and init an new signer */
+Signer* MakeSigner(void* heap)
+{
+    Signer* signer = (Signer*) XMALLOC(sizeof(Signer), heap,
+                                       DYNAMIC_TYPE_SIGNER);
+    if (signer) {
+        signer->pubKeySize = 0;
+        signer->keyOID     = 0;
+        signer->publicKey  = NULL;
+        signer->nameLen    = 0;
+        signer->name       = NULL;
+        #ifndef IGNORE_NAME_CONSTRAINTS
+            signer->permittedNames = NULL;
+            signer->excludedNames = NULL;
+        #endif /* IGNORE_NAME_CONSTRAINTS */
+        signer->next       = NULL;
+    }
+    (void)heap;
+
+    return signer;
+}
+
+
+/* Free an individual signer */
+void FreeSigner(Signer* signer, void* heap)
+{
+    XFREE(signer->name, heap, DYNAMIC_TYPE_SUBJECT_CN);
+    XFREE(signer->publicKey, heap, DYNAMIC_TYPE_PUBLIC_KEY);
+    #ifndef IGNORE_NAME_CONSTRAINTS
+        if (signer->permittedNames)
+            FreeNameSubtrees(signer->permittedNames, heap);
+        if (signer->excludedNames)
+            FreeNameSubtrees(signer->excludedNames, heap);
+    #endif
+    XFREE(signer, heap, DYNAMIC_TYPE_SIGNER);
+
+    (void)heap;
+}
+
+
+/* Free the whole singer table with number of rows */
+void FreeSignerTable(Signer** table, int rows, void* heap)
+{
+    int i;
+
+    for (i = 0; i < rows; i++) {
+        Signer* signer = table[i];
+        while (signer) {
+            Signer* next = signer->next;
+            FreeSigner(signer, heap);
+            signer = next;
+        }
+        table[i] = NULL;
+    }
+}
+
+
+WOLFSSL_LOCAL int SetMyVersion(word32 version, byte* output, int header)
+{
+    int i = 0;
+
+    if (header) {
+        output[i++] = ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED;
+        output[i++] = ASN_BIT_STRING;
+    }
+    output[i++] = ASN_INTEGER;
+    output[i++] = 0x01;
+    output[i++] = (byte)version;
+
+    return i;
+}
+
+
+WOLFSSL_LOCAL int SetSerialNumber(const byte* sn, word32 snSz, byte* output)
+{
+    int result = 0;
+
+    WOLFSSL_ENTER("SetSerialNumber");
+
+    if (snSz <= EXTERNAL_SERIAL_SIZE) {
+        output[0] = ASN_INTEGER;
+        /* The serial number is always positive. When encoding the
+         * INTEGER, if the MSB is 1, add a padding zero to keep the
+         * number positive. */
+        if (sn[0] & 0x80) {
+            output[1] = (byte)snSz + 1;
+            output[2] = 0;
+            XMEMCPY(&output[3], sn, snSz);
+            result = snSz + 3;
+        }
+        else {
+            output[1] = (byte)snSz;
+            XMEMCPY(&output[2], sn, snSz);
+            result = snSz + 2;
+        }
+    }
+    return result;
+}
+
+
+
+
+#if defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN)
+
+/* convert der buffer to pem into output, can't do inplace, der and output
+   need to be different */
+int wc_DerToPem(const byte* der, word32 derSz, byte* output, word32 outSz,
+             int type)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    char* header = NULL;
+    char* footer = NULL;
+#else
+    char header[80];
+    char footer[80];
+#endif
+
+    int headerLen = 80;
+    int footerLen = 80;
+    int i;
+    int err;
+    int outLen;   /* return length or error */
+
+    if (der == output)      /* no in place conversion */
+        return BAD_FUNC_ARG;
+
+#ifdef WOLFSSL_SMALL_STACK
+    header = (char*)XMALLOC(headerLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (header == NULL)
+        return MEMORY_E;
+    
+    footer = (char*)XMALLOC(footerLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (footer == NULL) {
+        XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    if (type == CERT_TYPE) {
+        XSTRNCPY(header, "-----BEGIN CERTIFICATE-----\n", headerLen);
+        XSTRNCPY(footer, "-----END CERTIFICATE-----\n",   footerLen);
+    }
+    else if (type == PRIVATEKEY_TYPE) {
+        XSTRNCPY(header, "-----BEGIN RSA PRIVATE KEY-----\n", headerLen);
+        XSTRNCPY(footer, "-----END RSA PRIVATE KEY-----\n",   footerLen);
+    }
+    #ifdef HAVE_ECC
+    else if (type == ECC_PRIVATEKEY_TYPE) {
+        XSTRNCPY(header, "-----BEGIN EC PRIVATE KEY-----\n", headerLen);
+        XSTRNCPY(footer, "-----END EC PRIVATE KEY-----\n",   footerLen);
+    }
+    #endif
+    #ifdef WOLFSSL_CERT_REQ
+    else if (type == CERTREQ_TYPE)
+    {
+        XSTRNCPY(header,
+                       "-----BEGIN CERTIFICATE REQUEST-----\n", headerLen);
+        XSTRNCPY(footer, "-----END CERTIFICATE REQUEST-----\n", footerLen);
+    }
+    #endif
+    else {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(footer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return BAD_FUNC_ARG;
+    }
+
+    headerLen = (int)XSTRLEN(header);
+    footerLen = (int)XSTRLEN(footer);
+
+    if (!der || !output) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(footer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return BAD_FUNC_ARG;
+    }
+
+    /* don't even try if outSz too short */
+    if (outSz < headerLen + footerLen + derSz) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(footer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return BAD_FUNC_ARG;
+    }
+
+    /* header */
+    XMEMCPY(output, header, headerLen);
+    i = headerLen;
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(header, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    /* body */
+    outLen = outSz - (headerLen + footerLen);  /* input to Base64_Encode */
+    if ( (err = Base64_Encode(der, derSz, output + i, (word32*)&outLen)) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(footer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return err;
+    }
+    i += outLen;
+
+    /* footer */
+    if ( (i + footerLen) > (int)outSz) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(footer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return BAD_FUNC_ARG;
+    }
+    XMEMCPY(output + i, footer, footerLen);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(footer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return outLen + headerLen + footerLen;
+}
+
+
+#endif /* WOLFSSL_KEY_GEN || WOLFSSL_CERT_GEN */
+
+
+#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA)
+
+
+static mp_int* GetRsaInt(RsaKey* key, int idx)
+{
+    if (idx == 0)
+        return &key->n;
+    if (idx == 1)
+        return &key->e;
+    if (idx == 2)
+        return &key->d;
+    if (idx == 3)
+        return &key->p;
+    if (idx == 4)
+        return &key->q;
+    if (idx == 5)
+        return &key->dP;
+    if (idx == 6)
+        return &key->dQ;
+    if (idx == 7)
+        return &key->u;
+
+    return NULL;
+}
+
+
+/* Release Tmp RSA resources */
+static INLINE void FreeTmpRsas(byte** tmps, void* heap)
+{
+    int i;
+
+    (void)heap;
+
+    for (i = 0; i < RSA_INTS; i++) 
+        XFREE(tmps[i], heap, DYNAMIC_TYPE_RSA);
+}
+
+
+/* Convert RsaKey key to DER format, write to output (inLen), return bytes
+   written */
+int wc_RsaKeyToDer(RsaKey* key, byte* output, word32 inLen)
+{
+    word32 seqSz, verSz, rawLen, intTotalLen = 0;
+    word32 sizes[RSA_INTS];
+    int    i, j, outLen, ret = 0;
+
+    byte  seq[MAX_SEQ_SZ];
+    byte  ver[MAX_VERSION_SZ];
+    byte* tmps[RSA_INTS];
+
+    if (!key || !output)
+        return BAD_FUNC_ARG;
+
+    if (key->type != RSA_PRIVATE)
+        return BAD_FUNC_ARG;
+
+    for (i = 0; i < RSA_INTS; i++)
+        tmps[i] = NULL;
+
+    /* write all big ints from key to DER tmps */
+    for (i = 0; i < RSA_INTS; i++) {
+        mp_int* keyInt = GetRsaInt(key, i);
+        rawLen = mp_unsigned_bin_size(keyInt);
+        tmps[i] = (byte*)XMALLOC(rawLen + MAX_SEQ_SZ, key->heap,
+                                 DYNAMIC_TYPE_RSA);
+        if (tmps[i] == NULL) {
+            ret = MEMORY_E;
+            break;
+        }
+
+        tmps[i][0] = ASN_INTEGER;
+        sizes[i] = SetLength(rawLen, tmps[i] + 1) + 1;  /* int tag */
+
+        if (sizes[i] <= MAX_SEQ_SZ) {
+            int err = mp_to_unsigned_bin(keyInt, tmps[i] + sizes[i]);
+            if (err == MP_OKAY) {
+                sizes[i] += rawLen;
+                intTotalLen += sizes[i];
+            }
+            else {
+                ret = err;
+                break;
+            }
+        }
+        else {
+            ret = ASN_INPUT_E;
+            break;
+        }
+    }
+
+    if (ret != 0) {
+        FreeTmpRsas(tmps, key->heap);
+        return ret;
+    }
+
+    /* make headers */
+    verSz = SetMyVersion(0, ver, FALSE);
+    seqSz = SetSequence(verSz + intTotalLen, seq);
+
+    outLen = seqSz + verSz + intTotalLen;
+    if (outLen > (int)inLen)
+        return BAD_FUNC_ARG;
+
+    /* write to output */
+    XMEMCPY(output, seq, seqSz);
+    j = seqSz;
+    XMEMCPY(output + j, ver, verSz);
+    j += verSz;
+
+    for (i = 0; i < RSA_INTS; i++) {
+        XMEMCPY(output + j, tmps[i], sizes[i]);
+        j += sizes[i];
+    }
+    FreeTmpRsas(tmps, key->heap);
+
+    return outLen;
+}
+
+#endif /* WOLFSSL_KEY_GEN && !NO_RSA */
+
+
+#if defined(WOLFSSL_CERT_GEN) && !defined(NO_RSA)
+
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* WOLFSSL_HAVE_MIN */
+
+
+/* Initialize and Set Certficate defaults:
+   version    = 3 (0x2)
+   serial     = 0
+   sigType    = SHA_WITH_RSA
+   issuer     = blank
+   daysValid  = 500
+   selfSigned = 1 (true) use subject as issuer
+   subject    = blank
+*/
+void wc_InitCert(Cert* cert)
+{
+    cert->version    = 2;   /* version 3 is hex 2 */
+    cert->sigType    = CTC_SHAwRSA;
+    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
+    cert->keyType    = RSA_KEY;
+    XMEMSET(cert->serial, 0, CTC_SERIAL_SIZE);
+
+    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
+}
+
+
+/* DER encoded x509 Certificate */
+typedef struct DerCert {
+    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 sigAlgo[MAX_ALGO_SZ];         /* signature algo encoded */
+    byte issuer[ASN_NAME_MAX];         /* issuer  encoded */
+    byte subject[ASN_NAME_MAX];        /* subject encoded */
+    byte validity[MAX_DATE_SIZE*2 + MAX_SEQ_SZ*2];  /* before and after dates */
+    byte publicKey[MAX_PUBLIC_KEY_SZ]; /* rsa / ntru public key encoded */
+    byte ca[MAX_CA_SZ];                /* basic constraint CA true size */
+    byte extensions[MAX_EXTENSIONS_SZ];  /* all extensions */
+#ifdef WOLFSSL_CERT_REQ
+    byte attrib[MAX_ATTRIB_SZ];        /* Cert req attributes encoded */
+#endif
+    int  sizeSz;                       /* encoded size length */
+    int  versionSz;                    /* encoded version length */
+    int  serialSz;                     /* encoded serial length */
+    int  sigAlgoSz;                    /* enocded sig alog length */
+    int  issuerSz;                     /* encoded issuer length */
+    int  subjectSz;                    /* encoded subject length */
+    int  validitySz;                   /* encoded validity length */
+    int  publicKeySz;                  /* encoded public key length */
+    int  caSz;                         /* encoded CA extension length */
+    int  extensionsSz;                 /* encoded extensions total length */
+    int  total;                        /* total encoded lengths */
+#ifdef WOLFSSL_CERT_REQ
+    int  attribSz;
+#endif
+} DerCert;
+
+
+#ifdef WOLFSSL_CERT_REQ
+
+/* Write a set header to output */
+static word32 SetUTF8String(word32 len, byte* output)
+{
+    output[0] = ASN_UTF8STRING;
+    return SetLength(len, output + 1) + 1;
+}
+
+#endif /* WOLFSSL_CERT_REQ */
+
+
+/* Write a serial number to output */
+static int SetSerial(const byte* serial, byte* output)
+{
+    int length = 0;
+
+    output[length++] = ASN_INTEGER;
+    length += SetLength(CTC_SERIAL_SIZE, &output[length]);
+    XMEMCPY(&output[length], serial, CTC_SERIAL_SIZE);
+
+    return length + CTC_SERIAL_SIZE;
+}
+
+
+#ifdef HAVE_ECC 
+
+
+/* Write a public ECC key to output */
+static int SetEccPublicKey(byte* output, ecc_key* key)
+{
+    byte len[MAX_LENGTH_SZ + 1];  /* trailing 0 */
+    int  algoSz;
+    int  curveSz;
+    int  lenSz;
+    int  idx;
+    word32 pubSz = ECC_BUFSIZE;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* algo = NULL;
+    byte* curve = NULL;
+    byte* pub = NULL;
+#else
+    byte algo[MAX_ALGO_SZ];
+    byte curve[MAX_ALGO_SZ];
+    byte pub[ECC_BUFSIZE];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    pub = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (pub == NULL)
+        return MEMORY_E;
+#endif
+
+    int ret = wc_ecc_export_x963(key, pub, &pubSz);
+    if (ret != 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ret;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    curve = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (curve == NULL) {
+        XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    /* headers */
+    curveSz = SetCurve(key, curve);
+    if (curveSz <= 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(pub,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return curveSz;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (algo == NULL) {
+        XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(pub,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    algoSz  = SetAlgoID(ECDSAk, algo, keyType, curveSz);
+    lenSz   = SetLength(pubSz + 1, len);
+    len[lenSz++] = 0;   /* trailing 0 */
+
+    /* write */
+    idx = SetSequence(pubSz + curveSz + lenSz + 1 + algoSz, output);
+        /* 1 is for ASN_BIT_STRING */
+    /* algo */
+    XMEMCPY(output + idx, algo, algoSz);
+    idx += algoSz;
+    /* curve */
+    XMEMCPY(output + idx, curve, curveSz);
+    idx += curveSz;
+    /* bit string */
+    output[idx++] = ASN_BIT_STRING;
+    /* length */
+    XMEMCPY(output + idx, len, lenSz);
+    idx += lenSz;
+    /* pub */
+    XMEMCPY(output + idx, pub, pubSz);
+    idx += pubSz;
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(algo,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(pub,   NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return idx;
+}
+
+
+#endif /* HAVE_ECC */
+
+
+/* Write a public RSA key to output */
+static int SetRsaPublicKey(byte* output, RsaKey* key)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    byte* n = NULL;
+    byte* e = NULL;
+    byte* algo = NULL;
+#else
+    byte n[MAX_RSA_INT_SZ];
+    byte e[MAX_RSA_E_SZ];
+    byte algo[MAX_ALGO_SZ];
+#endif
+    byte seq[MAX_SEQ_SZ];
+    byte len[MAX_LENGTH_SZ + 1];  /* trailing 0 */
+    int  nSz;
+    int  eSz;
+    int  algoSz;
+    int  seqSz;
+    int  lenSz;
+    int  idx;
+    int  rawLen;
+    int  leadingBit;
+    int  err;
+
+    /* n */
+#ifdef WOLFSSL_SMALL_STACK
+    n = (byte*)XMALLOC(MAX_RSA_INT_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (n == NULL)
+        return MEMORY_E;
+#endif
+
+    leadingBit = mp_leading_bit(&key->n);
+    rawLen = mp_unsigned_bin_size(&key->n) + leadingBit;
+    n[0] = ASN_INTEGER;
+    nSz  = SetLength(rawLen, n + 1) + 1;  /* int tag */
+
+    if ( (nSz + rawLen) < MAX_RSA_INT_SZ) {
+        if (leadingBit)
+            n[nSz] = 0;
+        err = mp_to_unsigned_bin(&key->n, n + nSz + leadingBit);
+        if (err == MP_OKAY)
+            nSz += rawLen;
+        else {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return MP_TO_E;
+        }
+    }
+    else {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return BUFFER_E;
+    }
+
+    /* e */
+#ifdef WOLFSSL_SMALL_STACK
+    e = (byte*)XMALLOC(MAX_RSA_E_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (e == NULL) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return MEMORY_E;
+    }
+#endif
+
+    leadingBit = mp_leading_bit(&key->e);
+    rawLen = mp_unsigned_bin_size(&key->e) + leadingBit;
+    e[0] = ASN_INTEGER;
+    eSz  = SetLength(rawLen, e + 1) + 1;  /* int tag */
+
+    if ( (eSz + rawLen) < MAX_RSA_E_SZ) {
+        if (leadingBit)
+            e[eSz] = 0;
+        err = mp_to_unsigned_bin(&key->e, e + eSz + leadingBit);
+        if (err == MP_OKAY)
+            eSz += rawLen;
+        else {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(e, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return MP_TO_E;
+        }
+    }
+    else {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(e, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return BUFFER_E;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (algo == NULL) {
+        XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(e, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    /* headers */
+    algoSz = SetAlgoID(RSAk, algo, keyType, 0);
+    seqSz  = SetSequence(nSz + eSz, seq);
+    lenSz  = SetLength(seqSz + nSz + eSz + 1, len);
+    len[lenSz++] = 0;   /* trailing 0 */
+
+    /* write */
+    idx = SetSequence(nSz + eSz + seqSz + lenSz + 1 + algoSz, output);
+        /* 1 is for ASN_BIT_STRING */
+    /* algo */
+    XMEMCPY(output + idx, algo, algoSz);
+    idx += algoSz;
+    /* bit string */
+    output[idx++] = ASN_BIT_STRING;
+    /* length */
+    XMEMCPY(output + idx, len, lenSz);
+    idx += lenSz;
+    /* seq */
+    XMEMCPY(output + idx, seq, seqSz);
+    idx += seqSz;
+    /* n */
+    XMEMCPY(output + idx, n, nSz);
+    idx += nSz;
+    /* e */
+    XMEMCPY(output + idx, e, eSz);
+    idx += eSz;
+
+#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);
+#endif
+
+    return idx;
+}
+
+
+static INLINE byte itob(int number)
+{
+    return (byte)number + 0x30;
+}
+
+
+/* write time to output, format */
+static void SetTime(struct tm* date, byte* output)
+{
+    int i = 0;
+
+    output[i++] = itob((date->tm_year % 10000) / 1000);
+    output[i++] = itob((date->tm_year % 1000)  /  100);
+    output[i++] = itob((date->tm_year % 100)   /   10);
+    output[i++] = itob( date->tm_year % 10);
+
+    output[i++] = itob(date->tm_mon / 10);
+    output[i++] = itob(date->tm_mon % 10);
+
+    output[i++] = itob(date->tm_mday / 10);
+    output[i++] = itob(date->tm_mday % 10);
+
+    output[i++] = itob(date->tm_hour / 10);
+    output[i++] = itob(date->tm_hour % 10);
+
+    output[i++] = itob(date->tm_min / 10);
+    output[i++] = itob(date->tm_min % 10);
+
+    output[i++] = itob(date->tm_sec / 10);
+    output[i++] = itob(date->tm_sec % 10);
+    
+    output[i] = 'Z';  /* Zulu profile */
+}
+
+
+#ifdef WOLFSSL_ALT_NAMES
+
+/* Copy Dates from cert, return bytes written */
+static int CopyValidity(byte* output, Cert* cert)
+{
+    int seqSz;
+
+    WOLFSSL_ENTER("CopyValidity");
+
+    /* headers and output */
+    seqSz = SetSequence(cert->beforeDateSz + cert->afterDateSz, output);
+    XMEMCPY(output + seqSz, cert->beforeDate, cert->beforeDateSz);
+    XMEMCPY(output + seqSz + cert->beforeDateSz, cert->afterDate,
+                                                 cert->afterDateSz);
+    return seqSz + cert->beforeDateSz + cert->afterDateSz;
+}
+
+#endif
+
+
+/* for systems where mktime() doesn't normalize fully */
+static void RebuildTime(time_t* in, struct tm* out)
+{
+    #ifdef FREESCALE_MQX
+        out = localtime_r(in, out);
+    #else
+        (void)in;
+        (void)out;
+    #endif
+}
+
+
+/* Set Date validity from now until now + daysValid */
+static int SetValidity(byte* output, int daysValid)
+{
+    byte before[MAX_DATE_SIZE];
+    byte  after[MAX_DATE_SIZE];
+
+    int beforeSz;
+    int afterSz;
+    int seqSz;
+
+    time_t     ticks;
+    time_t     normalTime;
+    struct tm* now;
+    struct tm* tmpTime = NULL;
+    struct tm  local;
+
+#if defined(FREESCALE_MQX) || defined(TIME_OVERRIDES)
+    /* for use with gmtime_r */
+    struct tm tmpTimeStorage;
+    tmpTime = &tmpTimeStorage;
+#else
+    (void)tmpTime;
+#endif
+
+    ticks = XTIME(0);
+    now   = XGMTIME(&ticks, tmpTime);
+
+    /* 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);
+
+    /* adjust */
+    local.tm_year += 1900;
+    local.tm_mon  +=    1;
+
+    SetTime(&local, 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);
+
+    /* adjust */
+    local.tm_year += 1900;
+    local.tm_mon  +=    1;
+
+    SetTime(&local, after + afterSz);
+    afterSz += ASN_GEN_TIME_SZ;
+
+    /* headers and output */
+    seqSz = SetSequence(beforeSz + afterSz, output);
+    XMEMCPY(output + seqSz, before, beforeSz);
+    XMEMCPY(output + seqSz + beforeSz, after, afterSz);
+
+    return seqSz + beforeSz + afterSz;
+}
+
+
+/* ASN Encoded Name field */
+typedef struct EncodedName {
+    int  nameLen;                /* actual string value length */
+    int  totalLen;               /* total encoded length */
+    int  type;                   /* type of name */
+    int  used;                   /* are we actually using this one */
+    byte encoded[CTC_NAME_SIZE * 2]; /* encoding */
+} EncodedName;
+
+
+/* Get Which Name from index */
+static const char* GetOneName(CertName* name, int idx)
+{
+    switch (idx) {
+    case 0:
+       return name->country;
+
+    case 1:
+       return name->state;
+
+    case 2:
+       return name->locality;
+
+    case 3:
+       return name->sur;
+
+    case 4:
+       return name->org;
+
+    case 5:
+       return name->unit;
+
+    case 6:
+       return name->commonName;
+
+    case 7:
+       return name->email;
+
+    default:
+       return 0;
+    }
+}
+
+
+/* Get Which Name Encoding from index */
+static char GetNameType(CertName* name, int idx)
+{
+    switch (idx) {
+    case 0:
+       return name->countryEnc;
+
+    case 1:
+       return name->stateEnc;
+
+    case 2:
+       return name->localityEnc;
+
+    case 3:
+       return name->surEnc;
+
+    case 4:
+       return name->orgEnc;
+
+    case 5:
+       return name->unitEnc;
+
+    case 6:
+       return name->commonNameEnc;
+
+    default:
+       return 0;
+    }
+}
+
+
+/* Get ASN Name from index */
+static byte GetNameId(int idx)
+{
+    switch (idx) {
+    case 0:
+       return ASN_COUNTRY_NAME;
+
+    case 1:
+       return ASN_STATE_NAME;
+
+    case 2:
+       return ASN_LOCALITY_NAME;
+
+    case 3:
+       return ASN_SUR_NAME;
+
+    case 4:
+       return ASN_ORG_NAME;
+
+    case 5:
+       return ASN_ORGUNIT_NAME;
+
+    case 6:
+       return ASN_COMMON_NAME;
+
+    case 7:
+       /* email uses different id type */
+       return 0;
+
+    default:
+       return 0;
+    }
+}
+
+
+/* encode all extensions, return total bytes written */
+static int SetExtensions(byte* output, const byte* ext, int extSz, int header)
+{
+    byte sequence[MAX_SEQ_SZ];
+    byte len[MAX_LENGTH_SZ];
+
+    int sz = 0;
+    int seqSz = SetSequence(extSz, sequence);
+
+    if (header) {
+        int lenSz = SetLength(seqSz + extSz, len);
+        output[0] = ASN_EXTENSIONS; /* extensions id */
+        sz++;
+        XMEMCPY(&output[sz], len, lenSz);  /* length */
+        sz += lenSz;
+    }
+    XMEMCPY(&output[sz], sequence, seqSz);  /* sequence */
+    sz += seqSz;
+    XMEMCPY(&output[sz], ext, extSz);  /* extensions */
+    sz += extSz;
+
+    return sz;
+}
+
+
+/* encode CA basic constraint true, return total bytes written */
+static int SetCa(byte* output)
+{
+    static const byte ca[] = { 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04,
+                               0x05, 0x30, 0x03, 0x01, 0x01, 0xff };
+    
+    XMEMCPY(output, ca, sizeof(ca));
+
+    return (int)sizeof(ca);
+}
+
+
+/* encode CertName into output, return total bytes written */
+static int SetName(byte* output, CertName* name)
+{
+    int          totalBytes = 0, i, idx;
+#ifdef WOLFSSL_SMALL_STACK
+    EncodedName* names = NULL;
+#else
+    EncodedName  names[NAME_ENTRIES];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    names = (EncodedName*)XMALLOC(sizeof(EncodedName) * NAME_ENTRIES, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (names == NULL)
+        return MEMORY_E;
+#endif
+
+    for (i = 0; i < NAME_ENTRIES; i++) {
+        const char* nameStr = GetOneName(name, i);
+        if (nameStr) {
+            /* bottom up */
+            byte firstLen[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;
+            }
+
+            secondSz = SetLength(strLen, secondLen);
+            thisLen += secondSz;
+            if (email) {
+                thisLen += EMAIL_JOINT_LEN;
+                thisLen ++;                               /* id type */
+                firstSz  = SetLength(EMAIL_JOINT_LEN, firstLen);
+            }
+            else {
+                thisLen++;                                 /* str type */
+                thisLen++;                                 /* id  type */
+                thisLen += JOINT_LEN;    
+                firstSz = SetLength(JOINT_LEN + 1, firstLen);
+            }
+            thisLen += firstSz;
+            thisLen++;                                /* object id */
+
+            seqSz = SetSequence(thisLen, sequence);
+            thisLen += seqSz;
+            setSz = SetSet(thisLen, set);
+            thisLen += setSz;
+
+            if (thisLen > (int)sizeof(names[i].encoded)) {
+#ifdef WOLFSSL_SMALL_STACK
+                XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+                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 */
+            names[i].encoded[idx++] = ASN_OBJECT_ID;
+            /* first length */
+            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);
+            }
+            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;
+    }
+
+    /* header */
+    idx = SetSequence(totalBytes, output);
+    totalBytes += idx;
+    if (totalBytes > ASN_NAME_MAX) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return BUFFER_E;
+    }
+
+    for (i = 0; i < NAME_ENTRIES; i++) {
+        if (names[i].used) {
+            XMEMCPY(output + idx, names[i].encoded, names[i].totalLen);
+            idx += names[i].totalLen;
+        }
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return totalBytes;
+}
+
+/* encode info from cert into DER encoded format */
+static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey,
+                      RNG* rng, const byte* ntruKey, word16 ntruSz)
+{
+    int ret;
+
+    (void)eccKey;
+    (void)ntruKey;
+    (void)ntruSz;
+
+    /* init */
+    XMEMSET(der, 0, sizeof(DerCert));
+
+    /* version */
+    der->versionSz = SetMyVersion(cert->version, der->version, TRUE);
+
+    /* serial number */
+    ret = wc_RNG_GenerateBlock(rng, cert->serial, CTC_SERIAL_SIZE);
+    if (ret != 0)
+        return ret;
+
+    cert->serial[0] = 0x01;   /* ensure positive */
+    der->serialSz  = SetSerial(cert->serial, der->serial);
+
+    /* signature algo */
+    der->sigAlgoSz = SetAlgoID(cert->sigType, der->sigAlgo, sigType, 0);
+    if (der->sigAlgoSz == 0)
+        return ALGO_ID_E;
+
+    /* public key */
+    if (cert->keyType == RSA_KEY) {
+        if (rsaKey == NULL)
+            return PUBLIC_KEY_E;
+        der->publicKeySz = SetRsaPublicKey(der->publicKey, rsaKey);
+        if (der->publicKeySz <= 0)
+            return PUBLIC_KEY_E;
+    }
+
+#ifdef HAVE_ECC
+    if (cert->keyType == ECC_KEY) {
+        if (eccKey == NULL)
+            return PUBLIC_KEY_E;
+        der->publicKeySz = SetEccPublicKey(der->publicKey, eccKey);
+        if (der->publicKeySz <= 0)
+            return PUBLIC_KEY_E;
+    }
+#endif /* HAVE_ECC */
+
+#ifdef HAVE_NTRU
+    if (cert->keyType == NTRU_KEY) {
+        word32 rc;
+        word16 encodedSz;
+
+        rc  = ntru_crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo( ntruSz,
+                                                   ntruKey, &encodedSz, NULL);
+        if (rc != NTRU_OK)
+            return PUBLIC_KEY_E;
+        if (encodedSz > MAX_PUBLIC_KEY_SZ)
+            return PUBLIC_KEY_E;
+
+        rc  = ntru_crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo( ntruSz,
+                                         ntruKey, &encodedSz, der->publicKey);
+        if (rc != NTRU_OK)
+            return PUBLIC_KEY_E;
+
+        der->publicKeySz = encodedSz;
+    }
+#endif /* HAVE_NTRU */
+
+    der->validitySz = 0;
+#ifdef WOLFSSL_ALT_NAMES
+    /* date validity copy ? */
+    if (cert->beforeDateSz && cert->afterDateSz) {
+        der->validitySz = CopyValidity(der->validity, cert);
+        if (der->validitySz == 0)
+            return DATE_E;
+    }
+#endif
+
+    /* date validity */
+    if (der->validitySz == 0) {
+        der->validitySz = SetValidity(der->validity, cert->daysValid);
+        if (der->validitySz == 0)
+            return DATE_E;
+    }
+
+    /* subject name */
+    der->subjectSz = SetName(der->subject, &cert->subject);
+    if (der->subjectSz == 0)
+        return SUBJECT_E;
+
+    /* issuer name */
+    der->issuerSz = SetName(der->issuer, cert->selfSigned ?
+             &cert->subject : &cert->issuer);
+    if (der->issuerSz == 0)
+        return ISSUER_E;
+
+    /* CA */
+    if (cert->isCA) {
+        der->caSz = SetCa(der->ca);
+        if (der->caSz == 0)
+            return CA_TRUE_E;
+    }
+    else
+        der->caSz = 0;
+
+    /* extensions, just CA now */
+    if (cert->isCA) {
+        der->extensionsSz = SetExtensions(der->extensions,
+                                          der->ca, der->caSz, TRUE);
+        if (der->extensionsSz == 0)
+            return EXTENSIONS_E;
+    }
+    else
+        der->extensionsSz = 0;
+
+#ifdef WOLFSSL_ALT_NAMES
+    if (der->extensionsSz == 0 && cert->altNamesSz) {
+        der->extensionsSz = SetExtensions(der->extensions, cert->altNames,
+                                          cert->altNamesSz, TRUE);
+        if (der->extensionsSz == 0)
+            return EXTENSIONS_E;
+    }
+#endif
+
+    der->total = der->versionSz + der->serialSz + der->sigAlgoSz +
+        der->publicKeySz + der->validitySz + der->subjectSz + der->issuerSz +
+        der->extensionsSz;
+
+    return 0;
+}
+
+
+/* write DER encoded cert to buffer, size already checked */
+static int WriteCertBody(DerCert* der, byte* buffer)
+{
+    int idx;
+
+    /* signed part header */
+    idx = SetSequence(der->total, buffer);
+    /* version */
+    XMEMCPY(buffer + idx, der->version, der->versionSz);
+    idx += der->versionSz;
+    /* serial */
+    XMEMCPY(buffer + idx, der->serial, der->serialSz);
+    idx += der->serialSz;
+    /* sig algo */
+    XMEMCPY(buffer + idx, der->sigAlgo, der->sigAlgoSz);
+    idx += der->sigAlgoSz;
+    /* issuer */
+    XMEMCPY(buffer + idx, der->issuer, der->issuerSz);
+    idx += der->issuerSz;
+    /* validity */
+    XMEMCPY(buffer + idx, der->validity, der->validitySz);
+    idx += der->validitySz;
+    /* subject */
+    XMEMCPY(buffer + idx, der->subject, der->subjectSz);
+    idx += der->subjectSz;
+    /* public key */
+    XMEMCPY(buffer + idx, der->publicKey, der->publicKeySz);
+    idx += der->publicKeySz;
+    if (der->extensionsSz) {
+        /* extensions */
+        XMEMCPY(buffer + idx, der->extensions, min(der->extensionsSz,
+                                                   sizeof(der->extensions)));
+        idx += der->extensionsSz;
+    }
+
+    return idx;
+}
+
+
+/* Make RSA signature from buffer (sz), write to sig (sigSz) */
+static int MakeSignature(const byte* buffer, int sz, byte* sig, int sigSz,
+                         RsaKey* rsaKey, ecc_key* eccKey, RNG* rng,
+                         int sigAlgoType)
+{
+    int encSigSz, digestSz, typeH = 0, ret = 0;
+    byte digest[SHA256_DIGEST_SIZE]; /* max size */
+#ifdef WOLFSSL_SMALL_STACK
+    byte* encSig;
+#else
+    byte encSig[MAX_ENCODED_DIG_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ];
+#endif
+
+    (void)digest;
+    (void)digestSz;
+    (void)encSig;
+    (void)encSigSz;
+    (void)typeH;
+
+    (void)buffer;
+    (void)sz;
+    (void)sig;
+    (void)sigSz;
+    (void)rsaKey;
+    (void)eccKey;
+    (void)rng;
+
+    switch (sigAlgoType) {
+    #ifndef NO_MD5
+        case CTC_MD5wRSA:
+        if ((ret = wc_Md5Hash(buffer, sz, digest)) == 0) {
+            typeH    = MD5h;
+            digestSz = MD5_DIGEST_SIZE;
+        }
+        break;
+    #endif
+    #ifndef NO_SHA
+        case CTC_SHAwRSA:
+        case CTC_SHAwECDSA:
+        if ((ret = wc_ShaHash(buffer, sz, digest)) == 0) {
+            typeH    = SHAh;
+            digestSz = SHA_DIGEST_SIZE;          
+        }
+        break;
+    #endif
+    #ifndef NO_SHA256
+        case CTC_SHA256wRSA:
+        case CTC_SHA256wECDSA:
+        if ((ret = wc_Sha256Hash(buffer, sz, digest)) == 0) {
+            typeH    = SHA256h;
+            digestSz = SHA256_DIGEST_SIZE;
+        }
+        break;
+    #endif
+        default:
+            WOLFSSL_MSG("MakeSignautre called with unsupported type");
+            ret = ALGO_ID_E;
+    }
+    
+    if (ret != 0)
+        return ret;
+    
+#ifdef WOLFSSL_SMALL_STACK
+    encSig = (byte*)XMALLOC(MAX_ENCODED_DIG_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ,
+                                                 NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (encSig == NULL)
+        return MEMORY_E;
+#endif
+    
+    ret = ALGO_ID_E;
+    
+#ifndef NO_RSA
+    if (rsaKey) {
+        /* signature */
+        encSigSz = wc_EncodeSignature(encSig, digest, digestSz, typeH);
+        ret = wc_RsaSSL_Sign(encSig, encSigSz, sig, sigSz, rsaKey, rng);
+    }
+#endif
+    
+#ifdef HAVE_ECC
+    if (!rsaKey && eccKey) {
+        word32 outSz = sigSz;
+        ret = wc_ecc_sign_hash(digest, digestSz, sig, &outSz, rng, eccKey);
+
+        if (ret == 0)
+            ret = outSz;
+    }
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(encSig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+/* add signature to end of buffer, size of buffer assumed checked, return
+   new length */
+static int AddSignature(byte* buffer, int bodySz, const byte* sig, int sigSz,
+                        int sigAlgoType)
+{
+    byte seq[MAX_SEQ_SZ];
+    int  idx = bodySz, seqSz;
+
+    /* algo */
+    idx += SetAlgoID(sigAlgoType, buffer + idx, sigType, 0);
+    /* bit string */
+    buffer[idx++] = ASN_BIT_STRING;
+    /* length */
+    idx += SetLength(sigSz + 1, buffer + idx);
+    buffer[idx++] = 0;   /* trailing 0 */
+    /* signature */
+    XMEMCPY(buffer + idx, sig, sigSz);
+    idx += sigSz;
+
+    /* make room for overall header */
+    seqSz = SetSequence(idx, seq);
+    XMEMMOVE(buffer + seqSz, buffer, idx);
+    XMEMCPY(buffer, seq, seqSz);
+
+    return idx + seqSz;
+}
+
+
+/* Make an x509 Certificate v3 any key type from cert input, write to buffer */
+static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz,
+                       RsaKey* rsaKey, ecc_key* eccKey, RNG* rng,
+                       const byte* ntruKey, word16 ntruSz)
+{
+    int ret;
+#ifdef WOLFSSL_SMALL_STACK
+    DerCert* der;
+#else
+    DerCert der[1];
+#endif
+
+    cert->keyType = eccKey ? ECC_KEY : (rsaKey ? RSA_KEY : NTRU_KEY);
+
+#ifdef WOLFSSL_SMALL_STACK
+    der = (DerCert*)XMALLOC(sizeof(DerCert), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (der == NULL)
+        return MEMORY_E;
+#endif
+
+    ret = EncodeCert(cert, der, rsaKey, eccKey, rng, ntruKey, ntruSz);
+
+    if (ret == 0) {
+        if (der->total + MAX_SEQ_SZ * 2 > (int)derSz)
+            ret = BUFFER_E;
+        else
+            ret = cert->bodySz = WriteCertBody(der, derBuffer);
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+/* Make an x509 Certificate v3 RSA or ECC from cert input, write to buffer */
+int wc_MakeCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey,
+             ecc_key* eccKey, RNG* rng)
+{
+    return MakeAnyCert(cert, derBuffer, derSz, rsaKey, eccKey, rng, NULL, 0);
+}
+
+
+#ifdef HAVE_NTRU
+
+int wc_MakeNtruCert(Cert* cert, byte* derBuffer, word32 derSz,
+                  const byte* ntruKey, word16 keySz, RNG* rng)
+{
+    return MakeAnyCert(cert, derBuffer, derSz, NULL, NULL, rng, ntruKey, keySz);
+}
+
+#endif /* HAVE_NTRU */
+
+
+#ifdef WOLFSSL_CERT_REQ
+
+static int SetReqAttrib(byte* output, char* pw, int extSz)
+{
+    static const byte cpOid[] =
+        { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+                         0x09, 0x07 };
+    static const byte erOid[] =
+        { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+                         0x09, 0x0e };
+
+    int sz      = 0; /* overall size */
+    int cpSz    = 0; /* Challenge Password section size */
+    int cpSeqSz = 0;
+    int cpSetSz = 0;
+    int cpStrSz = 0;
+    int pwSz    = 0;
+    int erSz    = 0; /* Extension Request section size */
+    int erSeqSz = 0;
+    int erSetSz = 0;
+    byte cpSeq[MAX_SEQ_SZ];
+    byte cpSet[MAX_SET_SZ];
+    byte cpStr[MAX_PRSTR_SZ];
+    byte erSeq[MAX_SEQ_SZ];
+    byte erSet[MAX_SET_SZ];
+
+    output[0] = 0xa0;
+    sz++;
+
+    if (pw && pw[0]) {
+        pwSz = (int)XSTRLEN(pw);
+        cpStrSz = SetUTF8String(pwSz, cpStr);
+        cpSetSz = SetSet(cpStrSz + pwSz, cpSet);
+        cpSeqSz = SetSequence(sizeof(cpOid) + cpSetSz + cpStrSz + pwSz, cpSeq);
+        cpSz = cpSeqSz + sizeof(cpOid) + cpSetSz + cpStrSz + pwSz;
+    }
+
+    if (extSz) {
+        erSetSz = SetSet(extSz, erSet);
+        erSeqSz = SetSequence(erSetSz + sizeof(erOid) + extSz, erSeq);
+        erSz = extSz + erSetSz + erSeqSz + sizeof(erOid);
+    }
+
+    /* Put the pieces together. */
+    sz += SetLength(cpSz + erSz, &output[sz]);
+
+    if (cpSz) {
+        XMEMCPY(&output[sz], cpSeq, cpSeqSz);
+        sz += cpSeqSz;
+        XMEMCPY(&output[sz], cpOid, sizeof(cpOid));
+        sz += sizeof(cpOid);
+        XMEMCPY(&output[sz], cpSet, cpSetSz);
+        sz += cpSetSz;
+        XMEMCPY(&output[sz], cpStr, cpStrSz);
+        sz += cpStrSz;
+        XMEMCPY(&output[sz], pw, pwSz);
+        sz += pwSz;
+    }
+
+    if (erSz) {
+        XMEMCPY(&output[sz], erSeq, erSeqSz);
+        sz += erSeqSz;
+        XMEMCPY(&output[sz], erOid, sizeof(erOid));
+        sz += sizeof(erOid);
+        XMEMCPY(&output[sz], erSet, erSetSz);
+        sz += erSetSz;
+        /* The actual extension data will be tacked onto the output later. */
+    }
+
+    return sz;
+}
+
+
+/* encode info from cert into DER encoded format */
+static int EncodeCertReq(Cert* cert, DerCert* der,
+                         RsaKey* rsaKey, ecc_key* eccKey)
+{
+    (void)eccKey;
+
+    /* init */
+    XMEMSET(der, 0, sizeof(DerCert));
+
+    /* version */
+    der->versionSz = SetMyVersion(cert->version, der->version, FALSE);
+
+    /* subject name */
+    der->subjectSz = SetName(der->subject, &cert->subject);
+    if (der->subjectSz == 0)
+        return SUBJECT_E;
+
+    /* public key */
+    if (cert->keyType == RSA_KEY) {
+        if (rsaKey == NULL)
+            return PUBLIC_KEY_E;
+        der->publicKeySz = SetRsaPublicKey(der->publicKey, rsaKey);
+        if (der->publicKeySz <= 0)
+            return PUBLIC_KEY_E;
+    }
+
+#ifdef HAVE_ECC
+    if (cert->keyType == ECC_KEY) {
+        if (eccKey == NULL)
+            return PUBLIC_KEY_E;
+        der->publicKeySz = SetEccPublicKey(der->publicKey, eccKey);
+        if (der->publicKeySz <= 0)
+            return PUBLIC_KEY_E;
+    }
+#endif /* HAVE_ECC */
+
+    /* CA */
+    if (cert->isCA) {
+        der->caSz = SetCa(der->ca);
+        if (der->caSz == 0)
+            return CA_TRUE_E;
+    }
+    else
+        der->caSz = 0;
+
+    /* extensions, just CA now */
+    if (cert->isCA) {
+        der->extensionsSz = SetExtensions(der->extensions,
+                                          der->ca, der->caSz, FALSE);
+        if (der->extensionsSz == 0)
+            return EXTENSIONS_E;
+    }
+    else
+        der->extensionsSz = 0;
+
+    der->attribSz = SetReqAttrib(der->attrib,
+                                 cert->challengePw, der->extensionsSz);
+    if (der->attribSz == 0)
+        return REQ_ATTRIBUTE_E;
+
+    der->total = der->versionSz + der->subjectSz + der->publicKeySz +
+        der->extensionsSz + der->attribSz;
+
+    return 0;
+}
+
+
+/* write DER encoded cert req to buffer, size already checked */
+static int WriteCertReqBody(DerCert* der, byte* buffer)
+{
+    int idx;
+
+    /* signed part header */
+    idx = SetSequence(der->total, buffer);
+    /* version */
+    XMEMCPY(buffer + idx, der->version, der->versionSz);
+    idx += der->versionSz;
+    /* subject */
+    XMEMCPY(buffer + idx, der->subject, der->subjectSz);
+    idx += der->subjectSz;
+    /* public key */
+    XMEMCPY(buffer + idx, der->publicKey, der->publicKeySz);
+    idx += der->publicKeySz;
+    /* attributes */
+    XMEMCPY(buffer + idx, der->attrib, der->attribSz);
+    idx += der->attribSz;
+    /* extensions */
+    if (der->extensionsSz) {
+        XMEMCPY(buffer + idx, der->extensions, min(der->extensionsSz,
+                                                   sizeof(der->extensions)));
+        idx += der->extensionsSz;
+    }
+
+    return idx;
+}
+
+
+int wc_MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz,
+                RsaKey* rsaKey, ecc_key* eccKey)
+{
+    int ret;
+#ifdef WOLFSSL_SMALL_STACK
+    DerCert* der;
+#else
+    DerCert der[1];
+#endif
+
+    cert->keyType = eccKey ? ECC_KEY : RSA_KEY;
+
+#ifdef WOLFSSL_SMALL_STACK
+    der = (DerCert*)XMALLOC(sizeof(DerCert), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (der == NULL)
+        return MEMORY_E;
+#endif
+
+    ret = EncodeCertReq(cert, der, rsaKey, eccKey);
+
+    if (ret == 0) {
+        if (der->total + MAX_SEQ_SZ * 2 > (int)derSz)
+            ret = BUFFER_E;
+        else
+            ret = cert->bodySz = WriteCertReqBody(der, derBuffer);
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+#endif /* WOLFSSL_CERT_REQ */
+
+
+int wc_SignCert(int requestSz, int sType, byte* buffer, word32 buffSz,
+             RsaKey* rsaKey, ecc_key* eccKey, RNG* rng)
+{
+    int sigSz;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* sig;
+#else
+    byte sig[MAX_ENCODED_SIG_SZ];
+#endif
+
+    if (requestSz < 0)
+        return requestSz;
+
+#ifdef WOLFSSL_SMALL_STACK
+    sig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (sig == NULL)
+        return MEMORY_E;
+#endif
+
+    sigSz = MakeSignature(buffer, requestSz, sig, MAX_ENCODED_SIG_SZ, rsaKey,
+                          eccKey, rng, sType);
+
+    if (sigSz >= 0) {
+        if (requestSz + MAX_SEQ_SZ * 2 + sigSz > (int)buffSz)
+            sigSz = BUFFER_E;
+        else
+            sigSz = AddSignature(buffer, requestSz, sig, sigSz, sType);
+    }
+    
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return sigSz;
+}
+
+
+int wc_MakeSelfCert(Cert* cert, byte* buffer, word32 buffSz, RsaKey* key, RNG* rng)
+{
+    int ret = wc_MakeCert(cert, buffer, buffSz, key, NULL, rng);
+
+    if (ret < 0)
+        return ret;
+
+    return wc_SignCert(cert->bodySz, cert->sigType, buffer, buffSz, key, NULL,rng);
+}
+
+
+#ifdef WOLFSSL_ALT_NAMES 
+
+/* Set Alt Names from der cert, return 0 on success */
+static int SetAltNamesFromCert(Cert* cert, const byte* der, int derSz)
+{
+    int ret;
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCert* decoded;
+#else
+    DecodedCert decoded[1];
+#endif
+
+    if (derSz < 0)
+        return derSz;
+
+#ifdef WOLFSSL_SMALL_STACK
+    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (decoded == NULL)
+        return MEMORY_E;
+#endif
+    
+    InitDecodedCert(decoded, (byte*)der, derSz, 0);
+    ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0);
+
+    if (ret < 0) {
+        WOLFSSL_MSG("ParseCertRelative error");
+    }
+    else if (decoded->extensions) {
+        byte   b;
+        int    length;
+        word32 maxExtensionsIdx;
+
+        decoded->srcIdx = decoded->extensionsIdx;
+        b = decoded->source[decoded->srcIdx++];
+        
+        if (b != ASN_EXTENSIONS) {
+            ret = ASN_PARSE_E;
+        }
+        else if (GetLength(decoded->source, &decoded->srcIdx, &length,
+                                                         decoded->maxIdx) < 0) {
+            ret = ASN_PARSE_E;
+        }
+        else if (GetSequence(decoded->source, &decoded->srcIdx, &length,
+                                                         decoded->maxIdx) < 0) {
+            ret = ASN_PARSE_E;
+        }
+        else {
+            maxExtensionsIdx = decoded->srcIdx + length;
+
+            while (decoded->srcIdx < maxExtensionsIdx) {
+                word32 oid;
+                word32 startIdx = decoded->srcIdx;
+                word32 tmpIdx;
+
+                if (GetSequence(decoded->source, &decoded->srcIdx, &length,
+                            decoded->maxIdx) < 0) {
+                    ret = ASN_PARSE_E;
+                    break;
+                }
+
+                tmpIdx = decoded->srcIdx;
+                decoded->srcIdx = startIdx;
+
+                if (GetAlgoId(decoded->source, &decoded->srcIdx, &oid,
+                              decoded->maxIdx) < 0) {
+                    ret = ASN_PARSE_E;
+                    break;
+                }
+
+                if (oid == ALT_NAMES_OID) {
+                    cert->altNamesSz = length + (tmpIdx - startIdx);
+
+                    if (cert->altNamesSz < (int)sizeof(cert->altNames))
+                        XMEMCPY(cert->altNames, &decoded->source[startIdx],
+                                cert->altNamesSz);
+                    else {
+                        cert->altNamesSz = 0;
+                        WOLFSSL_MSG("AltNames extensions too big");
+                        ret = ALT_NAME_E;
+                        break;
+                    }
+                }
+                decoded->srcIdx = tmpIdx + length;
+            }
+        }
+    }
+
+    FreeDecodedCert(decoded);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret < 0 ? ret : 0;
+}
+
+
+/* Set Dates from der cert, return 0 on success */
+static int SetDatesFromCert(Cert* cert, const byte* der, int derSz)
+{
+    int ret;
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCert* decoded;
+#else
+    DecodedCert decoded[1];
+#endif
+
+    WOLFSSL_ENTER("SetDatesFromCert");
+    if (derSz < 0)
+        return derSz;
+    
+#ifdef WOLFSSL_SMALL_STACK
+    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (decoded == NULL)
+        return MEMORY_E;
+#endif
+
+    InitDecodedCert(decoded, (byte*)der, derSz, 0);
+    ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0);
+
+    if (ret < 0) {
+        WOLFSSL_MSG("ParseCertRelative error");
+    }
+    else if (decoded->beforeDate == NULL || decoded->afterDate == NULL) {
+        WOLFSSL_MSG("Couldn't extract dates");
+        ret = -1;
+    }
+    else if (decoded->beforeDateLen > MAX_DATE_SIZE || 
+                                        decoded->afterDateLen > MAX_DATE_SIZE) {
+        WOLFSSL_MSG("Bad date size");
+        ret = -1;
+    }
+    else {
+        XMEMCPY(cert->beforeDate, decoded->beforeDate, decoded->beforeDateLen);
+        XMEMCPY(cert->afterDate,  decoded->afterDate,  decoded->afterDateLen);
+
+        cert->beforeDateSz = decoded->beforeDateLen;
+        cert->afterDateSz  = decoded->afterDateLen;
+    }
+
+    FreeDecodedCert(decoded);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret < 0 ? ret : 0;
+}
+
+
+#endif /* WOLFSSL_ALT_NAMES && !NO_RSA */
+
+
+/* Set cn name from der buffer, return 0 on success */
+static int SetNameFromCert(CertName* cn, const byte* der, int derSz)
+{
+    int ret, sz;
+#ifdef WOLFSSL_SMALL_STACK
+    DecodedCert* decoded;
+#else
+    DecodedCert decoded[1];
+#endif
+
+    if (derSz < 0)
+        return derSz;
+
+#ifdef WOLFSSL_SMALL_STACK
+    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (decoded == NULL)
+        return MEMORY_E;
+#endif
+
+    InitDecodedCert(decoded, (byte*)der, derSz, 0);
+    ret = ParseCertRelative(decoded, CA_TYPE, NO_VERIFY, 0);
+
+    if (ret < 0) {
+        WOLFSSL_MSG("ParseCertRelative error");
+    }
+    else {
+        if (decoded->subjectCN) {
+            sz = (decoded->subjectCNLen < CTC_NAME_SIZE) ? decoded->subjectCNLen
+                                                         : CTC_NAME_SIZE - 1;
+            strncpy(cn->commonName, decoded->subjectCN, CTC_NAME_SIZE);
+            cn->commonName[sz] = 0;
+            cn->commonNameEnc = decoded->subjectCNEnc;
+        }
+        if (decoded->subjectC) {
+            sz = (decoded->subjectCLen < CTC_NAME_SIZE) ? decoded->subjectCLen
+                                                        : CTC_NAME_SIZE - 1;
+            strncpy(cn->country, decoded->subjectC, CTC_NAME_SIZE);
+            cn->country[sz] = 0;
+            cn->countryEnc = decoded->subjectCEnc;
+        }
+        if (decoded->subjectST) {
+            sz = (decoded->subjectSTLen < CTC_NAME_SIZE) ? decoded->subjectSTLen
+                                                         : CTC_NAME_SIZE - 1;
+            strncpy(cn->state, decoded->subjectST, CTC_NAME_SIZE);
+            cn->state[sz] = 0;
+            cn->stateEnc = decoded->subjectSTEnc;
+        }
+        if (decoded->subjectL) {
+            sz = (decoded->subjectLLen < CTC_NAME_SIZE) ? decoded->subjectLLen
+                                                        : CTC_NAME_SIZE - 1;
+            strncpy(cn->locality, decoded->subjectL, CTC_NAME_SIZE);
+            cn->locality[sz] = 0;
+            cn->localityEnc = decoded->subjectLEnc;
+        }
+        if (decoded->subjectO) {
+            sz = (decoded->subjectOLen < CTC_NAME_SIZE) ? decoded->subjectOLen
+                                                        : CTC_NAME_SIZE - 1;
+            strncpy(cn->org, decoded->subjectO, CTC_NAME_SIZE);
+            cn->org[sz] = 0;
+            cn->orgEnc = decoded->subjectOEnc;
+        }
+        if (decoded->subjectOU) {
+            sz = (decoded->subjectOULen < CTC_NAME_SIZE) ? decoded->subjectOULen
+                                                         : CTC_NAME_SIZE - 1;
+            strncpy(cn->unit, decoded->subjectOU, CTC_NAME_SIZE);
+            cn->unit[sz] = 0;
+            cn->unitEnc = decoded->subjectOUEnc;
+        }
+        if (decoded->subjectSN) {
+            sz = (decoded->subjectSNLen < CTC_NAME_SIZE) ? decoded->subjectSNLen
+                                                         : CTC_NAME_SIZE - 1;
+            strncpy(cn->sur, decoded->subjectSN, CTC_NAME_SIZE);
+            cn->sur[sz] = 0;
+            cn->surEnc = decoded->subjectSNEnc;
+        }
+        if (decoded->subjectEmail) {
+            sz = (decoded->subjectEmailLen < CTC_NAME_SIZE)
+               ?  decoded->subjectEmailLen : CTC_NAME_SIZE - 1;
+            strncpy(cn->email, decoded->subjectEmail, CTC_NAME_SIZE);
+            cn->email[sz] = 0;
+        }
+    }
+
+    FreeDecodedCert(decoded);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret < 0 ? ret : 0;
+}
+
+
+#ifndef NO_FILESYSTEM
+
+/* Set cert issuer from issuerFile in PEM */
+int wc_SetIssuer(Cert* cert, const char* issuerFile)
+{
+    int         ret;
+    int         derSz;
+    byte*       der = (byte*)XMALLOC(EIGHTK_BUF, NULL, DYNAMIC_TYPE_CERT);
+
+    if (der == NULL) {
+        WOLFSSL_MSG("wc_SetIssuer OOF Problem");
+        return MEMORY_E;
+    }
+    derSz = wolfSSL_PemCertToDer(issuerFile, der, EIGHTK_BUF);
+    cert->selfSigned = 0;
+    ret = SetNameFromCert(&cert->issuer, der, derSz);
+    XFREE(der, NULL, DYNAMIC_TYPE_CERT);
+
+    return ret;
+}
+
+
+/* Set cert subject from subjectFile in PEM */
+int wc_SetSubject(Cert* cert, const char* subjectFile)
+{
+    int         ret;
+    int         derSz;
+    byte*       der = (byte*)XMALLOC(EIGHTK_BUF, NULL, DYNAMIC_TYPE_CERT);
+
+    if (der == NULL) {
+        WOLFSSL_MSG("wc_SetSubject OOF Problem");
+        return MEMORY_E;
+    }
+    derSz = wolfSSL_PemCertToDer(subjectFile, der, EIGHTK_BUF);
+    ret = SetNameFromCert(&cert->subject, der, derSz);
+    XFREE(der, NULL, DYNAMIC_TYPE_CERT);
+
+    return ret;
+}
+
+
+#ifdef WOLFSSL_ALT_NAMES
+
+/* Set atl names from file in PEM */
+int wc_SetAltNames(Cert* cert, const char* file)
+{
+    int         ret;
+    int         derSz;
+    byte*       der = (byte*)XMALLOC(EIGHTK_BUF, NULL, DYNAMIC_TYPE_CERT);
+
+    if (der == NULL) {
+        WOLFSSL_MSG("wc_SetAltNames OOF Problem");
+        return MEMORY_E;
+    }
+    derSz = wolfSSL_PemCertToDer(file, der, EIGHTK_BUF);
+    ret = SetAltNamesFromCert(cert, der, derSz);
+    XFREE(der, NULL, DYNAMIC_TYPE_CERT);
+
+    return ret;
+}
+
+#endif /* WOLFSSL_ALT_NAMES */
+
+#endif /* NO_FILESYSTEM */
+
+/* Set cert issuer from DER buffer */
+int wc_SetIssuerBuffer(Cert* cert, const byte* der, int derSz)
+{
+    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)
+{
+    return SetNameFromCert(&cert->subject, der, derSz);
+}
+
+
+#ifdef WOLFSSL_ALT_NAMES
+
+/* Set cert alt names from DER buffer */
+int wc_SetAltNamesBuffer(Cert* cert, const byte* der, int derSz)
+{
+    return SetAltNamesFromCert(cert, der, derSz);
+}
+
+/* Set cert dates from DER buffer */
+int wc_SetDatesBuffer(Cert* cert, const byte* der, int derSz)
+{
+    return SetDatesFromCert(cert, der, derSz);
+}
+
+#endif /* WOLFSSL_ALT_NAMES */
+
+#endif /* WOLFSSL_CERT_GEN */
+
+
+#ifdef HAVE_ECC
+
+/* Der Encode r & s ints into out, outLen is (in/out) size */
+int StoreECC_DSA_Sig(byte* out, word32* outLen, mp_int* r, mp_int* s)
+{
+    word32 idx = 0;
+    word32 rSz;                           /* encoding size */
+    word32 sSz;
+    word32 headerSz = 4;   /* 2*ASN_TAG + 2*LEN(ENUM) */
+
+    /* If the leading bit on the INTEGER is a 1, add a leading zero */
+    int rLeadingZero = mp_leading_bit(r);
+    int sLeadingZero = mp_leading_bit(s);
+    int rLen = mp_unsigned_bin_size(r);   /* big int size */
+    int sLen = mp_unsigned_bin_size(s);
+    int err;
+
+    if (*outLen < (rLen + rLeadingZero + sLen + sLeadingZero +
+                   headerSz + 2))  /* SEQ_TAG + LEN(ENUM) */
+        return BAD_FUNC_ARG;
+
+    idx = SetSequence(rLen+rLeadingZero+sLen+sLeadingZero+headerSz, out);
+
+    /* store r */
+    out[idx++] = ASN_INTEGER;
+    rSz = SetLength(rLen + rLeadingZero, &out[idx]);
+    idx += rSz;
+    if (rLeadingZero)
+        out[idx++] = 0;
+    err = mp_to_unsigned_bin(r, &out[idx]);
+    if (err != MP_OKAY) return err;
+    idx += rLen;
+
+    /* store s */
+    out[idx++] = ASN_INTEGER;
+    sSz = SetLength(sLen + sLeadingZero, &out[idx]);
+    idx += sSz;
+    if (sLeadingZero)
+        out[idx++] = 0;
+    err = mp_to_unsigned_bin(s, &out[idx]);
+    if (err != MP_OKAY) return err;
+    idx += sLen;
+
+    *outLen = idx;
+
+    return 0;
+}
+
+
+/* Der Decode ECC-DSA Signautre, r & s stored as big ints */
+int DecodeECC_DSA_Sig(const byte* sig, word32 sigLen, mp_int* r, mp_int* s)
+{
+    word32 idx = 0;
+    int    len = 0;
+
+    if (GetSequence(sig, &idx, &len, sigLen) < 0)
+        return ASN_ECC_KEY_E;
+
+    if ((word32)len > (sigLen - idx))
+        return ASN_ECC_KEY_E;
+
+    if (GetInt(r, sig, &idx, sigLen) < 0)
+        return ASN_ECC_KEY_E;
+
+    if (GetInt(s, sig, &idx, sigLen) < 0)
+        return ASN_ECC_KEY_E;
+
+    return 0;
+}
+
+
+int wc_EccPrivateKeyDecode(const byte* input, word32* inOutIdx, ecc_key* key,
+                        word32 inSz)
+{
+    word32 oid = 0;
+    int    version, length;
+    int    privSz, pubSz;
+    byte   b;
+    int    ret = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* priv;
+    byte* pub;
+#else
+    byte priv[ECC_MAXSIZE];
+    byte pub[ECC_MAXSIZE * 2 + 1]; /* public key has two parts plus header */
+#endif
+
+    if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0)
+        return BAD_FUNC_ARG;
+
+    if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetMyVersion(input, inOutIdx, &version) < 0)
+        return ASN_PARSE_E;
+
+    b = input[*inOutIdx];
+    *inOutIdx += 1;
+
+    /* priv type */
+    if (b != 4 && b != 6 && b != 7) 
+        return ASN_PARSE_E;
+
+    if (GetLength(input, inOutIdx, &length, inSz) < 0)
+        return ASN_PARSE_E;
+
+    if (length > ECC_MAXSIZE)
+        return BUFFER_E;
+
+#ifdef WOLFSSL_SMALL_STACK
+    priv = (byte*)XMALLOC(ECC_MAXSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (priv == NULL)
+        return MEMORY_E;
+    
+    pub = (byte*)XMALLOC(ECC_MAXSIZE * 2 + 1, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (pub == NULL) {
+        XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    /* priv key */
+    privSz = length;
+    XMEMCPY(priv, &input[*inOutIdx], privSz);
+    *inOutIdx += length;
+
+    /* prefix 0, may have */
+    b = input[*inOutIdx];
+    if (b == ECC_PREFIX_0) {
+        *inOutIdx += 1;
+
+        if (GetLength(input, inOutIdx, &length, inSz) < 0)
+            ret = ASN_PARSE_E;
+        else {
+            /* object id */
+            b = input[*inOutIdx];
+            *inOutIdx += 1;
+
+            if (b != ASN_OBJECT_ID) {
+                ret = ASN_OBJECT_ID_E;
+            }
+            else if (GetLength(input, inOutIdx, &length, inSz) < 0) {
+                ret = ASN_PARSE_E;
+            }
+            else {
+                while(length--) {
+                    oid += input[*inOutIdx];
+                    *inOutIdx += 1;
+                }
+                if (CheckCurve(oid) < 0)
+                    ret = ECC_CURVE_OID_E;
+            }
+        }
+    }
+
+    if (ret == 0) {
+        /* prefix 1 */
+        b = input[*inOutIdx];
+        *inOutIdx += 1;
+
+        if (b != ECC_PREFIX_1) {
+            ret = ASN_ECC_KEY_E;
+        }
+        else if (GetLength(input, inOutIdx, &length, inSz) < 0) {
+            ret = ASN_PARSE_E;
+        }
+        else {
+            /* key header */
+            b = input[*inOutIdx];
+            *inOutIdx += 1;
+            
+            if (b != ASN_BIT_STRING) {
+                ret = ASN_BITSTR_E;
+            }
+            else if (GetLength(input, inOutIdx, &length, inSz) < 0) {
+                ret = ASN_PARSE_E;
+            }
+            else {
+                b = input[*inOutIdx];
+                *inOutIdx += 1;
+
+                if (b != 0x00) {
+                    ret = ASN_EXPECT_0_E;
+                }
+                else {
+                    /* pub key */
+                    pubSz = length - 1;  /* null prefix */
+                    if (pubSz < (ECC_MAXSIZE*2 + 1)) {
+                        XMEMCPY(pub, &input[*inOutIdx], pubSz);
+                        *inOutIdx += length;
+                        ret = wc_ecc_import_private_key(priv, privSz, pub, pubSz,
+                                                     key);
+                    } else
+                        ret = BUFFER_E;
+                }
+            }
+        }
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(pub,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+#ifdef WOLFSSL_KEY_GEN
+
+/* Write a Private ecc key to DER format, length on success else < 0 */
+int wc_EccKeyToDer(ecc_key* key, byte* output, word32 inLen)
+{
+    byte   curve[MAX_ALGO_SZ];
+    byte   ver[MAX_VERSION_SZ];
+    byte   seq[MAX_SEQ_SZ];
+    int    ret;
+    int    curveSz;
+    int    verSz;
+    int    privHdrSz  = ASN_ECC_HEADER_SZ;
+    int    pubHdrSz   = ASN_ECC_CONTEXT_SZ + ASN_ECC_HEADER_SZ;
+    int    curveHdrSz = ASN_ECC_CONTEXT_SZ;
+    word32 seqSz;
+    word32 idx = 0;
+    word32 pubSz = ECC_BUFSIZE;
+    word32 privSz;
+    word32 totalSz;
+
+    if (key == NULL || output == NULL || inLen == 0)
+        return BAD_FUNC_ARG;
+
+    ret = wc_ecc_export_x963(key, NULL, &pubSz);
+    if (ret != LENGTH_ONLY_E) {
+        return ret;
+    }
+    curveSz = SetCurve(key, curve);
+    if (curveSz < 0) {
+        return curveSz;
+    }
+
+    privSz = key->dp->size;
+
+    verSz = SetMyVersion(1, ver, FALSE);
+    if (verSz < 0) {
+        return verSz;
+    }
+
+    totalSz = verSz + privSz + privHdrSz + curveSz + curveHdrSz +
+              pubSz + pubHdrSz + 1;  /* plus null byte b4 public */
+    seqSz = SetSequence(totalSz, seq);
+    totalSz += seqSz;
+
+    if (totalSz > inLen) {
+        return BUFFER_E;
+    }
+
+    /* write it out */
+    /* seq */
+    XMEMCPY(output + idx, seq, seqSz);
+    idx += seqSz;
+
+   /* ver */
+    XMEMCPY(output + idx, ver, verSz);
+    idx += verSz;
+
+    /* private */
+    output[idx++] = ASN_OCTET_STRING;
+    output[idx++] = (byte)privSz;
+    ret = wc_ecc_export_private_only(key, output + idx, &privSz);
+    if (ret < 0) {
+        return ret;
+    }
+    idx += privSz;
+
+    /* curve */
+    output[idx++] = ECC_PREFIX_0;
+    output[idx++] = (byte)curveSz;
+    XMEMCPY(output + idx, curve, curveSz);
+    idx += curveSz;
+
+    /* public */
+    output[idx++] = ECC_PREFIX_1;
+    output[idx++] = (byte)pubSz + ASN_ECC_CONTEXT_SZ + 1;  /* plus null byte */
+    output[idx++] = ASN_BIT_STRING;
+    output[idx++] = (byte)pubSz + 1;  /* plus null byte */
+    output[idx++] = (byte)0;          /* null byte */
+    ret = wc_ecc_export_x963(key, output + idx, &pubSz);
+    if (ret != 0) {
+        return ret;
+    }
+    /* idx += pubSz if do more later */
+
+    return totalSz;
+}
+
+#endif /* WOLFSSL_KEY_GEN */
+
+#endif  /* HAVE_ECC */
+
+
+#if defined(HAVE_OCSP) || defined(HAVE_CRL)
+
+/* Get raw Date only, no processing, 0 on success */
+static int GetBasicDate(const byte* source, word32* idx, byte* date,
+                        byte* format, int maxIdx)
+{
+    int    length;
+
+    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;
+
+    return 0;
+}
+
+#endif
+
+
+#ifdef HAVE_OCSP
+
+static int GetEnumerated(const byte* input, word32* inOutIdx, int *value)
+{
+    word32 idx = *inOutIdx;
+    word32 len;
+
+    WOLFSSL_ENTER("GetEnumerated");
+
+    *value = 0;
+
+    if (input[idx++] != ASN_ENUMERATED)
+        return ASN_PARSE_E;
+
+    len = input[idx++];
+    if (len > 4)
+        return ASN_PARSE_E;
+
+    while (len--) {
+        *value  = *value << 8 | input[idx++];
+    }
+
+    *inOutIdx = idx;
+
+    return *value;
+}
+
+
+static int DecodeSingleResponse(byte* source,
+                            word32* ioIndex, OcspResponse* resp, word32 size)
+{
+    word32 idx = *ioIndex, prevIndex, oid;
+    int length, wrapperSz;
+    CertStatus* cs = resp->status;
+
+    WOLFSSL_ENTER("DecodeSingleResponse");
+
+    /* Outer wrapper of the SEQUENCE OF Single Responses. */
+    if (GetSequence(source, &idx, &wrapperSz, size) < 0)
+        return ASN_PARSE_E;
+
+    prevIndex = idx;
+
+    /* When making a request, we only request one status on one certificate
+     * at a time. There should only be one SingleResponse */
+
+    /* Wrapper around the Single Response */
+    if (GetSequence(source, &idx, &length, size) < 0)
+        return ASN_PARSE_E;
+
+    /* Wrapper around the CertID */
+    if (GetSequence(source, &idx, &length, size) < 0)
+        return ASN_PARSE_E;
+    /* Skip the hash algorithm */
+    if (GetAlgoId(source, &idx, &oid, size) < 0)
+        return ASN_PARSE_E;
+    /* Save reference to the hash of CN */
+    if (source[idx++] != ASN_OCTET_STRING)
+        return ASN_PARSE_E;
+    if (GetLength(source, &idx, &length, size) < 0)
+        return ASN_PARSE_E;
+    resp->issuerHash = source + idx;
+    idx += length;
+    /* Save reference to the hash of the issuer public key */
+    if (source[idx++] != ASN_OCTET_STRING)
+        return ASN_PARSE_E;
+    if (GetLength(source, &idx, &length, size) < 0)
+        return ASN_PARSE_E;
+    resp->issuerKeyHash = source + idx;
+    idx += length;
+
+    /* Read the serial number, it is handled as a string, not as a 
+     * proper number. Just XMEMCPY the data over, rather than load it
+     * as an mp_int. */
+    if (source[idx++] != ASN_INTEGER)
+        return ASN_PARSE_E;
+    if (GetLength(source, &idx, &length, size) < 0)
+        return ASN_PARSE_E;
+    if (length <= EXTERNAL_SERIAL_SIZE)
+    {
+        if (source[idx] == 0)
+        {
+            idx++;
+            length--;
+        }
+        XMEMCPY(cs->serial, source + idx, length);
+        cs->serialSz = length;
+    }
+    else
+    {
+        return ASN_GETINT_E;
+    }
+    idx += length;
+
+    /* CertStatus */
+    switch (source[idx++])
+    {
+        case (ASN_CONTEXT_SPECIFIC | CERT_GOOD):
+            cs->status = CERT_GOOD;
+            idx++;
+            break;
+        case (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | CERT_REVOKED):
+            cs->status = CERT_REVOKED;
+            if (GetLength(source, &idx, &length, size) < 0)
+                return ASN_PARSE_E;
+            idx += length;
+            break;
+        case (ASN_CONTEXT_SPECIFIC | CERT_UNKNOWN):
+            cs->status = CERT_UNKNOWN;
+            idx++;
+            break;
+        default:
+            return ASN_PARSE_E;
+    }
+
+    if (GetBasicDate(source, &idx, cs->thisDate,
+                                                &cs->thisDateFormat, size) < 0)
+        return ASN_PARSE_E;
+    if (!XVALIDATE_DATE(cs->thisDate, cs->thisDateFormat, BEFORE))
+        return ASN_BEFORE_DATE_E;
+    
+    /* The following items are optional. Only check for them if there is more
+     * unprocessed data in the singleResponse wrapper. */
+    
+    if (((int)(idx - prevIndex) < wrapperSz) &&
+        (source[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)))
+    {
+        idx++;
+        if (GetLength(source, &idx, &length, size) < 0)
+            return ASN_PARSE_E;
+        if (GetBasicDate(source, &idx, cs->nextDate,
+                                                &cs->nextDateFormat, size) < 0)
+            return ASN_PARSE_E;
+    }
+    if (((int)(idx - prevIndex) < wrapperSz) &&
+        (source[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)))
+    {
+        idx++;
+        if (GetLength(source, &idx, &length, size) < 0)
+            return ASN_PARSE_E;
+        idx += length;
+    }
+
+    *ioIndex = idx;
+
+    return 0;
+}
+
+static int DecodeOcspRespExtensions(byte* source,
+                            word32* ioIndex, OcspResponse* resp, word32 sz)
+{
+    word32 idx = *ioIndex;
+    int length;
+    int ext_bound; /* boundary index for the sequence of extensions */
+    word32 oid;
+
+    WOLFSSL_ENTER("DecodeOcspRespExtensions");
+
+    if (source[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1))
+        return ASN_PARSE_E;
+
+    if (GetLength(source, &idx, &length, sz) < 0) return ASN_PARSE_E;
+
+    if (GetSequence(source, &idx, &length, sz) < 0) return ASN_PARSE_E;
+   
+    ext_bound = idx + length;
+
+    while (idx < (word32)ext_bound) {
+        if (GetSequence(source, &idx, &length, sz) < 0) {
+            WOLFSSL_MSG("\tfail: should be a SEQUENCE");
+            return ASN_PARSE_E;
+        }
+
+        oid = 0;
+        if (GetObjectId(source, &idx, &oid, sz) < 0) {
+            WOLFSSL_MSG("\tfail: OBJECT ID");
+            return ASN_PARSE_E;
+        }
+
+        /* check for critical flag */
+        if (source[idx] == ASN_BOOLEAN) {
+            WOLFSSL_MSG("\tfound optional critical flag, moving past");
+            idx += (ASN_BOOL_SIZE + 1);
+        }
+
+        /* process the extension based on the OID */
+        if (source[idx++] != ASN_OCTET_STRING) {
+            WOLFSSL_MSG("\tfail: should be an OCTET STRING");
+            return ASN_PARSE_E;
+        }
+
+        if (GetLength(source, &idx, &length, sz) < 0) {
+            WOLFSSL_MSG("\tfail: extension data length");
+            return ASN_PARSE_E;
+        }
+
+        if (oid == OCSP_NONCE_OID) {
+            resp->nonce = source + idx;
+            resp->nonceSz = length;
+        }
+
+        idx += length;
+    }
+
+    *ioIndex = idx;
+    return 0;
+}
+
+
+static int DecodeResponseData(byte* source,
+                            word32* ioIndex, OcspResponse* resp, word32 size)
+{
+    word32 idx = *ioIndex, prev_idx;
+    int length;
+    int version;
+    word32 responderId = 0;
+
+    WOLFSSL_ENTER("DecodeResponseData");
+
+    resp->response = source + idx;
+    prev_idx = idx;
+    if (GetSequence(source, &idx, &length, size) < 0)
+        return ASN_PARSE_E;
+    resp->responseSz = length + idx - prev_idx;
+
+    /* Get version. It is an EXPLICIT[0] DEFAULT(0) value. If this
+     * item isn't an EXPLICIT[0], then set version to zero and move
+     * onto the next item.
+     */
+    if (source[idx] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED))
+    {    
+        idx += 2; /* Eat the value and length */
+        if (GetMyVersion(source, &idx, &version) < 0)
+            return ASN_PARSE_E;
+    } else
+        version = 0;
+
+    responderId = source[idx++];
+    if ((responderId == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1)) ||
+        (responderId == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 2)))
+    {
+        if (GetLength(source, &idx, &length, size) < 0)
+            return ASN_PARSE_E;
+        idx += length;
+    }
+    else
+        return ASN_PARSE_E;
+    
+    /* save pointer to the producedAt time */
+    if (GetBasicDate(source, &idx, resp->producedDate,
+                                        &resp->producedDateFormat, size) < 0)
+        return ASN_PARSE_E;
+
+    if (DecodeSingleResponse(source, &idx, resp, size) < 0)
+        return ASN_PARSE_E;
+
+    if (DecodeOcspRespExtensions(source, &idx, resp, size) < 0)
+        return ASN_PARSE_E;
+
+    *ioIndex = idx;
+    return 0;
+}
+
+
+static int DecodeCerts(byte* source,
+                            word32* ioIndex, OcspResponse* resp, word32 size)
+{
+    word32 idx = *ioIndex;
+
+    WOLFSSL_ENTER("DecodeCerts");
+
+    if (source[idx++] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC))
+    {
+        int length;
+
+        if (GetLength(source, &idx, &length, size) < 0)
+            return ASN_PARSE_E;
+
+        if (GetSequence(source, &idx, &length, size) < 0)
+            return ASN_PARSE_E;
+
+        resp->cert = source + idx;
+        resp->certSz = length;
+
+        idx += length;
+    }
+    *ioIndex = idx;
+    return 0;
+}
+
+static int DecodeBasicOcspResponse(byte* source,
+                            word32* ioIndex, OcspResponse* resp, word32 size)
+{
+    int length;
+    word32 idx = *ioIndex;
+    word32 end_index;
+
+    WOLFSSL_ENTER("DecodeBasicOcspResponse");
+
+    if (GetSequence(source, &idx, &length, size) < 0)
+        return ASN_PARSE_E;
+
+    if (idx + length > size)
+        return ASN_INPUT_E;
+    end_index = idx + length;
+
+    if (DecodeResponseData(source, &idx, resp, size) < 0)
+        return ASN_PARSE_E;
+    
+    /* Get the signature algorithm */
+    if (GetAlgoId(source, &idx, &resp->sigOID, size) < 0)
+        return ASN_PARSE_E;
+
+    /* Obtain pointer to the start of the signature, and save the size */
+    if (source[idx++] == ASN_BIT_STRING)
+    {
+        int sigLength = 0;
+        if (GetLength(source, &idx, &sigLength, size) < 0)
+            return ASN_PARSE_E;
+        resp->sigSz = sigLength;
+        resp->sig = source + idx;
+        idx += sigLength;
+    }
+
+    /*
+     * Check the length of the BasicOcspResponse against the current index to
+     * see if there are certificates, they are optional.
+     */
+    if (idx < end_index)
+    {
+        DecodedCert cert;
+        int ret;
+
+        if (DecodeCerts(source, &idx, resp, size) < 0)
+            return ASN_PARSE_E;
+
+        InitDecodedCert(&cert, resp->cert, resp->certSz, 0);
+        ret = ParseCertRelative(&cert, CA_TYPE, NO_VERIFY, 0);
+        if (ret < 0)
+            return ret;
+
+        ret = ConfirmSignature(resp->response, resp->responseSz,
+                            cert.publicKey, cert.pubKeySize, cert.keyOID,
+                            resp->sig, resp->sigSz, resp->sigOID, NULL);
+        FreeDecodedCert(&cert);
+
+        if (ret == 0)
+        {
+            WOLFSSL_MSG("\tOCSP Confirm signature failed");
+            return ASN_OCSP_CONFIRM_E;
+        }
+    }
+
+    *ioIndex = idx;
+    return 0;
+}
+
+
+void InitOcspResponse(OcspResponse* resp, CertStatus* status,
+                                                    byte* source, word32 inSz)
+{
+    WOLFSSL_ENTER("InitOcspResponse");
+
+    resp->responseStatus = -1;
+    resp->response = NULL;
+    resp->responseSz = 0;
+    resp->producedDateFormat = 0;
+    resp->issuerHash = NULL;
+    resp->issuerKeyHash = NULL;
+    resp->sig = NULL;
+    resp->sigSz = 0;
+    resp->sigOID = 0;
+    resp->status = status;
+    resp->nonce = NULL;
+    resp->nonceSz = 0;
+    resp->source = source;
+    resp->maxIdx = inSz;
+}
+
+
+int OcspResponseDecode(OcspResponse* resp)
+{
+    int length = 0;
+    word32 idx = 0;
+    byte* source = resp->source;
+    word32 size = resp->maxIdx;
+    word32 oid;
+
+    WOLFSSL_ENTER("OcspResponseDecode");
+
+    /* peel the outer SEQUENCE wrapper */
+    if (GetSequence(source, &idx, &length, size) < 0)
+        return ASN_PARSE_E;
+    
+    /* First get the responseStatus, an ENUMERATED */
+    if (GetEnumerated(source, &idx, &resp->responseStatus) < 0)
+        return ASN_PARSE_E;
+
+    if (resp->responseStatus != OCSP_SUCCESSFUL)
+        return 0;
+
+    /* Next is an EXPLICIT record called ResponseBytes, OPTIONAL */
+    if (idx >= size)
+        return ASN_INPUT_E;
+    if (source[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC))
+        return ASN_PARSE_E;
+    if (GetLength(source, &idx, &length, size) < 0)
+        return ASN_PARSE_E;
+
+    /* Get the responseBytes SEQUENCE */
+    if (GetSequence(source, &idx, &length, size) < 0)
+        return ASN_PARSE_E;
+
+    /* Check ObjectID for the resposeBytes */
+    if (GetObjectId(source, &idx, &oid, size) < 0)
+        return ASN_PARSE_E;
+    if (oid != OCSP_BASIC_OID)
+        return ASN_PARSE_E;
+    if (source[idx++] != ASN_OCTET_STRING)
+        return ASN_PARSE_E;
+
+    if (GetLength(source, &idx, &length, size) < 0)
+        return ASN_PARSE_E;
+
+    if (DecodeBasicOcspResponse(source, &idx, resp, size) < 0)
+        return ASN_PARSE_E;
+    
+    return 0;
+}
+
+
+static word32 SetOcspReqExtensions(word32 extSz, byte* output,
+                                            const byte* nonce, word32 nonceSz)
+{
+    static const byte NonceObjId[] = { 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
+                                       0x30, 0x01, 0x02 };
+    byte seqArray[5][MAX_SEQ_SZ];
+    word32 seqSz[5], totalSz;
+
+    WOLFSSL_ENTER("SetOcspReqExtensions");
+
+    if (nonce == NULL || nonceSz == 0) return 0;
+    
+    seqArray[0][0] = ASN_OCTET_STRING;
+    seqSz[0] = 1 + SetLength(nonceSz, &seqArray[0][1]);
+
+    seqArray[1][0] = ASN_OBJECT_ID;
+    seqSz[1] = 1 + SetLength(sizeof(NonceObjId), &seqArray[1][1]);
+
+    totalSz = seqSz[0] + seqSz[1] + nonceSz + (word32)sizeof(NonceObjId);
+
+    seqSz[2] = SetSequence(totalSz, seqArray[2]);
+    totalSz += seqSz[2];
+
+    seqSz[3] = SetSequence(totalSz, seqArray[3]);
+    totalSz += seqSz[3];
+
+    seqArray[4][0] = (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 2);
+    seqSz[4] = 1 + SetLength(totalSz, &seqArray[4][1]);
+    totalSz += seqSz[4];
+
+    if (totalSz < extSz)
+    {
+        totalSz = 0;
+        XMEMCPY(output + totalSz, seqArray[4], seqSz[4]);
+        totalSz += seqSz[4];
+        XMEMCPY(output + totalSz, seqArray[3], seqSz[3]);
+        totalSz += seqSz[3];
+        XMEMCPY(output + totalSz, seqArray[2], seqSz[2]);
+        totalSz += seqSz[2];
+        XMEMCPY(output + totalSz, seqArray[1], seqSz[1]);
+        totalSz += seqSz[1];
+        XMEMCPY(output + totalSz, NonceObjId, sizeof(NonceObjId));
+        totalSz += (word32)sizeof(NonceObjId);
+        XMEMCPY(output + totalSz, seqArray[0], seqSz[0]);
+        totalSz += seqSz[0];
+        XMEMCPY(output + totalSz, nonce, nonceSz);
+        totalSz += nonceSz;
+    }
+
+    return totalSz;
+}
+
+
+int EncodeOcspRequest(OcspRequest* req)
+{
+    byte seqArray[5][MAX_SEQ_SZ];
+    /* The ASN.1 of the OCSP Request is an onion of sequences */
+    byte algoArray[MAX_ALGO_SZ];
+    byte issuerArray[MAX_ENCODED_DIG_SZ];
+    byte issuerKeyArray[MAX_ENCODED_DIG_SZ];
+    byte snArray[MAX_SN_SZ];
+    byte extArray[MAX_OCSP_EXT_SZ];
+    byte* output = req->dest;
+    word32 seqSz[5], algoSz, issuerSz, issuerKeySz, snSz, extSz, totalSz;
+    int i;
+
+    WOLFSSL_ENTER("EncodeOcspRequest");
+
+#ifdef NO_SHA
+    algoSz = SetAlgoID(SHA256h, algoArray, hashType, 0);
+#else
+    algoSz = SetAlgoID(SHAh, algoArray, hashType, 0);
+#endif
+
+    req->issuerHash = req->cert->issuerHash;
+    issuerSz = SetDigest(req->cert->issuerHash, KEYID_SIZE, issuerArray);
+
+    req->issuerKeyHash = req->cert->issuerKeyHash;
+    issuerKeySz = SetDigest(req->cert->issuerKeyHash,
+                                                    KEYID_SIZE, issuerKeyArray);
+
+    req->serial = req->cert->serial;
+    req->serialSz = req->cert->serialSz;
+    snSz = SetSerialNumber(req->cert->serial, req->cert->serialSz, snArray);
+
+    extSz = 0;
+    if (req->useNonce) {
+        RNG rng;
+        if (wc_InitRng(&rng) != 0) {
+            WOLFSSL_MSG("\tCannot initialize RNG. Skipping the OSCP Nonce.");
+        } else {
+            if (wc_RNG_GenerateBlock(&rng, req->nonce, MAX_OCSP_NONCE_SZ) != 0)
+                WOLFSSL_MSG("\tCannot run RNG. Skipping the OSCP Nonce.");
+            else {
+                req->nonceSz = MAX_OCSP_NONCE_SZ;
+                extSz = SetOcspReqExtensions(MAX_OCSP_EXT_SZ, extArray,
+                                                      req->nonce, req->nonceSz);
+            }
+            wc_FreeRng(&rng);
+        }
+    }
+
+    totalSz = algoSz + issuerSz + issuerKeySz + snSz;
+
+    for (i = 4; i >= 0; i--) {
+        seqSz[i] = SetSequence(totalSz, seqArray[i]);
+        totalSz += seqSz[i];
+        if (i == 2) totalSz += extSz;
+    }
+    totalSz = 0;
+    for (i = 0; i < 5; i++) {
+        XMEMCPY(output + totalSz, seqArray[i], seqSz[i]);
+        totalSz += seqSz[i];
+    }
+    XMEMCPY(output + totalSz, algoArray, algoSz);
+    totalSz += algoSz;
+    XMEMCPY(output + totalSz, issuerArray, issuerSz);
+    totalSz += issuerSz;
+    XMEMCPY(output + totalSz, issuerKeyArray, issuerKeySz);
+    totalSz += issuerKeySz;
+    XMEMCPY(output + totalSz, snArray, snSz);
+    totalSz += snSz;
+    if (extSz != 0) {
+        XMEMCPY(output + totalSz, extArray, extSz);
+        totalSz += extSz;
+    }
+
+    return totalSz;
+}
+
+
+void InitOcspRequest(OcspRequest* req, DecodedCert* cert, byte useNonce,
+                                                    byte* dest, word32 destSz)
+{
+    WOLFSSL_ENTER("InitOcspRequest");
+
+    req->cert = cert;
+    req->useNonce = useNonce;
+    req->nonceSz = 0;
+    req->issuerHash = NULL;
+    req->issuerKeyHash = NULL;
+    req->serial = NULL;
+    req->dest = dest;
+    req->destSz = destSz;
+}
+
+
+int CompareOcspReqResp(OcspRequest* req, OcspResponse* resp)
+{
+    int cmp;
+
+    WOLFSSL_ENTER("CompareOcspReqResp");
+
+    if (req == NULL)
+    {
+        WOLFSSL_MSG("\tReq missing");
+        return -1;
+    }
+
+    if (resp == NULL)
+    {
+        WOLFSSL_MSG("\tResp missing");
+        return 1;
+    }
+
+    /* Nonces are not critical. The responder may not necessarily add
+     * the nonce to the response. */
+    if (req->useNonce && resp->nonceSz != 0) {
+        cmp = req->nonceSz - resp->nonceSz;
+        if (cmp != 0)
+        {
+            WOLFSSL_MSG("\tnonceSz mismatch");
+            return cmp;
+        }
+    
+        cmp = XMEMCMP(req->nonce, resp->nonce, req->nonceSz);
+        if (cmp != 0)
+        {
+            WOLFSSL_MSG("\tnonce mismatch");
+            return cmp;
+        }
+    }
+
+    cmp = XMEMCMP(req->issuerHash, resp->issuerHash, KEYID_SIZE);
+    if (cmp != 0)
+    {
+        WOLFSSL_MSG("\tissuerHash mismatch");
+        return cmp;
+    }
+
+    cmp = XMEMCMP(req->issuerKeyHash, resp->issuerKeyHash, KEYID_SIZE);
+    if (cmp != 0)
+    {
+        WOLFSSL_MSG("\tissuerKeyHash mismatch");
+        return cmp;
+    }
+
+    cmp = req->serialSz - resp->status->serialSz;
+    if (cmp != 0)
+    {
+        WOLFSSL_MSG("\tserialSz mismatch");
+        return cmp;
+    }
+
+    cmp = XMEMCMP(req->serial, resp->status->serial, req->serialSz);
+    if (cmp != 0)
+    {
+        WOLFSSL_MSG("\tserial mismatch");
+        return cmp;
+    }
+
+    return 0;
+}
+
+#endif
+
+
+/* store SHA hash of NAME */
+WOLFSSL_LOCAL int GetNameHash(const byte* source, word32* idx, byte* hash,
+                             int maxIdx)
+{
+    int    length;  /* length of all distinguished names */
+    int    ret;
+    word32 dummy;
+
+    WOLFSSL_ENTER("GetNameHash");
+
+    if (source[*idx] == ASN_OBJECT_ID) {
+        WOLFSSL_MSG("Trying optional prefix...");
+
+        if (GetLength(source, idx, &length, maxIdx) < 0)
+            return ASN_PARSE_E;
+
+        *idx += length;
+        WOLFSSL_MSG("Got optional prefix");
+    }
+
+    /* For OCSP, RFC2560 section 4.1.1 states the issuer hash should be
+     * calculated over the entire DER encoding of the Name field, including
+     * the tag and length. */
+    dummy = *idx;
+    if (GetSequence(source, idx, &length, maxIdx) < 0)
+        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
+
+    *idx += length;
+
+    return ret;
+}
+
+
+#ifdef HAVE_CRL
+
+/* initialize decoded CRL */
+void InitDecodedCRL(DecodedCRL* dcrl)
+{
+    WOLFSSL_MSG("InitDecodedCRL");
+
+    dcrl->certBegin    = 0;
+    dcrl->sigIndex     = 0;
+    dcrl->sigLength    = 0;
+    dcrl->signatureOID = 0;
+    dcrl->certs        = NULL;
+    dcrl->totalCerts   = 0;
+}
+
+
+/* free decoded CRL resources */
+void FreeDecodedCRL(DecodedCRL* dcrl)
+{
+    RevokedCert* tmp = dcrl->certs;
+
+    WOLFSSL_MSG("FreeDecodedCRL");
+
+    while(tmp) {
+        RevokedCert* next = tmp->next;
+        XFREE(tmp, NULL, DYNAMIC_TYPE_REVOKED);
+        tmp = next;
+    }
+}
+
+
+/* Get Revoked Cert list, 0 on success */
+static int GetRevoked(const byte* buff, word32* idx, DecodedCRL* dcrl,
+                      int maxIdx)
+{
+    int    len;
+    word32 end;
+    byte   b;
+    RevokedCert* rc;
+
+    WOLFSSL_ENTER("GetRevoked");
+
+    if (GetSequence(buff, idx, &len, maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    end = *idx + len;
+
+    /* get serial number */
+    b = buff[*idx];
+    *idx += 1;
+
+    if (b != ASN_INTEGER) {
+        WOLFSSL_MSG("Expecting Integer");
+        return ASN_PARSE_E;
+    }
+
+    if (GetLength(buff, idx, &len, maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    if (len > EXTERNAL_SERIAL_SIZE) {
+        WOLFSSL_MSG("Serial Size too big");
+        return ASN_PARSE_E;
+    }
+
+    rc = (RevokedCert*)XMALLOC(sizeof(RevokedCert), NULL, DYNAMIC_TYPE_CRL);
+    if (rc == NULL) {
+        WOLFSSL_MSG("Alloc Revoked Cert failed");
+        return MEMORY_E;
+    }
+
+    XMEMCPY(rc->serialNumber, &buff[*idx], len);
+    rc->serialSz = len;
+
+    /* add to list */
+    rc->next = dcrl->certs;
+    dcrl->certs = rc;
+    dcrl->totalCerts++;
+
+    *idx += len;
+
+    /* get date */
+    b = buff[*idx];
+    *idx += 1;
+
+    if (b != ASN_UTC_TIME && b != ASN_GENERALIZED_TIME) {
+        WOLFSSL_MSG("Expecting Date");
+        return ASN_PARSE_E;
+    }
+
+    if (GetLength(buff, idx, &len, maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    /* skip for now */
+    *idx += len;
+
+    if (*idx != end)  /* skip extensions */
+        *idx = end;
+
+    return 0;
+}
+
+
+/* Get CRL Signature, 0 on success */
+static int GetCRL_Signature(const byte* source, word32* idx, DecodedCRL* dcrl,
+                            int maxIdx)
+{
+    int    length;
+    byte   b;
+
+    WOLFSSL_ENTER("GetCRL_Signature");
+
+    b = source[*idx];
+    *idx += 1;
+    if (b != ASN_BIT_STRING)
+        return ASN_BITSTR_E;
+
+    if (GetLength(source, idx, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    dcrl->sigLength = length;
+
+    b = source[*idx];
+    *idx += 1;
+    if (b != 0x00)
+        return ASN_EXPECT_0_E;
+
+    dcrl->sigLength--;
+    dcrl->signature = (byte*)&source[*idx];
+
+    *idx += dcrl->sigLength;
+
+    return 0;
+}
+
+
+/* prase crl buffer into decoded state, 0 on success */
+int ParseCRL(DecodedCRL* dcrl, const byte* buff, word32 sz, void* cm)
+{
+    int     version, len;
+    word32  oid, idx = 0;
+    Signer* ca = NULL;
+
+    WOLFSSL_MSG("ParseCRL");
+
+    /* raw crl hash */
+    /* hash here if needed for optimized comparisons
+     * Sha     sha;
+     * wc_InitSha(&sha);
+     * wc_ShaUpdate(&sha, buff, sz);
+     * wc_ShaFinal(&sha, dcrl->crlHash); */
+
+    if (GetSequence(buff, &idx, &len, sz) < 0)
+        return ASN_PARSE_E;
+
+    dcrl->certBegin = idx;
+
+    if (GetSequence(buff, &idx, &len, sz) < 0)
+        return ASN_PARSE_E;
+    dcrl->sigIndex = len + idx;
+
+    /* may have version */
+    if (buff[idx] == ASN_INTEGER) {
+        if (GetMyVersion(buff, &idx, &version) < 0)
+            return ASN_PARSE_E;
+    }
+
+    if (GetAlgoId(buff, &idx, &oid, sz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetNameHash(buff, &idx, dcrl->issuerHash, sz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetBasicDate(buff, &idx, dcrl->lastDate, &dcrl->lastDateFormat, sz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetBasicDate(buff, &idx, dcrl->nextDate, &dcrl->nextDateFormat, sz) < 0)
+        return ASN_PARSE_E;
+
+    if (!XVALIDATE_DATE(dcrl->nextDate, dcrl->nextDateFormat, AFTER)) {
+        WOLFSSL_MSG("CRL after date is no longer valid");
+        return ASN_AFTER_DATE_E;
+    }
+
+    if (idx != dcrl->sigIndex && buff[idx] != CRL_EXTENSIONS) {
+        if (GetSequence(buff, &idx, &len, sz) < 0)
+            return ASN_PARSE_E;
+
+        len += idx;
+
+        while (idx < (word32)len) {
+            if (GetRevoked(buff, &idx, dcrl, sz) < 0)
+                return ASN_PARSE_E;
+        }
+    }
+
+    if (idx != dcrl->sigIndex)
+        idx = dcrl->sigIndex;   /* skip extensions */
+
+    if (GetAlgoId(buff, &idx, &dcrl->signatureOID, sz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetCRL_Signature(buff, &idx, dcrl, sz) < 0)
+        return ASN_PARSE_E;
+
+    /* openssl doesn't add skid by default for CRLs cause firefox chokes
+       we're not assuming it's available yet */
+    #if !defined(NO_SKID) && defined(CRL_SKID_READY)
+        if (dcrl->extAuthKeyIdSet)
+            ca = GetCA(cm, dcrl->extAuthKeyId);
+        if (ca == NULL)
+            ca = GetCAByName(cm, dcrl->issuerHash);
+    #else /* NO_SKID */
+        ca = GetCA(cm, dcrl->issuerHash);
+    #endif /* NO_SKID */
+    WOLFSSL_MSG("About to verify CRL signature");
+
+    if (ca) {
+        WOLFSSL_MSG("Found CRL issuer CA");
+        /* try to confirm/verify signature */
+        #ifndef IGNORE_KEY_EXTENSIONS
+            if ((ca->keyUsage & KEYUSE_CRL_SIGN) == 0) {
+                WOLFSSL_MSG("CA cannot sign CRLs");
+                return ASN_CRL_NO_SIGNER_E;
+            }
+        #endif /* IGNORE_KEY_EXTENSIONS */
+        if (!ConfirmSignature(buff + dcrl->certBegin,
+                dcrl->sigIndex - dcrl->certBegin,
+                ca->publicKey, ca->pubKeySize, ca->keyOID,
+                dcrl->signature, dcrl->sigLength, dcrl->signatureOID, NULL)) {
+            WOLFSSL_MSG("CRL Confirm signature failed");
+            return ASN_CRL_CONFIRM_E;
+        }
+    }
+    else {
+        WOLFSSL_MSG("Did NOT find CRL issuer CA");
+        return ASN_CRL_NO_SIGNER_E;
+    }
+
+    return 0;
+}
+
+#endif /* HAVE_CRL */
+#endif
+
+#ifdef WOLFSSL_SEP
+
+
+
+#endif /* WOLFSSL_SEP */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/blake2b.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,434 @@
+/*
+   BLAKE2 reference source code package - reference C implementations
+
+   Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
+
+   To the extent possible under law, the author(s) have dedicated all copyright
+   and related and neighboring rights to this software to the public domain
+   worldwide. This software is distributed without any warranty.
+
+   You should have received a copy of the CC0 Public Domain Dedication along with
+   this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
+*/
+/* blake2b.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_BLAKE2
+
+#include <wolfssl/wolfcrypt/blake2.h>
+#include <wolfssl/wolfcrypt/blake2-impl.h>
+
+
+static const word64 blake2b_IV[8] =
+{
+  0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
+  0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
+  0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
+  0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
+};
+
+static const byte blake2b_sigma[12][16] =
+{
+  {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 } ,
+  { 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 } ,
+  { 11,  8, 12,  0,  5,  2, 15, 13, 10, 14,  3,  6,  7,  1,  9,  4 } ,
+  {  7,  9,  3,  1, 13, 12, 11, 14,  2,  6,  5, 10,  4,  0, 15,  8 } ,
+  {  9,  0,  5,  7,  2,  4, 10, 15, 14,  1, 11, 12,  6,  8,  3, 13 } ,
+  {  2, 12,  6, 10,  0, 11,  8,  3,  4, 13,  7,  5, 15, 14,  1,  9 } ,
+  { 12,  5,  1, 15, 14, 13,  4, 10,  0,  7,  6,  3,  9,  2,  8, 11 } ,
+  { 13, 11,  7, 14, 12,  1,  3,  9,  5,  0, 15,  4,  8,  6,  2, 10 } ,
+  {  6, 15, 14,  9, 11,  3,  0,  8, 12,  2, 13,  7,  1,  4, 10,  5 } ,
+  { 10,  2,  8,  4,  7,  6,  1,  5, 15, 11,  9, 14,  3, 12, 13 , 0 } ,
+  {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 } ,
+  { 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 }
+};
+
+
+static INLINE int blake2b_set_lastnode( blake2b_state *S )
+{
+  S->f[1] = ~0ULL;
+  return 0;
+}
+
+/* Some helper functions, not necessarily useful */
+static INLINE int blake2b_set_lastblock( blake2b_state *S )
+{
+  if( S->last_node ) blake2b_set_lastnode( S );
+
+  S->f[0] = ~0ULL;
+  return 0;
+}
+
+static INLINE int blake2b_increment_counter( blake2b_state *S, const word64
+                                             inc )
+{
+  S->t[0] += inc;
+  S->t[1] += ( S->t[0] < inc );
+  return 0;
+}
+
+static INLINE int blake2b_init0( blake2b_state *S )
+{
+  int i;
+  XMEMSET( S, 0, sizeof( blake2b_state ) );
+
+  for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
+
+  return 0;
+}
+
+/* init xors IV with input parameter block */
+int blake2b_init_param( blake2b_state *S, const blake2b_param *P )
+{
+  word32 i;
+  blake2b_init0( S );
+  byte *p = ( byte * )( P );
+
+  /* IV XOR ParamBlock */
+  for( i = 0; i < 8; ++i )
+    S->h[i] ^= load64( p + sizeof( S->h[i] ) * i );
+
+  return 0;
+}
+
+
+
+int blake2b_init( blake2b_state *S, const byte outlen )
+{
+  blake2b_param P[1];
+
+  if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
+
+  P->digest_length = outlen;
+  P->key_length    = 0;
+  P->fanout        = 1;
+  P->depth         = 1;
+  store32( &P->leaf_length, 0 );
+  store64( &P->node_offset, 0 );
+  P->node_depth    = 0;
+  P->inner_length  = 0;
+  XMEMSET( P->reserved, 0, sizeof( P->reserved ) );
+  XMEMSET( P->salt,     0, sizeof( P->salt ) );
+  XMEMSET( P->personal, 0, sizeof( P->personal ) );
+  return blake2b_init_param( S, P );
+}
+
+
+int blake2b_init_key( blake2b_state *S, const byte outlen, const void *key,
+                      const byte keylen )
+{
+  blake2b_param P[1];
+
+  if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
+
+  if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
+
+  P->digest_length = outlen;
+  P->key_length    = keylen;
+  P->fanout        = 1;
+  P->depth         = 1;
+  store32( &P->leaf_length, 0 );
+  store64( &P->node_offset, 0 );
+  P->node_depth    = 0;
+  P->inner_length  = 0;
+  XMEMSET( P->reserved, 0, sizeof( P->reserved ) );
+  XMEMSET( P->salt,     0, sizeof( P->salt ) );
+  XMEMSET( P->personal, 0, sizeof( P->personal ) );
+
+  if( blake2b_init_param( S, P ) < 0 ) return -1;
+
+  {
+#ifdef WOLFSSL_SMALL_STACK
+    byte* block;
+
+    block = (byte*)XMALLOC(BLAKE2B_BLOCKBYTES, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    if ( block == NULL ) return -1;
+#else
+    byte block[BLAKE2B_BLOCKBYTES];
+#endif
+
+    XMEMSET( block, 0, BLAKE2B_BLOCKBYTES );
+    XMEMCPY( block, key, keylen );
+    blake2b_update( S, block, BLAKE2B_BLOCKBYTES );
+    secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from */
+                                                     /* memory */
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(block, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+  }
+  return 0;
+}
+
+static int blake2b_compress( blake2b_state *S,
+                             const byte block[BLAKE2B_BLOCKBYTES] )
+{
+  int i;
+
+#ifdef WOLFSSL_SMALL_STACK
+  word64* m;
+  word64* v;
+
+  m = (word64*)XMALLOC(sizeof(word64) * 16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+  if ( m == NULL ) return -1;
+
+  v = (word64*)XMALLOC(sizeof(word64) * 16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+  if ( v == NULL )
+  {
+    XFREE(m, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    return -1;
+  }
+#else
+  word64 m[16];
+  word64 v[16];
+#endif
+
+  for( i = 0; i < 16; ++i )
+    m[i] = load64( block + i * sizeof( m[i] ) );
+
+  for( i = 0; i < 8; ++i )
+    v[i] = S->h[i];
+
+  v[ 8] = blake2b_IV[0];
+  v[ 9] = blake2b_IV[1];
+  v[10] = blake2b_IV[2];
+  v[11] = blake2b_IV[3];
+  v[12] = S->t[0] ^ blake2b_IV[4];
+  v[13] = S->t[1] ^ blake2b_IV[5];
+  v[14] = S->f[0] ^ blake2b_IV[6];
+  v[15] = S->f[1] ^ blake2b_IV[7];
+#define G(r,i,a,b,c,d) \
+  do { \
+    a = a + b + m[blake2b_sigma[r][2*i+0]]; \
+    d = rotr64(d ^ a, 32); \
+    c = c + d; \
+    b = rotr64(b ^ c, 24); \
+    a = a + b + m[blake2b_sigma[r][2*i+1]]; \
+    d = rotr64(d ^ a, 16); \
+    c = c + d; \
+    b = rotr64(b ^ c, 63); \
+  } while(0)
+#define ROUND(r)  \
+  do { \
+    G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
+    G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
+    G(r,2,v[ 2],v[ 6],v[10],v[14]); \
+    G(r,3,v[ 3],v[ 7],v[11],v[15]); \
+    G(r,4,v[ 0],v[ 5],v[10],v[15]); \
+    G(r,5,v[ 1],v[ 6],v[11],v[12]); \
+    G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
+    G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
+  } while(0)
+  ROUND( 0 );
+  ROUND( 1 );
+  ROUND( 2 );
+  ROUND( 3 );
+  ROUND( 4 );
+  ROUND( 5 );
+  ROUND( 6 );
+  ROUND( 7 );
+  ROUND( 8 );
+  ROUND( 9 );
+  ROUND( 10 );
+  ROUND( 11 );
+
+  for( i = 0; i < 8; ++i )
+    S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
+
+#undef G
+#undef ROUND
+
+#ifdef WOLFSSL_SMALL_STACK
+  XFREE(m, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+  XFREE(v, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+  return 0;
+}
+
+/* inlen now in bytes */
+int blake2b_update( blake2b_state *S, const byte *in, word64 inlen )
+{
+  while( inlen > 0 )
+  {
+    word64 left = S->buflen;
+    word64 fill = 2 * BLAKE2B_BLOCKBYTES - left;
+
+    if( inlen > fill )
+    {
+      XMEMCPY( S->buf + left, in, (wolfssl_word)fill ); /* Fill buffer */
+      S->buflen += fill;
+      blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
+
+      if ( blake2b_compress( S, S->buf ) < 0 ) return -1; /* Compress */
+
+      XMEMCPY( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES );
+              /* Shift buffer left */
+      S->buflen -= BLAKE2B_BLOCKBYTES;
+      in += fill;
+      inlen -= fill;
+    }
+    else /* inlen <= fill */
+    {
+      XMEMCPY( S->buf + left, in, (wolfssl_word)inlen );
+      S->buflen += inlen; /* Be lazy, do not compress */
+      in += inlen;
+      inlen -= inlen;
+    }
+  }
+
+  return 0;
+}
+
+/* Is this correct? */
+int blake2b_final( blake2b_state *S, byte *out, byte outlen )
+{
+  byte buffer[BLAKE2B_OUTBYTES];
+  int     i;
+
+  if( S->buflen > BLAKE2B_BLOCKBYTES )
+  {
+    blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
+
+    if ( blake2b_compress( S, S->buf ) < 0 ) return -1;
+
+    S->buflen -= BLAKE2B_BLOCKBYTES;
+    XMEMCPY( S->buf, S->buf + BLAKE2B_BLOCKBYTES, (wolfssl_word)S->buflen );
+  }
+
+  blake2b_increment_counter( S, S->buflen );
+  blake2b_set_lastblock( S );
+  XMEMSET( S->buf + S->buflen, 0, (wolfssl_word)(2 * BLAKE2B_BLOCKBYTES - S->buflen) );
+         /* Padding */
+  if ( blake2b_compress( S, S->buf ) < 0 ) return -1;
+
+  for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
+    store64( buffer + sizeof( S->h[i] ) * i, S->h[i] );
+
+  XMEMCPY( out, buffer, outlen );
+  return 0;
+}
+
+/* inlen, at least, should be word64. Others can be size_t. */
+int blake2b( byte *out, const void *in, const void *key, const byte outlen,
+             const word64 inlen, byte keylen )
+{
+  blake2b_state S[1];
+
+  /* Verify parameters */
+  if ( NULL == in ) return -1;
+
+  if ( NULL == out ) return -1;
+
+  if( NULL == key ) keylen = 0;
+
+  if( keylen > 0 )
+  {
+    if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1;
+  }
+  else
+  {
+    if( blake2b_init( S, outlen ) < 0 ) return -1;
+  }
+
+  if ( blake2b_update( S, ( byte * )in, inlen ) < 0) return -1;
+
+  return blake2b_final( S, out, outlen );
+}
+
+#if defined(BLAKE2B_SELFTEST)
+#include <string.h>
+#include "blake2-kat.h"
+int main( int argc, char **argv )
+{
+  byte key[BLAKE2B_KEYBYTES];
+  byte buf[KAT_LENGTH];
+
+  for( word32 i = 0; i < BLAKE2B_KEYBYTES; ++i )
+    key[i] = ( byte )i;
+
+  for( word32 i = 0; i < KAT_LENGTH; ++i )
+    buf[i] = ( byte )i;
+
+  for( word32 i = 0; i < KAT_LENGTH; ++i )
+  {
+    byte hash[BLAKE2B_OUTBYTES];
+    if ( blake2b( hash, buf, key, BLAKE2B_OUTBYTES, i, BLAKE2B_KEYBYTES ) < 0 )
+    {
+      puts( "error" );
+      return -1;
+    }
+
+    if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) )
+    {
+      puts( "error" );
+      return -1;
+    }
+  }
+
+  puts( "ok" );
+  return 0;
+}
+#endif
+
+
+/* wolfCrypt API */
+
+/* Init Blake2b digest, track size incase final doesn't want to "remember" */
+int wc_InitBlake2b(Blake2b* b2b, word32 digestSz)
+{
+    b2b->digestSz = digestSz;
+
+    return blake2b_init(b2b->S, (byte)digestSz);
+}
+
+
+/* Blake2b Update */
+int wc_Blake2bUpdate(Blake2b* b2b, const byte* data, word32 sz)
+{
+    return blake2b_update(b2b->S, data, sz);
+}
+
+
+/* Blake2b Final, if pass in zero size we use init digestSz */
+int wc_Blake2bFinal(Blake2b* b2b, byte* final, word32 requestSz)
+{
+    word32 sz = requestSz ? requestSz : b2b->digestSz;
+
+    return blake2b_final(b2b->S, final, (byte)sz);
+}
+
+
+/* end CTaoCrypt API */
+
+#endif  /* HAVE_BLAKE2 */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/camellia.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,1621 @@
+/* camellia.c ver 1.2.0
+ *
+ * Copyright (c) 2006,2007
+ * NTT (Nippon Telegraph and Telephone Corporation) . All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer as
+ *   the first lines of this file unmodified.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NTT ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL NTT BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* camellia.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+/*
+ * Algorithm Specification 
+ *  http://info.isl.ntt.co.jp/crypt/eng/camellia/specifications.html
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_CAMELLIA
+
+#include <wolfssl/wolfcrypt/camellia.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/logging.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+/* u32 must be 32bit word */
+typedef unsigned int u32;
+typedef unsigned char u8;
+
+/* key constants */
+
+#define CAMELLIA_SIGMA1L ((u32)0xA09E667FL)
+#define CAMELLIA_SIGMA1R ((u32)0x3BCC908BL)
+#define CAMELLIA_SIGMA2L ((u32)0xB67AE858L)
+#define CAMELLIA_SIGMA2R ((u32)0x4CAA73B2L)
+#define CAMELLIA_SIGMA3L ((u32)0xC6EF372FL)
+#define CAMELLIA_SIGMA3R ((u32)0xE94F82BEL)
+#define CAMELLIA_SIGMA4L ((u32)0x54FF53A5L)
+#define CAMELLIA_SIGMA4R ((u32)0xF1D36F1CL)
+#define CAMELLIA_SIGMA5L ((u32)0x10E527FAL)
+#define CAMELLIA_SIGMA5R ((u32)0xDE682D1DL)
+#define CAMELLIA_SIGMA6L ((u32)0xB05688C2L)
+#define CAMELLIA_SIGMA6R ((u32)0xB3E6C1FDL)
+
+/*
+ *  macros
+ */
+
+
+#if defined(_MSC_VER)
+
+# define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
+# define GETU32(p) SWAP(*((u32 *)(p)))
+# define PUTU32(ct, st) {*((u32 *)(ct)) = SWAP((st));}
+
+#else /* not MS-VC */
+
+# define GETU32(pt)				\
+    (((u32)(pt)[0] << 24)			\
+     ^ ((u32)(pt)[1] << 16)			\
+     ^ ((u32)(pt)[2] <<  8)			\
+     ^ ((u32)(pt)[3]))
+
+# define PUTU32(ct, st)  {			\
+	(ct)[0] = (u8)((st) >> 24);		\
+	(ct)[1] = (u8)((st) >> 16);		\
+	(ct)[2] = (u8)((st) >>  8);		\
+	(ct)[3] = (u8)(st); }
+
+#endif
+
+#define CamelliaSubkeyL(INDEX) (subkey[(INDEX)*2])
+#define CamelliaSubkeyR(INDEX) (subkey[(INDEX)*2 + 1])
+
+/* rotation right shift 1byte */
+#define CAMELLIA_RR8(x) (((x) >> 8) + ((x) << 24))
+/* rotation left shift 1bit */
+#define CAMELLIA_RL1(x) (((x) << 1) + ((x) >> 31))
+/* rotation left shift 1byte */
+#define CAMELLIA_RL8(x) (((x) << 8) + ((x) >> 24))
+
+#define CAMELLIA_ROLDQ(ll, lr, rl, rr, w0, w1, bits)	\
+    do {						\
+	w0 = ll;					\
+	ll = (ll << bits) + (lr >> (32 - bits));	\
+	lr = (lr << bits) + (rl >> (32 - bits));	\
+	rl = (rl << bits) + (rr >> (32 - bits));	\
+	rr = (rr << bits) + (w0 >> (32 - bits));	\
+    } while(0)
+
+#define CAMELLIA_ROLDQo32(ll, lr, rl, rr, w0, w1, bits)	\
+    do {						\
+	w0 = ll;					\
+	w1 = lr;					\
+	ll = (lr << (bits - 32)) + (rl >> (64 - bits));	\
+	lr = (rl << (bits - 32)) + (rr >> (64 - bits));	\
+	rl = (rr << (bits - 32)) + (w0 >> (64 - bits));	\
+	rr = (w0 << (bits - 32)) + (w1 >> (64 - bits));	\
+    } while(0)
+
+#define CAMELLIA_SP1110(INDEX) (camellia_sp1110[(INDEX)])
+#define CAMELLIA_SP0222(INDEX) (camellia_sp0222[(INDEX)])
+#define CAMELLIA_SP3033(INDEX) (camellia_sp3033[(INDEX)])
+#define CAMELLIA_SP4404(INDEX) (camellia_sp4404[(INDEX)])
+
+#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1)	\
+    do {							\
+	il = xl ^ kl;						\
+	ir = xr ^ kr;						\
+	t0 = il >> 16;						\
+	t1 = ir >> 16;						\
+	yl = CAMELLIA_SP1110(ir & 0xff)				\
+	    ^ CAMELLIA_SP0222((t1 >> 8) & 0xff)			\
+	    ^ CAMELLIA_SP3033(t1 & 0xff)			\
+	    ^ CAMELLIA_SP4404((ir >> 8) & 0xff);		\
+	yr = CAMELLIA_SP1110((t0 >> 8) & 0xff)			\
+	    ^ CAMELLIA_SP0222(t0 & 0xff)			\
+	    ^ CAMELLIA_SP3033((il >> 8) & 0xff)			\
+	    ^ CAMELLIA_SP4404(il & 0xff);			\
+	yl ^= yr;						\
+	yr = CAMELLIA_RR8(yr);					\
+	yr ^= yl;						\
+    } while(0)
+
+
+/*
+ * for speed up
+ *
+ */
+#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) \
+    do {								\
+	t0 = kll;							\
+	t0 &= ll;							\
+	lr ^= CAMELLIA_RL1(t0);						\
+	t1 = klr;							\
+	t1 |= lr;							\
+	ll ^= t1;							\
+									\
+	t2 = krr;							\
+	t2 |= rr;							\
+	rl ^= t2;							\
+	t3 = krl;							\
+	t3 &= rl;							\
+	rr ^= CAMELLIA_RL1(t3);						\
+    } while(0)
+
+#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir, t0, t1)	\
+    do {								\
+	ir = CAMELLIA_SP1110(xr & 0xff)					\
+	    ^ CAMELLIA_SP0222((xr >> 24) & 0xff)			\
+	    ^ CAMELLIA_SP3033((xr >> 16) & 0xff)			\
+	    ^ CAMELLIA_SP4404((xr >> 8) & 0xff);			\
+	il = CAMELLIA_SP1110((xl >> 24) & 0xff)				\
+	    ^ CAMELLIA_SP0222((xl >> 16) & 0xff)			\
+	    ^ CAMELLIA_SP3033((xl >> 8) & 0xff)				\
+	    ^ CAMELLIA_SP4404(xl & 0xff);				\
+	il ^= kl;							\
+	ir ^= kr;							\
+	ir ^= il;							\
+	il = CAMELLIA_RR8(il);						\
+	il ^= ir;							\
+	yl ^= ir;							\
+	yr ^= il;							\
+    } while(0)
+
+
+static const u32 camellia_sp1110[256] = {
+    0x70707000,0x82828200,0x2c2c2c00,0xececec00,
+    0xb3b3b300,0x27272700,0xc0c0c000,0xe5e5e500,
+    0xe4e4e400,0x85858500,0x57575700,0x35353500,
+    0xeaeaea00,0x0c0c0c00,0xaeaeae00,0x41414100,
+    0x23232300,0xefefef00,0x6b6b6b00,0x93939300,
+    0x45454500,0x19191900,0xa5a5a500,0x21212100,
+    0xededed00,0x0e0e0e00,0x4f4f4f00,0x4e4e4e00,
+    0x1d1d1d00,0x65656500,0x92929200,0xbdbdbd00,
+    0x86868600,0xb8b8b800,0xafafaf00,0x8f8f8f00,
+    0x7c7c7c00,0xebebeb00,0x1f1f1f00,0xcecece00,
+    0x3e3e3e00,0x30303000,0xdcdcdc00,0x5f5f5f00,
+    0x5e5e5e00,0xc5c5c500,0x0b0b0b00,0x1a1a1a00,
+    0xa6a6a600,0xe1e1e100,0x39393900,0xcacaca00,
+    0xd5d5d500,0x47474700,0x5d5d5d00,0x3d3d3d00,
+    0xd9d9d900,0x01010100,0x5a5a5a00,0xd6d6d600,
+    0x51515100,0x56565600,0x6c6c6c00,0x4d4d4d00,
+    0x8b8b8b00,0x0d0d0d00,0x9a9a9a00,0x66666600,
+    0xfbfbfb00,0xcccccc00,0xb0b0b000,0x2d2d2d00,
+    0x74747400,0x12121200,0x2b2b2b00,0x20202000,
+    0xf0f0f000,0xb1b1b100,0x84848400,0x99999900,
+    0xdfdfdf00,0x4c4c4c00,0xcbcbcb00,0xc2c2c200,
+    0x34343400,0x7e7e7e00,0x76767600,0x05050500,
+    0x6d6d6d00,0xb7b7b700,0xa9a9a900,0x31313100,
+    0xd1d1d100,0x17171700,0x04040400,0xd7d7d700,
+    0x14141400,0x58585800,0x3a3a3a00,0x61616100,
+    0xdedede00,0x1b1b1b00,0x11111100,0x1c1c1c00,
+    0x32323200,0x0f0f0f00,0x9c9c9c00,0x16161600,
+    0x53535300,0x18181800,0xf2f2f200,0x22222200,
+    0xfefefe00,0x44444400,0xcfcfcf00,0xb2b2b200,
+    0xc3c3c300,0xb5b5b500,0x7a7a7a00,0x91919100,
+    0x24242400,0x08080800,0xe8e8e800,0xa8a8a800,
+    0x60606000,0xfcfcfc00,0x69696900,0x50505000,
+    0xaaaaaa00,0xd0d0d000,0xa0a0a000,0x7d7d7d00,
+    0xa1a1a100,0x89898900,0x62626200,0x97979700,
+    0x54545400,0x5b5b5b00,0x1e1e1e00,0x95959500,
+    0xe0e0e000,0xffffff00,0x64646400,0xd2d2d200,
+    0x10101000,0xc4c4c400,0x00000000,0x48484800,
+    0xa3a3a300,0xf7f7f700,0x75757500,0xdbdbdb00,
+    0x8a8a8a00,0x03030300,0xe6e6e600,0xdadada00,
+    0x09090900,0x3f3f3f00,0xdddddd00,0x94949400,
+    0x87878700,0x5c5c5c00,0x83838300,0x02020200,
+    0xcdcdcd00,0x4a4a4a00,0x90909000,0x33333300,
+    0x73737300,0x67676700,0xf6f6f600,0xf3f3f300,
+    0x9d9d9d00,0x7f7f7f00,0xbfbfbf00,0xe2e2e200,
+    0x52525200,0x9b9b9b00,0xd8d8d800,0x26262600,
+    0xc8c8c800,0x37373700,0xc6c6c600,0x3b3b3b00,
+    0x81818100,0x96969600,0x6f6f6f00,0x4b4b4b00,
+    0x13131300,0xbebebe00,0x63636300,0x2e2e2e00,
+    0xe9e9e900,0x79797900,0xa7a7a700,0x8c8c8c00,
+    0x9f9f9f00,0x6e6e6e00,0xbcbcbc00,0x8e8e8e00,
+    0x29292900,0xf5f5f500,0xf9f9f900,0xb6b6b600,
+    0x2f2f2f00,0xfdfdfd00,0xb4b4b400,0x59595900,
+    0x78787800,0x98989800,0x06060600,0x6a6a6a00,
+    0xe7e7e700,0x46464600,0x71717100,0xbababa00,
+    0xd4d4d400,0x25252500,0xababab00,0x42424200,
+    0x88888800,0xa2a2a200,0x8d8d8d00,0xfafafa00,
+    0x72727200,0x07070700,0xb9b9b900,0x55555500,
+    0xf8f8f800,0xeeeeee00,0xacacac00,0x0a0a0a00,
+    0x36363600,0x49494900,0x2a2a2a00,0x68686800,
+    0x3c3c3c00,0x38383800,0xf1f1f100,0xa4a4a400,
+    0x40404000,0x28282800,0xd3d3d300,0x7b7b7b00,
+    0xbbbbbb00,0xc9c9c900,0x43434300,0xc1c1c100,
+    0x15151500,0xe3e3e300,0xadadad00,0xf4f4f400,
+    0x77777700,0xc7c7c700,0x80808000,0x9e9e9e00,
+};
+
+static const u32 camellia_sp0222[256] = {
+    0x00e0e0e0,0x00050505,0x00585858,0x00d9d9d9,
+    0x00676767,0x004e4e4e,0x00818181,0x00cbcbcb,
+    0x00c9c9c9,0x000b0b0b,0x00aeaeae,0x006a6a6a,
+    0x00d5d5d5,0x00181818,0x005d5d5d,0x00828282,
+    0x00464646,0x00dfdfdf,0x00d6d6d6,0x00272727,
+    0x008a8a8a,0x00323232,0x004b4b4b,0x00424242,
+    0x00dbdbdb,0x001c1c1c,0x009e9e9e,0x009c9c9c,
+    0x003a3a3a,0x00cacaca,0x00252525,0x007b7b7b,
+    0x000d0d0d,0x00717171,0x005f5f5f,0x001f1f1f,
+    0x00f8f8f8,0x00d7d7d7,0x003e3e3e,0x009d9d9d,
+    0x007c7c7c,0x00606060,0x00b9b9b9,0x00bebebe,
+    0x00bcbcbc,0x008b8b8b,0x00161616,0x00343434,
+    0x004d4d4d,0x00c3c3c3,0x00727272,0x00959595,
+    0x00ababab,0x008e8e8e,0x00bababa,0x007a7a7a,
+    0x00b3b3b3,0x00020202,0x00b4b4b4,0x00adadad,
+    0x00a2a2a2,0x00acacac,0x00d8d8d8,0x009a9a9a,
+    0x00171717,0x001a1a1a,0x00353535,0x00cccccc,
+    0x00f7f7f7,0x00999999,0x00616161,0x005a5a5a,
+    0x00e8e8e8,0x00242424,0x00565656,0x00404040,
+    0x00e1e1e1,0x00636363,0x00090909,0x00333333,
+    0x00bfbfbf,0x00989898,0x00979797,0x00858585,
+    0x00686868,0x00fcfcfc,0x00ececec,0x000a0a0a,
+    0x00dadada,0x006f6f6f,0x00535353,0x00626262,
+    0x00a3a3a3,0x002e2e2e,0x00080808,0x00afafaf,
+    0x00282828,0x00b0b0b0,0x00747474,0x00c2c2c2,
+    0x00bdbdbd,0x00363636,0x00222222,0x00383838,
+    0x00646464,0x001e1e1e,0x00393939,0x002c2c2c,
+    0x00a6a6a6,0x00303030,0x00e5e5e5,0x00444444,
+    0x00fdfdfd,0x00888888,0x009f9f9f,0x00656565,
+    0x00878787,0x006b6b6b,0x00f4f4f4,0x00232323,
+    0x00484848,0x00101010,0x00d1d1d1,0x00515151,
+    0x00c0c0c0,0x00f9f9f9,0x00d2d2d2,0x00a0a0a0,
+    0x00555555,0x00a1a1a1,0x00414141,0x00fafafa,
+    0x00434343,0x00131313,0x00c4c4c4,0x002f2f2f,
+    0x00a8a8a8,0x00b6b6b6,0x003c3c3c,0x002b2b2b,
+    0x00c1c1c1,0x00ffffff,0x00c8c8c8,0x00a5a5a5,
+    0x00202020,0x00898989,0x00000000,0x00909090,
+    0x00474747,0x00efefef,0x00eaeaea,0x00b7b7b7,
+    0x00151515,0x00060606,0x00cdcdcd,0x00b5b5b5,
+    0x00121212,0x007e7e7e,0x00bbbbbb,0x00292929,
+    0x000f0f0f,0x00b8b8b8,0x00070707,0x00040404,
+    0x009b9b9b,0x00949494,0x00212121,0x00666666,
+    0x00e6e6e6,0x00cecece,0x00ededed,0x00e7e7e7,
+    0x003b3b3b,0x00fefefe,0x007f7f7f,0x00c5c5c5,
+    0x00a4a4a4,0x00373737,0x00b1b1b1,0x004c4c4c,
+    0x00919191,0x006e6e6e,0x008d8d8d,0x00767676,
+    0x00030303,0x002d2d2d,0x00dedede,0x00969696,
+    0x00262626,0x007d7d7d,0x00c6c6c6,0x005c5c5c,
+    0x00d3d3d3,0x00f2f2f2,0x004f4f4f,0x00191919,
+    0x003f3f3f,0x00dcdcdc,0x00797979,0x001d1d1d,
+    0x00525252,0x00ebebeb,0x00f3f3f3,0x006d6d6d,
+    0x005e5e5e,0x00fbfbfb,0x00696969,0x00b2b2b2,
+    0x00f0f0f0,0x00313131,0x000c0c0c,0x00d4d4d4,
+    0x00cfcfcf,0x008c8c8c,0x00e2e2e2,0x00757575,
+    0x00a9a9a9,0x004a4a4a,0x00575757,0x00848484,
+    0x00111111,0x00454545,0x001b1b1b,0x00f5f5f5,
+    0x00e4e4e4,0x000e0e0e,0x00737373,0x00aaaaaa,
+    0x00f1f1f1,0x00dddddd,0x00595959,0x00141414,
+    0x006c6c6c,0x00929292,0x00545454,0x00d0d0d0,
+    0x00787878,0x00707070,0x00e3e3e3,0x00494949,
+    0x00808080,0x00505050,0x00a7a7a7,0x00f6f6f6,
+    0x00777777,0x00939393,0x00868686,0x00838383,
+    0x002a2a2a,0x00c7c7c7,0x005b5b5b,0x00e9e9e9,
+    0x00eeeeee,0x008f8f8f,0x00010101,0x003d3d3d,
+};
+
+static const u32 camellia_sp3033[256] = {
+    0x38003838,0x41004141,0x16001616,0x76007676,
+    0xd900d9d9,0x93009393,0x60006060,0xf200f2f2,
+    0x72007272,0xc200c2c2,0xab00abab,0x9a009a9a,
+    0x75007575,0x06000606,0x57005757,0xa000a0a0,
+    0x91009191,0xf700f7f7,0xb500b5b5,0xc900c9c9,
+    0xa200a2a2,0x8c008c8c,0xd200d2d2,0x90009090,
+    0xf600f6f6,0x07000707,0xa700a7a7,0x27002727,
+    0x8e008e8e,0xb200b2b2,0x49004949,0xde00dede,
+    0x43004343,0x5c005c5c,0xd700d7d7,0xc700c7c7,
+    0x3e003e3e,0xf500f5f5,0x8f008f8f,0x67006767,
+    0x1f001f1f,0x18001818,0x6e006e6e,0xaf00afaf,
+    0x2f002f2f,0xe200e2e2,0x85008585,0x0d000d0d,
+    0x53005353,0xf000f0f0,0x9c009c9c,0x65006565,
+    0xea00eaea,0xa300a3a3,0xae00aeae,0x9e009e9e,
+    0xec00ecec,0x80008080,0x2d002d2d,0x6b006b6b,
+    0xa800a8a8,0x2b002b2b,0x36003636,0xa600a6a6,
+    0xc500c5c5,0x86008686,0x4d004d4d,0x33003333,
+    0xfd00fdfd,0x66006666,0x58005858,0x96009696,
+    0x3a003a3a,0x09000909,0x95009595,0x10001010,
+    0x78007878,0xd800d8d8,0x42004242,0xcc00cccc,
+    0xef00efef,0x26002626,0xe500e5e5,0x61006161,
+    0x1a001a1a,0x3f003f3f,0x3b003b3b,0x82008282,
+    0xb600b6b6,0xdb00dbdb,0xd400d4d4,0x98009898,
+    0xe800e8e8,0x8b008b8b,0x02000202,0xeb00ebeb,
+    0x0a000a0a,0x2c002c2c,0x1d001d1d,0xb000b0b0,
+    0x6f006f6f,0x8d008d8d,0x88008888,0x0e000e0e,
+    0x19001919,0x87008787,0x4e004e4e,0x0b000b0b,
+    0xa900a9a9,0x0c000c0c,0x79007979,0x11001111,
+    0x7f007f7f,0x22002222,0xe700e7e7,0x59005959,
+    0xe100e1e1,0xda00dada,0x3d003d3d,0xc800c8c8,
+    0x12001212,0x04000404,0x74007474,0x54005454,
+    0x30003030,0x7e007e7e,0xb400b4b4,0x28002828,
+    0x55005555,0x68006868,0x50005050,0xbe00bebe,
+    0xd000d0d0,0xc400c4c4,0x31003131,0xcb00cbcb,
+    0x2a002a2a,0xad00adad,0x0f000f0f,0xca00caca,
+    0x70007070,0xff00ffff,0x32003232,0x69006969,
+    0x08000808,0x62006262,0x00000000,0x24002424,
+    0xd100d1d1,0xfb00fbfb,0xba00baba,0xed00eded,
+    0x45004545,0x81008181,0x73007373,0x6d006d6d,
+    0x84008484,0x9f009f9f,0xee00eeee,0x4a004a4a,
+    0xc300c3c3,0x2e002e2e,0xc100c1c1,0x01000101,
+    0xe600e6e6,0x25002525,0x48004848,0x99009999,
+    0xb900b9b9,0xb300b3b3,0x7b007b7b,0xf900f9f9,
+    0xce00cece,0xbf00bfbf,0xdf00dfdf,0x71007171,
+    0x29002929,0xcd00cdcd,0x6c006c6c,0x13001313,
+    0x64006464,0x9b009b9b,0x63006363,0x9d009d9d,
+    0xc000c0c0,0x4b004b4b,0xb700b7b7,0xa500a5a5,
+    0x89008989,0x5f005f5f,0xb100b1b1,0x17001717,
+    0xf400f4f4,0xbc00bcbc,0xd300d3d3,0x46004646,
+    0xcf00cfcf,0x37003737,0x5e005e5e,0x47004747,
+    0x94009494,0xfa00fafa,0xfc00fcfc,0x5b005b5b,
+    0x97009797,0xfe00fefe,0x5a005a5a,0xac00acac,
+    0x3c003c3c,0x4c004c4c,0x03000303,0x35003535,
+    0xf300f3f3,0x23002323,0xb800b8b8,0x5d005d5d,
+    0x6a006a6a,0x92009292,0xd500d5d5,0x21002121,
+    0x44004444,0x51005151,0xc600c6c6,0x7d007d7d,
+    0x39003939,0x83008383,0xdc00dcdc,0xaa00aaaa,
+    0x7c007c7c,0x77007777,0x56005656,0x05000505,
+    0x1b001b1b,0xa400a4a4,0x15001515,0x34003434,
+    0x1e001e1e,0x1c001c1c,0xf800f8f8,0x52005252,
+    0x20002020,0x14001414,0xe900e9e9,0xbd00bdbd,
+    0xdd00dddd,0xe400e4e4,0xa100a1a1,0xe000e0e0,
+    0x8a008a8a,0xf100f1f1,0xd600d6d6,0x7a007a7a,
+    0xbb00bbbb,0xe300e3e3,0x40004040,0x4f004f4f,
+};
+
+static const u32 camellia_sp4404[256] = {
+    0x70700070,0x2c2c002c,0xb3b300b3,0xc0c000c0,
+    0xe4e400e4,0x57570057,0xeaea00ea,0xaeae00ae,
+    0x23230023,0x6b6b006b,0x45450045,0xa5a500a5,
+    0xeded00ed,0x4f4f004f,0x1d1d001d,0x92920092,
+    0x86860086,0xafaf00af,0x7c7c007c,0x1f1f001f,
+    0x3e3e003e,0xdcdc00dc,0x5e5e005e,0x0b0b000b,
+    0xa6a600a6,0x39390039,0xd5d500d5,0x5d5d005d,
+    0xd9d900d9,0x5a5a005a,0x51510051,0x6c6c006c,
+    0x8b8b008b,0x9a9a009a,0xfbfb00fb,0xb0b000b0,
+    0x74740074,0x2b2b002b,0xf0f000f0,0x84840084,
+    0xdfdf00df,0xcbcb00cb,0x34340034,0x76760076,
+    0x6d6d006d,0xa9a900a9,0xd1d100d1,0x04040004,
+    0x14140014,0x3a3a003a,0xdede00de,0x11110011,
+    0x32320032,0x9c9c009c,0x53530053,0xf2f200f2,
+    0xfefe00fe,0xcfcf00cf,0xc3c300c3,0x7a7a007a,
+    0x24240024,0xe8e800e8,0x60600060,0x69690069,
+    0xaaaa00aa,0xa0a000a0,0xa1a100a1,0x62620062,
+    0x54540054,0x1e1e001e,0xe0e000e0,0x64640064,
+    0x10100010,0x00000000,0xa3a300a3,0x75750075,
+    0x8a8a008a,0xe6e600e6,0x09090009,0xdddd00dd,
+    0x87870087,0x83830083,0xcdcd00cd,0x90900090,
+    0x73730073,0xf6f600f6,0x9d9d009d,0xbfbf00bf,
+    0x52520052,0xd8d800d8,0xc8c800c8,0xc6c600c6,
+    0x81810081,0x6f6f006f,0x13130013,0x63630063,
+    0xe9e900e9,0xa7a700a7,0x9f9f009f,0xbcbc00bc,
+    0x29290029,0xf9f900f9,0x2f2f002f,0xb4b400b4,
+    0x78780078,0x06060006,0xe7e700e7,0x71710071,
+    0xd4d400d4,0xabab00ab,0x88880088,0x8d8d008d,
+    0x72720072,0xb9b900b9,0xf8f800f8,0xacac00ac,
+    0x36360036,0x2a2a002a,0x3c3c003c,0xf1f100f1,
+    0x40400040,0xd3d300d3,0xbbbb00bb,0x43430043,
+    0x15150015,0xadad00ad,0x77770077,0x80800080,
+    0x82820082,0xecec00ec,0x27270027,0xe5e500e5,
+    0x85850085,0x35350035,0x0c0c000c,0x41410041,
+    0xefef00ef,0x93930093,0x19190019,0x21210021,
+    0x0e0e000e,0x4e4e004e,0x65650065,0xbdbd00bd,
+    0xb8b800b8,0x8f8f008f,0xebeb00eb,0xcece00ce,
+    0x30300030,0x5f5f005f,0xc5c500c5,0x1a1a001a,
+    0xe1e100e1,0xcaca00ca,0x47470047,0x3d3d003d,
+    0x01010001,0xd6d600d6,0x56560056,0x4d4d004d,
+    0x0d0d000d,0x66660066,0xcccc00cc,0x2d2d002d,
+    0x12120012,0x20200020,0xb1b100b1,0x99990099,
+    0x4c4c004c,0xc2c200c2,0x7e7e007e,0x05050005,
+    0xb7b700b7,0x31310031,0x17170017,0xd7d700d7,
+    0x58580058,0x61610061,0x1b1b001b,0x1c1c001c,
+    0x0f0f000f,0x16160016,0x18180018,0x22220022,
+    0x44440044,0xb2b200b2,0xb5b500b5,0x91910091,
+    0x08080008,0xa8a800a8,0xfcfc00fc,0x50500050,
+    0xd0d000d0,0x7d7d007d,0x89890089,0x97970097,
+    0x5b5b005b,0x95950095,0xffff00ff,0xd2d200d2,
+    0xc4c400c4,0x48480048,0xf7f700f7,0xdbdb00db,
+    0x03030003,0xdada00da,0x3f3f003f,0x94940094,
+    0x5c5c005c,0x02020002,0x4a4a004a,0x33330033,
+    0x67670067,0xf3f300f3,0x7f7f007f,0xe2e200e2,
+    0x9b9b009b,0x26260026,0x37370037,0x3b3b003b,
+    0x96960096,0x4b4b004b,0xbebe00be,0x2e2e002e,
+    0x79790079,0x8c8c008c,0x6e6e006e,0x8e8e008e,
+    0xf5f500f5,0xb6b600b6,0xfdfd00fd,0x59590059,
+    0x98980098,0x6a6a006a,0x46460046,0xbaba00ba,
+    0x25250025,0x42420042,0xa2a200a2,0xfafa00fa,
+    0x07070007,0x55550055,0xeeee00ee,0x0a0a000a,
+    0x49490049,0x68680068,0x38380038,0xa4a400a4,
+    0x28280028,0x7b7b007b,0xc9c900c9,0xc1c100c1,
+    0xe3e300e3,0xf4f400f4,0xc7c700c7,0x9e9e009e,
+};
+
+
+/**
+ * Stuff related to the Camellia key schedule
+ */
+#define subl(x) subL[(x)]
+#define subr(x) subR[(x)]
+
+static int camellia_setup128(const unsigned char *key, u32 *subkey)
+{
+    u32 kll, klr, krl, krr;
+    u32 il, ir, t0, t1, w0, w1;
+    u32 kw4l, kw4r, dw, tl, tr;
+
+#ifdef WOLFSSL_SMALL_STACK
+    u32* subL;
+    u32* subR;
+
+    subL = (u32*) XMALLOC(sizeof(u32) * 26, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (subL == NULL)
+        return MEMORY_E;
+
+    subR = (u32*) XMALLOC(sizeof(u32) * 26, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (subR == NULL) {
+        XFREE(subL, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#else
+    u32 subL[26];
+    u32 subR[26];
+#endif
+
+    /**
+     *  k == kll || klr || krl || krr (|| is concatination)
+     */
+    kll = GETU32(key     );
+    klr = GETU32(key +  4);
+    krl = GETU32(key +  8);
+    krr = GETU32(key + 12);
+    /**
+     * generate KL dependent subkeys
+     */
+    subl(0) = kll; subr(0) = klr;
+    subl(1) = krl; subr(1) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(4) = kll; subr(4) = klr;
+    subl(5) = krl; subr(5) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30);
+    subl(10) = kll; subr(10) = klr;
+    subl(11) = krl; subr(11) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(13) = krl; subr(13) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+    subl(16) = kll; subr(16) = klr;
+    subl(17) = krl; subr(17) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+    subl(18) = kll; subr(18) = klr;
+    subl(19) = krl; subr(19) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+    subl(22) = kll; subr(22) = klr;
+    subl(23) = krl; subr(23) = krr;
+
+    /* generate KA */
+    kll = subl(0); klr = subr(0);
+    krl = subl(1); krr = subr(1);
+    CAMELLIA_F(kll, klr,
+	       CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R,
+	       w0, w1, il, ir, t0, t1);
+    krl ^= w0; krr ^= w1;
+    CAMELLIA_F(krl, krr,
+	       CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R,
+	       kll, klr, il, ir, t0, t1);
+    CAMELLIA_F(kll, klr,
+	       CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R,
+	       krl, krr, il, ir, t0, t1);
+    krl ^= w0; krr ^= w1;
+    CAMELLIA_F(krl, krr,
+	       CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R,
+	       w0, w1, il, ir, t0, t1);
+    kll ^= w0; klr ^= w1;
+
+    /* generate KA dependent subkeys */
+    subl(2) = kll; subr(2) = klr;
+    subl(3) = krl; subr(3) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(6) = kll; subr(6) = klr;
+    subl(7) = krl; subr(7) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(8) = kll; subr(8) = klr;
+    subl(9) = krl; subr(9) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(12) = kll; subr(12) = klr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(14) = kll; subr(14) = klr;
+    subl(15) = krl; subr(15) = krr;
+    CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
+    subl(20) = kll; subr(20) = klr;
+    subl(21) = krl; subr(21) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+    subl(24) = kll; subr(24) = klr;
+    subl(25) = krl; subr(25) = krr;
+
+
+    /* absorb kw2 to other subkeys */
+    subl(3) ^= subl(1); subr(3) ^= subr(1);
+    subl(5) ^= subl(1); subr(5) ^= subr(1);
+    subl(7) ^= subl(1); subr(7) ^= subr(1);
+    subl(1) ^= subr(1) & ~subr(9);
+    dw = subl(1) & subl(9), subr(1) ^= CAMELLIA_RL1(dw);
+    subl(11) ^= subl(1); subr(11) ^= subr(1);
+    subl(13) ^= subl(1); subr(13) ^= subr(1);
+    subl(15) ^= subl(1); subr(15) ^= subr(1);
+    subl(1) ^= subr(1) & ~subr(17);
+    dw = subl(1) & subl(17), subr(1) ^= CAMELLIA_RL1(dw);
+    subl(19) ^= subl(1); subr(19) ^= subr(1);
+    subl(21) ^= subl(1); subr(21) ^= subr(1);
+    subl(23) ^= subl(1); subr(23) ^= subr(1);
+    subl(24) ^= subl(1); subr(24) ^= subr(1);
+
+    /* absorb kw4 to other subkeys */
+    kw4l = subl(25); kw4r = subr(25);
+    subl(22) ^= kw4l; subr(22) ^= kw4r;
+    subl(20) ^= kw4l; subr(20) ^= kw4r;
+    subl(18) ^= kw4l; subr(18) ^= kw4r;
+    kw4l ^= kw4r & ~subr(16);
+    dw = kw4l & subl(16), kw4r ^= CAMELLIA_RL1(dw);
+    subl(14) ^= kw4l; subr(14) ^= kw4r;
+    subl(12) ^= kw4l; subr(12) ^= kw4r;
+    subl(10) ^= kw4l; subr(10) ^= kw4r;
+    kw4l ^= kw4r & ~subr(8);
+    dw = kw4l & subl(8), kw4r ^= CAMELLIA_RL1(dw);
+    subl(6) ^= kw4l; subr(6) ^= kw4r;
+    subl(4) ^= kw4l; subr(4) ^= kw4r;
+    subl(2) ^= kw4l; subr(2) ^= kw4r;
+    subl(0) ^= kw4l; subr(0) ^= kw4r;
+
+    /* key XOR is end of F-function */
+    CamelliaSubkeyL(0) = subl(0) ^ subl(2);
+    CamelliaSubkeyR(0) = subr(0) ^ subr(2);
+    CamelliaSubkeyL(2) = subl(3);
+    CamelliaSubkeyR(2) = subr(3);
+    CamelliaSubkeyL(3) = subl(2) ^ subl(4);
+    CamelliaSubkeyR(3) = subr(2) ^ subr(4);
+    CamelliaSubkeyL(4) = subl(3) ^ subl(5);
+    CamelliaSubkeyR(4) = subr(3) ^ subr(5);
+    CamelliaSubkeyL(5) = subl(4) ^ subl(6);
+    CamelliaSubkeyR(5) = subr(4) ^ subr(6);
+    CamelliaSubkeyL(6) = subl(5) ^ subl(7);
+    CamelliaSubkeyR(6) = subr(5) ^ subr(7);
+    tl = subl(10) ^ (subr(10) & ~subr(8));
+    dw = tl & subl(8), tr = subr(10) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(7) = subl(6) ^ tl;
+    CamelliaSubkeyR(7) = subr(6) ^ tr;
+    CamelliaSubkeyL(8) = subl(8);
+    CamelliaSubkeyR(8) = subr(8);
+    CamelliaSubkeyL(9) = subl(9);
+    CamelliaSubkeyR(9) = subr(9);
+    tl = subl(7) ^ (subr(7) & ~subr(9));
+    dw = tl & subl(9), tr = subr(7) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(10) = tl ^ subl(11);
+    CamelliaSubkeyR(10) = tr ^ subr(11);
+    CamelliaSubkeyL(11) = subl(10) ^ subl(12);
+    CamelliaSubkeyR(11) = subr(10) ^ subr(12);
+    CamelliaSubkeyL(12) = subl(11) ^ subl(13);
+    CamelliaSubkeyR(12) = subr(11) ^ subr(13);
+    CamelliaSubkeyL(13) = subl(12) ^ subl(14);
+    CamelliaSubkeyR(13) = subr(12) ^ subr(14);
+    CamelliaSubkeyL(14) = subl(13) ^ subl(15);
+    CamelliaSubkeyR(14) = subr(13) ^ subr(15);
+    tl = subl(18) ^ (subr(18) & ~subr(16));
+    dw = tl & subl(16),	tr = subr(18) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(15) = subl(14) ^ tl;
+    CamelliaSubkeyR(15) = subr(14) ^ tr;
+    CamelliaSubkeyL(16) = subl(16);
+    CamelliaSubkeyR(16) = subr(16);
+    CamelliaSubkeyL(17) = subl(17);
+    CamelliaSubkeyR(17) = subr(17);
+    tl = subl(15) ^ (subr(15) & ~subr(17));
+    dw = tl & subl(17),	tr = subr(15) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(18) = tl ^ subl(19);
+    CamelliaSubkeyR(18) = tr ^ subr(19);
+    CamelliaSubkeyL(19) = subl(18) ^ subl(20);
+    CamelliaSubkeyR(19) = subr(18) ^ subr(20);
+    CamelliaSubkeyL(20) = subl(19) ^ subl(21);
+    CamelliaSubkeyR(20) = subr(19) ^ subr(21);
+    CamelliaSubkeyL(21) = subl(20) ^ subl(22);
+    CamelliaSubkeyR(21) = subr(20) ^ subr(22);
+    CamelliaSubkeyL(22) = subl(21) ^ subl(23);
+    CamelliaSubkeyR(22) = subr(21) ^ subr(23);
+    CamelliaSubkeyL(23) = subl(22);
+    CamelliaSubkeyR(23) = subr(22);
+    CamelliaSubkeyL(24) = subl(24) ^ subl(23);
+    CamelliaSubkeyR(24) = subr(24) ^ subr(23);
+
+    /* apply the inverse of the last half of P-function */
+    dw = CamelliaSubkeyL(2) ^ CamelliaSubkeyR(2), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(2) = CamelliaSubkeyL(2) ^ dw, CamelliaSubkeyL(2) = dw;
+    dw = CamelliaSubkeyL(3) ^ CamelliaSubkeyR(3), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(3) = CamelliaSubkeyL(3) ^ dw, CamelliaSubkeyL(3) = dw;
+    dw = CamelliaSubkeyL(4) ^ CamelliaSubkeyR(4), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(4) = CamelliaSubkeyL(4) ^ dw, CamelliaSubkeyL(4) = dw;
+    dw = CamelliaSubkeyL(5) ^ CamelliaSubkeyR(5), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(5) = CamelliaSubkeyL(5) ^ dw, CamelliaSubkeyL(5) = dw;
+    dw = CamelliaSubkeyL(6) ^ CamelliaSubkeyR(6), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(6) = CamelliaSubkeyL(6) ^ dw, CamelliaSubkeyL(6) = dw;
+    dw = CamelliaSubkeyL(7) ^ CamelliaSubkeyR(7), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(7) = CamelliaSubkeyL(7) ^ dw, CamelliaSubkeyL(7) = dw;
+    dw = CamelliaSubkeyL(10) ^ CamelliaSubkeyR(10), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(10) = CamelliaSubkeyL(10) ^ dw, CamelliaSubkeyL(10) = dw;
+    dw = CamelliaSubkeyL(11) ^ CamelliaSubkeyR(11), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(11) = CamelliaSubkeyL(11) ^ dw, CamelliaSubkeyL(11) = dw;
+    dw = CamelliaSubkeyL(12) ^ CamelliaSubkeyR(12), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(12) = CamelliaSubkeyL(12) ^ dw, CamelliaSubkeyL(12) = dw;
+    dw = CamelliaSubkeyL(13) ^ CamelliaSubkeyR(13), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(13) = CamelliaSubkeyL(13) ^ dw, CamelliaSubkeyL(13) = dw;
+    dw = CamelliaSubkeyL(14) ^ CamelliaSubkeyR(14), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(14) = CamelliaSubkeyL(14) ^ dw, CamelliaSubkeyL(14) = dw;
+    dw = CamelliaSubkeyL(15) ^ CamelliaSubkeyR(15), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(15) = CamelliaSubkeyL(15) ^ dw, CamelliaSubkeyL(15) = dw;
+    dw = CamelliaSubkeyL(18) ^ CamelliaSubkeyR(18), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(18) = CamelliaSubkeyL(18) ^ dw, CamelliaSubkeyL(18) = dw;
+    dw = CamelliaSubkeyL(19) ^ CamelliaSubkeyR(19), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(19) = CamelliaSubkeyL(19) ^ dw, CamelliaSubkeyL(19) = dw;
+    dw = CamelliaSubkeyL(20) ^ CamelliaSubkeyR(20), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(20) = CamelliaSubkeyL(20) ^ dw, CamelliaSubkeyL(20) = dw;
+    dw = CamelliaSubkeyL(21) ^ CamelliaSubkeyR(21), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(21) = CamelliaSubkeyL(21) ^ dw, CamelliaSubkeyL(21) = dw;
+    dw = CamelliaSubkeyL(22) ^ CamelliaSubkeyR(22), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(22) = CamelliaSubkeyL(22) ^ dw, CamelliaSubkeyL(22) = dw;
+    dw = CamelliaSubkeyL(23) ^ CamelliaSubkeyR(23), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(23) = CamelliaSubkeyL(23) ^ dw, CamelliaSubkeyL(23) = dw;
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(subL, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(subR, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return 0;
+}
+
+static int camellia_setup256(const unsigned char *key, u32 *subkey)
+{
+    u32 kll,klr,krl,krr;           /* left half of key */
+    u32 krll,krlr,krrl,krrr;       /* right half of key */
+    u32 il, ir, t0, t1, w0, w1;    /* temporary variables */
+    u32 kw4l, kw4r, dw, tl, tr;
+
+#ifdef WOLFSSL_SMALL_STACK
+    u32* subL;
+    u32* subR;
+
+    subL = (u32*) XMALLOC(sizeof(u32) * 34, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (subL == NULL)
+        return MEMORY_E;
+
+    subR = (u32*) XMALLOC(sizeof(u32) * 34, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (subR == NULL) {
+        XFREE(subL, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#else
+    u32 subL[34];
+    u32 subR[34];
+#endif
+
+    /**
+     *  key = (kll || klr || krl || krr || krll || krlr || krrl || krrr)
+     *  (|| is concatination)
+     */
+
+    kll  = GETU32(key     );
+    klr  = GETU32(key +  4);
+    krl  = GETU32(key +  8);
+    krr  = GETU32(key + 12);
+    krll = GETU32(key + 16);
+    krlr = GETU32(key + 20);
+    krrl = GETU32(key + 24);
+    krrr = GETU32(key + 28);
+
+    /* generate KL dependent subkeys */
+    subl(0) = kll; subr(0) = klr;
+    subl(1) = krl; subr(1) = krr;
+    CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 45);
+    subl(12) = kll; subr(12) = klr;
+    subl(13) = krl; subr(13) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(16) = kll; subr(16) = klr;
+    subl(17) = krl; subr(17) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+    subl(22) = kll; subr(22) = klr;
+    subl(23) = krl; subr(23) = krr;
+    CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
+    subl(30) = kll; subr(30) = klr;
+    subl(31) = krl; subr(31) = krr;
+
+    /* generate KR dependent subkeys */
+    CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
+    subl(4) = krll; subr(4) = krlr;
+    subl(5) = krrl; subr(5) = krrr;
+    CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
+    subl(8) = krll; subr(8) = krlr;
+    subl(9) = krrl; subr(9) = krrr;
+    CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+    subl(18) = krll; subr(18) = krlr;
+    subl(19) = krrl; subr(19) = krrr;
+    CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
+    subl(26) = krll; subr(26) = krlr;
+    subl(27) = krrl; subr(27) = krrr;
+    CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
+
+    /* generate KA */
+    kll = subl(0) ^ krll; klr = subr(0) ^ krlr;
+    krl = subl(1) ^ krrl; krr = subr(1) ^ krrr;
+    CAMELLIA_F(kll, klr,
+	       CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R,
+	       w0, w1, il, ir, t0, t1);
+    krl ^= w0; krr ^= w1;
+    CAMELLIA_F(krl, krr,
+	       CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R,
+	       kll, klr, il, ir, t0, t1);
+    kll ^= krll; klr ^= krlr;
+    CAMELLIA_F(kll, klr,
+	       CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R,
+	       krl, krr, il, ir, t0, t1);
+    krl ^= w0 ^ krrl; krr ^= w1 ^ krrr;
+    CAMELLIA_F(krl, krr,
+	       CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R,
+	       w0, w1, il, ir, t0, t1);
+    kll ^= w0; klr ^= w1;
+
+    /* generate KB */
+    krll ^= kll; krlr ^= klr;
+    krrl ^= krl; krrr ^= krr;
+    CAMELLIA_F(krll, krlr,
+	       CAMELLIA_SIGMA5L, CAMELLIA_SIGMA5R,
+	       w0, w1, il, ir, t0, t1);
+    krrl ^= w0; krrr ^= w1;
+    CAMELLIA_F(krrl, krrr,
+	       CAMELLIA_SIGMA6L, CAMELLIA_SIGMA6R,
+	       w0, w1, il, ir, t0, t1);
+    krll ^= w0; krlr ^= w1;
+
+    /* generate KA dependent subkeys */
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+    subl(6) = kll; subr(6) = klr;
+    subl(7) = krl; subr(7) = krr;
+    CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30);
+    subl(14) = kll; subr(14) = klr;
+    subl(15) = krl; subr(15) = krr;
+    subl(24) = klr; subr(24) = krl;
+    subl(25) = krr; subr(25) = kll;
+    CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 49);
+    subl(28) = kll; subr(28) = klr;
+    subl(29) = krl; subr(29) = krr;
+
+    /* generate KB dependent subkeys */
+    subl(2) = krll; subr(2) = krlr;
+    subl(3) = krrl; subr(3) = krrr;
+    CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+    subl(10) = krll; subr(10) = krlr;
+    subl(11) = krrl; subr(11) = krrr;
+    CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+    subl(20) = krll; subr(20) = krlr;
+    subl(21) = krrl; subr(21) = krrr;
+    CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 51);
+    subl(32) = krll; subr(32) = krlr;
+    subl(33) = krrl; subr(33) = krrr;
+
+    /* absorb kw2 to other subkeys */
+    subl(3) ^= subl(1); subr(3) ^= subr(1);
+    subl(5) ^= subl(1); subr(5) ^= subr(1);
+    subl(7) ^= subl(1); subr(7) ^= subr(1);
+    subl(1) ^= subr(1) & ~subr(9);
+    dw = subl(1) & subl(9), subr(1) ^= CAMELLIA_RL1(dw);
+    subl(11) ^= subl(1); subr(11) ^= subr(1);
+    subl(13) ^= subl(1); subr(13) ^= subr(1);
+    subl(15) ^= subl(1); subr(15) ^= subr(1);
+    subl(1) ^= subr(1) & ~subr(17);
+    dw = subl(1) & subl(17), subr(1) ^= CAMELLIA_RL1(dw);
+    subl(19) ^= subl(1); subr(19) ^= subr(1);
+    subl(21) ^= subl(1); subr(21) ^= subr(1);
+    subl(23) ^= subl(1); subr(23) ^= subr(1);
+    subl(1) ^= subr(1) & ~subr(25);
+    dw = subl(1) & subl(25), subr(1) ^= CAMELLIA_RL1(dw);
+    subl(27) ^= subl(1); subr(27) ^= subr(1);
+    subl(29) ^= subl(1); subr(29) ^= subr(1);
+    subl(31) ^= subl(1); subr(31) ^= subr(1);
+    subl(32) ^= subl(1); subr(32) ^= subr(1);
+
+    /* absorb kw4 to other subkeys */
+    kw4l = subl(33); kw4r = subr(33);
+    subl(30) ^= kw4l; subr(30) ^= kw4r;
+    subl(28) ^= kw4l; subr(28) ^= kw4r;
+    subl(26) ^= kw4l; subr(26) ^= kw4r;
+    kw4l ^= kw4r & ~subr(24);
+    dw = kw4l & subl(24), kw4r ^= CAMELLIA_RL1(dw);
+    subl(22) ^= kw4l; subr(22) ^= kw4r;
+    subl(20) ^= kw4l; subr(20) ^= kw4r;
+    subl(18) ^= kw4l; subr(18) ^= kw4r;
+    kw4l ^= kw4r & ~subr(16);
+    dw = kw4l & subl(16), kw4r ^= CAMELLIA_RL1(dw);
+    subl(14) ^= kw4l; subr(14) ^= kw4r;
+    subl(12) ^= kw4l; subr(12) ^= kw4r;
+    subl(10) ^= kw4l; subr(10) ^= kw4r;
+    kw4l ^= kw4r & ~subr(8);
+    dw = kw4l & subl(8), kw4r ^= CAMELLIA_RL1(dw);
+    subl(6) ^= kw4l; subr(6) ^= kw4r;
+    subl(4) ^= kw4l; subr(4) ^= kw4r;
+    subl(2) ^= kw4l; subr(2) ^= kw4r;
+    subl(0) ^= kw4l; subr(0) ^= kw4r;
+
+    /* key XOR is end of F-function */
+    CamelliaSubkeyL(0) = subl(0) ^ subl(2);
+    CamelliaSubkeyR(0) = subr(0) ^ subr(2);
+    CamelliaSubkeyL(2) = subl(3);
+    CamelliaSubkeyR(2) = subr(3);
+    CamelliaSubkeyL(3) = subl(2) ^ subl(4);
+    CamelliaSubkeyR(3) = subr(2) ^ subr(4);
+    CamelliaSubkeyL(4) = subl(3) ^ subl(5);
+    CamelliaSubkeyR(4) = subr(3) ^ subr(5);
+    CamelliaSubkeyL(5) = subl(4) ^ subl(6);
+    CamelliaSubkeyR(5) = subr(4) ^ subr(6);
+    CamelliaSubkeyL(6) = subl(5) ^ subl(7);
+    CamelliaSubkeyR(6) = subr(5) ^ subr(7);
+    tl = subl(10) ^ (subr(10) & ~subr(8));
+    dw = tl & subl(8), tr = subr(10) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(7) = subl(6) ^ tl;
+    CamelliaSubkeyR(7) = subr(6) ^ tr;
+    CamelliaSubkeyL(8) = subl(8);
+    CamelliaSubkeyR(8) = subr(8);
+    CamelliaSubkeyL(9) = subl(9);
+    CamelliaSubkeyR(9) = subr(9);
+    tl = subl(7) ^ (subr(7) & ~subr(9));
+    dw = tl & subl(9), tr = subr(7) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(10) = tl ^ subl(11);
+    CamelliaSubkeyR(10) = tr ^ subr(11);
+    CamelliaSubkeyL(11) = subl(10) ^ subl(12);
+    CamelliaSubkeyR(11) = subr(10) ^ subr(12);
+    CamelliaSubkeyL(12) = subl(11) ^ subl(13);
+    CamelliaSubkeyR(12) = subr(11) ^ subr(13);
+    CamelliaSubkeyL(13) = subl(12) ^ subl(14);
+    CamelliaSubkeyR(13) = subr(12) ^ subr(14);
+    CamelliaSubkeyL(14) = subl(13) ^ subl(15);
+    CamelliaSubkeyR(14) = subr(13) ^ subr(15);
+    tl = subl(18) ^ (subr(18) & ~subr(16));
+    dw = tl & subl(16), tr = subr(18) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(15) = subl(14) ^ tl;
+    CamelliaSubkeyR(15) = subr(14) ^ tr;
+    CamelliaSubkeyL(16) = subl(16);
+    CamelliaSubkeyR(16) = subr(16);
+    CamelliaSubkeyL(17) = subl(17);
+    CamelliaSubkeyR(17) = subr(17);
+    tl = subl(15) ^ (subr(15) & ~subr(17));
+    dw = tl & subl(17), tr = subr(15) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(18) = tl ^ subl(19);
+    CamelliaSubkeyR(18) = tr ^ subr(19);
+    CamelliaSubkeyL(19) = subl(18) ^ subl(20);
+    CamelliaSubkeyR(19) = subr(18) ^ subr(20);
+    CamelliaSubkeyL(20) = subl(19) ^ subl(21);
+    CamelliaSubkeyR(20) = subr(19) ^ subr(21);
+    CamelliaSubkeyL(21) = subl(20) ^ subl(22);
+    CamelliaSubkeyR(21) = subr(20) ^ subr(22);
+    CamelliaSubkeyL(22) = subl(21) ^ subl(23);
+    CamelliaSubkeyR(22) = subr(21) ^ subr(23);
+    tl = subl(26) ^ (subr(26) & ~subr(24));
+    dw = tl & subl(24), tr = subr(26) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(23) = subl(22) ^ tl;
+    CamelliaSubkeyR(23) = subr(22) ^ tr;
+    CamelliaSubkeyL(24) = subl(24);
+    CamelliaSubkeyR(24) = subr(24);
+    CamelliaSubkeyL(25) = subl(25);
+    CamelliaSubkeyR(25) = subr(25);
+    tl = subl(23) ^ (subr(23) &  ~subr(25));
+    dw = tl & subl(25), tr = subr(23) ^ CAMELLIA_RL1(dw);
+    CamelliaSubkeyL(26) = tl ^ subl(27);
+    CamelliaSubkeyR(26) = tr ^ subr(27);
+    CamelliaSubkeyL(27) = subl(26) ^ subl(28);
+    CamelliaSubkeyR(27) = subr(26) ^ subr(28);
+    CamelliaSubkeyL(28) = subl(27) ^ subl(29);
+    CamelliaSubkeyR(28) = subr(27) ^ subr(29);
+    CamelliaSubkeyL(29) = subl(28) ^ subl(30);
+    CamelliaSubkeyR(29) = subr(28) ^ subr(30);
+    CamelliaSubkeyL(30) = subl(29) ^ subl(31);
+    CamelliaSubkeyR(30) = subr(29) ^ subr(31);
+    CamelliaSubkeyL(31) = subl(30);
+    CamelliaSubkeyR(31) = subr(30);
+    CamelliaSubkeyL(32) = subl(32) ^ subl(31);
+    CamelliaSubkeyR(32) = subr(32) ^ subr(31);
+
+    /* apply the inverse of the last half of P-function */
+    dw = CamelliaSubkeyL(2) ^ CamelliaSubkeyR(2), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(2) = CamelliaSubkeyL(2) ^ dw, CamelliaSubkeyL(2) = dw;
+    dw = CamelliaSubkeyL(3) ^ CamelliaSubkeyR(3), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(3) = CamelliaSubkeyL(3) ^ dw, CamelliaSubkeyL(3) = dw;
+    dw = CamelliaSubkeyL(4) ^ CamelliaSubkeyR(4), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(4) = CamelliaSubkeyL(4) ^ dw, CamelliaSubkeyL(4) = dw;
+    dw = CamelliaSubkeyL(5) ^ CamelliaSubkeyR(5), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(5) = CamelliaSubkeyL(5) ^ dw, CamelliaSubkeyL(5) = dw;
+    dw = CamelliaSubkeyL(6) ^ CamelliaSubkeyR(6), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(6) = CamelliaSubkeyL(6) ^ dw, CamelliaSubkeyL(6) = dw;
+    dw = CamelliaSubkeyL(7) ^ CamelliaSubkeyR(7), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(7) = CamelliaSubkeyL(7) ^ dw, CamelliaSubkeyL(7) = dw;
+    dw = CamelliaSubkeyL(10) ^ CamelliaSubkeyR(10), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(10) = CamelliaSubkeyL(10) ^ dw, CamelliaSubkeyL(10) = dw;
+    dw = CamelliaSubkeyL(11) ^ CamelliaSubkeyR(11), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(11) = CamelliaSubkeyL(11) ^ dw, CamelliaSubkeyL(11) = dw;
+    dw = CamelliaSubkeyL(12) ^ CamelliaSubkeyR(12), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(12) = CamelliaSubkeyL(12) ^ dw, CamelliaSubkeyL(12) = dw;
+    dw = CamelliaSubkeyL(13) ^ CamelliaSubkeyR(13), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(13) = CamelliaSubkeyL(13) ^ dw, CamelliaSubkeyL(13) = dw;
+    dw = CamelliaSubkeyL(14) ^ CamelliaSubkeyR(14), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(14) = CamelliaSubkeyL(14) ^ dw, CamelliaSubkeyL(14) = dw;
+    dw = CamelliaSubkeyL(15) ^ CamelliaSubkeyR(15), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(15) = CamelliaSubkeyL(15) ^ dw, CamelliaSubkeyL(15) = dw;
+    dw = CamelliaSubkeyL(18) ^ CamelliaSubkeyR(18), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(18) = CamelliaSubkeyL(18) ^ dw, CamelliaSubkeyL(18) = dw;
+    dw = CamelliaSubkeyL(19) ^ CamelliaSubkeyR(19), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(19) = CamelliaSubkeyL(19) ^ dw, CamelliaSubkeyL(19) = dw;
+    dw = CamelliaSubkeyL(20) ^ CamelliaSubkeyR(20), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(20) = CamelliaSubkeyL(20) ^ dw, CamelliaSubkeyL(20) = dw;
+    dw = CamelliaSubkeyL(21) ^ CamelliaSubkeyR(21), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(21) = CamelliaSubkeyL(21) ^ dw, CamelliaSubkeyL(21) = dw;
+    dw = CamelliaSubkeyL(22) ^ CamelliaSubkeyR(22), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(22) = CamelliaSubkeyL(22) ^ dw, CamelliaSubkeyL(22) = dw;
+    dw = CamelliaSubkeyL(23) ^ CamelliaSubkeyR(23), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(23) = CamelliaSubkeyL(23) ^ dw, CamelliaSubkeyL(23) = dw;
+    dw = CamelliaSubkeyL(26) ^ CamelliaSubkeyR(26), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(26) = CamelliaSubkeyL(26) ^ dw, CamelliaSubkeyL(26) = dw;
+    dw = CamelliaSubkeyL(27) ^ CamelliaSubkeyR(27), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(27) = CamelliaSubkeyL(27) ^ dw, CamelliaSubkeyL(27) = dw;
+    dw = CamelliaSubkeyL(28) ^ CamelliaSubkeyR(28), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(28) = CamelliaSubkeyL(28) ^ dw, CamelliaSubkeyL(28) = dw;
+    dw = CamelliaSubkeyL(29) ^ CamelliaSubkeyR(29), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(29) = CamelliaSubkeyL(29) ^ dw, CamelliaSubkeyL(29) = dw;
+    dw = CamelliaSubkeyL(30) ^ CamelliaSubkeyR(30), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(30) = CamelliaSubkeyL(30) ^ dw, CamelliaSubkeyL(30) = dw;
+    dw = CamelliaSubkeyL(31) ^ CamelliaSubkeyR(31), dw = CAMELLIA_RL8(dw);
+    CamelliaSubkeyR(31) = CamelliaSubkeyL(31) ^ dw,CamelliaSubkeyL(31) = dw;
+    
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(subL, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(subR, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return 0;
+}
+
+static int camellia_setup192(const unsigned char *key, u32 *subkey)
+{
+    unsigned char kk[32];
+    u32 krll, krlr, krrl,krrr;
+
+    memcpy(kk, key, 24);
+    memcpy((unsigned char *)&krll, key+16,4);
+    memcpy((unsigned char *)&krlr, key+20,4);
+    krrl = ~krll;
+    krrr = ~krlr;
+    memcpy(kk+24, (unsigned char *)&krrl, 4);
+    memcpy(kk+28, (unsigned char *)&krrr, 4);
+
+    return camellia_setup256(kk, subkey);
+}
+
+
+/**
+ * Stuff related to camellia encryption/decryption
+ *
+ * "io" must be 4byte aligned and big-endian data.
+ */
+static void camellia_encrypt128(const u32 *subkey, u32 *io)
+{
+    u32 il, ir, t0, t1;
+
+    /* pre whitening but absorb kw2*/
+    io[0] ^= CamelliaSubkeyL(0);
+    io[1] ^= CamelliaSubkeyR(0);
+    /* main iteration */
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(2),CamelliaSubkeyR(2),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(3),CamelliaSubkeyR(3),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(4),CamelliaSubkeyR(4),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(5),CamelliaSubkeyR(5),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(6),CamelliaSubkeyR(6),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(7),CamelliaSubkeyR(7),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(8),CamelliaSubkeyR(8),
+		 CamelliaSubkeyL(9),CamelliaSubkeyR(9),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(10),CamelliaSubkeyR(10),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(11),CamelliaSubkeyR(11),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(12),CamelliaSubkeyR(12),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(13),CamelliaSubkeyR(13),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(14),CamelliaSubkeyR(14),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(15),CamelliaSubkeyR(15),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(16),CamelliaSubkeyR(16),
+		 CamelliaSubkeyL(17),CamelliaSubkeyR(17),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(18),CamelliaSubkeyR(18),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(19),CamelliaSubkeyR(19),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(20),CamelliaSubkeyR(20),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(21),CamelliaSubkeyR(21),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(22),CamelliaSubkeyR(22),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(23),CamelliaSubkeyR(23),
+		     io[0],io[1],il,ir,t0,t1);
+
+    /* post whitening but kw4 */
+    io[2] ^= CamelliaSubkeyL(24);
+    io[3] ^= CamelliaSubkeyR(24);
+
+    t0 = io[0];
+    t1 = io[1];
+    io[0] = io[2];
+    io[1] = io[3];
+    io[2] = t0;
+    io[3] = t1;
+	
+    return;
+}
+
+static void camellia_decrypt128(const u32 *subkey, u32 *io)
+{
+    u32 il,ir,t0,t1;               /* temporary valiables */
+    
+    /* pre whitening but absorb kw2*/
+    io[0] ^= CamelliaSubkeyL(24);
+    io[1] ^= CamelliaSubkeyR(24);
+
+    /* main iteration */
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(23),CamelliaSubkeyR(23),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(22),CamelliaSubkeyR(22),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(21),CamelliaSubkeyR(21),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(20),CamelliaSubkeyR(20),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(19),CamelliaSubkeyR(19),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(18),CamelliaSubkeyR(18),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(17),CamelliaSubkeyR(17),
+		 CamelliaSubkeyL(16),CamelliaSubkeyR(16),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(15),CamelliaSubkeyR(15),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(14),CamelliaSubkeyR(14),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(13),CamelliaSubkeyR(13),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(12),CamelliaSubkeyR(12),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(11),CamelliaSubkeyR(11),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(10),CamelliaSubkeyR(10),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(9),CamelliaSubkeyR(9),
+		 CamelliaSubkeyL(8),CamelliaSubkeyR(8),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(7),CamelliaSubkeyR(7),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(6),CamelliaSubkeyR(6),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(5),CamelliaSubkeyR(5),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(4),CamelliaSubkeyR(4),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(3),CamelliaSubkeyR(3),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(2),CamelliaSubkeyR(2),
+		     io[0],io[1],il,ir,t0,t1);
+
+    /* post whitening but kw4 */
+    io[2] ^= CamelliaSubkeyL(0);
+    io[3] ^= CamelliaSubkeyR(0);
+
+    t0 = io[0];
+    t1 = io[1];
+    io[0] = io[2];
+    io[1] = io[3];
+    io[2] = t0;
+    io[3] = t1;
+
+    return;
+}
+
+/**
+ * stuff for 192 and 256bit encryption/decryption
+ */
+static void camellia_encrypt256(const u32 *subkey, u32 *io)
+{
+    u32 il,ir,t0,t1;           /* temporary valiables */
+
+    /* pre whitening but absorb kw2*/
+    io[0] ^= CamelliaSubkeyL(0);
+    io[1] ^= CamelliaSubkeyR(0);
+
+    /* main iteration */
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(2),CamelliaSubkeyR(2),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(3),CamelliaSubkeyR(3),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(4),CamelliaSubkeyR(4),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(5),CamelliaSubkeyR(5),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(6),CamelliaSubkeyR(6),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(7),CamelliaSubkeyR(7),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(8),CamelliaSubkeyR(8),
+		 CamelliaSubkeyL(9),CamelliaSubkeyR(9),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(10),CamelliaSubkeyR(10),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(11),CamelliaSubkeyR(11),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(12),CamelliaSubkeyR(12),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(13),CamelliaSubkeyR(13),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(14),CamelliaSubkeyR(14),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(15),CamelliaSubkeyR(15),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(16),CamelliaSubkeyR(16),
+		 CamelliaSubkeyL(17),CamelliaSubkeyR(17),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(18),CamelliaSubkeyR(18),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(19),CamelliaSubkeyR(19),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(20),CamelliaSubkeyR(20),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(21),CamelliaSubkeyR(21),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(22),CamelliaSubkeyR(22),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(23),CamelliaSubkeyR(23),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(24),CamelliaSubkeyR(24),
+		 CamelliaSubkeyL(25),CamelliaSubkeyR(25),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(26),CamelliaSubkeyR(26),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(27),CamelliaSubkeyR(27),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(28),CamelliaSubkeyR(28),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(29),CamelliaSubkeyR(29),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(30),CamelliaSubkeyR(30),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(31),CamelliaSubkeyR(31),
+		     io[0],io[1],il,ir,t0,t1);
+
+    /* post whitening but kw4 */
+    io[2] ^= CamelliaSubkeyL(32);
+    io[3] ^= CamelliaSubkeyR(32);
+
+    t0 = io[0];
+    t1 = io[1];
+    io[0] = io[2];
+    io[1] = io[3];
+    io[2] = t0;
+    io[3] = t1;
+
+    return;
+}
+
+static void camellia_decrypt256(const u32 *subkey, u32 *io)
+{
+    u32 il,ir,t0,t1;           /* temporary valiables */
+
+    /* pre whitening but absorb kw2*/
+    io[0] ^= CamelliaSubkeyL(32);
+    io[1] ^= CamelliaSubkeyR(32);
+	
+    /* main iteration */
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(31),CamelliaSubkeyR(31),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(30),CamelliaSubkeyR(30),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(29),CamelliaSubkeyR(29),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(28),CamelliaSubkeyR(28),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(27),CamelliaSubkeyR(27),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(26),CamelliaSubkeyR(26),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(25),CamelliaSubkeyR(25),
+		 CamelliaSubkeyL(24),CamelliaSubkeyR(24),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(23),CamelliaSubkeyR(23),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(22),CamelliaSubkeyR(22),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(21),CamelliaSubkeyR(21),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(20),CamelliaSubkeyR(20),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(19),CamelliaSubkeyR(19),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(18),CamelliaSubkeyR(18),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(17),CamelliaSubkeyR(17),
+		 CamelliaSubkeyL(16),CamelliaSubkeyR(16),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(15),CamelliaSubkeyR(15),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(14),CamelliaSubkeyR(14),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(13),CamelliaSubkeyR(13),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(12),CamelliaSubkeyR(12),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(11),CamelliaSubkeyR(11),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(10),CamelliaSubkeyR(10),
+		     io[0],io[1],il,ir,t0,t1);
+
+    CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		 CamelliaSubkeyL(9),CamelliaSubkeyR(9),
+		 CamelliaSubkeyL(8),CamelliaSubkeyR(8),
+		 t0,t1,il,ir);
+
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(7),CamelliaSubkeyR(7),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(6),CamelliaSubkeyR(6),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(5),CamelliaSubkeyR(5),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(4),CamelliaSubkeyR(4),
+		     io[0],io[1],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[0],io[1],
+		     CamelliaSubkeyL(3),CamelliaSubkeyR(3),
+		     io[2],io[3],il,ir,t0,t1);
+    CAMELLIA_ROUNDSM(io[2],io[3],
+		     CamelliaSubkeyL(2),CamelliaSubkeyR(2),
+		     io[0],io[1],il,ir,t0,t1);
+
+    /* post whitening but kw4 */
+    io[2] ^= CamelliaSubkeyL(0);
+    io[3] ^= CamelliaSubkeyR(0);
+
+    t0 = io[0];
+    t1 = io[1];
+    io[0] = io[2];
+    io[1] = io[3];
+    io[2] = t0;
+    io[3] = t1;
+
+    return;
+}
+
+/***
+ *
+ * API for compatibility
+ */
+
+static void Camellia_EncryptBlock(const int keyBitLength, 
+			   const unsigned char *plaintext, 
+			   const KEY_TABLE_TYPE keyTable, 
+			   unsigned char *ciphertext)
+{
+    u32 tmp[4];
+
+    tmp[0] = GETU32(plaintext);
+    tmp[1] = GETU32(plaintext + 4);
+    tmp[2] = GETU32(plaintext + 8);
+    tmp[3] = GETU32(plaintext + 12);
+
+    switch (keyBitLength) {
+    case 128:
+	camellia_encrypt128(keyTable, tmp);
+	break;
+    case 192:
+	/* fall through */
+    case 256:
+	camellia_encrypt256(keyTable, tmp);
+	break;
+    default:
+	break;
+    }
+
+    PUTU32(ciphertext, tmp[0]);
+    PUTU32(ciphertext + 4, tmp[1]);
+    PUTU32(ciphertext + 8, tmp[2]);
+    PUTU32(ciphertext + 12, tmp[3]);
+}
+
+static void Camellia_DecryptBlock(const int keyBitLength, 
+			   const unsigned char *ciphertext, 
+			   const KEY_TABLE_TYPE keyTable, 
+			   unsigned char *plaintext)
+{
+    u32 tmp[4];
+
+    tmp[0] = GETU32(ciphertext);
+    tmp[1] = GETU32(ciphertext + 4);
+    tmp[2] = GETU32(ciphertext + 8);
+    tmp[3] = GETU32(ciphertext + 12);
+
+    switch (keyBitLength) {
+    case 128:
+	camellia_decrypt128(keyTable, tmp);
+	break;
+    case 192:
+	/* fall through */
+    case 256:
+	camellia_decrypt256(keyTable, tmp);
+	break;
+    default:
+	break;
+    }
+    PUTU32(plaintext, tmp[0]);
+    PUTU32(plaintext + 4, tmp[1]);
+    PUTU32(plaintext + 8, tmp[2]);
+    PUTU32(plaintext + 12, tmp[3]);
+}
+
+
+
+/* wolfCrypt wrappers to the Camellia code */
+
+int wc_CamelliaSetKey(Camellia* cam, const byte* key, word32 len, const byte* iv)
+{
+    int ret = 0;
+
+    if (cam == NULL) return BAD_FUNC_ARG;
+
+    XMEMSET(cam->key, 0, sizeof(KEY_TABLE_TYPE));
+
+    switch (len) {
+        case 16:
+        	ret = camellia_setup128(key, cam->key);
+            break;
+        case 24:
+        	ret = camellia_setup192(key, cam->key);
+            break;
+        case 32:
+            ret = camellia_setup256(key, cam->key);
+            break;
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    if (ret != 0)
+        return ret;
+
+    cam->keySz = len * 8;
+
+    return wc_CamelliaSetIV(cam, iv);
+}
+
+
+int wc_CamelliaSetIV(Camellia* cam, const byte* iv)
+{
+    if (cam == NULL)
+        return BAD_FUNC_ARG;
+
+    if (iv)
+        XMEMCPY(cam->reg, iv, CAMELLIA_BLOCK_SIZE);
+    else
+        XMEMSET(cam->reg,  0, CAMELLIA_BLOCK_SIZE);
+
+    return 0;
+}
+
+
+void wc_CamelliaEncryptDirect(Camellia* cam, byte* out, const byte* in)
+{
+    Camellia_EncryptBlock(cam->keySz, in, cam->key, out);
+}
+
+
+void wc_CamelliaDecryptDirect(Camellia* cam, byte* out, const byte* in)
+{
+    Camellia_DecryptBlock(cam->keySz, in, cam->key, out);
+}
+
+
+void wc_CamelliaCbcEncrypt(Camellia* cam, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / CAMELLIA_BLOCK_SIZE;
+
+    while (blocks--) {
+        xorbuf((byte*)cam->reg, in, CAMELLIA_BLOCK_SIZE);
+        Camellia_EncryptBlock(cam->keySz, (byte*)cam->reg,
+                                                     cam->key, (byte*)cam->reg);
+        XMEMCPY(out, cam->reg, CAMELLIA_BLOCK_SIZE);
+
+        out += CAMELLIA_BLOCK_SIZE;
+        in  += CAMELLIA_BLOCK_SIZE;
+    }
+}
+
+
+void wc_CamelliaCbcDecrypt(Camellia* cam, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / CAMELLIA_BLOCK_SIZE;
+
+    while (blocks--) {
+        XMEMCPY(cam->tmp, in, CAMELLIA_BLOCK_SIZE);
+        Camellia_DecryptBlock(cam->keySz, (byte*)cam->tmp, cam->key, out);
+        xorbuf(out, (byte*)cam->reg, CAMELLIA_BLOCK_SIZE);
+        XMEMCPY(cam->reg, cam->tmp, CAMELLIA_BLOCK_SIZE);
+
+        out += CAMELLIA_BLOCK_SIZE;
+        in  += CAMELLIA_BLOCK_SIZE;
+    }
+}
+
+
+#endif /* HAVE_CAMELLIA */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/chacha.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,252 @@
+/* chacha.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ *
+ *  based from
+ *  chacha-ref.c version 20080118
+ *  D. J. Bernstein
+ *  Public domain.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_CHACHA
+
+#include <wolfssl/wolfcrypt/chacha.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/logging.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+#ifdef CHACHA_AEAD_TEST
+    #include <stdio.h>
+#endif
+
+#ifdef BIG_ENDIAN_ORDER
+    #define LITTLE32(x) ByteReverseWord32(x)
+#else
+    #define LITTLE32(x) (x)
+#endif
+
+/* Number of rounds */
+#define ROUNDS  20
+
+#define U32C(v) (v##U)
+#define U32V(v) ((word32)(v) & U32C(0xFFFFFFFF))
+#define U8TO32_LITTLE(p) LITTLE32(((word32*)(p))[0])
+
+#define ROTATE(v,c) rotlFixed(v, c)
+#define XOR(v,w)    ((v) ^ (w))
+#define PLUS(v,w)   (U32V((v) + (w)))
+#define PLUSONE(v)  (PLUS((v),1))
+
+#define QUARTERROUND(a,b,c,d) \
+  x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
+  x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \
+  x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
+  x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);
+
+
+/**
+  * Set up iv(nonce). Earlier versions used 64 bits instead of 96, this version
+  * uses the typical AEAD 96 bit nonce and can do record sizes of 256 GB.
+  */
+int wc_Chacha_SetIV(ChaCha* ctx, const byte* inIv, word32 counter)
+{
+    word32 temp[3];       /* used for alignment of memory */
+
+#ifdef CHACHA_AEAD_TEST
+    word32 i;
+    printf("NONCE : ");
+    for (i = 0; i < 12; i++) {
+        printf("%02x", inIv[i]);
+    }
+    printf("\n\n");
+#endif
+
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    XMEMCPY(temp, inIv, 12);
+
+    ctx->X[12] = LITTLE32(counter); /* block counter */
+    ctx->X[13] = LITTLE32(temp[0]); /* fixed variable from nonce */
+    ctx->X[14] = LITTLE32(temp[1]); /* counter from nonce */
+    ctx->X[15] = LITTLE32(temp[2]); /* counter from nonce */
+
+    return 0;
+}
+
+/* "expand 32-byte k" as unsigned 32 byte */
+static const word32 sigma[4] = {0x61707865, 0x3320646e, 0x79622d32, 0x6b206574};
+/* "expand 16-byte k" as unsigned 16 byte */
+static const word32 tau[4] = {0x61707865, 0x3120646e, 0x79622d36, 0x6b206574};
+
+/**
+  * Key setup. 8 word iv (nonce)
+  */
+int wc_Chacha_SetKey(ChaCha* ctx, const byte* key, word32 keySz)
+{
+    const word32* constants;
+    const byte*   k;
+
+#ifdef XSTREAM_ALIGN
+    word32 alignKey[8];
+#endif
+
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    if (keySz != 16 && keySz != 32)
+        return BAD_FUNC_ARG;
+
+#ifdef XSTREAM_ALIGN
+    if ((wolfssl_word)key % 4) {
+        WOLFSSL_MSG("wc_ChachaSetKey unaligned key");
+        XMEMCPY(alignKey, key, keySz);
+        k = (byte*)alignKey;
+    }
+    else {
+        k = key;
+    }
+#else
+    k = key;
+#endif /* XSTREAM_ALIGN */
+
+#ifdef CHACHA_AEAD_TEST
+    word32 i;
+    printf("ChaCha key used :\n");
+    for (i = 0; i < keySz; i++) {
+        printf("%02x", key[i]);
+        if ((i + 1) % 8 == 0)
+           printf("\n");
+    }
+    printf("\n\n");
+#endif
+
+    ctx->X[4] = U8TO32_LITTLE(k +  0);
+    ctx->X[5] = U8TO32_LITTLE(k +  4);
+    ctx->X[6] = U8TO32_LITTLE(k +  8);
+    ctx->X[7] = U8TO32_LITTLE(k + 12);
+    if (keySz == 32) {
+        k += 16;
+        constants = sigma;
+    }
+    else {
+        constants = tau;
+    }
+    ctx->X[ 8] = U8TO32_LITTLE(k +  0);
+    ctx->X[ 9] = U8TO32_LITTLE(k +  4);
+    ctx->X[10] = U8TO32_LITTLE(k +  8);
+    ctx->X[11] = U8TO32_LITTLE(k + 12);
+    ctx->X[ 0] = constants[0];
+    ctx->X[ 1] = constants[1];
+    ctx->X[ 2] = constants[2];
+    ctx->X[ 3] = constants[3];
+
+    return 0;
+}
+
+/**
+  * Converts word into bytes with rotations having been done.
+  */
+static INLINE void wc_Chacha_wordtobyte(word32 output[16], const word32 input[16])
+{
+    word32 x[16];
+    word32 i;
+
+    for (i = 0; i < 16; i++) {
+        x[i] = input[i];
+    }
+
+    for (i = (ROUNDS); i > 0; i -= 2) {
+        QUARTERROUND(0, 4,  8, 12)
+        QUARTERROUND(1, 5,  9, 13)
+        QUARTERROUND(2, 6, 10, 14)
+        QUARTERROUND(3, 7, 11, 15)
+        QUARTERROUND(0, 5, 10, 15)
+        QUARTERROUND(1, 6, 11, 12)
+        QUARTERROUND(2, 7,  8, 13)
+        QUARTERROUND(3, 4,  9, 14)
+    }
+
+    for (i = 0; i < 16; i++) {
+        x[i] = PLUS(x[i], input[i]);
+    }
+
+    for (i = 0; i < 16; i++) {
+        output[i] = LITTLE32(x[i]);
+    }
+}
+
+/**
+  * Encrypt a stream of bytes
+  */
+static void wc_Chacha_encrypt_bytes(ChaCha* ctx, const byte* m, byte* c,
+                                 word32 bytes)
+{
+    byte*  output;
+    word32 temp[16]; /* used to make sure aligned */
+    word32 i;
+
+    output = (byte*)temp;
+
+    if (!bytes) return;
+    for (;;) {
+        wc_Chacha_wordtobyte(temp, ctx->X);
+        ctx->X[12] = PLUSONE(ctx->X[12]);
+        if (bytes <= 64) {
+            for (i = 0; i < bytes; ++i) {
+                c[i] = m[i] ^ output[i];
+            }
+            return;
+        }
+        for (i = 0; i < 64; ++i) {
+            c[i] = m[i] ^ output[i];
+        }
+        bytes -= 64;
+        c += 64;
+        m += 64;
+    }
+}
+
+/**
+  * API to encrypt/decrypt a message of any size.
+  */
+int wc_Chacha_Process(ChaCha* ctx, byte* output, const byte* input, word32 msglen)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    wc_Chacha_encrypt_bytes(ctx, input, output, msglen);
+
+    return 0;
+}
+
+#endif /* HAVE_CHACHA*/
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/chacha20_poly1305.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,275 @@
+/* chacha.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
+
+#include <wolfssl/wolfcrypt/chacha20_poly1305.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/logging.h>
+#include <wolfssl/wolfcrypt/chacha.h>
+#include <wolfssl/wolfcrypt/poly1305.h>
+
+#ifdef NO_INLINE
+#include <wolfssl/wolfcrypt/misc.h>
+#else
+#include <wolfcrypt/src/misc.c>
+#endif
+
+#ifdef CHACHA_AEAD_TEST
+#include <stdio.h>
+#endif
+
+#define CHACHA20_POLY1305_AEAD_INITIAL_COUNTER  0
+#define CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT 16
+
+static void word32ToLittle64(const word32 inLittle32, byte outLittle64[8]);
+static int calculateAuthTag(
+                  const byte inAuthKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
+                  const byte* inAAD, const word32 inAADLen,
+                  const byte *inCiphertext, const word32 inCiphertextLen,
+                  byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]);
+
+int wc_ChaCha20Poly1305_Encrypt(
+                const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
+                const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE],
+                const byte* inAAD, const word32 inAADLen,
+                const byte* inPlaintext, const word32 inPlaintextLen,
+                byte* outCiphertext,
+                byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE])
+{
+    int err;
+    byte poly1305Key[CHACHA20_POLY1305_AEAD_KEYSIZE];
+    ChaCha chaChaCtx;
+
+    /* Validate function arguments */
+
+    if (!inKey || !inIV ||
+        !inPlaintext || !inPlaintextLen ||
+        !outCiphertext ||
+        !outAuthTag)
+    {
+        return BAD_FUNC_ARG;
+    }
+
+    XMEMSET(poly1305Key, 0, sizeof(poly1305Key));
+
+    /* Create the Poly1305 key */
+    err = wc_Chacha_SetKey(&chaChaCtx, inKey, CHACHA20_POLY1305_AEAD_KEYSIZE);
+    if (err != 0) return err;
+
+    err = wc_Chacha_SetIV(&chaChaCtx, inIV,
+                           CHACHA20_POLY1305_AEAD_INITIAL_COUNTER);
+    if (err != 0) return err;
+
+    err = wc_Chacha_Process(&chaChaCtx, poly1305Key, poly1305Key,
+                             CHACHA20_POLY1305_AEAD_KEYSIZE);
+    if (err != 0) return err;
+
+    /* Encrypt the plaintext using ChaCha20 */
+    err = wc_Chacha_Process(&chaChaCtx, outCiphertext, inPlaintext,
+                            inPlaintextLen);
+    /* Calculate the Poly1305 auth tag */
+    if (err == 0)
+        err = calculateAuthTag(poly1305Key,
+                               inAAD, inAADLen,
+                               outCiphertext, inPlaintextLen,
+                               outAuthTag);
+    ForceZero(poly1305Key, sizeof(poly1305Key));
+
+    return err;
+}
+
+
+int wc_ChaCha20Poly1305_Decrypt(
+                const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
+                const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE],
+                const byte* inAAD, const word32 inAADLen,
+                const byte* inCiphertext, const word32 inCiphertextLen,
+                const byte inAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE],
+                byte* outPlaintext)
+{
+    int err;
+    byte poly1305Key[CHACHA20_POLY1305_AEAD_KEYSIZE];
+    ChaCha chaChaCtx;
+    byte calculatedAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
+
+    /* Validate function arguments */
+
+    if (!inKey || !inIV ||
+        !inCiphertext || !inCiphertextLen ||
+        !inAuthTag ||
+        !outPlaintext)
+    {
+        return BAD_FUNC_ARG;
+    }
+
+    XMEMSET(calculatedAuthTag, 0, sizeof(calculatedAuthTag));
+    XMEMSET(poly1305Key, 0, sizeof(poly1305Key));
+
+    /* Create the Poly1305 key */
+    err = wc_Chacha_SetKey(&chaChaCtx, inKey, CHACHA20_POLY1305_AEAD_KEYSIZE);
+    if (err != 0) return err;
+
+    err = wc_Chacha_SetIV(&chaChaCtx, inIV,
+                           CHACHA20_POLY1305_AEAD_INITIAL_COUNTER);
+    if (err != 0) return err;
+
+    err = wc_Chacha_Process(&chaChaCtx, poly1305Key, poly1305Key,
+                             CHACHA20_POLY1305_AEAD_KEYSIZE);
+    if (err != 0) return err;
+
+    /* Calculate the Poly1305 auth tag */
+    err = calculateAuthTag(poly1305Key,
+                           inAAD, inAADLen,
+                           inCiphertext, inCiphertextLen,
+                           calculatedAuthTag);
+
+    /* Compare the calculated auth tag with the received one */
+    if (err == 0 && ConstantCompare(inAuthTag, calculatedAuthTag,
+                                    CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) != 0)
+    {
+        err = MAC_CMP_FAILED_E;
+    }
+
+    /* Decrypt the received ciphertext */
+    if (err == 0)
+        err = wc_Chacha_Process(&chaChaCtx, outPlaintext, inCiphertext,
+                                inCiphertextLen);
+    ForceZero(poly1305Key, sizeof(poly1305Key));
+
+    return err;
+}
+
+
+static int calculateAuthTag(
+                const byte inAuthKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
+                const byte *inAAD, const word32 inAADLen,
+                const byte *inCiphertext, const word32 inCiphertextLen,
+                 byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE])
+{
+    int err;
+    Poly1305 poly1305Ctx;
+    byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1];
+    word32 paddingLen;
+    byte little64[8];
+
+    XMEMSET(padding, 0, sizeof(padding));
+
+    /* Initialize Poly1305 */
+
+    err = wc_Poly1305SetKey(&poly1305Ctx, inAuthKey,
+                            CHACHA20_POLY1305_AEAD_KEYSIZE);
+    if (err)
+    {
+        return err;
+    }
+
+    /* Create the authTag by MAC'ing the following items: */
+
+    /* -- AAD */
+
+    if (inAAD && inAADLen)
+    {
+        err = wc_Poly1305Update(&poly1305Ctx, inAAD, inAADLen);
+
+        /* -- padding1: pad the AAD to 16 bytes */
+
+        paddingLen = -inAADLen & (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1);
+        if (paddingLen)
+        {
+            err += wc_Poly1305Update(&poly1305Ctx, padding, paddingLen);
+        }
+
+        if (err)
+        {
+            return err;
+        }
+    }
+
+    /* -- Ciphertext */
+
+    err = wc_Poly1305Update(&poly1305Ctx, inCiphertext, inCiphertextLen);
+    if (err)
+    {
+        return err;
+    }
+
+    /* -- padding2: pad the ciphertext to 16 bytes */
+
+    paddingLen = -inCiphertextLen &
+                                  (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1);
+    if (paddingLen)
+    {
+        err = wc_Poly1305Update(&poly1305Ctx, padding, paddingLen);
+        if (err)
+        {
+            return err;
+        }
+    }
+
+    /* -- AAD length as a 64-bit little endian integer */
+
+    word32ToLittle64(inAADLen, little64);
+
+    err = wc_Poly1305Update(&poly1305Ctx, little64, sizeof(little64));
+    if (err)
+    {
+        return err;
+    }
+
+    /* -- Ciphertext length as a 64-bit little endian integer */
+
+    word32ToLittle64(inCiphertextLen, little64);
+
+    err = wc_Poly1305Update(&poly1305Ctx, little64, sizeof(little64));
+    if (err)
+    {
+        return err;
+    }
+
+    /* Finalize the auth tag */
+
+    err = wc_Poly1305Final(&poly1305Ctx, outAuthTag);
+
+    return err;
+}
+
+
+static void word32ToLittle64(const word32 inLittle32, byte outLittle64[8])
+{
+    XMEMSET(outLittle64, 0, 8);
+
+    outLittle64[0] = (inLittle32 & 0x000000FF);
+    outLittle64[1] = (inLittle32 & 0x0000FF00) >> 8;
+    outLittle64[2] = (inLittle32 & 0x00FF0000) >> 16;
+    outLittle64[3] = (inLittle32 & 0xFF000000) >> 24;
+}
+
+
+#endif /* HAVE_CHACHA && HAVE_POLY1305 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/coding.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,400 @@
+/* coding.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifndef NO_CODING
+
+#include <wolfssl/wolfcrypt/coding.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/logging.h>
+
+
+enum {
+    BAD         = 0xFF,  /* invalid encoding */
+    PAD         = '=',
+    PEM_LINE_SZ = 64
+};
+
+
+static
+const byte base64Decode[] = { 62, BAD, BAD, BAD, 63,   /* + starts at 0x2B */
+                              52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+                              BAD, BAD, BAD, BAD, BAD, BAD, BAD,
+                              0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+                              10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+                              20, 21, 22, 23, 24, 25,
+                              BAD, BAD, BAD, BAD, BAD, BAD,
+                              26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+                              36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+                              46, 47, 48, 49, 50, 51
+                            };
+
+
+int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
+{
+    word32 i = 0;
+    word32 j = 0;
+    word32 plainSz = inLen - ((inLen + (PEM_LINE_SZ - 1)) / PEM_LINE_SZ );
+    const byte maxIdx = (byte)sizeof(base64Decode) + 0x2B - 1;
+
+    plainSz = (plainSz * 3 + 3) / 4;
+    if (plainSz > *outLen) return BAD_FUNC_ARG;
+
+    while (inLen > 3) {
+        byte b1, b2, b3;
+        byte e1 = in[j++];
+        byte e2 = in[j++];
+        byte e3 = in[j++];
+        byte e4 = in[j++];
+
+        int pad3 = 0;
+        int pad4 = 0;
+
+        if (e1 == 0)            /* end file 0's */
+            break;
+        if (e3 == PAD)
+            pad3 = 1;
+        if (e4 == PAD)
+            pad4 = 1;
+
+        if (e1 < 0x2B || e2 < 0x2B || e3 < 0x2B || e4 < 0x2B) {
+            WOLFSSL_MSG("Bad Base64 Decode data, too small");
+            return ASN_INPUT_E;
+        }
+
+        if (e1 > maxIdx || e2 > maxIdx || e3 > maxIdx || e4 > maxIdx) {
+            WOLFSSL_MSG("Bad Base64 Decode data, too big");
+            return ASN_INPUT_E;
+        }
+
+        e1 = base64Decode[e1 - 0x2B];
+        e2 = base64Decode[e2 - 0x2B];
+        e3 = (e3 == PAD) ? 0 : base64Decode[e3 - 0x2B];
+        e4 = (e4 == PAD) ? 0 : base64Decode[e4 - 0x2B];
+
+        b1 = (byte)((e1 << 2) | (e2 >> 4));
+        b2 = (byte)(((e2 & 0xF) << 4) | (e3 >> 2));
+        b3 = (byte)(((e3 & 0x3) << 6) | e4);
+
+        out[i++] = b1;
+        if (!pad3)
+            out[i++] = b2;
+        if (!pad4)
+            out[i++] = b3;
+        else
+            break;
+
+        inLen -= 4;
+        if (inLen && (in[j] == ' ' || in[j] == '\r' || in[j] == '\n')) {
+            byte endLine = in[j++];
+            inLen--;
+            while (inLen && endLine == ' ') {   /* allow trailing whitespace */
+                endLine = in[j++];
+                inLen--;
+            }
+            if (endLine == '\r') {
+                if (inLen) {
+                    endLine = in[j++];
+                    inLen--;
+                }
+            }
+            if (endLine != '\n') {
+                WOLFSSL_MSG("Bad end of line in Base64 Decode");
+                return ASN_INPUT_E;
+            }
+        }
+    }
+    *outLen = i;
+
+    return 0;
+}
+
+
+#if defined(WOLFSSL_BASE64_ENCODE)
+
+static
+const byte base64Encode[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+                              'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+                              'U', 'V', 'W', 'X', 'Y', 'Z',
+                              'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
+                              'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+                              'u', 'v', 'w', 'x', 'y', 'z',
+                              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+                              '+', '/'
+                            };
+
+
+/* make sure *i (idx) won't exceed max, store and possibly escape to out,
+ * raw means use e w/o decode,  0 on success */
+static int CEscape(int escaped, byte e, byte* out, word32* i, word32 max,
+                  int raw)
+{
+    int    doEscape = 0;
+    word32 needed = 1;
+    word32 idx = *i;
+
+    byte basic;
+    byte plus    = 0;
+    byte equals  = 0;
+    byte newline = 0;
+
+    if (raw)
+        basic = e;
+    else
+        basic = base64Encode[e];
+
+    /* check whether to escape */
+    if (escaped) {
+        switch ((char)basic) {
+            case '+' :
+                plus     = 1;
+                doEscape = 1;
+                needed  += 2;
+                break;
+            case '=' :
+                equals   = 1;
+                doEscape = 1;
+                needed  += 2;
+                break;
+            case '\n' :
+                newline  = 1;
+                doEscape = 1;
+                needed  += 2;
+                break;
+            default:
+                /* do nothing */
+                break;
+        }
+    }
+
+    /* check size */
+    if ( (idx+needed) > max) {
+        WOLFSSL_MSG("Escape buffer max too small");
+        return BUFFER_E;
+    }
+
+    /* store it */
+    if (doEscape == 0) {
+        out[idx++] = basic;
+    }
+    else {
+        out[idx++] = '%';  /* start escape */
+
+        if (plus) {
+            out[idx++] = '2';
+            out[idx++] = 'B';
+        }
+        else if (equals) {
+            out[idx++] = '3';
+            out[idx++] = 'D';
+        }
+        else if (newline) {
+            out[idx++] = '0';
+            out[idx++] = 'A';
+        }
+
+    }
+    *i = idx;
+
+    return 0;
+}
+
+
+/* internal worker, handles both escaped and normal line endings */
+static int DoBase64_Encode(const byte* in, word32 inLen, byte* out,
+                           word32* outLen, int escaped)
+{
+    int    ret = 0;
+    word32 i = 0,
+           j = 0,
+           n = 0;   /* new line counter */
+
+    word32 outSz = (inLen + 3 - 1) / 3 * 4;
+    word32 addSz = (outSz + PEM_LINE_SZ - 1) / PEM_LINE_SZ;  /* new lines */
+
+    if (escaped)
+        addSz *= 3;   /* instead of just \n, we're doing %0A triplet */
+
+    outSz += addSz;
+
+    /* if escaped we can't predetermine size for one pass encoding, but
+     * make sure we have enough if no escapes are in input */
+    if (outSz > *outLen) return BAD_FUNC_ARG;
+    
+    while (inLen > 2) {
+        byte b1 = in[j++];
+        byte b2 = in[j++];
+        byte b3 = in[j++];
+
+        /* encoded idx */
+        byte e1 = b1 >> 2;
+        byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
+        byte e3 = (byte)(((b2 & 0xF) << 2) | (b3 >> 6));
+        byte e4 = b3 & 0x3F;
+
+        /* store */
+        ret = CEscape(escaped, e1, out, &i, *outLen, 0);
+        if (ret != 0) break;
+        ret = CEscape(escaped, e2, out, &i, *outLen, 0);
+        if (ret != 0) break;
+        ret = CEscape(escaped, e3, out, &i, *outLen, 0);
+        if (ret != 0) break;
+        ret = CEscape(escaped, e4, out, &i, *outLen, 0);
+        if (ret != 0) break;
+
+        inLen -= 3;
+
+        if ((++n % (PEM_LINE_SZ / 4)) == 0 && inLen) {
+            ret = CEscape(escaped, '\n', out, &i, *outLen, 1);
+            if (ret != 0) break;
+        }
+    }
+
+    /* last integral */
+    if (inLen && ret == 0) {
+        int twoBytes = (inLen == 2);
+
+        byte b1 = in[j++];
+        byte b2 = (twoBytes) ? in[j++] : 0;
+
+        byte e1 = b1 >> 2;
+        byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
+        byte e3 = (byte)((b2 & 0xF) << 2);
+
+        ret = CEscape(escaped, e1, out, &i, *outLen, 0);
+        if (ret == 0) 
+            ret = CEscape(escaped, e2, out, &i, *outLen, 0);
+        if (ret == 0) {
+            /* third */
+            if (twoBytes)
+                ret = CEscape(escaped, e3, out, &i, *outLen, 0);
+            else 
+                ret = CEscape(escaped, '=', out, &i, *outLen, 1);
+        }
+        /* fourth always pad */
+        if (ret == 0)
+            ret = CEscape(escaped, '=', out, &i, *outLen, 1);
+    } 
+
+    if (ret == 0) 
+        ret = CEscape(escaped, '\n', out, &i, *outLen, 1);
+
+    if (i != outSz && escaped == 0 && ret == 0)
+        return ASN_INPUT_E; 
+
+    *outLen = i;
+    return ret; 
+}
+
+
+/* Base64 Encode, PEM style, with \n line endings */
+int Base64_Encode(const byte* in, word32 inLen, byte* out, word32* outLen)
+{
+    return DoBase64_Encode(in, inLen, out, outLen, 0);
+}
+
+
+/* Base64 Encode, with %0A esacped line endings instead of \n */
+int Base64_EncodeEsc(const byte* in, word32 inLen, byte* out, word32* outLen)
+{
+    return DoBase64_Encode(in, inLen, out, outLen, 1);
+}
+
+
+#endif  /* defined(WOLFSSL_BASE64_ENCODE) */
+
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || defined(HAVE_FIPS)
+
+static
+const byte hexDecode[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+                           BAD, BAD, BAD, BAD, BAD, BAD, BAD,
+                           10, 11, 12, 13, 14, 15,  /* upper case A-F */
+                           BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
+                           BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
+                           BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
+                           BAD, BAD,  /* G - ` */
+                           10, 11, 12, 13, 14, 15   /* lower case a-f */
+                         };  /* A starts at 0x41 not 0x3A */
+
+int Base16_Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
+{
+    word32 inIdx  = 0;
+    word32 outIdx = 0;
+
+    if (inLen == 1 && *outLen && in) {
+        byte b = in[inIdx++] - 0x30;  /* 0 starts at 0x30 */
+
+        /* sanity check */
+        if (b >=  sizeof(hexDecode)/sizeof(hexDecode[0]))
+            return ASN_INPUT_E;
+
+        b  = hexDecode[b];
+
+        if (b == BAD)
+            return ASN_INPUT_E;
+        
+        out[outIdx++] = b;
+
+        *outLen = outIdx;
+        return 0;
+    }
+
+    if (inLen % 2)
+        return BAD_FUNC_ARG;
+
+    if (*outLen < (inLen / 2))
+        return BAD_FUNC_ARG;
+
+    while (inLen) {
+        byte b  = in[inIdx++] - 0x30;  /* 0 starts at 0x30 */
+        byte b2 = in[inIdx++] - 0x30;
+
+        /* sanity checks */
+        if (b >=  sizeof(hexDecode)/sizeof(hexDecode[0]))
+            return ASN_INPUT_E;
+        if (b2 >= sizeof(hexDecode)/sizeof(hexDecode[0]))
+            return ASN_INPUT_E;
+
+        b  = hexDecode[b];
+        b2 = hexDecode[b2];
+
+        if (b == BAD || b2 == BAD)
+            return ASN_INPUT_E;
+        
+        out[outIdx++] = (byte)((b << 4) | b2);
+        inLen -= 2;
+    }
+
+    *outLen = outIdx;
+    return 0;
+}
+
+
+#endif /* (OPENSSL_EXTRA) || (HAVE_WEBSERVER) || (HAVE_FIPS) */
+
+#endif /* NO_CODING */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/compress.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,170 @@
+/* compress.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ wc_*
+ * 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-1301, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_LIBZ
+
+
+#include <wolfssl/wolfcrypt/compress.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/logging.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+#include <zlib.h>
+
+
+/* alloc user allocs to work with zlib */
+static void* myAlloc(void* opaque, unsigned int item, unsigned int size)
+{
+    (void)opaque;
+    return XMALLOC(item * size, opaque, DYNAMIC_TYPE_LIBZ);
+}
+
+
+static void myFree(void* opaque, void* memory)
+{
+    (void)opaque;
+    XFREE(memory, opaque, DYNAMIC_TYPE_LIBZ);
+}
+
+
+#ifdef HAVE_MCAPI
+    #define DEFLATE_DEFAULT_WINDOWBITS  11
+    #define DEFLATE_DEFAULT_MEMLEVEL     1
+#else
+    #define DEFLATE_DEFAULT_WINDOWBITS 15
+    #define DEFLATE_DEFAULT_MEMLEVEL    8
+#endif
+
+
+int wc_Compress(byte* out, word32 outSz, const byte* in, word32 inSz, word32 flags)
+/*
+ * out - pointer to destination buffer
+ * outSz - size of destination buffer
+ * in - pointer to source buffer to compress
+ * inSz - size of source to compress
+ * flags - flags to control how compress operates 
+ *
+ * return:
+ *    negative - error code
+ *    positive - bytes stored in out buffer
+ * 
+ * Note, the output buffer still needs to be larger than the input buffer.
+ * The right chunk of data won't compress at all, and the lookup table will
+ * add to the size of the output. The libz code says the compressed
+ * buffer should be srcSz + 0.1% + 12.
+ */
+{
+    z_stream stream;
+    int result = 0;
+
+    stream.next_in = (Bytef*)in;
+    stream.avail_in = (uInt)inSz;
+#ifdef MAXSEG_64K
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != inSz) return COMPRESS_INIT_E;
+#endif
+    stream.next_out = out;
+    stream.avail_out = (uInt)outSz;
+    if ((uLong)stream.avail_out != outSz) return COMPRESS_INIT_E;
+
+    stream.zalloc = (alloc_func)myAlloc;
+    stream.zfree = (free_func)myFree;
+    stream.opaque = (voidpf)0;
+
+    if (deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
+                     DEFLATE_DEFAULT_WINDOWBITS, DEFLATE_DEFAULT_MEMLEVEL,
+                     flags ? Z_FIXED : Z_DEFAULT_STRATEGY) != Z_OK)
+        return COMPRESS_INIT_E;
+
+    if (deflate(&stream, Z_FINISH) != Z_STREAM_END) {
+        deflateEnd(&stream);
+        return COMPRESS_E;
+    }
+
+    result = (int)stream.total_out;
+
+    if (deflateEnd(&stream) != Z_OK)
+        result = COMPRESS_E;
+
+    return result;
+}
+
+
+int wc_DeCompress(byte* out, word32 outSz, const byte* in, word32 inSz)
+/*
+ * out - pointer to destination buffer
+ * outSz - size of destination buffer
+ * in - pointer to source buffer to compress
+ * inSz - size of source to compress
+ * flags - flags to control how compress operates 
+ *
+ * return:
+ *    negative - error code
+ *    positive - bytes stored in out buffer
+ */ 
+{
+    z_stream stream;
+    int result = 0;
+
+    stream.next_in = (Bytef*)in;
+    stream.avail_in = (uInt)inSz;
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != inSz) return DECOMPRESS_INIT_E;
+
+    stream.next_out = out;
+    stream.avail_out = (uInt)outSz;
+    if ((uLong)stream.avail_out != outSz) return DECOMPRESS_INIT_E;
+
+    stream.zalloc = (alloc_func)myAlloc;
+    stream.zfree = (free_func)myFree;
+    stream.opaque = (voidpf)0;
+
+    if (inflateInit2(&stream, DEFLATE_DEFAULT_WINDOWBITS) != Z_OK)
+        return DECOMPRESS_INIT_E;
+
+    if (inflate(&stream, Z_FINISH) != Z_STREAM_END) {
+        inflateEnd(&stream);
+        return DECOMPRESS_E;
+    }
+    
+    result = (int)stream.total_out;
+
+    if (inflateEnd(&stream) != Z_OK)
+        result = DECOMPRESS_E;
+
+    return result;
+}
+
+
+#endif /* HAVE_LIBZ */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/curve25519.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,261 @@
+/* curve25519.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+ /* Based On Daniel J Bernstein's curve25519 Public Domain ref10 work. */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_CURVE25519
+
+#include <wolfssl/wolfcrypt/curve25519.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+const curve25519_set_type curve25519_sets[] = {
+{
+        32,
+        "CURVE25519",
+}
+};
+
+
+
+int wc_curve25519_make_key(RNG* rng, int keysize, curve25519_key* key)
+{
+  unsigned char basepoint[CURVE25519_KEYSIZE] = {9};
+  unsigned char n[CURVE25519_KEYSIZE];
+  unsigned char p[CURVE25519_KEYSIZE];
+  int  i;
+  int  ret;
+
+  if (key == NULL || rng == NULL)
+      return ECC_BAD_ARG_E;
+
+  /* currently only a key size of 32 bytes is used */
+  if (keysize != CURVE25519_KEYSIZE)
+      return ECC_BAD_ARG_E;
+
+  /* get random number from RNG */
+  ret = wc_RNG_GenerateBlock(rng, n, keysize);
+  if (ret != 0)
+      return ret;
+
+  for (i = 0; i < keysize; ++i) key->k.point[i] = n[i];
+  key->k.point[ 0] &= 248;
+  key->k.point[31] &= 127;
+  key->k.point[31] |= 64;
+
+  /* compute public key */
+  ret = curve25519(p, key->k.point, basepoint);
+
+  /* store keys in big endian format */
+  for (i = 0; i < keysize; ++i) n[i] = key->k.point[i];
+  for (i = 0; i < keysize; ++i) {
+      key->p.point[keysize - i - 1] = p[i];
+      key->k.point[keysize - i - 1] = n[i];
+  }
+
+  ForceZero(n, keysize);
+  ForceZero(p, keysize);
+
+  return ret;
+}
+
+
+int wc_curve25519_shared_secret(curve25519_key* private_key,
+                                curve25519_key* public_key,
+                                byte* out, word32* outlen)
+{
+    unsigned char k[CURVE25519_KEYSIZE];
+    unsigned char p[CURVE25519_KEYSIZE];
+    unsigned char o[CURVE25519_KEYSIZE];
+    int ret = 0;
+    int i;
+
+    /* sanity check */
+    if (private_key == NULL || public_key == NULL || out == NULL ||
+            outlen == NULL)
+        return BAD_FUNC_ARG;
+
+    /* avoid implementation fingerprinting */
+    if (public_key->p.point[0] > 0x7F)
+        return ECC_BAD_ARG_E;
+
+    XMEMSET(p,   0, sizeof(p));
+    XMEMSET(k,   0, sizeof(k));
+    XMEMSET(out, 0, CURVE25519_KEYSIZE);
+
+    for (i = 0; i < CURVE25519_KEYSIZE; ++i) {
+        p[i] = public_key->p.point [CURVE25519_KEYSIZE - i - 1];
+        k[i] = private_key->k.point[CURVE25519_KEYSIZE - i - 1];
+    }
+
+    ret     = curve25519(o , k, p);
+    *outlen = CURVE25519_KEYSIZE;
+
+    for (i = 0; i < CURVE25519_KEYSIZE; ++i) {
+        out[i] = o[CURVE25519_KEYSIZE - i -1];
+    }
+
+    ForceZero(p, sizeof(p));
+    ForceZero(k, sizeof(k));
+    ForceZero(o, sizeof(o));
+
+    return ret;
+}
+
+
+/* curve25519 uses a serialized string for key representation */
+int wc_curve25519_export_public(curve25519_key* key, byte* out, word32* outLen)
+{
+    word32 keySz;
+
+    if (key == NULL || out == NULL || outLen == NULL)
+        return BAD_FUNC_ARG;
+
+    /* check size of outgoing key */
+    keySz  = wc_curve25519_size(key);
+
+    /* copy in public key */
+    XMEMCPY(out, key->p.point, keySz);
+    *outLen = keySz;
+
+    return 0;
+}
+
+/* import curve25519 public key
+   return 0 on success */
+int wc_curve25519_import_public(const byte* in, word32 inLen,
+                                curve25519_key* key)
+{
+    word32 keySz;
+
+    /* sanity check */
+    if (key == NULL || in == NULL)
+        return ECC_BAD_ARG_E;
+
+    /* check size of incoming keys */
+    keySz = wc_curve25519_size(key);
+    if (inLen != keySz)
+       return ECC_BAD_ARG_E;
+
+    XMEMCPY(key->p.point, in, inLen);
+
+    key->dp = &curve25519_sets[0];
+
+    return 0;
+}
+
+
+/* export curve25519 private key only raw, outLen is in/out size
+   return 0 on success */
+int wc_curve25519_export_private_raw(curve25519_key* key, byte* out,
+                                     word32* outLen)
+{
+    word32 keySz;
+
+    /* sanity check */
+    if (key == NULL || out == NULL || outLen == NULL)
+        return ECC_BAD_ARG_E;
+
+    keySz = wc_curve25519_size(key);
+    *outLen = keySz;
+    XMEMSET(out, 0, keySz);
+    XMEMCPY(out, key->k.point, keySz);
+
+    return 0;
+}
+
+
+/* curve25519 private key import.
+   Public key to match private key needs to be imported too */
+int wc_curve25519_import_private_raw(const byte* priv, word32 privSz,
+                             const byte* pub, word32 pubSz, curve25519_key* key)
+{
+    int ret = 0;
+    word32 keySz;
+
+    /* sanity check */
+    if (key == NULL || priv == NULL || pub == NULL)
+        return ECC_BAD_ARG_E;
+
+    /* check size of incoming keys */
+    keySz = wc_curve25519_size(key);
+    if (privSz != keySz || pubSz != keySz)
+       return ECC_BAD_ARG_E;
+
+    XMEMCPY(key->k.point, priv, privSz);
+    XMEMCPY(key->p.point, pub, pubSz);
+
+    return ret;
+}
+
+
+int wc_curve25519_init(curve25519_key* key)
+{
+    word32 keySz;
+
+    if (key == NULL)
+       return ECC_BAD_ARG_E;
+
+    /* currently the format for curve25519 */
+    key->dp = &curve25519_sets[0];
+    keySz   = key->dp->size;
+
+    XMEMSET(key->k.point, 0, keySz);
+    XMEMSET(key->p.point, 0, keySz);
+
+    return 0;
+}
+
+
+/* Clean the memory of a key */
+void wc_curve25519_free(curve25519_key* key)
+{
+   if (key == NULL)
+       return;
+
+   key->dp = NULL;
+   ForceZero(key->p.point, sizeof(key->p.point));
+   ForceZero(key->k.point, sizeof(key->k.point));
+}
+
+
+/* get key size */
+int wc_curve25519_size(curve25519_key* key)
+{
+    if (key == NULL) return 0;
+
+    return key->dp->size;
+}
+
+#endif /*HAVE_CURVE25519*/
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/des3.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,1679 @@
+/* des3.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifndef NO_DES3
+
+#include <wolfssl/wolfcrypt/des3.h>
+
+#ifdef HAVE_FIPS
+#ifdef HAVE_CAVIUM
+    static int wc_Des3_CaviumSetKey(Des3* des3, const byte* key, const byte* iv);
+    static int wc_Des3_CaviumCbcEncrypt(Des3* des3, byte* out, const byte* in,
+                                      word32 length);
+    static int wc_Des3_CaviumCbcDecrypt(Des3* des3, byte* out, const byte* in,
+                                      word32 length);
+#endif
+
+int wc_Des_SetKey(Des* des, const byte* key, const byte* iv, int dir)
+{
+    return Des_SetKey(des, key, iv, dir);
+}
+
+
+int wc_Des3_SetKey(Des3* des, const byte* key, const byte* iv, int dir)
+{
+    return Des3_SetKey_fips(des, key, iv, dir);
+}
+
+
+int wc_Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz)
+{
+    return Des_CbcEncrypt(des, out, in, sz);
+}
+
+
+int wc_Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz)
+{
+    return Des_CbcDecrypt(des, out, in, sz);
+}
+
+
+int wc_Des3_CbcEncrypt(Des3* des, byte* out, const byte* in, word32 sz)
+{
+    return Des3_CbcEncrypt_fips(des, out, in, sz);
+}
+
+
+int wc_Des3_CbcDecrypt(Des3* des, byte* out, const byte* in, word32 sz)
+{
+    return Des3_CbcDecrypt_fips(des, out, in, sz);
+}
+
+
+#ifdef WOLFSSL_DES_ECB
+
+/* One block, compatibility only */
+int wc_Des_EcbEncrypt(Des* des, byte* out, const byte* in, word32 sz)
+{
+    return Des_EcbEncrypt(des, out, in, sz);
+}
+
+#endif /* WOLFSSL_DES_ECB */
+
+
+void wc_Des_SetIV(Des* des, const byte* iv)
+{
+    Des_SetIV(des, iv);
+}
+
+
+int wc_Des_CbcDecryptWithKey(byte* out, const byte* in, word32 sz,
+                                                const byte* key, const byte* iv)
+{
+    return Des_CbcDecryptWithKey(out, in, sz, key, iv);
+}
+
+
+int wc_Des3_SetIV(Des3* des, const byte* iv)
+{
+    return Des3_SetIV_fips(des, iv);
+}
+
+
+int wc_Des3_CbcDecryptWithKey(byte* out, const byte* in, word32 sz,
+                                                const byte* key, const byte* iv)
+{
+    return Des3_CbcDecryptWithKey(out, in, sz, key, iv);
+}
+
+
+#ifdef HAVE_CAVIUM
+
+/* Initiliaze Des3 for use with Nitrox device */
+int wc_Des3_InitCavium(Des3* des3, int devId)
+{
+    return Des3_InitCavium(des3, devId);
+}
+
+
+/* Free Des3 from use with Nitrox device */
+void wc_Des3_FreeCavium(Des3* des3)
+{
+    Des3_FreeCavium(des3);
+}
+
+
+#endif /* HAVE_CAVIUM */
+#else /* build without fips */
+
+#if defined(WOLFSSL_TI_CRYPT)
+    #include <wolfcrypt/src/port/ti/ti-des3.c>
+#else
+
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/logging.h>
+
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+
+#ifdef HAVE_CAVIUM
+    static int wc_Des3_CaviumSetKey(Des3* des3, const byte* key, const byte* iv);
+    static int wc_Des3_CaviumCbcEncrypt(Des3* des3, byte* out, const byte* in,
+                                      word32 length);
+    static int wc_Des3_CaviumCbcDecrypt(Des3* des3, byte* out, const byte* in,
+                                      word32 length);
+#endif
+
+
+
+
+#ifdef STM32F2_CRYPTO
+    /*
+     * STM32F2 hardware DES/3DES support through the STM32F2 standard
+     * peripheral library. Documentation located in STM32F2xx Standard
+     * Peripheral Library document (See note in README).
+     */
+    #include "stm32f2xx.h"
+		#include "stm32f2xx_cryp.h"
+
+    int wc_Des_SetKey(Des* des, const byte* key, const byte* iv, int dir)
+    {
+        word32 *dkey = des->key;
+
+        XMEMCPY(dkey, key, 8);
+        ByteReverseWords(dkey, dkey, 8);
+
+        wc_Des_SetIV(des, iv);
+
+        return 0;
+    }
+
+    int wc_Des3_SetKey(Des3* des, const byte* key, const byte* iv, int dir)
+    {
+        word32 *dkey1 = des->key[0];
+        word32 *dkey2 = des->key[1];
+        word32 *dkey3 = des->key[2];
+
+        XMEMCPY(dkey1, key, 8);         /* set key 1 */
+        XMEMCPY(dkey2, key + 8, 8);     /* set key 2 */
+        XMEMCPY(dkey3, key + 16, 8);    /* set key 3 */
+
+        ByteReverseWords(dkey1, dkey1, 8);
+        ByteReverseWords(dkey2, dkey2, 8);
+        ByteReverseWords(dkey3, dkey3, 8);
+
+        return wc_Des3_SetIV(des, iv);
+    }
+
+    void DesCrypt(Des* des, byte* out, const byte* in, word32 sz,
+                  int dir, int mode)
+    {
+        word32 *dkey, *iv;
+        CRYP_InitTypeDef DES_CRYP_InitStructure;
+        CRYP_KeyInitTypeDef DES_CRYP_KeyInitStructure;
+        CRYP_IVInitTypeDef DES_CRYP_IVInitStructure;
+
+        dkey = des->key;
+        iv = des->reg;
+
+        /* crypto structure initialization */
+        CRYP_KeyStructInit(&DES_CRYP_KeyInitStructure);
+        CRYP_StructInit(&DES_CRYP_InitStructure);
+        CRYP_IVStructInit(&DES_CRYP_IVInitStructure);
+
+        /* reset registers to their default values */
+        CRYP_DeInit();
+
+        /* set direction, mode, and datatype */
+        if (dir == DES_ENCRYPTION) {
+            DES_CRYP_InitStructure.CRYP_AlgoDir  = CRYP_AlgoDir_Encrypt;
+        } else { /* DES_DECRYPTION */
+            DES_CRYP_InitStructure.CRYP_AlgoDir  = CRYP_AlgoDir_Decrypt;
+        }
+
+        if (mode == DES_CBC) {
+            DES_CRYP_InitStructure.CRYP_AlgoMode = CRYP_AlgoMode_DES_CBC;
+        } else { /* DES_ECB */
+            DES_CRYP_InitStructure.CRYP_AlgoMode = CRYP_AlgoMode_DES_ECB;
+        }
+
+        DES_CRYP_InitStructure.CRYP_DataType = CRYP_DataType_8b;
+        CRYP_Init(&DES_CRYP_InitStructure);
+
+        /* load key into correct registers */
+        DES_CRYP_KeyInitStructure.CRYP_Key1Left  = dkey[0];
+        DES_CRYP_KeyInitStructure.CRYP_Key1Right = dkey[1];
+        CRYP_KeyInit(&DES_CRYP_KeyInitStructure);
+
+        /* set iv */
+        ByteReverseWords(iv, iv, DES_BLOCK_SIZE);
+        DES_CRYP_IVInitStructure.CRYP_IV0Left  = iv[0];
+        DES_CRYP_IVInitStructure.CRYP_IV0Right = iv[1];
+        CRYP_IVInit(&DES_CRYP_IVInitStructure);
+
+        /* enable crypto processor */
+        CRYP_Cmd(ENABLE);
+
+        while (sz > 0)
+        {
+            /* flush IN/OUT FIFOs */
+            CRYP_FIFOFlush();
+
+            /* if input and output same will overwrite input iv */
+            XMEMCPY(des->tmp, in + sz - DES_BLOCK_SIZE, DES_BLOCK_SIZE);
+
+            CRYP_DataIn(*(uint32_t*)&in[0]);
+            CRYP_DataIn(*(uint32_t*)&in[4]);
+
+            /* wait until the complete message has been processed */
+            while(CRYP_GetFlagStatus(CRYP_FLAG_BUSY) != RESET) {}
+
+            *(uint32_t*)&out[0]  = CRYP_DataOut();
+            *(uint32_t*)&out[4]  = CRYP_DataOut();
+
+            /* store iv for next call */
+            XMEMCPY(des->reg, des->tmp, DES_BLOCK_SIZE);
+
+            sz  -= DES_BLOCK_SIZE;
+            in  += DES_BLOCK_SIZE;
+            out += DES_BLOCK_SIZE;
+        }
+
+        /* disable crypto processor */
+        CRYP_Cmd(DISABLE);
+    }
+
+    int wc_Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz)
+    {
+        DesCrypt(des, out, in, sz, DES_ENCRYPTION, DES_CBC);
+        return 0;
+    }
+
+    int wc_Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz)
+    {
+        DesCrypt(des, out, in, sz, DES_DECRYPTION, DES_CBC);
+        return 0;
+    }
+
+    int wc_Des_EcbEncrypt(Des* des, byte* out, const byte* in, word32 sz)
+    {
+        DesCrypt(des, out, in, sz, DES_ENCRYPTION, DES_ECB);
+        return 0;
+    }
+
+    void Des3Crypt(Des3* des, byte* out, const byte* in, word32 sz,
+                   int dir)
+    {
+        word32 *dkey1, *dkey2, *dkey3, *iv;
+        CRYP_InitTypeDef DES3_CRYP_InitStructure;
+        CRYP_KeyInitTypeDef DES3_CRYP_KeyInitStructure;
+        CRYP_IVInitTypeDef DES3_CRYP_IVInitStructure;
+
+        dkey1 = des->key[0];
+        dkey2 = des->key[1];
+        dkey3 = des->key[2];
+        iv = des->reg;
+
+        /* crypto structure initialization */
+        CRYP_KeyStructInit(&DES3_CRYP_KeyInitStructure);
+        CRYP_StructInit(&DES3_CRYP_InitStructure);
+        CRYP_IVStructInit(&DES3_CRYP_IVInitStructure);
+
+        /* reset registers to their default values */
+        CRYP_DeInit();
+
+        /* set direction, mode, and datatype */
+        if (dir == DES_ENCRYPTION) {
+            DES3_CRYP_InitStructure.CRYP_AlgoDir  = CRYP_AlgoDir_Encrypt;
+        } else {
+            DES3_CRYP_InitStructure.CRYP_AlgoDir  = CRYP_AlgoDir_Decrypt;
+        }
+
+        DES3_CRYP_InitStructure.CRYP_AlgoMode = CRYP_AlgoMode_TDES_CBC;
+        DES3_CRYP_InitStructure.CRYP_DataType = CRYP_DataType_8b;
+        CRYP_Init(&DES3_CRYP_InitStructure);
+
+        /* load key into correct registers */
+        DES3_CRYP_KeyInitStructure.CRYP_Key1Left  = dkey1[0];
+        DES3_CRYP_KeyInitStructure.CRYP_Key1Right = dkey1[1];
+        DES3_CRYP_KeyInitStructure.CRYP_Key2Left  = dkey2[0];
+        DES3_CRYP_KeyInitStructure.CRYP_Key2Right = dkey2[1];
+        DES3_CRYP_KeyInitStructure.CRYP_Key3Left  = dkey3[0];
+        DES3_CRYP_KeyInitStructure.CRYP_Key3Right = dkey3[1];
+        CRYP_KeyInit(&DES3_CRYP_KeyInitStructure);
+
+        /* set iv */
+        ByteReverseWords(iv, iv, DES_BLOCK_SIZE);
+        DES3_CRYP_IVInitStructure.CRYP_IV0Left  = iv[0];
+        DES3_CRYP_IVInitStructure.CRYP_IV0Right = iv[1];
+        CRYP_IVInit(&DES3_CRYP_IVInitStructure);
+
+        /* enable crypto processor */
+        CRYP_Cmd(ENABLE);
+
+        while (sz > 0)
+        {
+            /* flush IN/OUT FIFOs */
+            CRYP_FIFOFlush();
+
+            CRYP_DataIn(*(uint32_t*)&in[0]);
+            CRYP_DataIn(*(uint32_t*)&in[4]);
+
+            /* wait until the complete message has been processed */
+            while(CRYP_GetFlagStatus(CRYP_FLAG_BUSY) != RESET) {}
+
+            *(uint32_t*)&out[0]  = CRYP_DataOut();
+            *(uint32_t*)&out[4]  = CRYP_DataOut();
+
+            /* store iv for next call */
+            XMEMCPY(des->reg, out + sz - DES_BLOCK_SIZE, DES_BLOCK_SIZE);
+
+            sz  -= DES_BLOCK_SIZE;
+            in  += DES_BLOCK_SIZE;
+            out += DES_BLOCK_SIZE;
+        }
+
+        /* disable crypto processor */
+        CRYP_Cmd(DISABLE);
+
+    }
+
+    int wc_Des3_CbcEncrypt(Des3* des, byte* out, const byte* in, word32 sz)
+    {
+        Des3Crypt(des, out, in, sz, DES_ENCRYPTION);
+        return 0;
+    }
+
+    int wc_Des3_CbcDecrypt(Des3* des, byte* out, const byte* in, word32 sz)
+    {
+        Des3Crypt(des, out, in, sz, DES_DECRYPTION);
+        return 0;
+    }
+
+#elif defined(HAVE_COLDFIRE_SEC)
+
+#include <wolfssl/ctaocrypt/types.h>
+
+#include "sec.h"
+#include "mcf5475_sec.h"
+#include "mcf5475_siu.h"
+
+#if defined (HAVE_THREADX)
+#include "memory_pools.h"
+extern TX_BYTE_POOL mp_ncached;  /* Non Cached memory pool */
+#endif
+
+#define DES_BUFFER_SIZE (DES_BLOCK_SIZE * 64)
+static unsigned char *desBuffIn = NULL ;
+static unsigned char *desBuffOut = NULL ;
+static byte *secIV ; 
+static byte *secKey ; 
+static volatile SECdescriptorType *secDesc ;
+
+static wolfSSL_Mutex Mutex_DesSEC ;
+
+#define SEC_DESC_DES_CBC_ENCRYPT  0x20500010
+#define SEC_DESC_DES_CBC_DECRYPT  0x20400010
+#define SEC_DESC_DES3_CBC_ENCRYPT 0x20700010
+#define SEC_DESC_DES3_CBC_DECRYPT 0x20600010
+
+#define DES_IVLEN 8
+#define DES_KEYLEN 8
+#define DES3_IVLEN 8
+#define DES3_KEYLEN 24
+
+extern volatile unsigned char __MBAR[];
+
+static void wc_Des_Cbc(byte* out, const byte* in, word32 sz, 
+                    byte *key, byte *iv, word32 desc)
+{
+    #ifdef DEBUG_WOLFSSL
+    int ret ;  int stat1,stat2 ; 
+	  #endif
+    int size ;
+    volatile int v ;
+ 
+    LockMutex(&Mutex_DesSEC) ;
+    
+    secDesc->length1 = 0x0;
+    secDesc->pointer1 = NULL;
+    if((desc==SEC_DESC_DES_CBC_ENCRYPT)||(desc==SEC_DESC_DES_CBC_DECRYPT)){
+        secDesc->length2 = DES_IVLEN ;  
+        secDesc->length3 = DES_KEYLEN ;
+    } else {
+        secDesc->length2 = DES3_IVLEN ; 
+        secDesc->length3 = DES3_KEYLEN ;
+    }
+    secDesc->pointer2 = secIV ;
+    secDesc->pointer3 = secKey;
+    secDesc->pointer4 = desBuffIn ;
+    secDesc->pointer5 = desBuffOut ;
+    secDesc->length6 = 0; 
+    secDesc->pointer6 = NULL; 
+    secDesc->length7 = 0x0;
+    secDesc->pointer7 = NULL;
+    secDesc->nextDescriptorPtr = NULL ; 
+    
+    while(sz) {
+        XMEMCPY(secIV, iv, secDesc->length2) ;
+        if((sz%DES_BUFFER_SIZE) == sz) {
+            size = sz ;
+            sz = 0 ;
+        } else {
+            size = DES_BUFFER_SIZE ;
+            sz -= DES_BUFFER_SIZE ;
+        }
+        
+        XMEMCPY(desBuffIn, in, size) ;
+        XMEMCPY(secKey, key, secDesc->length3) ;
+        
+        secDesc->header = desc ;
+        secDesc->length4 = size;
+        secDesc->length5 = size;
+        /* Point SEC to the location of the descriptor */
+        MCF_SEC_FR0 = (uint32)secDesc;
+        /* Initialize SEC and wait for encryption to complete */
+        MCF_SEC_CCCR0 = 0x0000001a;
+        /* poll SISR to determine when channel is complete */
+        v=0 ;
+        while((secDesc->header>> 24) != 0xff) {
+            if(v++ > 1000)break ;
+        }
+				
+#ifdef DEBUG_WOLFSSL
+        ret = MCF_SEC_SISRH;
+        stat1 = MCF_SEC_DSR ; 
+        stat2 = MCF_SEC_DISR ; 
+        if(ret & 0xe0000000) {
+            /* db_printf("Des_Cbc(%x):ISRH=%08x, DSR=%08x, DISR=%08x\n", desc, ret, stat1, stat2) ; */
+        }
+#endif
+				
+        XMEMCPY(out, desBuffOut, size) ;
+
+        if((desc==SEC_DESC_DES3_CBC_ENCRYPT)||(desc==SEC_DESC_DES_CBC_ENCRYPT)) {
+            XMEMCPY((void*)iv, (void*)&(out[size-secDesc->length2]), secDesc->length2) ;
+        } else {
+            XMEMCPY((void*)iv, (void*)&(in[size-secDesc->length2]), secDesc->length2) ;
+        }
+        
+        in  += size ;   
+        out += size ;
+                
+    }
+    UnLockMutex(&Mutex_DesSEC) ;
+    
+}
+
+
+int wc_Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz)
+{
+    wc_Des_Cbc(out, in, sz,  (byte *)des->key,  (byte *)des->reg, SEC_DESC_DES_CBC_ENCRYPT) ;
+    return 0;
+}
+
+int wc_Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz)
+{
+    wc_Des_Cbc(out, in, sz,   (byte *)des->key,  (byte *)des->reg, SEC_DESC_DES_CBC_DECRYPT) ;
+    return 0;
+}
+
+int wc_Des3_CbcEncrypt(Des3* des3, byte* out, const byte* in, word32 sz)
+{
+    wc_Des_Cbc(out, in, sz,  (byte *)des3->key,  (byte *)des3->reg, SEC_DESC_DES3_CBC_ENCRYPT) ;
+	  return 0;
+}
+
+
+int wc_Des3_CbcDecrypt(Des3* des3, byte* out, const byte* in, word32 sz)
+{
+    wc_Des_Cbc(out, in, sz,   (byte *)des3->key,  (byte *)des3->reg, SEC_DESC_DES3_CBC_DECRYPT) ;
+	  return 0;
+}
+
+static void setParity(byte *buf, int len) 
+{
+    int i, j ;
+    byte v ;
+    int bits ;
+
+    for(i=0; i<len; i++) 
+    {
+        v = buf[i] >> 1 ;
+        buf[i] = v << 1 ;
+        bits = 0 ;
+        for(j=0; j<7; j++)
+        {
+            bits += (v&0x1) ;
+            v = v >> 1 ;
+        }
+        buf[i] |= (1 - (bits&0x1)) ;
+    }
+    
+}
+
+
+int wc_Des_SetKey(Des* des, const byte* key, const byte* iv, int dir)
+{
+    if(desBuffIn == NULL) {
+        #if defined (HAVE_THREADX)
+			  int s1, s2, s3, s4, s5 ;
+        s5 = tx_byte_allocate(&mp_ncached,(void *)&secDesc, 
+                                                     sizeof(SECdescriptorType), TX_NO_WAIT);
+        s1 = tx_byte_allocate(&mp_ncached,(void *)&desBuffIn,  DES_BUFFER_SIZE, TX_NO_WAIT);
+        s2 = tx_byte_allocate(&mp_ncached,(void *)&desBuffOut, DES_BUFFER_SIZE, TX_NO_WAIT);
+        /* Don't know des or des3 to be used. Allocate larger buffers */
+        s3 = tx_byte_allocate(&mp_ncached,(void *)&secKey,     DES3_KEYLEN,TX_NO_WAIT);
+        s4 = tx_byte_allocate(&mp_ncached,(void *)&secIV,      DES3_IVLEN,  TX_NO_WAIT);              
+        #else
+        #warning "Allocate non-Cache buffers"
+        #endif
+        
+        InitMutex(&Mutex_DesSEC) ;
+    }
+     
+    XMEMCPY(des->key, key, DES_KEYLEN);  
+    setParity((byte *)des->key, DES_KEYLEN) ;  
+		
+    if (iv) {
+        XMEMCPY(des->reg, iv, DES_IVLEN);
+    }   else {
+        XMEMSET(des->reg, 0x0, DES_IVLEN) ;
+    }
+		return 0;
+}
+
+int wc_Des3_SetKey(Des3* des3, const byte* key, const byte* iv, int dir)
+{
+    
+    if(desBuffIn == NULL) {
+        #if defined (HAVE_THREADX)
+			  int s1, s2, s3, s4, s5 ;
+        s5 = tx_byte_allocate(&mp_ncached,(void *)&secDesc, 
+                                                     sizeof(SECdescriptorType), TX_NO_WAIT);
+        s1 = tx_byte_allocate(&mp_ncached,(void *)&desBuffIn,  DES_BUFFER_SIZE, TX_NO_WAIT);
+        s2 = tx_byte_allocate(&mp_ncached,(void *)&desBuffOut, DES_BUFFER_SIZE, TX_NO_WAIT);
+        s3 = tx_byte_allocate(&mp_ncached,(void *)&secKey,     DES3_KEYLEN,TX_NO_WAIT);
+        s4 = tx_byte_allocate(&mp_ncached,(void *)&secIV,      DES3_IVLEN,  TX_NO_WAIT);              
+        #else
+        #warning "Allocate non-Cache buffers"
+        #endif
+        
+        InitMutex(&Mutex_DesSEC) ;
+    }
+    
+    XMEMCPY(des3->key[0], key, DES3_KEYLEN); 
+    setParity((byte *)des3->key[0], DES3_KEYLEN) ;  
+		
+    if (iv) {
+        XMEMCPY(des3->reg, iv, DES3_IVLEN);
+    }   else {
+        XMEMSET(des3->reg, 0x0, DES3_IVLEN) ;
+    }
+    return 0;
+
+}
+
+#elif defined FREESCALE_MMCAU
+    /*
+     * Freescale mmCAU hardware DES/3DES support through the CAU/mmCAU library.
+     * Documentation located in ColdFire/ColdFire+ CAU and Kinetis mmCAU
+     * Software Library User Guide (See note in README).
+     */
+    #include "cau_api.h"
+
+    const unsigned char parityLookup[128] =
+    {
+        1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+        0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+        0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+        1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
+     };
+
+    int wc_Des_SetKey(Des* des, const byte* key, const byte* iv, int dir)
+    {
+        int i = 0;
+        byte* dkey = (byte*)des->key;
+
+        XMEMCPY(dkey, key, 8);
+
+        wc_Des_SetIV(des, iv);
+
+        /* fix key parity, if needed */
+        for (i = 0; i < 8; i++) {
+            dkey[i] = ((dkey[i] & 0xFE) | parityLookup[dkey[i] >> 1]);
+        }
+
+        return 0;
+    }
+
+    int wc_Des3_SetKey(Des3* des, const byte* key, const byte* iv, int dir)
+    {
+        int i = 0, ret = 0;
+        byte* dkey1 = (byte*)des->key[0];
+        byte* dkey2 = (byte*)des->key[1];
+        byte* dkey3 = (byte*)des->key[2];
+
+        XMEMCPY(dkey1, key, 8);         /* set key 1 */
+        XMEMCPY(dkey2, key + 8, 8);     /* set key 2 */
+        XMEMCPY(dkey3, key + 16, 8);    /* set key 3 */
+
+        ret = wc_Des3_SetIV(des, iv);
+        if (ret != 0)
+            return ret;
+
+        /* fix key parity if needed */
+        for (i = 0; i < 8; i++)
+           dkey1[i] = ((dkey1[i] & 0xFE) | parityLookup[dkey1[i] >> 1]);
+
+        for (i = 0; i < 8; i++)
+           dkey2[i] = ((dkey2[i] & 0xFE) | parityLookup[dkey2[i] >> 1]);
+
+        for (i = 0; i < 8; i++)
+           dkey3[i] = ((dkey3[i] & 0xFE) | parityLookup[dkey3[i] >> 1]);
+
+        return ret;
+    }
+
+    int wc_Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz)
+    {
+        int i;
+        int offset = 0;
+        int len = sz;
+        byte *iv;
+        byte temp_block[DES_BLOCK_SIZE];
+
+        iv = (byte*)des->reg;
+
+        if ((wolfssl_word)out % WOLFSSL_MMCAU_ALIGNMENT) {
+            WOLFSSL_MSG("Bad cau_des_encrypt alignment"); 
+            return BAD_ALIGN_E;
+        }
+
+        while (len > 0)
+        {
+            XMEMCPY(temp_block, in + offset, DES_BLOCK_SIZE);
+
+            /* XOR block with IV for CBC */
+            for (i = 0; i < DES_BLOCK_SIZE; i++)
+                temp_block[i] ^= iv[i];
+
+            cau_des_encrypt(temp_block, (byte*)des->key, out + offset);
+
+            len    -= DES_BLOCK_SIZE;
+            offset += DES_BLOCK_SIZE;
+
+            /* store IV for next block */
+            XMEMCPY(iv, out + offset - DES_BLOCK_SIZE, DES_BLOCK_SIZE);
+        }
+
+        return 0;
+    }
+
+    int wc_Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz)
+    {
+        int i;
+        int offset = 0;
+        int len = sz;
+        byte* iv;
+        byte temp_block[DES_BLOCK_SIZE];
+
+        iv = (byte*)des->reg;
+
+        if ((wolfssl_word)out % WOLFSSL_MMCAU_ALIGNMENT) {
+            WOLFSSL_MSG("Bad cau_des_decrypt alignment"); 
+            return BAD_ALIGN_E;
+        }
+
+        while (len > 0)
+        {
+            XMEMCPY(temp_block, in + offset, DES_BLOCK_SIZE);
+
+            cau_des_decrypt(in + offset, (byte*)des->key, out + offset);
+
+            /* XOR block with IV for CBC */
+            for (i = 0; i < DES_BLOCK_SIZE; i++)
+                (out + offset)[i] ^= iv[i];
+
+            /* store IV for next block */
+            XMEMCPY(iv, temp_block, DES_BLOCK_SIZE);
+
+            len     -= DES_BLOCK_SIZE;
+            offset += DES_BLOCK_SIZE;
+        }
+
+        return 0;
+    }
+
+    int wc_Des3_CbcEncrypt(Des3* des, byte* out, const byte* in, word32 sz)
+    {
+        int i;
+        int offset = 0;
+        int len = sz;
+
+        byte *iv;
+        byte temp_block[DES_BLOCK_SIZE];
+
+        iv = (byte*)des->reg;
+
+        if ((wolfssl_word)out % WOLFSSL_MMCAU_ALIGNMENT) {
+            WOLFSSL_MSG("Bad 3ede cau_des_encrypt alignment"); 
+            return BAD_ALIGN_E;
+        }
+
+        while (len > 0)
+        {
+            XMEMCPY(temp_block, in + offset, DES_BLOCK_SIZE);
+
+            /* XOR block with IV for CBC */
+            for (i = 0; i < DES_BLOCK_SIZE; i++)
+                temp_block[i] ^= iv[i];
+
+            cau_des_encrypt(temp_block  , (byte*)des->key[0], out + offset);
+            cau_des_decrypt(out + offset, (byte*)des->key[1], out + offset);
+            cau_des_encrypt(out + offset, (byte*)des->key[2], out + offset);
+
+            len    -= DES_BLOCK_SIZE;
+            offset += DES_BLOCK_SIZE;
+
+            /* store IV for next block */
+            XMEMCPY(iv, out + offset - DES_BLOCK_SIZE, DES_BLOCK_SIZE);
+        }
+
+        return 0;
+    }
+
+    int wc_Des3_CbcDecrypt(Des3* des, byte* out, const byte* in, word32 sz)
+    {
+        int i;
+        int offset = 0;
+        int len = sz;
+
+        byte* iv;
+        byte temp_block[DES_BLOCK_SIZE];
+
+        iv = (byte*)des->reg;
+
+        if ((wolfssl_word)out % WOLFSSL_MMCAU_ALIGNMENT) {
+            WOLFSSL_MSG("Bad 3ede cau_des_decrypt alignment"); 
+            return BAD_ALIGN_E;
+        }
+
+        while (len > 0)
+        {
+            XMEMCPY(temp_block, in + offset, DES_BLOCK_SIZE);
+
+            cau_des_decrypt(in + offset , (byte*)des->key[2], out + offset);
+            cau_des_encrypt(out + offset, (byte*)des->key[1], out + offset);
+            cau_des_decrypt(out + offset, (byte*)des->key[0], out + offset);
+
+            /* XOR block with IV for CBC */
+            for (i = 0; i < DES_BLOCK_SIZE; i++)
+                (out + offset)[i] ^= iv[i];
+
+            /* store IV for next block */
+            XMEMCPY(iv, temp_block, DES_BLOCK_SIZE);
+
+            len    -= DES_BLOCK_SIZE;
+            offset += DES_BLOCK_SIZE;
+        }
+
+        return 0;
+    }
+
+
+#elif defined(WOLFSSL_PIC32MZ_CRYPT)
+
+    #include "wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h"
+
+void wc_Des_SetIV(Des* des, const byte* iv);
+int  wc_Des3_SetIV(Des3* des, const byte* iv);
+
+    int wc_Des_SetKey(Des* des, const byte* key, const byte* iv, int dir)
+    {
+        word32 *dkey = des->key ;
+        word32 *dreg = des->reg ;
+
+        XMEMCPY((byte *)dkey, (byte *)key, 8);
+        ByteReverseWords(dkey, dkey, 8);
+        XMEMCPY((byte *)dreg, (byte *)iv, 8);
+        ByteReverseWords(dreg, dreg, 8);
+
+        return 0;
+    }
+
+    int wc_Des3_SetKey(Des3* des, const byte* key, const byte* iv, int dir)
+    {
+        word32 *dkey1 = des->key[0];
+        word32 *dreg = des->reg ;
+
+        XMEMCPY(dkey1, key, 24);
+        ByteReverseWords(dkey1, dkey1, 24);
+        XMEMCPY(dreg, iv, 8);
+        ByteReverseWords(dreg, dreg, 8) ;
+
+        return 0;
+    }
+
+    void DesCrypt(word32 *key, word32 *iv, byte* out, const byte* in, word32 sz,
+                  int dir, int algo, int cryptoalgo)
+    {
+        securityAssociation *sa_p ;
+        bufferDescriptor *bd_p ;
+        const byte *in_p, *in_l ;
+        byte *out_p, *out_l ;
+        volatile securityAssociation sa __attribute__((aligned (8)));
+        volatile bufferDescriptor bd __attribute__((aligned (8)));
+        volatile int k ;
+        
+        /* get uncached address */
+
+        in_l = in;
+        out_l = out ;
+        sa_p = KVA0_TO_KVA1(&sa) ; 
+        bd_p = KVA0_TO_KVA1(&bd) ;
+        in_p = KVA0_TO_KVA1(in_l) ;
+        out_p= KVA0_TO_KVA1(out_l);
+        
+        if(PIC32MZ_IF_RAM(in_p))
+            XMEMCPY((void *)in_p, (void *)in, sz);
+        XMEMSET((void *)out_p, 0, sz);
+
+        /* Set up the Security Association */
+        XMEMSET((byte *)KVA0_TO_KVA1(&sa), 0, sizeof(sa));
+        sa_p->SA_CTRL.ALGO = algo ; 
+        sa_p->SA_CTRL.LNC = 1;
+        sa_p->SA_CTRL.LOADIV = 1;
+        sa_p->SA_CTRL.FB = 1;
+        sa_p->SA_CTRL.ENCTYPE = dir ; /* Encryption/Decryption */
+        sa_p->SA_CTRL.CRYPTOALGO = cryptoalgo;
+        sa_p->SA_CTRL.KEYSIZE = 1 ; /* KEY is 192 bits */
+        XMEMCPY((byte *)KVA0_TO_KVA1(&sa.SA_ENCKEY[algo==PIC32_ALGO_TDES ? 2 : 6]),
+                (byte *)key, algo==PIC32_ALGO_TDES ? 24 : 8);
+        XMEMCPY((byte *)KVA0_TO_KVA1(&sa.SA_ENCIV[2]), (byte *)iv, 8);
+
+        XMEMSET((byte *)KVA0_TO_KVA1(&bd), 0, sizeof(bd));
+        /* Set up the Buffer Descriptor */
+        bd_p->BD_CTRL.BUFLEN = sz;
+        bd_p->BD_CTRL.LIFM = 1;
+        bd_p->BD_CTRL.SA_FETCH_EN = 1;
+        bd_p->BD_CTRL.LAST_BD = 1;
+        bd_p->BD_CTRL.DESC_EN = 1;
+    
+        bd_p->SA_ADDR = (unsigned int)KVA_TO_PA(&sa) ; /* (unsigned int)sa_p; */
+        bd_p->SRCADDR = (unsigned int)KVA_TO_PA(in) ; /* (unsigned int)in_p; */
+        bd_p->DSTADDR = (unsigned int)KVA_TO_PA(out); /* (unsigned int)out_p; */
+        bd_p->NXTPTR = (unsigned int)KVA_TO_PA(&bd);
+        bd_p->MSGLEN = sz ;
+        
+        /* Fire in the hole! */
+        CECON = 1 << 6;
+        while (CECON);
+        
+        /* Run the engine */
+        CEBDPADDR = (unsigned int)KVA_TO_PA(&bd) ; /* (unsigned int)bd_p ; */
+        CEINTEN = 0x07;
+        CECON = 0x27;
+
+        WAIT_ENGINE ;
+
+        if((cryptoalgo == PIC32_CRYPTOALGO_CBC) ||
+           (cryptoalgo == PIC32_CRYPTOALGO_TCBC)||
+           (cryptoalgo == PIC32_CRYPTOALGO_RCBC)) {
+            /* set iv for the next call */
+            if(dir == PIC32_ENCRYPTION) {
+	        XMEMCPY((void *)iv, (void*)&(out_p[sz-DES_IVLEN]), DES_IVLEN) ;
+	        } else {
+                ByteReverseWords((word32*)iv, (word32 *)&(in_p[sz-DES_IVLEN]),
+                                 DES_IVLEN);
+	        }
+
+        }
+
+        ByteReverseWords((word32*)out, (word32 *)KVA0_TO_KVA1(out), sz);
+    }
+
+    int wc_Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz)
+    {
+        DesCrypt(des->key, des->reg, out, in, sz, 
+                PIC32_ENCRYPTION, PIC32_ALGO_DES, PIC32_CRYPTOALGO_CBC );
+        return 0;
+    }
+
+    int wc_Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz)
+    {
+        DesCrypt(des->key, des->reg, out, in, sz, 
+                PIC32_DECRYPTION, PIC32_ALGO_DES, PIC32_CRYPTOALGO_CBC);
+        return 0;
+    }
+
+    int wc_Des3_CbcEncrypt(Des3* des, byte* out, const byte* in, word32 sz)
+    {
+        DesCrypt(des->key[0], des->reg, out, in, sz, 
+                PIC32_ENCRYPTION, PIC32_ALGO_TDES, PIC32_CRYPTOALGO_TCBC);
+        return 0;
+    }
+
+    int wc_Des3_CbcDecrypt(Des3* des, byte* out, const byte* in, word32 sz)
+    {
+        DesCrypt(des->key[0], des->reg, out, in, sz, 
+                PIC32_DECRYPTION, PIC32_ALGO_TDES, PIC32_CRYPTOALGO_TCBC);
+        return 0;
+    }
+    
+#else /* CTaoCrypt software implementation */
+
+/* permuted choice table (key) */
+static const byte pc1[] = {
+       57, 49, 41, 33, 25, 17,  9,
+        1, 58, 50, 42, 34, 26, 18,
+       10,  2, 59, 51, 43, 35, 27,
+       19, 11,  3, 60, 52, 44, 36,
+
+       63, 55, 47, 39, 31, 23, 15,
+        7, 62, 54, 46, 38, 30, 22,
+       14,  6, 61, 53, 45, 37, 29,
+       21, 13,  5, 28, 20, 12,  4
+};
+
+/* number left rotations of pc1 */
+static const byte totrot[] = {
+       1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
+};
+
+/* permuted choice key (table) */
+static const byte pc2[] = {
+       14, 17, 11, 24,  1,  5,
+        3, 28, 15,  6, 21, 10,
+       23, 19, 12,  4, 26,  8,
+       16,  7, 27, 20, 13,  2,
+       41, 52, 31, 37, 47, 55,
+       30, 40, 51, 45, 33, 48,
+       44, 49, 39, 56, 34, 53,
+       46, 42, 50, 36, 29, 32
+};
+
+/* End of DES-defined tables */
+
+/* bit 0 is left-most in byte */
+static const int bytebit[] = {
+       0200,0100,040,020,010,04,02,01
+};
+
+static const word32 Spbox[8][64] = {
+{
+0x01010400,0x00000000,0x00010000,0x01010404,
+0x01010004,0x00010404,0x00000004,0x00010000,
+0x00000400,0x01010400,0x01010404,0x00000400,
+0x01000404,0x01010004,0x01000000,0x00000004,
+0x00000404,0x01000400,0x01000400,0x00010400,
+0x00010400,0x01010000,0x01010000,0x01000404,
+0x00010004,0x01000004,0x01000004,0x00010004,
+0x00000000,0x00000404,0x00010404,0x01000000,
+0x00010000,0x01010404,0x00000004,0x01010000,
+0x01010400,0x01000000,0x01000000,0x00000400,
+0x01010004,0x00010000,0x00010400,0x01000004,
+0x00000400,0x00000004,0x01000404,0x00010404,
+0x01010404,0x00010004,0x01010000,0x01000404,
+0x01000004,0x00000404,0x00010404,0x01010400,
+0x00000404,0x01000400,0x01000400,0x00000000,
+0x00010004,0x00010400,0x00000000,0x01010004},
+{
+0x80108020,0x80008000,0x00008000,0x00108020,
+0x00100000,0x00000020,0x80100020,0x80008020,
+0x80000020,0x80108020,0x80108000,0x80000000,
+0x80008000,0x00100000,0x00000020,0x80100020,
+0x00108000,0x00100020,0x80008020,0x00000000,
+0x80000000,0x00008000,0x00108020,0x80100000,
+0x00100020,0x80000020,0x00000000,0x00108000,
+0x00008020,0x80108000,0x80100000,0x00008020,
+0x00000000,0x00108020,0x80100020,0x00100000,
+0x80008020,0x80100000,0x80108000,0x00008000,
+0x80100000,0x80008000,0x00000020,0x80108020,
+0x00108020,0x00000020,0x00008000,0x80000000,
+0x00008020,0x80108000,0x00100000,0x80000020,
+0x00100020,0x80008020,0x80000020,0x00100020,
+0x00108000,0x00000000,0x80008000,0x00008020,
+0x80000000,0x80100020,0x80108020,0x00108000},
+{
+0x00000208,0x08020200,0x00000000,0x08020008,
+0x08000200,0x00000000,0x00020208,0x08000200,
+0x00020008,0x08000008,0x08000008,0x00020000,
+0x08020208,0x00020008,0x08020000,0x00000208,
+0x08000000,0x00000008,0x08020200,0x00000200,
+0x00020200,0x08020000,0x08020008,0x00020208,
+0x08000208,0x00020200,0x00020000,0x08000208,
+0x00000008,0x08020208,0x00000200,0x08000000,
+0x08020200,0x08000000,0x00020008,0x00000208,
+0x00020000,0x08020200,0x08000200,0x00000000,
+0x00000200,0x00020008,0x08020208,0x08000200,
+0x08000008,0x00000200,0x00000000,0x08020008,
+0x08000208,0x00020000,0x08000000,0x08020208,
+0x00000008,0x00020208,0x00020200,0x08000008,
+0x08020000,0x08000208,0x00000208,0x08020000,
+0x00020208,0x00000008,0x08020008,0x00020200},
+{
+0x00802001,0x00002081,0x00002081,0x00000080,
+0x00802080,0x00800081,0x00800001,0x00002001,
+0x00000000,0x00802000,0x00802000,0x00802081,
+0x00000081,0x00000000,0x00800080,0x00800001,
+0x00000001,0x00002000,0x00800000,0x00802001,
+0x00000080,0x00800000,0x00002001,0x00002080,
+0x00800081,0x00000001,0x00002080,0x00800080,
+0x00002000,0x00802080,0x00802081,0x00000081,
+0x00800080,0x00800001,0x00802000,0x00802081,
+0x00000081,0x00000000,0x00000000,0x00802000,
+0x00002080,0x00800080,0x00800081,0x00000001,
+0x00802001,0x00002081,0x00002081,0x00000080,
+0x00802081,0x00000081,0x00000001,0x00002000,
+0x00800001,0x00002001,0x00802080,0x00800081,
+0x00002001,0x00002080,0x00800000,0x00802001,
+0x00000080,0x00800000,0x00002000,0x00802080},
+{
+0x00000100,0x02080100,0x02080000,0x42000100,
+0x00080000,0x00000100,0x40000000,0x02080000,
+0x40080100,0x00080000,0x02000100,0x40080100,
+0x42000100,0x42080000,0x00080100,0x40000000,
+0x02000000,0x40080000,0x40080000,0x00000000,
+0x40000100,0x42080100,0x42080100,0x02000100,
+0x42080000,0x40000100,0x00000000,0x42000000,
+0x02080100,0x02000000,0x42000000,0x00080100,
+0x00080000,0x42000100,0x00000100,0x02000000,
+0x40000000,0x02080000,0x42000100,0x40080100,
+0x02000100,0x40000000,0x42080000,0x02080100,
+0x40080100,0x00000100,0x02000000,0x42080000,
+0x42080100,0x00080100,0x42000000,0x42080100,
+0x02080000,0x00000000,0x40080000,0x42000000,
+0x00080100,0x02000100,0x40000100,0x00080000,
+0x00000000,0x40080000,0x02080100,0x40000100},
+{
+0x20000010,0x20400000,0x00004000,0x20404010,
+0x20400000,0x00000010,0x20404010,0x00400000,
+0x20004000,0x00404010,0x00400000,0x20000010,
+0x00400010,0x20004000,0x20000000,0x00004010,
+0x00000000,0x00400010,0x20004010,0x00004000,
+0x00404000,0x20004010,0x00000010,0x20400010,
+0x20400010,0x00000000,0x00404010,0x20404000,
+0x00004010,0x00404000,0x20404000,0x20000000,
+0x20004000,0x00000010,0x20400010,0x00404000,
+0x20404010,0x00400000,0x00004010,0x20000010,
+0x00400000,0x20004000,0x20000000,0x00004010,
+0x20000010,0x20404010,0x00404000,0x20400000,
+0x00404010,0x20404000,0x00000000,0x20400010,
+0x00000010,0x00004000,0x20400000,0x00404010,
+0x00004000,0x00400010,0x20004010,0x00000000,
+0x20404000,0x20000000,0x00400010,0x20004010},
+{
+0x00200000,0x04200002,0x04000802,0x00000000,
+0x00000800,0x04000802,0x00200802,0x04200800,
+0x04200802,0x00200000,0x00000000,0x04000002,
+0x00000002,0x04000000,0x04200002,0x00000802,
+0x04000800,0x00200802,0x00200002,0x04000800,
+0x04000002,0x04200000,0x04200800,0x00200002,
+0x04200000,0x00000800,0x00000802,0x04200802,
+0x00200800,0x00000002,0x04000000,0x00200800,
+0x04000000,0x00200800,0x00200000,0x04000802,
+0x04000802,0x04200002,0x04200002,0x00000002,
+0x00200002,0x04000000,0x04000800,0x00200000,
+0x04200800,0x00000802,0x00200802,0x04200800,
+0x00000802,0x04000002,0x04200802,0x04200000,
+0x00200800,0x00000000,0x00000002,0x04200802,
+0x00000000,0x00200802,0x04200000,0x00000800,
+0x04000002,0x04000800,0x00000800,0x00200002},
+{
+0x10001040,0x00001000,0x00040000,0x10041040,
+0x10000000,0x10001040,0x00000040,0x10000000,
+0x00040040,0x10040000,0x10041040,0x00041000,
+0x10041000,0x00041040,0x00001000,0x00000040,
+0x10040000,0x10000040,0x10001000,0x00001040,
+0x00041000,0x00040040,0x10040040,0x10041000,
+0x00001040,0x00000000,0x00000000,0x10040040,
+0x10000040,0x10001000,0x00041040,0x00040000,
+0x00041040,0x00040000,0x10041000,0x00001000,
+0x00000040,0x10040040,0x00001000,0x00041040,
+0x10001000,0x00000040,0x10000040,0x10040000,
+0x10040040,0x10000000,0x00040000,0x10001040,
+0x00000000,0x10041040,0x00040040,0x10000040,
+0x10040000,0x10001000,0x10001040,0x00000000,
+0x10041040,0x00041000,0x00041000,0x00001040,
+0x00001040,0x00040040,0x10000000,0x10041000}
+};
+
+
+static INLINE void IPERM(word32* left, word32* right)
+{
+    word32 work;
+
+    *right = rotlFixed(*right, 4U);
+    work = (*left ^ *right) & 0xf0f0f0f0;
+    *left ^= work;
+
+    *right = rotrFixed(*right^work, 20U);
+    work = (*left ^ *right) & 0xffff0000;
+    *left ^= work;
+
+    *right = rotrFixed(*right^work, 18U);
+    work = (*left ^ *right) & 0x33333333;
+    *left ^= work;
+
+    *right = rotrFixed(*right^work, 6U);
+    work = (*left ^ *right) & 0x00ff00ff;
+    *left ^= work;
+
+    *right = rotlFixed(*right^work, 9U);
+    work = (*left ^ *right) & 0xaaaaaaaa;
+    *left = rotlFixed(*left^work, 1U);
+    *right ^= work;
+}
+
+
+static INLINE void FPERM(word32* left, word32* right)
+{
+    word32 work;
+
+    *right = rotrFixed(*right, 1U);
+    work = (*left ^ *right) & 0xaaaaaaaa;
+    *right ^= work;
+
+    *left = rotrFixed(*left^work, 9U);
+    work = (*left ^ *right) & 0x00ff00ff;
+    *right ^= work;
+
+    *left = rotlFixed(*left^work, 6U);
+    work = (*left ^ *right) & 0x33333333;
+    *right ^= work;
+
+    *left = rotlFixed(*left^work, 18U);
+    work = (*left ^ *right) & 0xffff0000;
+    *right ^= work;
+
+    *left = rotlFixed(*left^work, 20U);
+    work = (*left ^ *right) & 0xf0f0f0f0;
+    *right ^= work;
+
+    *left = rotrFixed(*left^work, 4U);
+}
+
+
+static int DesSetKey(const byte* key, int dir, word32* out)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    byte* buffer = (byte*)XMALLOC(56+56+8, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    if (buffer == NULL)
+        return MEMORY_E;
+#else
+    byte buffer[56+56+8];
+#endif
+
+    {
+        byte* const  pc1m = buffer;               /* place to modify pc1 into */
+        byte* const  pcr  = pc1m + 56;            /* place to rotate pc1 into */
+        byte* const  ks   = pcr  + 56;
+        register int i, j, l;
+        int          m;
+
+        for (j = 0; j < 56; j++) {             /* convert pc1 to bits of key  */
+            l = pc1[j] - 1;                    /* integer bit location        */
+            m = l & 07;                        /* find bit                    */
+            pc1m[j] = (key[l >> 3] &           /* find which key byte l is in */
+                bytebit[m])                    /* and which bit of that byte  */
+                ? 1 : 0;                       /* and store 1-bit result      */
+        }
+
+        for (i = 0; i < 16; i++) {            /* key chunk for each iteration */
+            XMEMSET(ks, 0, 8);                /* Clear key schedule */
+
+            for (j = 0; j < 56; j++)          /* rotate pc1 the right amount  */
+                pcr[j] =
+                      pc1m[(l = j + totrot[i]) < (j < 28 ? 28 : 56) ? l : l-28];
+
+            /* rotate left and right halves independently */
+            for (j = 0; j < 48; j++) {        /* select bits individually     */
+                if (pcr[pc2[j] - 1]) {        /* check bit that goes to ks[j] */
+                    l= j % 6;                 /* mask it in if it's there     */
+                    ks[j/6] |= bytebit[l] >> 2;
+                }
+            }
+
+            /* Now convert to odd/even interleaved form for use in F */
+            out[2*i] = ((word32) ks[0] << 24)
+                     | ((word32) ks[2] << 16)
+                     | ((word32) ks[4] << 8)
+                     | ((word32) ks[6]);
+
+            out[2*i + 1] = ((word32) ks[1] << 24)
+                         | ((word32) ks[3] << 16)
+                         | ((word32) ks[5] << 8)
+                         | ((word32) ks[7]);
+        }
+
+        /* reverse key schedule order */
+        if (dir == DES_DECRYPTION) {
+            for (i = 0; i < 16; i += 2) {
+                word32 swap = out[i];
+                out[i] = out[DES_KS_SIZE - 2 - i];
+                out[DES_KS_SIZE - 2 - i] = swap;
+    
+                swap = out[i + 1];
+                out[i + 1] = out[DES_KS_SIZE - 1 - i];
+                out[DES_KS_SIZE - 1 - i] = swap;
+            }
+        }
+
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+    }
+
+    return 0;
+}
+
+
+static INLINE int Reverse(int dir)
+{
+    return !dir;
+}
+
+
+int wc_Des_SetKey(Des* des, const byte* key, const byte* iv, int dir)
+{
+    wc_Des_SetIV(des, iv);
+
+    return DesSetKey(key, dir, des->key);
+}
+
+
+int wc_Des3_SetKey(Des3* des, const byte* key, const byte* iv, int dir)
+{
+    int ret;
+
+#ifdef HAVE_CAVIUM
+    if (des->magic == WOLFSSL_3DES_CAVIUM_MAGIC)
+        return wc_Des3_CaviumSetKey(des, key, iv);
+#endif
+
+    ret = DesSetKey(key + (dir == DES_ENCRYPTION ? 0:16), dir, des->key[0]);
+    if (ret != 0)
+        return ret;
+
+    ret = DesSetKey(key + 8, Reverse(dir), des->key[1]);
+    if (ret != 0)
+        return ret;
+
+    ret = DesSetKey(key + (dir == DES_DECRYPTION ? 0:16), dir, des->key[2]);
+    if (ret != 0)
+        return ret;
+
+    return wc_Des3_SetIV(des, iv);
+}
+
+
+static void DesRawProcessBlock(word32* lIn, word32* rIn, const word32* kptr)
+{
+    word32 l = *lIn, r = *rIn, i;
+
+    for (i=0; i<8; i++)
+    {
+        word32 work = rotrFixed(r, 4U) ^ kptr[4*i+0];
+        l ^= Spbox[6][(work) & 0x3f]
+          ^  Spbox[4][(work >> 8) & 0x3f]
+          ^  Spbox[2][(work >> 16) & 0x3f]
+          ^  Spbox[0][(work >> 24) & 0x3f];
+        work = r ^ kptr[4*i+1];
+        l ^= Spbox[7][(work) & 0x3f]
+          ^  Spbox[5][(work >> 8) & 0x3f]
+          ^  Spbox[3][(work >> 16) & 0x3f]
+          ^  Spbox[1][(work >> 24) & 0x3f];
+
+        work = rotrFixed(l, 4U) ^ kptr[4*i+2];
+        r ^= Spbox[6][(work) & 0x3f]
+          ^  Spbox[4][(work >> 8) & 0x3f]
+          ^  Spbox[2][(work >> 16) & 0x3f]
+          ^  Spbox[0][(work >> 24) & 0x3f];
+        work = l ^ kptr[4*i+3];
+        r ^= Spbox[7][(work) & 0x3f]
+          ^  Spbox[5][(work >> 8) & 0x3f]
+          ^  Spbox[3][(work >> 16) & 0x3f]
+          ^  Spbox[1][(work >> 24) & 0x3f];
+    }
+
+    *lIn = l; *rIn = r;
+}
+
+
+static void DesProcessBlock(Des* des, const byte* in, byte* out)
+{
+    word32 l, r;
+
+    XMEMCPY(&l, in, sizeof(l));
+    XMEMCPY(&r, in + sizeof(l), sizeof(r));
+    #ifdef LITTLE_ENDIAN_ORDER
+        l = ByteReverseWord32(l);
+        r = ByteReverseWord32(r);
+    #endif
+    IPERM(&l,&r);
+    
+    DesRawProcessBlock(&l, &r, des->key);   
+
+    FPERM(&l,&r);
+    #ifdef LITTLE_ENDIAN_ORDER
+        l = ByteReverseWord32(l);
+        r = ByteReverseWord32(r);
+    #endif
+    XMEMCPY(out, &r, sizeof(r));
+    XMEMCPY(out + sizeof(r), &l, sizeof(l));
+}
+
+
+static void Des3ProcessBlock(Des3* des, const byte* in, byte* out)
+{
+    word32 l, r;
+
+    XMEMCPY(&l, in, sizeof(l));
+    XMEMCPY(&r, in + sizeof(l), sizeof(r));
+    #ifdef LITTLE_ENDIAN_ORDER
+        l = ByteReverseWord32(l);
+        r = ByteReverseWord32(r);
+    #endif
+    IPERM(&l,&r);
+    
+    DesRawProcessBlock(&l, &r, des->key[0]);   
+    DesRawProcessBlock(&r, &l, des->key[1]);   
+    DesRawProcessBlock(&l, &r, des->key[2]);   
+
+    FPERM(&l,&r);
+    #ifdef LITTLE_ENDIAN_ORDER
+        l = ByteReverseWord32(l);
+        r = ByteReverseWord32(r);
+    #endif
+    XMEMCPY(out, &r, sizeof(r));
+    XMEMCPY(out + sizeof(r), &l, sizeof(l));
+}
+
+
+int wc_Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / DES_BLOCK_SIZE;
+
+    while (blocks--) {
+        xorbuf((byte*)des->reg, in, DES_BLOCK_SIZE);
+        DesProcessBlock(des, (byte*)des->reg, (byte*)des->reg);
+        XMEMCPY(out, des->reg, DES_BLOCK_SIZE);
+
+        out += DES_BLOCK_SIZE;
+        in  += DES_BLOCK_SIZE; 
+    }
+    return 0;
+}
+
+
+int wc_Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / DES_BLOCK_SIZE;
+    byte   hold[DES_BLOCK_SIZE];
+
+    while (blocks--) {
+        XMEMCPY(des->tmp, in, DES_BLOCK_SIZE);
+        DesProcessBlock(des, (byte*)des->tmp, out);
+        xorbuf(out, (byte*)des->reg, DES_BLOCK_SIZE);
+
+        XMEMCPY(hold, des->reg, DES_BLOCK_SIZE);
+        XMEMCPY(des->reg, des->tmp, DES_BLOCK_SIZE);
+        XMEMCPY(des->tmp, hold, DES_BLOCK_SIZE);
+
+        out += DES_BLOCK_SIZE;
+        in  += DES_BLOCK_SIZE; 
+    }
+    return 0;
+}
+
+
+int wc_Des3_CbcEncrypt(Des3* des, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks;
+
+#ifdef HAVE_CAVIUM
+    if (des->magic == WOLFSSL_3DES_CAVIUM_MAGIC)
+        return wc_Des3_CaviumCbcEncrypt(des, out, in, sz);
+#endif
+
+    blocks = sz / DES_BLOCK_SIZE;
+    while (blocks--) {
+        xorbuf((byte*)des->reg, in, DES_BLOCK_SIZE);
+        Des3ProcessBlock(des, (byte*)des->reg, (byte*)des->reg);
+        XMEMCPY(out, des->reg, DES_BLOCK_SIZE);
+
+        out += DES_BLOCK_SIZE;
+        in  += DES_BLOCK_SIZE; 
+    }
+    return 0;
+}
+
+
+int wc_Des3_CbcDecrypt(Des3* des, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks;
+
+#ifdef HAVE_CAVIUM
+    if (des->magic == WOLFSSL_3DES_CAVIUM_MAGIC)
+        return wc_Des3_CaviumCbcDecrypt(des, out, in, sz);
+#endif
+
+    blocks = sz / DES_BLOCK_SIZE;
+    while (blocks--) {
+        XMEMCPY(des->tmp, in, DES_BLOCK_SIZE);
+        Des3ProcessBlock(des, (byte*)des->tmp, out);
+        xorbuf(out, (byte*)des->reg, DES_BLOCK_SIZE);
+        XMEMCPY(des->reg, des->tmp, DES_BLOCK_SIZE);
+
+        out += DES_BLOCK_SIZE;
+        in  += DES_BLOCK_SIZE; 
+    }
+    return 0;
+}
+
+#ifdef WOLFSSL_DES_ECB
+
+/* One block, compatibility only */
+int wc_Des_EcbEncrypt(Des* des, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / DES_BLOCK_SIZE;
+
+    while (blocks--) {
+        DesProcessBlock(des, in, out);
+
+        out += DES_BLOCK_SIZE;
+        in  += DES_BLOCK_SIZE; 
+    }
+    return 0;
+}
+
+#endif /* WOLFSSL_DES_ECB */
+
+#endif /* STM32F2_CRYPTO */
+
+void wc_Des_SetIV(Des* des, const byte* iv)
+{
+    if (des && iv)
+        XMEMCPY(des->reg, iv, DES_BLOCK_SIZE);
+    else if (des)
+        XMEMSET(des->reg,  0, DES_BLOCK_SIZE);
+}
+
+
+int wc_Des_CbcDecryptWithKey(byte* out, const byte* in, word32 sz,
+                                                const byte* key, const byte* iv)
+{
+    int ret  = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    Des* des = NULL;
+#else
+    Des  des[1];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    des = (Des*)XMALLOC(sizeof(Des), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (des == NULL)
+        return MEMORY_E;
+#endif
+
+    ret = wc_Des_SetKey(des, key, iv, DES_DECRYPTION);
+    if (ret == 0)
+        ret = wc_Des_CbcDecrypt(des, out, in, sz); 
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(des, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+int wc_Des3_SetIV(Des3* des, const byte* iv)
+{
+    if (des && iv)
+        XMEMCPY(des->reg, iv, DES_BLOCK_SIZE);
+    else if (des)
+        XMEMSET(des->reg,  0, DES_BLOCK_SIZE);
+
+    return 0;
+}
+
+
+int wc_Des3_CbcDecryptWithKey(byte* out, const byte* in, word32 sz,
+                                                const byte* key, const byte* iv)
+{
+    int ret    = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    Des3* des3 = NULL;
+#else
+    Des3  des3[1];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    des3 = (Des3*)XMALLOC(sizeof(Des3), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (des3 == NULL)
+        return MEMORY_E;
+#endif
+
+    ret = wc_Des3_SetKey(des3, key, iv, DES_DECRYPTION);
+    if (ret == 0)
+        ret = wc_Des3_CbcDecrypt(des3, out, in, sz); 
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(des3, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+#ifdef HAVE_CAVIUM
+
+#include "cavium_common.h"
+
+/* Initiliaze Des3 for use with Nitrox device */
+int wc_Des3_InitCavium(Des3* des3, int devId)
+{
+    if (des3 == NULL)
+        return -1;
+
+    if (CspAllocContext(CONTEXT_SSL, &des3->contextHandle, devId) != 0)
+        return -1;
+
+    des3->devId = devId;
+    des3->magic = WOLFSSL_3DES_CAVIUM_MAGIC;
+   
+    return 0;
+}
+
+
+/* Free Des3 from use with Nitrox device */
+void wc_Des3_FreeCavium(Des3* des3)
+{
+    if (des3 == NULL)
+        return;
+
+    if (des3->magic != WOLFSSL_3DES_CAVIUM_MAGIC)
+        return;
+
+    CspFreeContext(CONTEXT_SSL, des3->contextHandle, des3->devId);
+    des3->magic = 0;
+}
+
+
+static int wc_Des3_CaviumSetKey(Des3* des3, const byte* key, const byte* iv)
+{
+    if (des3 == NULL)
+        return -1;
+
+    /* key[0] holds key, iv in reg */
+    XMEMCPY(des3->key[0], key, DES_BLOCK_SIZE*3);
+
+    return wc_Des3_SetIV(des3, iv);
+}
+
+
+static int wc_Des3_CaviumCbcEncrypt(Des3* des3, byte* out, const byte* in,
+                                  word32 length)
+{
+    wolfssl_word offset = 0;
+    word32 requestId;
+   
+    while (length > WOLFSSL_MAX_16BIT) {
+        word16 slen = (word16)WOLFSSL_MAX_16BIT;
+        if (CspEncrypt3Des(CAVIUM_BLOCKING, des3->contextHandle,
+                           CAVIUM_NO_UPDATE, slen, (byte*)in + offset,
+                           out + offset, (byte*)des3->reg, (byte*)des3->key[0],
+                           &requestId, des3->devId) != 0) {
+            WOLFSSL_MSG("Bad Cavium 3DES Cbc Encrypt");
+            return -1;
+        }
+        length -= WOLFSSL_MAX_16BIT;
+        offset += WOLFSSL_MAX_16BIT;
+        XMEMCPY(des3->reg, out + offset - DES_BLOCK_SIZE, DES_BLOCK_SIZE);
+    }
+    if (length) {
+        word16 slen = (word16)length;
+
+        if (CspEncrypt3Des(CAVIUM_BLOCKING, des3->contextHandle,
+                           CAVIUM_NO_UPDATE, slen, (byte*)in + offset,
+                           out + offset, (byte*)des3->reg, (byte*)des3->key[0],
+                           &requestId, des3->devId) != 0) {
+            WOLFSSL_MSG("Bad Cavium 3DES Cbc Encrypt");
+            return -1;
+        }
+        XMEMCPY(des3->reg, out+offset+length - DES_BLOCK_SIZE, DES_BLOCK_SIZE);
+    }
+    return 0;
+}
+
+static int wc_Des3_CaviumCbcDecrypt(Des3* des3, byte* out, const byte* in,
+                                 word32 length)
+{
+    word32 requestId;
+    wolfssl_word offset = 0;
+
+    while (length > WOLFSSL_MAX_16BIT) {
+        word16 slen = (word16)WOLFSSL_MAX_16BIT;
+        XMEMCPY(des3->tmp, in + offset + slen - DES_BLOCK_SIZE, DES_BLOCK_SIZE);
+        if (CspDecrypt3Des(CAVIUM_BLOCKING, des3->contextHandle,
+                           CAVIUM_NO_UPDATE, slen, (byte*)in+offset, out+offset,
+                           (byte*)des3->reg, (byte*)des3->key[0], &requestId,
+                           des3->devId) != 0) {
+            WOLFSSL_MSG("Bad Cavium 3Des Decrypt");
+            return -1;
+        }
+        length -= WOLFSSL_MAX_16BIT;
+        offset += WOLFSSL_MAX_16BIT;
+        XMEMCPY(des3->reg, des3->tmp, DES_BLOCK_SIZE);
+    }
+    if (length) {
+        word16 slen = (word16)length;
+        XMEMCPY(des3->tmp, in + offset + slen - DES_BLOCK_SIZE,DES_BLOCK_SIZE);
+        if (CspDecrypt3Des(CAVIUM_BLOCKING, des3->contextHandle,
+                           CAVIUM_NO_UPDATE, slen, (byte*)in+offset, out+offset,
+                           (byte*)des3->reg, (byte*)des3->key[0], &requestId,
+                           des3->devId) != 0) {
+            WOLFSSL_MSG("Bad Cavium 3Des Decrypt");
+            return -1;
+        }
+        XMEMCPY(des3->reg, des3->tmp, DES_BLOCK_SIZE);
+    }
+    return 0;
+}
+
+#endif /* HAVE_CAVIUM */
+#endif /* WOLFSSL_TI_CRYPT */
+#endif /* HAVE_FIPS */
+#endif /* NO_DES3 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/dh.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,217 @@
+/* dh.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifndef NO_DH
+
+#include <wolfssl/wolfcrypt/dh.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+#ifndef USER_MATH_LIB
+    #include <math.h>
+    #define XPOW(x,y) pow((x),(y))
+    #define XLOG(x)   log((x))
+#else
+    /* user's own math lib */
+#endif
+
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* WOLFSSL_HAVE_MIN */
+
+
+void wc_InitDhKey(DhKey* key)
+{
+    (void)key;
+/* TomsFastMath doesn't use memory allocation */
+#ifndef USE_FAST_MATH
+    key->p.dp = 0;
+    key->g.dp = 0;
+#endif
+}
+
+
+void wc_FreeDhKey(DhKey* key)
+{
+    (void)key;
+/* TomsFastMath doesn't use memory allocation */
+#ifndef USE_FAST_MATH
+    mp_clear(&key->p);
+    mp_clear(&key->g);
+#endif
+}
+
+
+static word32 DiscreteLogWorkFactor(word32 n)
+{
+    /* assuming discrete log takes about the same time as factoring */
+    if (n<5)
+        return 0;
+    else
+        return (word32)(2.4 * XPOW((double)n, 1.0/3.0) *
+                XPOW(XLOG((double)n), 2.0/3.0) - 5);
+}
+
+
+static int GeneratePrivate(DhKey* key, RNG* rng, byte* priv, word32* privSz)
+{
+    int ret;
+    word32 sz = mp_unsigned_bin_size(&key->p);
+    sz = min(sz, 2 * DiscreteLogWorkFactor(sz * WOLFSSL_BIT_SIZE) /
+                                           WOLFSSL_BIT_SIZE + 1);
+
+    ret = wc_RNG_GenerateBlock(rng, priv, sz);
+    if (ret != 0)
+        return ret;
+
+    priv[0] |= 0x0C;
+
+    *privSz = sz;
+
+    return 0;
+}
+
+
+static int GeneratePublic(DhKey* key, const byte* priv, word32 privSz,
+                          byte* pub, word32* pubSz)
+{
+    int ret = 0;
+
+    mp_int x; 
+    mp_int y;
+
+    if (mp_init_multi(&x, &y, 0, 0, 0, 0) != MP_OKAY)
+        return MP_INIT_E;
+
+    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)
+        ret = MP_EXPTMOD_E;
+
+    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);
+
+    return ret;
+}
+
+
+int wc_DhGenerateKeyPair(DhKey* key, RNG* rng, byte* priv, word32* privSz,
+                      byte* pub, word32* pubSz)
+{
+    int ret = GeneratePrivate(key, rng, priv, privSz);
+
+    return (ret != 0) ? ret : GeneratePublic(key, priv, *privSz, pub, pubSz);
+}
+
+int wc_DhAgree(DhKey* key, byte* agree, word32* agreeSz, const byte* priv,
+            word32 privSz, const byte* otherPub, word32 pubSz)
+{
+    int ret = 0;
+
+    mp_int x; 
+    mp_int y;
+    mp_int z;
+
+    if (mp_init_multi(&x, &y, &z, 0, 0, 0) != MP_OKAY)
+        return MP_INIT_E;
+
+    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)
+        ret = MP_READ_E;
+
+    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)
+        ret = MP_TO_E;
+
+    if (ret == 0)
+        *agreeSz = mp_unsigned_bin_size(&z);
+
+    mp_clear(&z);
+    mp_clear(&y);
+    mp_clear(&x);
+
+    return ret;
+}
+
+
+/* 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;
+}
+
+
+#endif /* NO_DH */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/dsa.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,233 @@
+/* dsa.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifndef NO_DSA
+
+#include <wolfssl/wolfcrypt/dsa.h>
+#include <wolfssl/wolfcrypt/sha.h>
+#include <wolfssl/wolfcrypt/random.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+
+enum {
+    DSA_HALF_SIZE = 20,   /* r and s size  */
+    DSA_SIG_SIZE  = 40    /* signature size */
+};
+
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* WOLFSSL_HAVE_MIN */
+
+
+void wc_InitDsaKey(DsaKey* key)
+{
+    key->type = -1;  /* haven't decided yet */
+
+/* TomsFastMath doesn't use memory allocation */
+#ifndef USE_FAST_MATH
+    key->p.dp = 0;   /* public  alloc parts */
+    key->q.dp = 0;    
+    key->g.dp = 0;    
+    key->y.dp = 0;    
+
+    key->x.dp = 0;   /* private alloc parts */
+#endif
+}
+
+
+void wc_FreeDsaKey(DsaKey* key)
+{
+    (void)key;
+/* TomsFastMath doesn't use memory allocation */
+#ifndef USE_FAST_MATH
+    if (key->type == DSA_PRIVATE)
+        mp_clear(&key->x);
+    mp_clear(&key->y);
+    mp_clear(&key->g);
+    mp_clear(&key->q);
+    mp_clear(&key->p);
+#endif
+}
+
+
+int wc_DsaSign(const byte* digest, byte* out, DsaKey* key, RNG* rng)
+{
+    mp_int k, kInv, r, s, H;
+    int    ret, sz;
+    byte   buffer[DSA_HALF_SIZE];
+
+    sz = min(sizeof(buffer), mp_unsigned_bin_size(&key->q));
+
+    /* generate k */
+    ret = wc_RNG_GenerateBlock(rng, buffer, sz);
+    if (ret != 0)
+        return ret;
+
+    buffer[0] |= 0x0C;
+
+    if (mp_init_multi(&k, &kInv, &r, &s, &H, 0) != MP_OKAY)
+        return MP_INIT_E;
+
+    if (mp_read_unsigned_bin(&k, buffer, sz) != MP_OKAY)
+        ret = MP_READ_E;
+
+    if (ret == 0 && mp_cmp_d(&k, 1) != MP_GT)
+        ret = MP_CMP_E;
+
+    /* inverse k mod q */
+    if (ret == 0 && mp_invmod(&k, &key->q, &kInv) != MP_OKAY)
+        ret = MP_INVMOD_E;
+
+    /* generate r, r = (g exp k mod p) mod q */
+    if (ret == 0 && mp_exptmod(&key->g, &k, &key->p, &r) != MP_OKAY)
+        ret = MP_EXPTMOD_E;
+
+    if (ret == 0 && mp_mod(&r, &key->q, &r) != MP_OKAY)
+        ret = MP_MOD_E;
+
+    /* generate H from sha digest */
+    if (ret == 0 && mp_read_unsigned_bin(&H, digest,SHA_DIGEST_SIZE) != MP_OKAY)
+        ret = MP_READ_E;
+
+    /* generate s, s = (kInv * (H + x*r)) % q */
+    if (ret == 0 && mp_mul(&key->x, &r, &s) != MP_OKAY)
+        ret = MP_MUL_E;
+
+    if (ret == 0 && mp_add(&s, &H, &s) != MP_OKAY)
+        ret = MP_ADD_E;
+
+    if (ret == 0 && mp_mulmod(&s, &kInv, &key->q, &s) != MP_OKAY)
+        ret = MP_MULMOD_E;
+
+    /* write out */
+    if (ret == 0)  {
+        int rSz = mp_unsigned_bin_size(&r);
+        int sSz = mp_unsigned_bin_size(&s);
+
+        if (rSz == DSA_HALF_SIZE - 1) {
+            out[0] = 0;
+            out++;
+        }
+
+        if (mp_to_unsigned_bin(&r, out) != MP_OKAY)
+            ret = MP_TO_E;
+        else {
+            if (sSz == DSA_HALF_SIZE - 1) {
+                out[rSz] = 0;
+                out++;
+            }    
+            ret = mp_to_unsigned_bin(&s, out + rSz);
+        }
+    }
+
+    mp_clear(&H);
+    mp_clear(&s);
+    mp_clear(&r);
+    mp_clear(&kInv);
+    mp_clear(&k);
+
+    return ret;
+}
+
+
+int wc_DsaVerify(const byte* digest, const byte* sig, DsaKey* key, int* answer)
+{
+    mp_int w, u1, u2, v, r, s;
+    int    ret = 0;
+
+    if (mp_init_multi(&w, &u1, &u2, &v, &r, &s) != MP_OKAY)
+        return MP_INIT_E;
+
+    /* set r and s from signature */
+    if (mp_read_unsigned_bin(&r, sig, DSA_HALF_SIZE) != MP_OKAY ||
+        mp_read_unsigned_bin(&s, sig + DSA_HALF_SIZE, DSA_HALF_SIZE) != MP_OKAY)
+        ret = MP_READ_E;
+
+    /* sanity checks */
+    if (ret == 0) {
+        if (mp_iszero(&r) == MP_YES || mp_iszero(&s) == MP_YES ||
+                mp_cmp(&r, &key->q) != MP_LT || mp_cmp(&s, &key->q) != MP_LT) {
+            ret = MP_ZERO_E;
+        }
+    }
+
+    /* put H into u1 from sha digest */
+    if (ret == 0 && mp_read_unsigned_bin(&u1,digest,SHA_DIGEST_SIZE) != MP_OKAY)
+        ret = MP_READ_E;
+
+    /* w = s invmod q */
+    if (ret == 0 && mp_invmod(&s, &key->q, &w) != MP_OKAY)
+        ret = MP_INVMOD_E;
+
+    /* u1 = (H * w) % q */
+    if (ret == 0 && mp_mulmod(&u1, &w, &key->q, &u1) != MP_OKAY)
+        ret = MP_MULMOD_E;
+
+    /* u2 = (r * w) % q */
+    if (ret == 0 && mp_mulmod(&r, &w, &key->q, &u2) != MP_OKAY)
+        ret = MP_MULMOD_E;
+
+    /* verify v = ((g^u1 * y^u2) mod p) mod q */
+    if (ret == 0 && mp_exptmod(&key->g, &u1, &key->p, &u1) != MP_OKAY)
+        ret = MP_EXPTMOD_E;
+
+    if (ret == 0 && mp_exptmod(&key->y, &u2, &key->p, &u2) != MP_OKAY)
+        ret = MP_EXPTMOD_E;
+
+    if (ret == 0 && mp_mulmod(&u1, &u2, &key->p, &v) != MP_OKAY)
+        ret = MP_MULMOD_E;
+
+    if (ret == 0 && mp_mod(&v, &key->q, &v) != MP_OKAY)
+        ret = MP_MULMOD_E;
+
+    /* do they match */
+    if (ret == 0 && mp_cmp(&r, &v) == MP_EQ)
+        *answer = 1;
+    else
+        *answer = 0;
+
+    mp_clear(&s);
+    mp_clear(&r);
+    mp_clear(&u1);
+    mp_clear(&u2);
+    mp_clear(&w);
+    mp_clear(&v);
+
+    return ret;
+}
+
+
+#endif /* NO_DSA */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/ecc.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,5187 @@
+/* ecc.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+/* in case user set HAVE_ECC there */
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_ECC
+
+#include <wolfssl/wolfcrypt/ecc.h>
+#include <wolfssl/wolfcrypt/asn.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+#ifdef HAVE_ECC_ENCRYPT
+    #include <wolfssl/wolfcrypt/hmac.h>
+    #include <wolfssl/wolfcrypt/aes.h>
+#endif
+
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+/* map
+
+   ptmul -> mulmod
+
+*/
+
+
+/* p256 curve on by default whether user curves or not */
+#if defined(HAVE_ECC112) || defined(HAVE_ALL_CURVES)
+    #define ECC112
+#endif
+#if defined(HAVE_ECC128) || defined(HAVE_ALL_CURVES)
+    #define ECC128
+#endif
+#if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES)
+    #define ECC160
+#endif
+#if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)
+    #define ECC192
+#endif
+#if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)
+    #define ECC224
+#endif
+#if !defined(NO_ECC256)  || defined(HAVE_ALL_CURVES)
+    #define ECC256
+#endif
+#if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+    #define ECC384
+#endif
+#if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+    #define ECC521
+#endif
+
+
+
+/* This holds the key settings.  ***MUST*** be organized by size from
+   smallest to largest. */
+
+const ecc_set_type ecc_sets[] = {
+#ifdef ECC112
+{
+        14,
+        "SECP112R1",
+        "DB7C2ABF62E35E668076BEAD208B",
+        "DB7C2ABF62E35E668076BEAD2088",
+        "659EF8BA043916EEDE8911702B22",
+        "DB7C2ABF62E35E7628DFAC6561C5",
+        "09487239995A5EE76B55F9C2F098",
+        "A89CE5AF8724C0A23E0E0FF77500"
+},
+#endif
+#ifdef ECC128
+{
+        16,
+        "SECP128R1",
+        "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF",
+        "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC",
+        "E87579C11079F43DD824993C2CEE5ED3",
+        "FFFFFFFE0000000075A30D1B9038A115",
+        "161FF7528B899B2D0C28607CA52C5B86",
+        "CF5AC8395BAFEB13C02DA292DDED7A83",
+},
+#endif
+#ifdef ECC160
+{
+        20,
+        "SECP160R1",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC",
+        "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45",
+        "0100000000000000000001F4C8F927AED3CA752257",
+        "4A96B5688EF573284664698968C38BB913CBFC82",
+        "23A628553168947D59DCC912042351377AC5FB32",
+},
+#endif
+#ifdef ECC192
+{
+        24,
+        "ECC-192",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC",
+        "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1",
+        "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831",
+        "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
+        "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
+},
+#endif
+#ifdef ECC224
+{
+        28,
+        "ECC-224",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE",
+        "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D",
+        "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21",
+        "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34",
+},
+#endif
+#ifdef ECC256
+{
+        32,
+        "ECC-256",
+        "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
+        "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
+        "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
+        "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
+        "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
+        "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
+},
+#endif
+#ifdef ECC384
+{
+        48,
+        "ECC-384",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
+        "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
+        "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
+        "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
+},
+#endif
+#ifdef ECC521
+{
+        66,
+        "ECC-521",
+        "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+        "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
+        "51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
+        "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
+        "C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
+        "11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
+},
+#endif
+{
+   0,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL
+}
+};
+
+
+ecc_point* ecc_new_point(void);
+void ecc_del_point(ecc_point* p);
+int  ecc_map(ecc_point*, mp_int*, mp_digit*);
+int  ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R,
+                              mp_int* modulus, mp_digit* mp);
+int  ecc_projective_dbl_point(ecc_point* P, ecc_point* R, mp_int* modulus,
+                              mp_digit* mp);
+static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus,
+                      int map);
+static int ecc_check_pubkey_order(ecc_key* key, 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* modulus);
+#endif
+
+int mp_jacobi(mp_int* a, mp_int* p, int* c);
+int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret);
+int mp_submod(mp_int* a, mp_int* b, mp_int* c, mp_int* d);
+
+#ifdef HAVE_COMP_KEY
+static int wc_ecc_export_x963_compressed(ecc_key*, byte* out, word32* outLen);
+#endif
+
+/* helper for either lib */
+static int get_digit_count(mp_int* a)
+{
+    if (a == NULL)
+        return 0;
+
+    return a->used;
+}
+
+/* helper for either lib */
+static mp_digit get_digit(mp_int* a, int n)
+{
+    if (a == NULL)
+        return 0;
+
+    return (n >= a->used || n < 0) ? 0 : a->dp[n];
+}
+
+
+#if defined(USE_FAST_MATH)
+
+/* fast math accelerated version, but not for fp ecc yet */
+
+/**
+   Add two ECC points
+   P        The point to add
+   Q        The point to add
+   R        [out] The destination of the double
+   modulus  The modulus of the field the ECC curve is in
+   mp       The "b" value from montgomery_setup()
+   return   MP_OKAY on success
+*/
+int ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R,
+                             mp_int* modulus, mp_digit* mp)
+{
+   fp_int t1, t2, x, y, z;
+   int    err;
+
+   if (P == NULL || Q == NULL || R == NULL || modulus == NULL || mp == NULL)
+       return ECC_BAD_ARG_E;
+
+   if ((err = mp_init_multi(&t1, &t2, &x, &y, &z, NULL)) != MP_OKAY) {
+      return err;
+   }
+
+   /* should we dbl instead? */
+   fp_sub(modulus, Q->y, &t1);
+   if ( (fp_cmp(P->x, Q->x) == FP_EQ) && 
+        (get_digit_count(Q->z) && fp_cmp(P->z, Q->z) == FP_EQ) &&
+        (fp_cmp(P->y, Q->y) == FP_EQ || fp_cmp(P->y, &t1) == FP_EQ)) {
+        return ecc_projective_dbl_point(P, R, modulus, mp);
+   }
+
+   fp_copy(P->x, &x);
+   fp_copy(P->y, &y);
+   fp_copy(P->z, &z);
+
+   /* if Z is one then these are no-operations */
+   if (get_digit_count(Q->z)) {
+      /* T1 = Z' * Z' */
+      fp_sqr(Q->z, &t1);
+      fp_montgomery_reduce(&t1, modulus, *mp);
+      /* X = X * T1 */
+      fp_mul(&t1, &x, &x);
+      fp_montgomery_reduce(&x, modulus, *mp);
+      /* T1 = Z' * T1 */
+      fp_mul(Q->z, &t1, &t1);
+      fp_montgomery_reduce(&t1, modulus, *mp);
+      /* Y = Y * T1 */
+      fp_mul(&t1, &y, &y);
+      fp_montgomery_reduce(&y, modulus, *mp);
+   }
+
+   /* T1 = Z*Z */
+   fp_sqr(&z, &t1);
+   fp_montgomery_reduce(&t1, modulus, *mp);
+   /* T2 = X' * T1 */
+   fp_mul(Q->x, &t1, &t2);
+   fp_montgomery_reduce(&t2, modulus, *mp);
+   /* T1 = Z * T1 */
+   fp_mul(&z, &t1, &t1);
+   fp_montgomery_reduce(&t1, modulus, *mp);
+   /* T1 = Y' * T1 */
+   fp_mul(Q->y, &t1, &t1);
+   fp_montgomery_reduce(&t1, modulus, *mp);
+
+   /* Y = Y - T1 */
+   fp_sub(&y, &t1, &y);
+   if (fp_cmp_d(&y, 0) == FP_LT) {
+      fp_add(&y, modulus, &y);
+   }
+   /* T1 = 2T1 */
+   fp_add(&t1, &t1, &t1);
+   if (fp_cmp(&t1, modulus) != FP_LT) {
+      fp_sub(&t1, modulus, &t1);
+   }
+   /* T1 = Y + T1 */
+   fp_add(&t1, &y, &t1);
+   if (fp_cmp(&t1, modulus) != FP_LT) {
+      fp_sub(&t1, modulus, &t1);
+   }
+   /* X = X - T2 */
+   fp_sub(&x, &t2, &x);
+   if (fp_cmp_d(&x, 0) == FP_LT) {
+      fp_add(&x, modulus, &x);
+   }
+   /* T2 = 2T2 */
+   fp_add(&t2, &t2, &t2);
+   if (fp_cmp(&t2, modulus) != FP_LT) {
+      fp_sub(&t2, modulus, &t2);
+   }
+   /* T2 = X + T2 */
+   fp_add(&t2, &x, &t2);
+   if (fp_cmp(&t2, modulus) != FP_LT) {
+      fp_sub(&t2, modulus, &t2);
+   }
+
+   /* if Z' != 1 */
+   if (get_digit_count(Q->z)) {
+      /* Z = Z * Z' */
+      fp_mul(&z, Q->z, &z);
+      fp_montgomery_reduce(&z, modulus, *mp);
+   }
+
+   /* Z = Z * X */
+   fp_mul(&z, &x, &z);
+   fp_montgomery_reduce(&z, modulus, *mp);
+
+   /* T1 = T1 * X  */
+   fp_mul(&t1, &x, &t1);
+   fp_montgomery_reduce(&t1, modulus, *mp);
+   /* X = X * X */
+   fp_sqr(&x, &x);
+   fp_montgomery_reduce(&x, modulus, *mp);
+   /* T2 = T2 * x */
+   fp_mul(&t2, &x, &t2);
+   fp_montgomery_reduce(&t2, modulus, *mp);
+   /* T1 = T1 * X  */
+   fp_mul(&t1, &x, &t1);
+   fp_montgomery_reduce(&t1, modulus, *mp);
+ 
+   /* X = Y*Y */
+   fp_sqr(&y, &x);
+   fp_montgomery_reduce(&x, modulus, *mp);
+   /* X = X - T2 */
+   fp_sub(&x, &t2, &x);
+   if (fp_cmp_d(&x, 0) == FP_LT) {
+      fp_add(&x, modulus, &x);
+   }
+
+   /* T2 = T2 - X */
+   fp_sub(&t2, &x, &t2);
+   if (fp_cmp_d(&t2, 0) == FP_LT) {
+      fp_add(&t2, modulus, &t2);
+   } 
+   /* T2 = T2 - X */
+   fp_sub(&t2, &x, &t2);
+   if (fp_cmp_d(&t2, 0) == FP_LT) {
+      fp_add(&t2, modulus, &t2);
+   }
+   /* T2 = T2 * Y */
+   fp_mul(&t2, &y, &t2);
+   fp_montgomery_reduce(&t2, modulus, *mp);
+   /* Y = T2 - T1 */
+   fp_sub(&t2, &t1, &y);
+   if (fp_cmp_d(&y, 0) == FP_LT) {
+      fp_add(&y, modulus, &y);
+   }
+   /* Y = Y/2 */
+   if (fp_isodd(&y)) {
+      fp_add(&y, modulus, &y);
+   }
+   fp_div_2(&y, &y);
+
+   fp_copy(&x, R->x);
+   fp_copy(&y, R->y);
+   fp_copy(&z, R->z);
+   
+   return MP_OKAY;
+}
+
+
+/**
+   Double an ECC point
+   P   The point to double
+   R   [out] The destination of the double
+   modulus  The modulus of the field the ECC curve is in
+   mp       The "b" value from montgomery_setup()
+   return   MP_OKAY on success
+*/
+int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* modulus,
+                             mp_digit* mp)
+{
+   fp_int   t1, t2;
+   int      err;
+
+   if (P == NULL || R == NULL || modulus == NULL || mp == NULL)
+       return ECC_BAD_ARG_E;
+
+   if (P != R) {
+      fp_copy(P->x, R->x);
+      fp_copy(P->y, R->y);
+      fp_copy(P->z, R->z);
+   }
+
+   if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+      return err;
+   }
+
+   /* t1 = Z * Z */
+   fp_sqr(R->z, &t1);
+   fp_montgomery_reduce(&t1, modulus, *mp);
+   /* Z = Y * Z */
+   fp_mul(R->z, R->y, R->z);
+   fp_montgomery_reduce(R->z, modulus, *mp);
+   /* Z = 2Z */
+   fp_add(R->z, R->z, R->z);
+   if (fp_cmp(R->z, modulus) != FP_LT) {
+      fp_sub(R->z, modulus, R->z);
+   }
+   
+   /* &t2 = X - T1 */
+   fp_sub(R->x, &t1, &t2);
+   if (fp_cmp_d(&t2, 0) == FP_LT) {
+      fp_add(&t2, modulus, &t2);
+   }
+   /* T1 = X + T1 */
+   fp_add(&t1, R->x, &t1);
+   if (fp_cmp(&t1, modulus) != FP_LT) {
+      fp_sub(&t1, modulus, &t1);
+   }
+   /* T2 = T1 * T2 */
+   fp_mul(&t1, &t2, &t2);
+   fp_montgomery_reduce(&t2, modulus, *mp);
+   /* T1 = 2T2 */
+   fp_add(&t2, &t2, &t1);
+   if (fp_cmp(&t1, modulus) != FP_LT) {
+      fp_sub(&t1, modulus, &t1);
+   }
+   /* T1 = T1 + T2 */
+   fp_add(&t1, &t2, &t1);
+   if (fp_cmp(&t1, modulus) != FP_LT) {
+      fp_sub(&t1, modulus, &t1);
+   }
+
+   /* Y = 2Y */
+   fp_add(R->y, R->y, R->y);
+   if (fp_cmp(R->y, modulus) != FP_LT) {
+      fp_sub(R->y, modulus, R->y);
+   }
+   /* Y = Y * Y */
+   fp_sqr(R->y, R->y);
+   fp_montgomery_reduce(R->y, modulus, *mp);
+   /* T2 = Y * Y */
+   fp_sqr(R->y, &t2);
+   fp_montgomery_reduce(&t2, modulus, *mp);
+   /* T2 = T2/2 */
+   if (fp_isodd(&t2)) {
+      fp_add(&t2, modulus, &t2);
+   }
+   fp_div_2(&t2, &t2);
+   /* Y = Y * X */
+   fp_mul(R->y, R->x, R->y);
+   fp_montgomery_reduce(R->y, modulus, *mp);
+
+   /* X  = T1 * T1 */
+   fp_sqr(&t1, R->x);
+   fp_montgomery_reduce(R->x, modulus, *mp);
+   /* X = X - Y */
+   fp_sub(R->x, R->y, R->x);
+   if (fp_cmp_d(R->x, 0) == FP_LT) {
+      fp_add(R->x, modulus, R->x);
+   }
+   /* X = X - Y */
+   fp_sub(R->x, R->y, R->x);
+   if (fp_cmp_d(R->x, 0) == FP_LT) {
+      fp_add(R->x, modulus, R->x);
+   }
+
+   /* Y = Y - X */     
+   fp_sub(R->y, R->x, R->y);
+   if (fp_cmp_d(R->y, 0) == FP_LT) {
+      fp_add(R->y, modulus, R->y);
+   }
+   /* Y = Y * T1 */
+   fp_mul(R->y, &t1, R->y);
+   fp_montgomery_reduce(R->y, modulus, *mp);
+   /* Y = Y - T2 */
+   fp_sub(R->y, &t2, R->y);
+   if (fp_cmp_d(R->y, 0) == FP_LT) {
+      fp_add(R->y, modulus, R->y);
+   }
+ 
+   return MP_OKAY;
+}
+
+#else /* USE_FAST_MATH */
+
+/**
+   Add two ECC points
+   P        The point to add
+   Q        The point to add
+   R        [out] The destination of the double
+   modulus  The modulus of the field the ECC curve is in
+   mp       The "b" value from montgomery_setup()
+   return   MP_OKAY on success
+*/
+int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R,
+                             mp_int* modulus, mp_digit* mp)
+{
+   mp_int t1;
+   mp_int t2;
+   mp_int x;
+   mp_int y;
+   mp_int z;
+   int    err;
+
+   if (P == NULL || Q == NULL || R == NULL || modulus == NULL || mp == NULL)
+       return ECC_BAD_ARG_E;
+
+   if ((err = mp_init_multi(&t1, &t2, &x, &y, &z, NULL)) != MP_OKAY) {
+      return err;
+   }
+   
+   /* should we dbl instead? */
+   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_clear(&x);
+                mp_clear(&y);
+                mp_clear(&z);
+
+                return ecc_projective_dbl_point(P, R, modulus, mp);
+       }
+   }
+
+   if (err == MP_OKAY)
+       err = mp_copy(P->x, &x);
+   if (err == MP_OKAY)
+       err = mp_copy(P->y, &y);
+   if (err == MP_OKAY)
+       err = mp_copy(P->z, &z);
+
+   /* if Z is one then these are no-operations */
+   if (err == MP_OKAY) {
+       if (get_digit_count(Q->z)) {
+           /* T1 = Z' * Z' */
+           err = mp_sqr(Q->z, &t1);
+           if (err == MP_OKAY)
+               err = mp_montgomery_reduce(&t1, modulus, *mp);
+
+           /* X = X * T1 */
+           if (err == MP_OKAY)
+               err = mp_mul(&t1, &x, &x);
+           if (err == MP_OKAY)
+               err = mp_montgomery_reduce(&x, modulus, *mp);
+
+           /* T1 = Z' * T1 */
+           if (err == MP_OKAY)
+               err = mp_mul(Q->z, &t1, &t1);
+           if (err == MP_OKAY)
+               err = mp_montgomery_reduce(&t1, modulus, *mp);
+
+           /* Y = Y * T1 */
+           if (err == MP_OKAY)
+               err = mp_mul(&t1, &y, &y);
+           if (err == MP_OKAY)
+               err = mp_montgomery_reduce(&y, modulus, *mp);
+       }
+   }
+
+   /* T1 = Z*Z */
+   if (err == MP_OKAY)
+       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);
+
+   /* T1 = Z * T1 */
+   if (err == MP_OKAY)
+       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);
+
+   /* Y = Y - T1 */
+   if (err == MP_OKAY)
+       err = mp_sub(&y, &t1, &y);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&y, 0) == MP_LT)
+           err = mp_add(&y, modulus, &y);
+   }
+   /* T1 = 2T1 */
+   if (err == MP_OKAY)
+       err = mp_add(&t1, &t1, &t1);
+   if (err == MP_OKAY) {
+       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);
+   if (err == MP_OKAY) {
+       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);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&x, 0) == MP_LT)
+           err = mp_add(&x, modulus, &x);
+   }
+   /* T2 = 2T2 */
+   if (err == MP_OKAY)
+       err = mp_add(&t2, &t2, &t2);
+   if (err == MP_OKAY) {
+       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);
+   if (err == MP_OKAY) {
+       if (mp_cmp(&t2, modulus) != MP_LT)
+           err = mp_sub(&t2, modulus, &t2);
+   }
+
+   if (err == MP_OKAY) {
+       if (get_digit_count(Q->z)) {
+           /* Z = Z * Z' */
+           err = mp_mul(&z, Q->z, &z);
+           if (err == MP_OKAY)
+               err = mp_montgomery_reduce(&z, modulus, *mp);
+       }
+   }
+
+   /* Z = Z * X */
+   if (err == MP_OKAY)
+       err = mp_mul(&z, &x, &z);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&z, 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);
+
+   /* X = X * X */
+   if (err == MP_OKAY)
+       err = mp_sqr(&x, &x);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&x, modulus, *mp);
+   
+   /* T2 = T2 * x */
+   if (err == MP_OKAY)
+       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);
+ 
+   /* X = Y*Y */
+   if (err == MP_OKAY)
+       err = mp_sqr(&y, &x);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&x, modulus, *mp);
+
+   /* X = X - T2 */
+   if (err == MP_OKAY)
+       err = mp_sub(&x, &t2, &x);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&x, 0) == MP_LT)
+           err = mp_add(&x, modulus, &x);
+   }
+   /* T2 = T2 - X */
+   if (err == MP_OKAY)
+       err = mp_sub(&t2, &x, &t2);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&t2, 0) == MP_LT)
+           err = mp_add(&t2, modulus, &t2);
+   } 
+   /* T2 = T2 - X */
+   if (err == MP_OKAY)
+       err = mp_sub(&t2, &x, &t2);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&t2, 0) == MP_LT)
+           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);
+
+   /* Y = T2 - T1 */
+   if (err == MP_OKAY)
+       err = mp_sub(&t2, &t1, &y);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&y, 0) == MP_LT)
+           err = mp_add(&y, modulus, &y);
+   }
+   /* Y = Y/2 */
+   if (err == MP_OKAY) {
+       if (mp_isodd(&y))
+           err = mp_add(&y, modulus, &y);
+   }
+   if (err == MP_OKAY)
+       err = mp_div_2(&y, &y);
+
+   if (err == MP_OKAY)
+       err = mp_copy(&x, R->x);
+   if (err == MP_OKAY)
+       err = mp_copy(&y, R->y);
+   if (err == MP_OKAY)
+       err = mp_copy(&z, R->z);
+
+   /* clean up */
+   mp_clear(&t1);
+   mp_clear(&t2);
+   mp_clear(&x);
+   mp_clear(&y);
+   mp_clear(&z);
+
+   return err;
+}
+
+
+/**
+   Double an ECC point
+   P   The point to double
+   R   [out] The destination of the double
+   modulus  The modulus of the field the ECC curve is in
+   mp       The "b" value from montgomery_setup()
+   return   MP_OKAY on success
+*/
+int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* modulus,
+                             mp_digit* mp)
+{
+   mp_int t1;
+   mp_int t2;
+   int    err;
+
+   if (P == NULL || R == NULL || modulus == NULL || mp == NULL)
+       return ECC_BAD_ARG_E;
+
+   if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+      return err;
+   }
+
+   if (P != R) {
+      err = mp_copy(P->x, R->x);
+      if (err == MP_OKAY)
+          err = mp_copy(P->y, R->y);
+      if (err == MP_OKAY)
+          err = mp_copy(P->z, R->z);
+   }
+
+   /* t1 = Z * Z */
+   if (err == MP_OKAY)
+       err = mp_sqr(R->z, &t1);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&t1, modulus, *mp);
+
+   /* Z = Y * Z */
+   if (err == MP_OKAY)
+       err = mp_mul(R->z, R->y, R->z);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(R->z, modulus, *mp);
+
+   /* Z = 2Z */
+   if (err == MP_OKAY)
+       err = mp_add(R->z, R->z, R->z);
+   if (err == MP_OKAY) {
+       if (mp_cmp(R->z, modulus) != MP_LT)
+           err = mp_sub(R->z, modulus, R->z);
+   }
+
+   /* T2 = X - T1 */
+   if (err == MP_OKAY)
+       err = mp_sub(R->x, &t1, &t2);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&t2, 0) == MP_LT)
+           err = mp_add(&t2, modulus, &t2);
+   }
+   /* T1 = X + T1 */
+   if (err == MP_OKAY)
+       err = mp_add(&t1, R->x, &t1);
+   if (err == MP_OKAY) {
+       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);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&t2, modulus, *mp);
+
+   /* T1 = 2T2 */
+   if (err == MP_OKAY)
+       err = mp_add(&t2, &t2, &t1);
+   if (err == MP_OKAY) {
+       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);
+   if (err == MP_OKAY) {
+       if (mp_cmp(&t1, modulus) != MP_LT)
+           err = mp_sub(&t1, modulus, &t1);
+   }
+   /* Y = 2Y */
+   if (err == MP_OKAY)
+       err = mp_add(R->y, R->y, R->y);
+   if (err == MP_OKAY) {
+       if (mp_cmp(R->y, modulus) != MP_LT)
+           err = mp_sub(R->y, modulus, R->y);
+   }
+   /* Y = Y * Y */
+   if (err == MP_OKAY)
+       err = mp_sqr(R->y, R->y);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(R->y, modulus, *mp);
+   
+   /* T2 = Y * Y */
+   if (err == MP_OKAY)
+       err = mp_sqr(R->y, &t2);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&t2, modulus, *mp);
+
+   /* T2 = T2/2 */
+   if (err == MP_OKAY) {
+       if (mp_isodd(&t2))
+           err = mp_add(&t2, modulus, &t2);
+   }
+   if (err == MP_OKAY)
+       err = mp_div_2(&t2, &t2);
+   
+   /* Y = Y * X */
+   if (err == MP_OKAY)
+       err = mp_mul(R->y, R->x, R->y);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(R->y, modulus, *mp);
+
+   /* X  = T1 * T1 */
+   if (err == MP_OKAY)
+       err = mp_sqr(&t1, R->x);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(R->x, modulus, *mp);
+
+   /* X = X - Y */
+   if (err == MP_OKAY)
+       err = mp_sub(R->x, R->y, R->x);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(R->x, 0) == MP_LT)
+           err = mp_add(R->x, modulus, R->x);
+   }
+   /* X = X - Y */
+   if (err == MP_OKAY)
+       err = mp_sub(R->x, R->y, R->x);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(R->x, 0) == MP_LT)
+           err = mp_add(R->x, modulus, R->x);
+   }
+   /* Y = Y - X */     
+   if (err == MP_OKAY)
+       err = mp_sub(R->y, R->x, R->y);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(R->y, 0) == MP_LT)
+           err = mp_add(R->y, modulus, R->y);
+   }
+   /* Y = Y * T1 */
+   if (err == MP_OKAY)
+       err = mp_mul(R->y, &t1, R->y);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(R->y, modulus, *mp);
+
+   /* Y = Y - T2 */
+   if (err == MP_OKAY)
+       err = mp_sub(R->y, &t2, R->y);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(R->y, 0) == MP_LT)
+           err = mp_add(R->y, modulus, R->y);
+   }
+
+   /* clean up */ 
+   mp_clear(&t1);
+   mp_clear(&t2);
+
+   return err;
+}
+
+#endif /* USE_FAST_MATH */
+
+/**
+  Map a projective jacbobian point back to affine space
+  P        [in/out] The point to map
+  modulus  The modulus of the field the ECC curve is in
+  mp       The "b" value from montgomery_setup()
+  return   MP_OKAY on success
+*/
+int ecc_map(ecc_point* P, mp_int* modulus, mp_digit* mp)
+{
+   mp_int t1;
+   mp_int t2;
+   int    err;
+
+   if (P == NULL || mp == NULL || modulus == NULL)
+       return ECC_BAD_ARG_E;
+
+   /* special case for point at infinity */
+   if (mp_cmp_d(P->z, 0) == MP_EQ) {
+       mp_set(P->x, 0);
+       mp_set(P->y, 0);
+       mp_set(P->z, 1);
+       return MP_OKAY;
+   }
+
+   if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+      return MEMORY_E;
+   }
+
+   /* first map z back to normal */
+   err = mp_montgomery_reduce(P->z, modulus, *mp);
+
+   /* get 1/z */
+   if (err == MP_OKAY)
+       err = mp_invmod(P->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);
+
+   /* multiply against x/y */
+   if (err == MP_OKAY)
+       err = mp_mul(P->x, &t2, P->x);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(P->x, modulus, *mp);
+   if (err == MP_OKAY)
+       err = mp_mul(P->y, &t1, P->y);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(P->y, modulus, *mp);
+   
+   if (err == MP_OKAY)
+       mp_set(P->z, 1);
+
+   /* clean up */
+   mp_clear(&t1);
+   mp_clear(&t2);
+
+   return err;
+}
+
+
+#ifndef ECC_TIMING_RESISTANT
+
+/* size of sliding window, don't change this! */
+#define WINSIZE 4
+
+/**
+   Perform a point multiplication 
+   k    The scalar to multiply by
+   G    The base point
+   R    [out] Destination for kG
+   modulus  The modulus of the field the ECC curve is in
+   map      Boolean whether to map back to affine or not
+                (1==map, 0 == leave in projective)
+   return MP_OKAY on success
+*/
+#ifdef FP_ECC
+static int normal_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R,
+                             mp_int* modulus, int map)
+#else
+static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus,
+                      int map)
+#endif
+{
+   ecc_point *tG, *M[8];
+   int           i, j, err;
+   mp_int        mu;
+   mp_digit      mp;
+   mp_digit      buf;
+   int           first = 1, bitbuf = 0, bitcpy = 0, bitcnt = 0, mode = 0,
+                 digidx = 0;
+
+   if (k == NULL || G == NULL || R == NULL || modulus == NULL)
+       return ECC_BAD_ARG_E;
+
+   /* init montgomery reduction */
+   if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) {
+      return err;
+   }
+   if ((err = mp_init(&mu)) != MP_OKAY) {
+      return err;
+   }
+   if ((err = mp_montgomery_calc_normalization(&mu, modulus)) != MP_OKAY) {
+      mp_clear(&mu);
+      return err;
+   }
+  
+  /* alloc ram for window temps */
+  for (i = 0; i < 8; i++) {
+      M[i] = ecc_new_point();
+      if (M[i] == NULL) {
+         for (j = 0; j < i; j++) {
+             ecc_del_point(M[j]);
+         }
+         mp_clear(&mu);
+         return MEMORY_E;
+      }
+  }
+
+   /* make a copy of G incase R==G */
+   tG = ecc_new_point();
+   if (tG == NULL)
+       err = MEMORY_E;
+
+   /* tG = G  and convert to montgomery */
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&mu, 1) == MP_EQ) {
+           err = mp_copy(G->x, tG->x);
+           if (err == MP_OKAY)
+               err = mp_copy(G->y, tG->y);
+           if (err == MP_OKAY)
+               err = mp_copy(G->z, tG->z);
+       } else {
+           err = mp_mulmod(G->x, &mu, modulus, tG->x);
+           if (err == MP_OKAY)
+               err = mp_mulmod(G->y, &mu, modulus, tG->y);
+           if (err == MP_OKAY)
+               err = mp_mulmod(G->z, &mu, modulus, tG->z);
+       }
+   }
+   mp_clear(&mu);
+   
+   /* calc the M tab, which holds kG for k==8..15 */
+   /* M[0] == 8G */
+   if (err == MP_OKAY)
+       err = ecc_projective_dbl_point(tG, M[0], modulus, &mp);
+   if (err == MP_OKAY)
+       err = ecc_projective_dbl_point(M[0], M[0], modulus, &mp);
+   if (err == MP_OKAY)
+       err = ecc_projective_dbl_point(M[0], M[0], modulus, &mp);
+
+   /* now find (8+k)G for k=1..7 */
+   if (err == MP_OKAY)
+       for (j = 9; j < 16; j++) {
+           err = ecc_projective_add_point(M[j-9], tG, M[j-8], modulus, &mp);
+           if (err != MP_OKAY) break;
+       }
+
+   /* setup sliding window */
+   if (err == MP_OKAY) {
+       mode   = 0;
+       bitcnt = 1;
+       buf    = 0;
+       digidx = get_digit_count(k) - 1;
+       bitcpy = bitbuf = 0;
+       first  = 1;
+
+       /* perform ops */
+       for (;;) {
+           /* grab next digit as required */
+           if (--bitcnt == 0) {
+               if (digidx == -1) {
+                   break;
+               }
+               buf    = get_digit(k, digidx);
+               bitcnt = (int) DIGIT_BIT; 
+               --digidx;
+           }
+
+           /* grab the next msb from the ltiplicand */
+           i = (int)(buf >> (DIGIT_BIT - 1)) & 1;
+           buf <<= 1;
+
+           /* skip leading zero bits */
+           if (mode == 0 && i == 0)
+               continue;
+
+           /* if the bit is zero and mode == 1 then we double */
+           if (mode == 1 && i == 0) {
+               err = ecc_projective_dbl_point(R, R, modulus, &mp);
+               if (err != MP_OKAY) break;
+               continue;
+           }
+
+           /* else we add it to the window */
+           bitbuf |= (i << (WINSIZE - ++bitcpy));
+           mode = 2;
+
+           if (bitcpy == WINSIZE) {
+               /* if this is the first window we do a simple copy */
+               if (first == 1) {
+                   /* R = kG [k = first window] */
+                   err = mp_copy(M[bitbuf-8]->x, R->x);
+                   if (err != MP_OKAY) break;
+
+                   err = mp_copy(M[bitbuf-8]->y, R->y);
+                   if (err != MP_OKAY) break;
+
+                   err = mp_copy(M[bitbuf-8]->z, R->z);
+                   first = 0;
+               } else {
+                   /* normal window */
+                   /* ok window is filled so double as required and add  */
+                   /* double first */
+                   for (j = 0; j < WINSIZE; j++) {
+                       err = ecc_projective_dbl_point(R, R, modulus, &mp);
+                       if (err != MP_OKAY) break;
+                   }
+                   if (err != MP_OKAY) break;  /* out of first for(;;) */
+
+                   /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranted */
+                   err = ecc_projective_add_point(R,M[bitbuf-8],R,modulus,&mp);
+               }
+               if (err != MP_OKAY) break;
+               /* empty window and reset */
+               bitcpy = bitbuf = 0;
+               mode = 1;
+           }
+       }
+   }
+
+   /* if bits remain then double/add */
+   if (err == MP_OKAY) {
+       if (mode == 2 && bitcpy > 0) {
+           /* double then add */
+           for (j = 0; j < bitcpy; j++) {
+               /* only double if we have had at least one add first */
+               if (first == 0) {
+                   err = ecc_projective_dbl_point(R, R, modulus, &mp);
+                   if (err != MP_OKAY) break;
+               }
+
+               bitbuf <<= 1;
+               if ((bitbuf & (1 << WINSIZE)) != 0) {
+                   if (first == 1) {
+                       /* first add, so copy */
+                       err = mp_copy(tG->x, R->x);
+                       if (err != MP_OKAY) break;
+
+                       err = mp_copy(tG->y, R->y);
+                       if (err != MP_OKAY) break;
+
+                       err = mp_copy(tG->z, R->z);
+                       if (err != MP_OKAY) break;
+                       first = 0;
+                   } else {
+                       /* then add */
+                       err = ecc_projective_add_point(R, tG, R, modulus, &mp);
+                       if (err != MP_OKAY) break;
+                   }
+               }
+           }
+       }
+   }
+
+   /* map R back from projective space */
+   if (err == MP_OKAY && map)
+       err = ecc_map(R, modulus, &mp);
+
+   mp_clear(&mu);
+   ecc_del_point(tG);
+   for (i = 0; i < 8; i++) {
+       ecc_del_point(M[i]);
+   }
+   return err;
+}
+
+#undef WINSIZE
+
+#else /* ECC_TIMING_RESISTANT */
+
+/**
+   Perform a point multiplication  (timing resistant)
+   k    The scalar to multiply by
+   G    The base point
+   R    [out] Destination for kG
+   modulus  The modulus of the field the ECC curve is in
+   map      Boolean whether to map back to affine or not
+            (1==map, 0 == leave in projective)
+   return MP_OKAY on success
+*/
+#ifdef FP_ECC
+static int normal_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R,
+                             mp_int* modulus, int map)
+#else
+static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus,
+                      int map)
+#endif
+{
+   ecc_point    *tG, *M[3];
+   int           i, j, err;
+   mp_int        mu;
+   mp_digit      mp;
+   mp_digit      buf;
+   int           bitcnt = 0, mode = 0, digidx = 0;
+
+   if (k == NULL || G == NULL || R == NULL || modulus == NULL)
+       return ECC_BAD_ARG_E;
+
+   /* init montgomery reduction */
+   if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) {
+      return err;
+   }
+   if ((err = mp_init(&mu)) != MP_OKAY) {
+      return err;
+   }
+   if ((err = mp_montgomery_calc_normalization(&mu, modulus)) != MP_OKAY) {
+      mp_clear(&mu);
+      return err;
+   }
+
+  /* alloc ram for window temps */
+  for (i = 0; i < 3; i++) {
+      M[i] = ecc_new_point();
+      if (M[i] == NULL) {
+         for (j = 0; j < i; j++) {
+             ecc_del_point(M[j]);
+         }
+         mp_clear(&mu);
+         return MEMORY_E;
+      }
+  }
+
+   /* make a copy of G incase R==G */
+   tG = ecc_new_point();
+   if (tG == NULL)
+       err = MEMORY_E;
+
+   /* tG = G  and convert to montgomery */
+   if (err == MP_OKAY) {
+       err = mp_mulmod(G->x, &mu, modulus, tG->x);
+       if (err == MP_OKAY)
+           err = mp_mulmod(G->y, &mu, modulus, tG->y);
+       if (err == MP_OKAY)
+           err = mp_mulmod(G->z, &mu, modulus, tG->z);
+   }
+   mp_clear(&mu);
+
+   /* calc the M tab */
+   /* M[0] == G */
+   if (err == MP_OKAY)
+       err = mp_copy(tG->x, M[0]->x);
+   if (err == MP_OKAY)
+       err = mp_copy(tG->y, M[0]->y);
+   if (err == MP_OKAY)
+       err = mp_copy(tG->z, M[0]->z);
+
+   /* M[1] == 2G */
+   if (err == MP_OKAY)
+       err = ecc_projective_dbl_point(tG, M[1], modulus, &mp);
+
+   /* setup sliding window */
+   mode   = 0;
+   bitcnt = 1;
+   buf    = 0;
+   digidx = get_digit_count(k) - 1;
+
+   /* perform ops */
+   if (err == MP_OKAY) {
+       for (;;) {
+           /* grab next digit as required */
+           if (--bitcnt == 0) {
+               if (digidx == -1) {
+                   break;
+               }
+               buf = get_digit(k, digidx);
+               bitcnt = (int) DIGIT_BIT;
+               --digidx;
+           }
+
+           /* grab the next msb from the ltiplicand */
+           i = (buf >> (DIGIT_BIT - 1)) & 1;
+           buf <<= 1;
+
+           if (mode == 0 && i == 0) {
+               /* dummy operations */
+               if (err == MP_OKAY)
+                   err = ecc_projective_add_point(M[0], M[1], M[2], modulus,
+                                                  &mp);
+               if (err == MP_OKAY)
+                   err = ecc_projective_dbl_point(M[1], M[2], modulus, &mp);
+               if (err == MP_OKAY)
+                   continue;
+           }
+
+           if (mode == 0 && i == 1) {
+               mode = 1;
+               /* dummy operations */
+               if (err == MP_OKAY)
+                   err = ecc_projective_add_point(M[0], M[1], M[2], modulus,
+                                                  &mp);
+               if (err == MP_OKAY)
+                   err = ecc_projective_dbl_point(M[1], M[2], modulus, &mp);
+               if (err == MP_OKAY)
+                   continue;
+           }
+
+           if (err == MP_OKAY)
+               err = ecc_projective_add_point(M[0], M[1], M[i^1], modulus, &mp);
+           if (err == MP_OKAY)
+               err = ecc_projective_dbl_point(M[i], M[i], modulus, &mp);
+           if (err != MP_OKAY)
+               break;
+       } /* end for */
+   }
+
+   /* copy result out */
+   if (err == MP_OKAY)
+       err = mp_copy(M[0]->x, R->x);
+   if (err == MP_OKAY)
+       err = mp_copy(M[0]->y, R->y);
+   if (err == MP_OKAY)
+       err = mp_copy(M[0]->z, R->z);
+
+   /* map R back from projective space */
+   if (err == MP_OKAY && map)
+      err = ecc_map(R, modulus, &mp);
+
+   /* done */
+   mp_clear(&mu);
+   ecc_del_point(tG);
+   for (i = 0; i < 3; i++) {
+       ecc_del_point(M[i]);
+   }
+   return err;
+}
+
+#endif /* ECC_TIMING_RESISTANT */
+
+
+#ifdef ALT_ECC_SIZE
+
+static void alt_fp_init(fp_int* a)
+{
+    a->size = FP_SIZE_ECC;
+    fp_zero(a);
+}
+
+#endif /* ALT_ECC_SIZE */
+
+
+/**
+   Allocate a new ECC point
+   return A newly allocated point or NULL on error 
+*/
+ecc_point* ecc_new_point(void)
+{
+   ecc_point* p;
+
+   p = (ecc_point*)XMALLOC(sizeof(ecc_point), 0, DYNAMIC_TYPE_ECC);
+   if (p == NULL) {
+      return NULL;
+   }
+   XMEMSET(p, 0, sizeof(ecc_point));
+
+#ifndef USE_FAST_MATH
+   p->x->dp = NULL;
+   p->y->dp = NULL;
+   p->z->dp = NULL;
+#endif
+
+#ifndef ALT_ECC_SIZE
+   if (mp_init_multi(p->x, p->y, p->z, NULL, NULL, NULL) != MP_OKAY) {
+      XFREE(p, 0, DYNAMIC_TYPE_ECC);
+      return NULL;
+   }
+#else
+   p->x = (mp_int*)&p->xyz[0];
+   p->y = (mp_int*)&p->xyz[1];
+   p->z = (mp_int*)&p->xyz[2];
+   alt_fp_init(p->x);
+   alt_fp_init(p->y);
+   alt_fp_init(p->z);
+#endif
+
+   return p;
+}
+
+/** Free an ECC point from memory
+  p   The point to free
+*/
+void ecc_del_point(ecc_point* p)
+{
+   /* prevents free'ing null arguments */
+   if (p != NULL) {
+      mp_clear(p->x);
+      mp_clear(p->y);
+      mp_clear(p->z);
+      XFREE(p, 0, DYNAMIC_TYPE_ECC);
+   }
+}
+
+
+/** Returns whether an ECC idx is valid or not
+  n      The idx number to check
+  return 1 if valid, 0 if not
+*/  
+static int ecc_is_valid_idx(int n)
+{
+   int x;
+
+   for (x = 0; ecc_sets[x].size != 0; x++)
+       ;
+   /* -1 is a valid index --- indicating that the domain params
+      were supplied by the user */
+   if ((n >= -1) && (n < x)) {
+      return 1;
+   }
+   return 0;
+}
+
+
+/**
+  Create an ECC shared secret between two keys
+  private_key      The private ECC key
+  public_key       The public key
+  out              [out] Destination of the shared secret
+                   Conforms to EC-DH from ANSI X9.63
+  outlen           [in/out] The max size and resulting size of the shared secret
+  return           MP_OKAY if successful
+*/
+int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out,
+                      word32* outlen)
+{
+   word32         x = 0;
+   ecc_point*     result;
+   mp_int         prime;
+   int            err;
+
+   if (private_key == NULL || public_key == NULL || out == NULL ||
+                                                    outlen == NULL)
+       return BAD_FUNC_ARG;
+
+   /* type valid? */
+   if (private_key->type != ECC_PRIVATEKEY) {
+      return ECC_BAD_ARG_E;
+   }
+
+   if (ecc_is_valid_idx(private_key->idx) == 0 ||
+       ecc_is_valid_idx(public_key->idx)  == 0)
+      return ECC_BAD_ARG_E;
+
+   if (XSTRNCMP(private_key->dp->name, public_key->dp->name, ECC_MAXNAME) != 0)
+      return ECC_BAD_ARG_E;
+
+   /* make new point */
+   result = ecc_new_point();
+   if (result == NULL) {
+      return MEMORY_E;
+   }
+
+   if ((err = mp_init(&prime)) != MP_OKAY) {
+      ecc_del_point(result);
+      return err;
+   }
+
+   err = mp_read_radix(&prime, (char *)private_key->dp->prime, 16);
+
+   if (err == MP_OKAY)
+       err = ecc_mulmod(&private_key->k, &public_key->pubkey, result, &prime,1);
+
+   if (err == MP_OKAY) {
+       x = mp_unsigned_bin_size(&prime);
+       if (*outlen < x)
+          err = BUFFER_E;
+   }
+
+   if (err == MP_OKAY) {
+       XMEMSET(out, 0, x);
+       err = mp_to_unsigned_bin(result->x,out + (x -
+                                              mp_unsigned_bin_size(result->x)));
+       *outlen = x;
+   }
+
+   mp_clear(&prime);
+   ecc_del_point(result);
+
+   return err;
+}
+
+
+/* return 1 if point is at infinity, 0 if not, < 0 on error */
+static int ecc_point_is_at_infinity(ecc_point* p)
+{
+    if (p == NULL)
+        return BAD_FUNC_ARG;
+
+    if (get_digit_count(p->x) == 0 && get_digit_count(p->y) == 0)
+        return 1;
+
+    return 0;
+}
+
+
+int wc_ecc_make_key_ex(RNG* rng, ecc_key* key, const ecc_set_type* dp);
+
+/**
+  Make a new ECC key 
+  rng          An active RNG state
+  keysize      The keysize for the new key (in octets from 20 to 65 bytes)
+  key          [out] Destination of the newly created key
+  return       MP_OKAY if successful,
+                       upon error all allocated memory will be freed
+*/
+int wc_ecc_make_key(RNG* rng, int keysize, ecc_key* key)
+{
+   int x, err;
+
+   if (key == NULL || rng == NULL)
+       return ECC_BAD_ARG_E;
+
+   /* find key size */
+   for (x = 0; (keysize > ecc_sets[x].size) && (ecc_sets[x].size != 0); x++)
+       ;
+   keysize = ecc_sets[x].size;
+
+   if (keysize > ECC_MAXSIZE || ecc_sets[x].size == 0) {
+      return BAD_FUNC_ARG;
+   }
+   err = wc_ecc_make_key_ex(rng, key, &ecc_sets[x]);
+   key->idx = x;
+
+   return err;
+}
+
+int wc_ecc_make_key_ex(RNG* rng, ecc_key* key, const ecc_set_type* dp)
+{
+   int            err;
+   ecc_point*     base;
+   mp_int         prime;
+   mp_int         order;
+#ifdef WOLFSSL_SMALL_STACK
+   byte*          buf;
+#else
+   byte           buf[ECC_MAXSIZE];
+#endif
+   int            keysize;
+   int            po_init = 0;  /* prime order Init flag for clear */
+
+   if (key == NULL || rng == NULL || dp == NULL)
+       return ECC_BAD_ARG_E;
+
+#ifdef WOLFSSL_SMALL_STACK
+   buf = (byte*)XMALLOC(ECC_MAXSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+   if (buf == NULL)
+       return MEMORY_E;
+#endif
+
+   key->idx = -1;
+   key->dp  = dp;
+   keysize  = dp->size;
+
+   /* allocate ram */
+   base = NULL;
+
+   /* make up random string */
+   err = wc_RNG_GenerateBlock(rng, buf, keysize);
+   if (err == 0)
+       buf[0] |= 0x0c;
+
+   /* setup the key variables */
+   if (err == 0) {
+#ifndef ALT_ECC_SIZE
+       err = mp_init_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z,
+                            &key->k, &prime, &order);
+#else
+       key->pubkey.x = (mp_int*)&key->pubkey.xyz[0];
+       key->pubkey.y = (mp_int*)&key->pubkey.xyz[1];
+       key->pubkey.z = (mp_int*)&key->pubkey.xyz[2];
+       alt_fp_init(key->pubkey.x);
+       alt_fp_init(key->pubkey.y);
+       alt_fp_init(key->pubkey.z);
+       err = mp_init_multi(&key->k, &prime, &order, NULL, NULL, NULL);
+#endif
+       if (err != MP_OKAY)
+           err = MEMORY_E;
+       else
+           po_init = 1;
+   }
+
+   if (err == MP_OKAY) {
+       base = ecc_new_point();
+       if (base == NULL)
+           err = MEMORY_E;
+   }
+
+   /* read in the specs for this key */
+   if (err == MP_OKAY) 
+       err = mp_read_radix(&prime,   (char *)key->dp->prime, 16);
+   if (err == MP_OKAY) 
+       err = mp_read_radix(&order,   (char *)key->dp->order, 16);
+   if (err == MP_OKAY) 
+       err = mp_read_radix(base->x, (char *)key->dp->Gx, 16);
+   if (err == MP_OKAY) 
+       err = mp_read_radix(base->y, (char *)key->dp->Gy, 16);
+   
+   if (err == MP_OKAY) 
+       mp_set(base->z, 1);
+   if (err == MP_OKAY) 
+       err = mp_read_unsigned_bin(&key->k, (byte*)buf, keysize);
+
+   /* the key should be smaller than the order of base point */
+   if (err == MP_OKAY) { 
+       if (mp_cmp(&key->k, &order) != MP_LT)
+           err = mp_mod(&key->k, &order, &key->k);
+   }
+   /* make the public key */
+   if (err == MP_OKAY)
+       err = ecc_mulmod(&key->k, base, &key->pubkey, &prime, 1);
+
+#ifdef WOLFSSL_VALIDATE_ECC_KEYGEN
+   /* validate the public key, order * pubkey = point at infinity */
+   if (err == MP_OKAY)
+       err = ecc_check_pubkey_order(key, &prime, &order);
+#endif /* WOLFSSL_VALIDATE_KEYGEN */
+
+   if (err == MP_OKAY)
+       key->type = ECC_PRIVATEKEY;
+
+   if (err != MP_OKAY) {
+       /* clean up */
+       mp_clear(key->pubkey.x);
+       mp_clear(key->pubkey.y);
+       mp_clear(key->pubkey.z);
+       mp_clear(&key->k);
+   }
+   ecc_del_point(base);
+   if (po_init) {
+       mp_clear(&prime);
+       mp_clear(&order);
+   }
+
+   ForceZero(buf, ECC_MAXSIZE);
+#ifdef WOLFSSL_SMALL_STACK
+   XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+   return err;
+}
+
+
+/* Setup dynamic pointers is using normal math for proper freeing */
+int wc_ecc_init(ecc_key* key)
+{
+    (void)key;
+
+#ifndef USE_FAST_MATH
+    key->pubkey.x->dp = NULL;
+    key->pubkey.y->dp = NULL;
+    key->pubkey.z->dp = NULL;
+
+    key->k.dp = NULL;
+#endif
+
+#ifdef ALT_ECC_SIZE
+    if (mp_init(&key->k) != MP_OKAY)
+        return MEMORY_E;
+
+    key->pubkey.x = (mp_int*)&key->pubkey.xyz[0];
+    key->pubkey.y = (mp_int*)&key->pubkey.xyz[1];
+    key->pubkey.z = (mp_int*)&key->pubkey.xyz[2];
+    alt_fp_init(key->pubkey.x);
+    alt_fp_init(key->pubkey.y);
+    alt_fp_init(key->pubkey.z);
+#endif
+
+    return 0;
+}
+
+
+/**
+  Sign a message digest
+  in        The message digest to sign
+  inlen     The length of the digest
+  out       [out] The destination for the signature
+  outlen    [in/out] The max size and resulting size of the signature
+  key       A private ECC key
+  return    MP_OKAY if successful
+*/
+int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, 
+                  RNG* rng, ecc_key* key)
+{
+   mp_int        r;
+   mp_int        s;
+   mp_int        e;
+   mp_int        p;
+   int           err;
+
+   if (in == NULL || out == NULL || outlen == NULL || key == NULL || rng ==NULL)
+       return ECC_BAD_ARG_E;
+
+   /* is this a private key? */
+   if (key->type != ECC_PRIVATEKEY) {
+      return ECC_BAD_ARG_E;
+   }
+   
+   /* is the IDX valid ?  */
+   if (ecc_is_valid_idx(key->idx) != 1) {
+      return ECC_BAD_ARG_E;
+   }
+
+   /* get the hash and load it as a bignum into 'e' */
+   /* init the bignums */
+   if ((err = mp_init_multi(&r, &s, &p, &e, NULL, NULL)) != MP_OKAY) { 
+      return err;
+   }
+   err = mp_read_radix(&p, (char *)key->dp->order, 16);
+
+   if (err == MP_OKAY) {
+       /* we may need to truncate if hash is longer than key size */
+       word32 orderBits = mp_count_bits(&p);
+
+       /* truncate down to byte size, may be all that's needed */
+       if ( (WOLFSSL_BIT_SIZE * inlen) > orderBits)
+           inlen = (orderBits + WOLFSSL_BIT_SIZE - 1)/WOLFSSL_BIT_SIZE;
+       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));
+   }
+
+   /* make up a key and export the public copy */
+   if (err == MP_OKAY) {
+       int loop_check = 0;
+       ecc_key pubkey;
+       wc_ecc_init(&pubkey);
+       for (;;) {
+           if (++loop_check > 64) {
+                err = RNG_FAILURE_E;
+                break;
+           }
+           err = wc_ecc_make_key_ex(rng, &pubkey, key->dp);
+           if (err != MP_OKAY) break;
+
+           /* find r = x1 mod n */
+           err = mp_mod(pubkey.pubkey.x, &p, &r);
+           if (err != MP_OKAY) break;
+
+           if (mp_iszero(&r) == MP_YES) {
+               mp_clear(pubkey.pubkey.x);
+               mp_clear(pubkey.pubkey.y);
+               mp_clear(pubkey.pubkey.z);
+               mp_clear(&pubkey.k);
+           }
+           else { 
+               /* find s = (e + xr)/k */
+               err = mp_invmod(&pubkey.k, &p, &pubkey.k);
+               if (err != MP_OKAY) break;
+
+               err = mp_mulmod(&key->k, &r, &p, &s);   /* s = xr */
+               if (err != MP_OKAY) break;
+           
+               err = mp_add(&e, &s, &s);               /* s = e +  xr */
+               if (err != MP_OKAY) break;
+
+               err = mp_mod(&s, &p, &s);               /* s = e +  xr */
+               if (err != MP_OKAY) break;
+
+               err = mp_mulmod(&s, &pubkey.k, &p, &s); /* s = (e + xr)/k */
+               if (err != MP_OKAY) break;
+
+               if (mp_iszero(&s) == MP_NO)
+                   break;
+            }
+       }
+       wc_ecc_free(&pubkey);
+   }
+
+   /* store as SEQUENCE { r, s -- integer } */
+   if (err == MP_OKAY)
+       err = StoreECC_DSA_Sig(out, outlen, &r, &s);
+
+   mp_clear(&r);
+   mp_clear(&s);
+   mp_clear(&p);
+   mp_clear(&e);
+
+   return err;
+}
+
+
+/**
+  Free an ECC key from memory
+  key   The key you wish to free
+*/
+void wc_ecc_free(ecc_key* key)
+{
+   if (key == NULL)
+       return;
+
+   mp_clear(key->pubkey.x);
+   mp_clear(key->pubkey.y);
+   mp_clear(key->pubkey.z);
+   mp_clear(&key->k);
+}
+
+
+#ifdef USE_FAST_MATH
+    #define GEN_MEM_ERR FP_MEM
+#else
+    #define GEN_MEM_ERR MP_MEM
+#endif
+
+#ifdef ECC_SHAMIR
+
+/** Computes kA*A + kB*B = C using Shamir's Trick
+  A        First point to multiply
+  kA       What to multiple A by
+  B        Second point to multiply
+  kB       What to multiple B by
+  C        [out] Destination point (can overlap with A or B)
+  modulus  Modulus for curve 
+  return MP_OKAY on success
+*/
+#ifdef FP_ECC
+static int normal_ecc_mul2add(ecc_point* A, mp_int* kA,
+                             ecc_point* B, mp_int* kB,
+                             ecc_point* C, mp_int* modulus)
+#else
+static int ecc_mul2add(ecc_point* A, mp_int* kA,
+                    ecc_point* B, mp_int* kB,
+                    ecc_point* C, mp_int* modulus)
+#endif
+{
+  ecc_point*     precomp[16];
+  unsigned       bitbufA, bitbufB, lenA, lenB, len, x, y, nA, nB, nibble;
+  unsigned char* tA;
+  unsigned char* tB;
+  int            err = MP_OKAY, first;
+  int            muInit    = 0;
+  int            tableInit = 0;
+  mp_digit mp;
+  mp_int   mu;
+ 
+  /* argchks */
+  if (A == NULL || kA == NULL || B == NULL || kB == NULL || C == NULL || 
+                   modulus == NULL)
+    return ECC_BAD_ARG_E;
+
+
+  /* allocate memory */
+  tA = (unsigned char*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+  if (tA == NULL) {
+     return GEN_MEM_ERR;
+  }
+  tB = (unsigned char*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+  if (tB == NULL) {
+     XFREE(tA, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+     return GEN_MEM_ERR;
+  }
+  XMEMSET(tA, 0, ECC_BUFSIZE);
+  XMEMSET(tB, 0, ECC_BUFSIZE);
+
+  /* get sizes */
+  lenA = mp_unsigned_bin_size(kA);
+  lenB = mp_unsigned_bin_size(kB);
+  len  = MAX(lenA, lenB);
+
+  /* sanity check */
+  if ((lenA > ECC_BUFSIZE) || (lenB > ECC_BUFSIZE)) {
+     err = BAD_FUNC_ARG;
+  }
+
+  if (err == MP_OKAY) {
+    /* extract and justify kA */
+    err = mp_to_unsigned_bin(kA, (len - lenA) + tA);
+
+    /* extract and justify kB */
+    if (err == MP_OKAY)
+        err = mp_to_unsigned_bin(kB, (len - lenB) + tB);
+
+    /* allocate the table */
+    if (err == MP_OKAY) {
+        for (x = 0; x < 16; x++) {
+            precomp[x] = ecc_new_point();
+            if (precomp[x] == NULL) {
+                for (y = 0; y < x; ++y) {
+                    ecc_del_point(precomp[y]);
+                }
+                err = GEN_MEM_ERR;
+                break;
+            }
+        }
+    }
+  }
+
+  if (err == MP_OKAY)
+    tableInit = 1;
+
+  if (err == MP_OKAY)
+   /* init montgomery reduction */
+   err = mp_montgomery_setup(modulus, &mp);
+
+  if (err == MP_OKAY)
+    err = mp_init(&mu);
+  if (err == MP_OKAY)
+    muInit = 1;
+
+  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);
+
+  if (err == MP_OKAY)
+    err = mp_mulmod(A->y, &mu, modulus, precomp[1]->y);
+  if (err == MP_OKAY)
+    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);
+  if (err == MP_OKAY)
+    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);
+
+  if (err == MP_OKAY)
+    /* precomp [i,0](A + B) table */
+    err = ecc_projective_dbl_point(precomp[1], precomp[2], modulus, &mp);
+
+  if (err == MP_OKAY)
+    err = ecc_projective_add_point(precomp[1], precomp[2], precomp[3],
+                                   modulus, &mp);
+  if (err == MP_OKAY)
+    /* precomp [0,i](A + B) table */
+    err = ecc_projective_dbl_point(precomp[1<<2], precomp[2<<2], modulus, &mp);
+
+  if (err == MP_OKAY)
+    err = ecc_projective_add_point(precomp[1<<2], precomp[2<<2], precomp[3<<2],
+                                   modulus, &mp);
+
+  if (err == MP_OKAY) {
+    /* precomp [i,j](A + B) table (i != 0, j != 0) */
+    for (x = 1; x < 4; x++) {
+        for (y = 1; y < 4; y++) {
+            if (err == MP_OKAY)
+                err = ecc_projective_add_point(precomp[x], precomp[(y<<2)],
+                                               precomp[x+(y<<2)], modulus, &mp);
+        }
+    } 
+  }  
+
+  if (err == MP_OKAY) {
+    nibble  = 3;
+    first   = 1;
+    bitbufA = tA[0];
+    bitbufB = tB[0];
+
+    /* for every byte of the multiplicands */
+    for (x = -1;; ) {
+        /* grab a nibble */
+        if (++nibble == 4) {
+            ++x; if (x == len) break;
+            bitbufA = tA[x];
+            bitbufB = tB[x];
+            nibble  = 0;
+        }
+
+        /* extract two bits from both, shift/update */
+        nA = (bitbufA >> 6) & 0x03;
+        nB = (bitbufB >> 6) & 0x03;
+        bitbufA = (bitbufA << 2) & 0xFF;   
+        bitbufB = (bitbufB << 2) & 0xFF;   
+
+        /* if both zero, if first, continue */
+        if ((nA == 0) && (nB == 0) && (first == 1)) {
+            continue;
+        }
+
+        /* double twice, only if this isn't the first */
+        if (first == 0) {
+            /* double twice */
+            if (err == MP_OKAY)
+                err = ecc_projective_dbl_point(C, C, modulus, &mp);
+            if (err == MP_OKAY)
+                err = ecc_projective_dbl_point(C, C, modulus, &mp);
+            else
+                break;
+        }
+
+        /* if not both zero */
+        if ((nA != 0) || (nB != 0)) {
+            if (first == 1) {
+                /* if first, copy from table */
+                first = 0;
+                if (err == MP_OKAY)
+                    err = mp_copy(precomp[nA + (nB<<2)]->x, C->x);
+
+                if (err == MP_OKAY)
+                    err = mp_copy(precomp[nA + (nB<<2)]->y, C->y);
+
+                if (err == MP_OKAY)
+                    err = mp_copy(precomp[nA + (nB<<2)]->z, C->z);
+                else
+                    break;
+            } else {
+                /* if not first, add from table */
+                if (err == MP_OKAY)
+                    err = ecc_projective_add_point(C, precomp[nA + (nB<<2)], C,
+                                                   modulus, &mp);
+                else
+                    break;
+            }
+        }
+    }
+  }
+
+  if (err == MP_OKAY)
+    /* reduce to affine */
+    err = ecc_map(C, modulus, &mp);
+
+  /* clean up */
+  if (muInit)
+    mp_clear(&mu);
+
+  if (tableInit) {
+    for (x = 0; x < 16; x++) {
+       ecc_del_point(precomp[x]);
+    }
+  }
+   ForceZero(tA, ECC_BUFSIZE);
+   ForceZero(tB, ECC_BUFSIZE);
+   XFREE(tA, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+   XFREE(tB, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+   return err;
+}
+
+
+#endif /* ECC_SHAMIR */
+
+
+
+/* verify 
+ *
+ * w  = s^-1 mod n
+ * u1 = xw 
+ * u2 = rw
+ * X = u1*G + u2*Q
+ * v = X_x1 mod n
+ * accept if v == r
+ */
+
+/**
+   Verify an ECC signature
+   sig         The signature to verify
+   siglen      The length of the signature (octets)
+   hash        The hash (message digest) that was signed
+   hashlen     The length of the hash (octets)
+   stat        Result of signature, 1==valid, 0==invalid
+   key         The corresponding public ECC key
+   return      MP_OKAY if successful (even if the signature is not valid)
+*/
+int wc_ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash,
+                    word32 hashlen, int* stat, ecc_key* key)
+{
+   ecc_point    *mG, *mQ;
+   mp_int        r;
+   mp_int        s;
+   mp_int        v;
+   mp_int        w;
+   mp_int        u1;
+   mp_int        u2;
+   mp_int        e;
+   mp_int        p;
+   mp_int        m;
+   int           err;
+
+   if (sig == NULL || hash == NULL || stat == NULL || key == NULL)
+       return ECC_BAD_ARG_E; 
+
+   /* default to invalid signature */
+   *stat = 0;
+
+   /* is the IDX valid ?  */
+   if (ecc_is_valid_idx(key->idx) != 1) {
+      return ECC_BAD_ARG_E;
+   }
+
+   /* allocate ints */
+   if ((err = mp_init_multi(&v, &w, &u1, &u2, &p, &e)) != MP_OKAY) {
+      return MEMORY_E;
+   }
+
+   if ((err = mp_init(&m)) != MP_OKAY) {
+      mp_clear(&v);
+      mp_clear(&w);
+      mp_clear(&u1);
+      mp_clear(&u2);
+      mp_clear(&p);
+      mp_clear(&e);
+      return MEMORY_E;
+   }
+
+   /* allocate points */
+   mG = ecc_new_point();
+   mQ = ecc_new_point();
+   if (mQ  == NULL || mG == NULL)
+      err = MEMORY_E;
+
+   /* Note, DecodeECC_DSA_Sig() calls mp_init() on r and s.
+    * If either of those don't allocate correctly, none of
+    * the rest of this function will execute, and everything
+    * gets cleaned up at the end. */
+   XMEMSET(&r, 0, sizeof(r));
+   XMEMSET(&s, 0, sizeof(s));
+   if (err == MP_OKAY)
+       err = DecodeECC_DSA_Sig(sig, siglen, &r, &s);
+
+   /* get the order */
+   if (err == MP_OKAY)
+       err = mp_read_radix(&p, (char *)key->dp->order, 16);
+
+   /* get the modulus */
+   if (err == MP_OKAY)
+       err = mp_read_radix(&m, (char *)key->dp->prime, 16);
+
+   /* check for zero */
+   if (err == MP_OKAY) {
+       if (mp_iszero(&r) || mp_iszero(&s) || mp_cmp(&r, &p) != MP_LT ||
+                                             mp_cmp(&s, &p) != MP_LT)
+           err = MP_ZERO_E; 
+   }
+   /* read hash */
+   if (err == MP_OKAY) {
+       /* we may need to truncate if hash is longer than key size */
+       unsigned int orderBits = mp_count_bits(&p);
+
+       /* truncate down to byte size, may be all that's needed */
+       if ( (WOLFSSL_BIT_SIZE * hashlen) > orderBits)
+           hashlen = (orderBits + WOLFSSL_BIT_SIZE - 1)/WOLFSSL_BIT_SIZE;
+       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));
+   }
+
+   /*  w  = s^-1 mod n */
+   if (err == MP_OKAY)
+       err = mp_invmod(&s, &p, &w);
+
+   /* u1 = ew */
+   if (err == MP_OKAY)
+       err = mp_mulmod(&e, &w, &p, &u1);
+
+   /* u2 = rw */
+   if (err == MP_OKAY)
+       err = mp_mulmod(&r, &w, &p, &u2);
+
+   /* find mG and mQ */
+   if (err == MP_OKAY)
+       err = mp_read_radix(mG->x, (char *)key->dp->Gx, 16);
+
+   if (err == MP_OKAY)
+       err = mp_read_radix(mG->y, (char *)key->dp->Gy, 16);
+   if (err == MP_OKAY)
+       mp_set(mG->z, 1);
+
+   if (err == MP_OKAY)
+       err = mp_copy(key->pubkey.x, mQ->x);
+   if (err == MP_OKAY)
+       err = mp_copy(key->pubkey.y, mQ->y);
+   if (err == MP_OKAY)
+       err = mp_copy(key->pubkey.z, mQ->z);
+
+#ifndef ECC_SHAMIR
+    {
+       mp_digit      mp;
+
+       /* compute u1*mG + u2*mQ = mG */
+       if (err == MP_OKAY)
+           err = ecc_mulmod(&u1, mG, mG, &m, 0);
+       if (err == MP_OKAY)
+           err = ecc_mulmod(&u2, mQ, mQ, &m, 0);
+  
+       /* find the montgomery mp */
+       if (err == MP_OKAY)
+           err = mp_montgomery_setup(&m, &mp);
+
+       /* add them */
+       if (err == MP_OKAY)
+           err = ecc_projective_add_point(mQ, mG, mG, &m, &mp);
+   
+       /* reduce */
+       if (err == MP_OKAY)
+           err = ecc_map(mG, &m, &mp);
+    }
+#else
+       /* 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, &m);
+#endif /* ECC_SHAMIR */ 
+
+   /* v = X_x1 mod n */
+   if (err == MP_OKAY)
+       err = mp_mod(mG->x, &p, &v);
+
+   /* does v == r */
+   if (err == MP_OKAY) {
+       if (mp_cmp(&v, &r) == MP_EQ)
+           *stat = 1;
+   }
+
+   ecc_del_point(mG);
+   ecc_del_point(mQ);
+
+   mp_clear(&r);
+   mp_clear(&s);
+   mp_clear(&v);
+   mp_clear(&w);
+   mp_clear(&u1);
+   mp_clear(&u2);
+   mp_clear(&p);
+   mp_clear(&e);
+   mp_clear(&m);
+
+   return err;
+}
+
+
+/* export public ECC key in ANSI X9.63 format */
+int wc_ecc_export_x963(ecc_key* key, byte* out, word32* outLen)
+{
+#ifdef WOLFSSL_SMALL_STACK
+   byte*  buf;
+#else
+   byte   buf[ECC_BUFSIZE];
+#endif
+   word32 numlen;
+   int    ret = MP_OKAY;
+
+   /* return length needed only */
+   if (key != NULL && out == NULL && outLen != NULL) {
+      numlen = key->dp->size;
+      *outLen = 1 + 2*numlen;
+      return LENGTH_ONLY_E;
+   }
+
+   if (key == NULL || out == NULL || outLen == NULL)
+      return ECC_BAD_ARG_E;
+
+   if (ecc_is_valid_idx(key->idx) == 0) {
+      return ECC_BAD_ARG_E;
+   }
+   numlen = key->dp->size;
+
+   if (*outLen < (1 + 2*numlen)) {
+      *outLen = 1 + 2*numlen;
+      return BUFFER_E;
+   }
+
+   /* store byte 0x04 */
+   out[0] = 0x04;
+
+#ifdef WOLFSSL_SMALL_STACK
+   buf = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+   if (buf == NULL)
+      return MEMORY_E;
+#endif
+
+   do {
+      /* pad and store x */
+      XMEMSET(buf, 0, ECC_BUFSIZE);
+      ret = mp_to_unsigned_bin(key->pubkey.x,
+                         buf + (numlen - mp_unsigned_bin_size(key->pubkey.x)));
+      if (ret != MP_OKAY)
+         break;
+      XMEMCPY(out+1, buf, numlen);
+
+      /* pad and store y */
+      XMEMSET(buf, 0, ECC_BUFSIZE);
+      ret = mp_to_unsigned_bin(key->pubkey.y,
+                         buf + (numlen - mp_unsigned_bin_size(key->pubkey.y)));
+      if (ret != MP_OKAY)
+         break;
+      XMEMCPY(out+1+numlen, buf, numlen);
+
+      *outLen = 1 + 2*numlen;
+   } while (0);
+
+#ifdef WOLFSSL_SMALL_STACK
+   XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+   return ret;
+}
+
+
+/* export public ECC key in ANSI X9.63 format, extended with
+ * compression option */
+int wc_ecc_export_x963_ex(ecc_key* key, byte* out, word32* outLen, int compressed)
+{
+    if (compressed == 0)
+        return wc_ecc_export_x963(key, out, outLen);
+#ifdef HAVE_COMP_KEY
+    else
+        return wc_ecc_export_x963_compressed(key, out, outLen);
+#endif
+
+    return NOT_COMPILED_IN;
+}
+
+
+/* is ec point on curve descriped by dp ? */
+static int ecc_is_point(const ecc_set_type* dp, ecc_point* ecp, mp_int* prime)
+{
+   mp_int b, t1, t2;
+   int err;
+
+   if ((err = mp_init_multi(&b, &t1, &t2, NULL, NULL, NULL)) != MP_OKAY) {
+      return err;
+   }
+
+   /* load  b */
+   err = mp_read_radix(&b, dp->Bf, 16);
+
+   /* compute y^2 */
+   if (err == MP_OKAY)
+       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);
+
+   /* compute y^2 - x^3 */
+   if (err == MP_OKAY)
+       err = mp_sub(&t1, &t2, &t1);
+
+   /* compute y^2 - x^3 + 3x */
+   if (err == MP_OKAY)
+       err = mp_add(&t1, ecp->x, &t1);
+   if (err == MP_OKAY)
+       err = mp_add(&t1, ecp->x, &t1);
+   if (err == MP_OKAY)
+       err = mp_add(&t1, ecp->x, &t1);
+   if (err == MP_OKAY)
+       err = mp_mod(&t1, prime, &t1);
+
+   while (err == MP_OKAY && mp_cmp_d(&t1, 0) == MP_LT) {
+      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) {
+          err = MP_VAL;
+       } else {
+          err = MP_OKAY;
+       }
+   }
+
+   mp_clear(&b);
+   mp_clear(&t1);
+   mp_clear(&t2);
+
+   return err;
+}
+
+
+/* validate privkey * generator == pubkey, 0 on success */
+static int ecc_check_privkey_gen(ecc_key* key, mp_int* prime)
+{
+    ecc_point* base = NULL;
+    ecc_point* res  = NULL;
+    int        err;
+
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    base = ecc_new_point();
+    if (base == NULL)
+        return MEMORY_E;
+
+    /* set up base generator */
+    err = mp_read_radix(base->x, (char*)key->dp->Gx, 16);
+    if (err == MP_OKAY)
+        err = mp_read_radix(base->y, (char*)key->dp->Gy, 16);
+    if (err == MP_OKAY)
+        mp_set(base->z, 1);
+
+    if (err == MP_OKAY) {
+        res = ecc_new_point();
+        if (res == NULL)
+            err = MEMORY_E;
+        else {
+            err = ecc_mulmod(&key->k, base, res, prime, 1);
+            if (err == MP_OKAY) {
+                /* compare result to public key */
+                if (mp_cmp(res->x, key->pubkey.x) != MP_EQ ||
+                    mp_cmp(res->y, key->pubkey.y) != MP_EQ ||
+                    mp_cmp(res->z, key->pubkey.z) != MP_EQ) {
+                    /* didn't match */
+                    err = ECC_PRIV_KEY_E;
+                }
+            }
+        }
+    }
+
+    ecc_del_point(res);
+    ecc_del_point(base);
+
+    return err;
+}
+
+
+#ifdef WOLFSSL_VALIDATE_ECC_IMPORT
+
+/* check privkey generator helper, creates prime needed */
+static int ecc_check_privkey_gen_helper(ecc_key* key)
+{
+    mp_int prime;
+    int    err;
+
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    err = mp_init(&prime);
+    if (err != MP_OKAY)
+        return err;
+
+    err = mp_read_radix(&prime, (char*)key->dp->prime, 16);
+
+    if (err == MP_OKAY);
+        err = ecc_check_privkey_gen(key, &prime);
+
+    mp_clear(&prime);
+
+    return err;
+}
+
+#endif /* WOLFSSL_VALIDATE_ECC_IMPORT */
+
+
+/* validate order * pubkey = point at infinity, 0 on success */
+static int ecc_check_pubkey_order(ecc_key* key, mp_int* prime, mp_int* order)
+{
+    ecc_point* inf = NULL;
+    int        err;
+
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    inf = ecc_new_point();
+    if (inf == NULL)
+        err = MEMORY_E;
+    else {
+        err = ecc_mulmod(order, &key->pubkey, inf, prime, 1);
+        if (err == MP_OKAY && !ecc_point_is_at_infinity(inf))
+            err = ECC_INF_E;
+    }
+
+    ecc_del_point(inf);
+
+    return err;
+}
+
+
+/* perform sanity checks on ec key validity, 0 on success */
+int wc_ecc_check_key(ecc_key* key)
+{
+    mp_int prime;  /* used by multiple calls so let's cache */
+    mp_int order;  /* other callers have, so let's gen here */
+    int    err;
+
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    /* pubkey point cannot be at inifinity */
+    if (ecc_point_is_at_infinity(&key->pubkey))
+        return ECC_INF_E;
+
+    err = mp_init_multi(&prime, &order, NULL, NULL, NULL, NULL);
+    if (err != MP_OKAY)
+        return err;
+
+    err = mp_read_radix(&prime, (char*)key->dp->prime, 16);
+
+    /* make sure point is actually on curve */
+    if (err == MP_OKAY)
+        err = ecc_is_point(key->dp, &key->pubkey, &prime);
+
+    if (err == MP_OKAY)
+        err = mp_read_radix(&order, (char*)key->dp->order, 16);
+
+    /* pubkey * order must be at infinity */
+    if (err == MP_OKAY)
+        err = ecc_check_pubkey_order(key, &prime, &order);
+
+    /* private * base generator must equal pubkey */
+    if (err == MP_OKAY && key->type == ECC_PRIVATEKEY)
+        err = ecc_check_privkey_gen(key, &prime);
+
+    mp_clear(&order);
+    mp_clear(&prime);
+
+    return err;
+}
+
+
+/* import public ECC key in ANSI X9.63 format */
+int wc_ecc_import_x963(const byte* in, word32 inLen, ecc_key* key)
+{
+   int x, err;
+   int compressed = 0;
+   
+   if (in == NULL || key == NULL)
+       return ECC_BAD_ARG_E;
+
+   /* must be odd */
+   if ((inLen & 1) == 0) {
+      return ECC_BAD_ARG_E;
+   }
+
+   /* init key */
+#ifdef ALT_ECC_SIZE
+   key->pubkey.x = (mp_int*)&key->pubkey.xyz[0];
+   key->pubkey.y = (mp_int*)&key->pubkey.xyz[1];
+   key->pubkey.z = (mp_int*)&key->pubkey.xyz[2];
+   alt_fp_init(key->pubkey.x);
+   alt_fp_init(key->pubkey.y);
+   alt_fp_init(key->pubkey.z);
+   err = mp_init(&key->k);
+#else
+   err = mp_init_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, &key->k,
+                     NULL, NULL);
+#endif
+   if (err != MP_OKAY)
+      return MEMORY_E;
+
+   /* check for 4, 2, or 3 */
+   if (in[0] != 0x04 && in[0] != 0x02 && in[0] != 0x03) {
+      err = ASN_PARSE_E;
+   }
+
+   if (in[0] == 0x02 || in[0] == 0x03) {
+#ifdef HAVE_COMP_KEY
+       compressed = 1;
+#else
+       err = NOT_COMPILED_IN;
+#endif
+   }
+
+   if (err == MP_OKAY) {
+      /* determine the idx */
+
+      if (compressed)
+          inLen = (inLen-1)*2 + 1;  /* used uncompressed len */
+
+      for (x = 0; ecc_sets[x].size != 0; x++) {
+         if ((unsigned)ecc_sets[x].size >= ((inLen-1)>>1)) {
+            break;
+         }
+      }
+      if (ecc_sets[x].size == 0) {
+         err = ASN_PARSE_E;
+      } else {
+          /* set the idx */
+          key->idx  = x;
+          key->dp = &ecc_sets[x];
+          key->type = ECC_PUBLICKEY;
+      }
+   }
+
+   /* read data */
+   if (err == MP_OKAY)
+       err = mp_read_unsigned_bin(key->pubkey.x, (byte*)in+1, (inLen-1)>>1);
+
+#ifdef HAVE_COMP_KEY
+   if (err == MP_OKAY && compressed == 1) {   /* build y */
+        mp_int t1, t2, prime, a, b;
+
+        if (mp_init_multi(&t1, &t2, &prime, &a, &b, NULL) != MP_OKAY)
+            err = MEMORY_E;
+
+        /* load prime */
+        if (err == MP_OKAY)
+            err = mp_read_radix(&prime, (char *)key->dp->prime, 16);
+
+        /* load a */
+        if (err == MP_OKAY)
+            err = mp_read_radix(&a, (char *)key->dp->Af, 16);
+
+        /* load b */
+        if (err == MP_OKAY)
+            err = mp_read_radix(&b, (char *)key->dp->Bf, 16);
+
+        /* compute x^3 */
+        if (err == MP_OKAY)
+            err = mp_sqr(key->pubkey.x, &t1);
+
+        if (err == MP_OKAY)
+            err = mp_mulmod(&t1, key->pubkey.x, &prime, &t1);
+
+        /* compute x^3 + a*x */
+        if (err == MP_OKAY)
+            err = mp_mulmod(&a, key->pubkey.x, &prime, &t2);
+
+        if (err == MP_OKAY)
+            err = mp_add(&t1, &t2, &t1);
+
+        /* compute x^3 + a*x + b */
+        if (err == MP_OKAY)
+            err = mp_add(&t1, &b, &t1);
+
+        /* compute sqrt(x^3 + a*x + b) */
+        if (err == MP_OKAY)
+            err = mp_sqrtmod_prime(&t1, &prime, &t2);
+
+        /* adjust y */
+        if (err == MP_OKAY) {
+            if ((mp_isodd(&t2) && in[0] == 0x03) ||
+               (!mp_isodd(&t2) && in[0] == 0x02)) {
+                err = mp_mod(&t2, &prime, key->pubkey.y);
+            }
+            else {
+                err = mp_submod(&prime, &t2, &prime, key->pubkey.y);
+            }
+        }
+
+        mp_clear(&a);
+        mp_clear(&b);
+        mp_clear(&prime);
+        mp_clear(&t2);
+        mp_clear(&t1);
+   }
+#endif
+
+   if (err == MP_OKAY && compressed == 0)
+       err = mp_read_unsigned_bin(key->pubkey.y, (byte*)in+1+((inLen-1)>>1),
+                                  (inLen-1)>>1);
+   if (err == MP_OKAY)
+       mp_set(key->pubkey.z, 1);
+
+#ifdef WOLFSSL_VALIDATE_ECC_IMPORT
+   if (err == MP_OKAY)
+       err = wc_ecc_check_key(key);
+#endif
+
+   if (err != MP_OKAY) {
+       mp_clear(key->pubkey.x);
+       mp_clear(key->pubkey.y);
+       mp_clear(key->pubkey.z);
+       mp_clear(&key->k);
+   }
+
+   return err;
+}
+
+
+/* export ecc private key only raw, outLen is in/out size 
+   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)
+       return ECC_BAD_ARG_E;
+
+   if (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);
+   return mp_to_unsigned_bin(&key->k, out + (numlen -
+                                             mp_unsigned_bin_size(&key->k)));
+}
+
+
+/* ecc private key import, public key in ANSI X9.63 format, private raw */
+int wc_ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub,
+                           word32 pubSz, ecc_key* key)
+{
+    int ret = wc_ecc_import_x963(pub, pubSz, key);
+    if (ret != 0)
+        return ret;
+
+    key->type = ECC_PRIVATEKEY;
+
+    ret = mp_read_unsigned_bin(&key->k, priv, privSz);
+
+#ifdef WOLFSSL_VALIDATE_ECC_IMPORT
+    if (ret == MP_OKAY)
+        ret = ecc_check_privkey_gen_helper(key);
+#endif
+
+    return ret;
+}
+
+/**
+   Convert ECC R,S to signature
+   r       R component of signature
+   s       S component of signature
+   out     DER-encoded ECDSA signature
+   outlen  [in/out] output buffer size, output signature size
+   return  MP_OKAY on success
+*/
+int wc_ecc_rs_to_sig(const char* r, const char* s, byte* out, word32* outlen)
+{
+    int err;
+    mp_int rtmp;
+    mp_int stmp;
+
+    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)
+        return err;
+
+    err = mp_read_radix(&rtmp, r, 16);
+    if (err == MP_OKAY)
+        err = mp_read_radix(&stmp, s, 16);
+
+    /* 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_iszero(&stmp))
+            err = MP_ZERO_E;
+    }
+
+    mp_clear(&rtmp);
+    mp_clear(&stmp);
+
+    return err;
+}
+
+/**
+   Import raw ECC key
+   key       The destination ecc_key structure
+   qx        x component of base point, as ASCII hex string
+   qy        y component of base point, as ASCII hex string
+   d         private key, as ASCII hex string
+   curveName ECC curve name, from ecc_sets[]
+   return    MP_OKAY on success
+*/
+int wc_ecc_import_raw(ecc_key* key, const char* qx, const char* qy,
+                   const char* d, const char* curveName)
+{
+    int err, x;
+
+    if (key == NULL || qx == NULL || qy == NULL || d == NULL ||
+        curveName == NULL)
+        return ECC_BAD_ARG_E;
+
+    /* init key */
+#ifdef ALT_ECC_SIZE
+    key->pubkey.x = (mp_int*)&key->pubkey.xyz[0];
+    key->pubkey.y = (mp_int*)&key->pubkey.xyz[1];
+    key->pubkey.z = (mp_int*)&key->pubkey.xyz[2];
+    alt_fp_init(key->pubkey.x);
+    alt_fp_init(key->pubkey.y);
+    alt_fp_init(key->pubkey.z);
+    err = mp_init(&key->k);
+#else
+    err = mp_init_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, &key->k,
+                      NULL, NULL);
+#endif
+    if (err != MP_OKAY)
+        return MEMORY_E;
+
+    /* read Qx */
+    if (err == MP_OKAY)
+        err = mp_read_radix(key->pubkey.x, qx, 16);
+
+    /* read Qy */
+    if (err == MP_OKAY)
+        err = mp_read_radix(key->pubkey.y, qy, 16);
+
+    if (err == MP_OKAY)
+        mp_set(key->pubkey.z, 1);
+
+    /* read and set the curve */
+    if (err == MP_OKAY) {
+        for (x = 0; ecc_sets[x].size != 0; x++) {
+            if (XSTRNCMP(ecc_sets[x].name, curveName,
+                         XSTRLEN(curveName)) == 0) {
+                break;
+            }
+        }
+        if (ecc_sets[x].size == 0) {
+            err = ASN_PARSE_E;
+        } else {
+            /* set the curve */
+            key->idx = x;
+            key->dp = &ecc_sets[x];
+            key->type = ECC_PUBLICKEY;
+        }
+    }
+
+    /* import private key */
+    if (err == MP_OKAY) {
+        key->type = ECC_PRIVATEKEY;
+        err = mp_read_radix(&key->k, d, 16);
+    }
+
+#ifdef WOLFSSL_VALIDATE_ECC_IMPORT
+    if (err == MP_OKAY)
+        err = wc_ecc_check_key(key);
+#endif
+
+    if (err != MP_OKAY) {
+        mp_clear(key->pubkey.x);
+        mp_clear(key->pubkey.y);
+        mp_clear(key->pubkey.z);
+        mp_clear(&key->k);
+    }
+
+    return err;
+}
+
+
+/* key size in octets */
+int wc_ecc_size(ecc_key* key)
+{
+    if (key == NULL) return 0;
+
+    return key->dp->size;
+}
+
+
+/* worst case estimate, check actual return from wc_ecc_sign_hash for actual value
+   of signature size in octets */
+int wc_ecc_sig_size(ecc_key* key)
+{
+    int sz = wc_ecc_size(key);
+    if (sz <= 0)
+        return sz;
+
+    return sz * 2 + SIG_HEADER_SZ + 4;  /* (4) worst case estimate */
+}
+
+
+#ifdef FP_ECC
+
+/* fixed point ECC cache */
+/* number of entries in the cache */
+#ifndef FP_ENTRIES
+    #define FP_ENTRIES 16
+#endif
+
+/* number of bits in LUT */
+#ifndef FP_LUT
+    #define FP_LUT     8U
+#endif
+
+#ifdef ECC_SHAMIR
+    /* Sharmir requires a bigger LUT, TAO */
+    #if (FP_LUT > 12) || (FP_LUT < 4)
+        #error FP_LUT must be between 4 and 12 inclusively
+    #endif
+#else
+    #if (FP_LUT > 12) || (FP_LUT < 2)
+        #error FP_LUT must be between 2 and 12 inclusively
+    #endif
+#endif
+
+
+/** Our FP cache */
+typedef struct {
+   ecc_point* g;               /* cached COPY of base point */
+   ecc_point* LUT[1U<<FP_LUT]; /* fixed point lookup */ 
+   mp_int     mu;              /* copy of the montgomery constant */
+   int        lru_count;       /* amount of times this entry has been used */
+   int        lock;            /* flag to indicate cache eviction */
+                               /* permitted (0) or not (1) */
+} fp_cache_t;
+
+/* if HAVE_THREAD_LS this cache is per thread, no locking needed */
+static THREAD_LS_T fp_cache_t fp_cache[FP_ENTRIES];
+
+#ifndef HAVE_THREAD_LS
+    static volatile int initMutex = 0;  /* prevent multiple mutex inits */
+    static wolfSSL_Mutex ecc_fp_lock;
+#endif /* HAVE_THREAD_LS */
+
+/* simple table to help direct the generation of the LUT */
+static const struct {
+   int ham, terma, termb;
+} lut_orders[] = {
+   { 0, 0, 0 }, { 1, 0, 0 }, { 1, 0, 0 }, { 2, 1, 2 }, { 1, 0, 0 }, { 2, 1, 4 }, { 2, 2, 4 }, { 3, 3, 4 }, 
+   { 1, 0, 0 }, { 2, 1, 8 }, { 2, 2, 8 }, { 3, 3, 8 }, { 2, 4, 8 }, { 3, 5, 8 }, { 3, 6, 8 }, { 4, 7, 8 }, 
+   { 1, 0, 0 }, { 2, 1, 16 }, { 2, 2, 16 }, { 3, 3, 16 }, { 2, 4, 16 }, { 3, 5, 16 }, { 3, 6, 16 }, { 4, 7, 16 }, 
+   { 2, 8, 16 }, { 3, 9, 16 }, { 3, 10, 16 }, { 4, 11, 16 }, { 3, 12, 16 }, { 4, 13, 16 }, { 4, 14, 16 }, { 5, 15, 16 }, 
+   { 1, 0, 0 }, { 2, 1, 32 }, { 2, 2, 32 }, { 3, 3, 32 }, { 2, 4, 32 }, { 3, 5, 32 }, { 3, 6, 32 }, { 4, 7, 32 }, 
+   { 2, 8, 32 }, { 3, 9, 32 }, { 3, 10, 32 }, { 4, 11, 32 }, { 3, 12, 32 }, { 4, 13, 32 }, { 4, 14, 32 }, { 5, 15, 32 }, 
+   { 2, 16, 32 }, { 3, 17, 32 }, { 3, 18, 32 }, { 4, 19, 32 }, { 3, 20, 32 }, { 4, 21, 32 }, { 4, 22, 32 }, { 5, 23, 32 }, 
+   { 3, 24, 32 }, { 4, 25, 32 }, { 4, 26, 32 }, { 5, 27, 32 }, { 4, 28, 32 }, { 5, 29, 32 }, { 5, 30, 32 }, { 6, 31, 32 }, 
+#if FP_LUT > 6
+   { 1, 0, 0 }, { 2, 1, 64 }, { 2, 2, 64 }, { 3, 3, 64 }, { 2, 4, 64 }, { 3, 5, 64 }, { 3, 6, 64 }, { 4, 7, 64 }, 
+   { 2, 8, 64 }, { 3, 9, 64 }, { 3, 10, 64 }, { 4, 11, 64 }, { 3, 12, 64 }, { 4, 13, 64 }, { 4, 14, 64 }, { 5, 15, 64 }, 
+   { 2, 16, 64 }, { 3, 17, 64 }, { 3, 18, 64 }, { 4, 19, 64 }, { 3, 20, 64 }, { 4, 21, 64 }, { 4, 22, 64 }, { 5, 23, 64 }, 
+   { 3, 24, 64 }, { 4, 25, 64 }, { 4, 26, 64 }, { 5, 27, 64 }, { 4, 28, 64 }, { 5, 29, 64 }, { 5, 30, 64 }, { 6, 31, 64 }, 
+   { 2, 32, 64 }, { 3, 33, 64 }, { 3, 34, 64 }, { 4, 35, 64 }, { 3, 36, 64 }, { 4, 37, 64 }, { 4, 38, 64 }, { 5, 39, 64 }, 
+   { 3, 40, 64 }, { 4, 41, 64 }, { 4, 42, 64 }, { 5, 43, 64 }, { 4, 44, 64 }, { 5, 45, 64 }, { 5, 46, 64 }, { 6, 47, 64 }, 
+   { 3, 48, 64 }, { 4, 49, 64 }, { 4, 50, 64 }, { 5, 51, 64 }, { 4, 52, 64 }, { 5, 53, 64 }, { 5, 54, 64 }, { 6, 55, 64 }, 
+   { 4, 56, 64 }, { 5, 57, 64 }, { 5, 58, 64 }, { 6, 59, 64 }, { 5, 60, 64 }, { 6, 61, 64 }, { 6, 62, 64 }, { 7, 63, 64 }, 
+#if FP_LUT > 7
+   { 1, 0, 0 }, { 2, 1, 128 }, { 2, 2, 128 }, { 3, 3, 128 }, { 2, 4, 128 }, { 3, 5, 128 }, { 3, 6, 128 }, { 4, 7, 128 }, 
+   { 2, 8, 128 }, { 3, 9, 128 }, { 3, 10, 128 }, { 4, 11, 128 }, { 3, 12, 128 }, { 4, 13, 128 }, { 4, 14, 128 }, { 5, 15, 128 }, 
+   { 2, 16, 128 }, { 3, 17, 128 }, { 3, 18, 128 }, { 4, 19, 128 }, { 3, 20, 128 }, { 4, 21, 128 }, { 4, 22, 128 }, { 5, 23, 128 }, 
+   { 3, 24, 128 }, { 4, 25, 128 }, { 4, 26, 128 }, { 5, 27, 128 }, { 4, 28, 128 }, { 5, 29, 128 }, { 5, 30, 128 }, { 6, 31, 128 }, 
+   { 2, 32, 128 }, { 3, 33, 128 }, { 3, 34, 128 }, { 4, 35, 128 }, { 3, 36, 128 }, { 4, 37, 128 }, { 4, 38, 128 }, { 5, 39, 128 }, 
+   { 3, 40, 128 }, { 4, 41, 128 }, { 4, 42, 128 }, { 5, 43, 128 }, { 4, 44, 128 }, { 5, 45, 128 }, { 5, 46, 128 }, { 6, 47, 128 }, 
+   { 3, 48, 128 }, { 4, 49, 128 }, { 4, 50, 128 }, { 5, 51, 128 }, { 4, 52, 128 }, { 5, 53, 128 }, { 5, 54, 128 }, { 6, 55, 128 }, 
+   { 4, 56, 128 }, { 5, 57, 128 }, { 5, 58, 128 }, { 6, 59, 128 }, { 5, 60, 128 }, { 6, 61, 128 }, { 6, 62, 128 }, { 7, 63, 128 }, 
+   { 2, 64, 128 }, { 3, 65, 128 }, { 3, 66, 128 }, { 4, 67, 128 }, { 3, 68, 128 }, { 4, 69, 128 }, { 4, 70, 128 }, { 5, 71, 128 }, 
+   { 3, 72, 128 }, { 4, 73, 128 }, { 4, 74, 128 }, { 5, 75, 128 }, { 4, 76, 128 }, { 5, 77, 128 }, { 5, 78, 128 }, { 6, 79, 128 }, 
+   { 3, 80, 128 }, { 4, 81, 128 }, { 4, 82, 128 }, { 5, 83, 128 }, { 4, 84, 128 }, { 5, 85, 128 }, { 5, 86, 128 }, { 6, 87, 128 }, 
+   { 4, 88, 128 }, { 5, 89, 128 }, { 5, 90, 128 }, { 6, 91, 128 }, { 5, 92, 128 }, { 6, 93, 128 }, { 6, 94, 128 }, { 7, 95, 128 }, 
+   { 3, 96, 128 }, { 4, 97, 128 }, { 4, 98, 128 }, { 5, 99, 128 }, { 4, 100, 128 }, { 5, 101, 128 }, { 5, 102, 128 }, { 6, 103, 128 }, 
+   { 4, 104, 128 }, { 5, 105, 128 }, { 5, 106, 128 }, { 6, 107, 128 }, { 5, 108, 128 }, { 6, 109, 128 }, { 6, 110, 128 }, { 7, 111, 128 }, 
+   { 4, 112, 128 }, { 5, 113, 128 }, { 5, 114, 128 }, { 6, 115, 128 }, { 5, 116, 128 }, { 6, 117, 128 }, { 6, 118, 128 }, { 7, 119, 128 }, 
+   { 5, 120, 128 }, { 6, 121, 128 }, { 6, 122, 128 }, { 7, 123, 128 }, { 6, 124, 128 }, { 7, 125, 128 }, { 7, 126, 128 }, { 8, 127, 128 }, 
+#if FP_LUT > 8
+   { 1, 0, 0 }, { 2, 1, 256 }, { 2, 2, 256 }, { 3, 3, 256 }, { 2, 4, 256 }, { 3, 5, 256 }, { 3, 6, 256 }, { 4, 7, 256 }, 
+   { 2, 8, 256 }, { 3, 9, 256 }, { 3, 10, 256 }, { 4, 11, 256 }, { 3, 12, 256 }, { 4, 13, 256 }, { 4, 14, 256 }, { 5, 15, 256 }, 
+   { 2, 16, 256 }, { 3, 17, 256 }, { 3, 18, 256 }, { 4, 19, 256 }, { 3, 20, 256 }, { 4, 21, 256 }, { 4, 22, 256 }, { 5, 23, 256 }, 
+   { 3, 24, 256 }, { 4, 25, 256 }, { 4, 26, 256 }, { 5, 27, 256 }, { 4, 28, 256 }, { 5, 29, 256 }, { 5, 30, 256 }, { 6, 31, 256 }, 
+   { 2, 32, 256 }, { 3, 33, 256 }, { 3, 34, 256 }, { 4, 35, 256 }, { 3, 36, 256 }, { 4, 37, 256 }, { 4, 38, 256 }, { 5, 39, 256 }, 
+   { 3, 40, 256 }, { 4, 41, 256 }, { 4, 42, 256 }, { 5, 43, 256 }, { 4, 44, 256 }, { 5, 45, 256 }, { 5, 46, 256 }, { 6, 47, 256 }, 
+   { 3, 48, 256 }, { 4, 49, 256 }, { 4, 50, 256 }, { 5, 51, 256 }, { 4, 52, 256 }, { 5, 53, 256 }, { 5, 54, 256 }, { 6, 55, 256 }, 
+   { 4, 56, 256 }, { 5, 57, 256 }, { 5, 58, 256 }, { 6, 59, 256 }, { 5, 60, 256 }, { 6, 61, 256 }, { 6, 62, 256 }, { 7, 63, 256 }, 
+   { 2, 64, 256 }, { 3, 65, 256 }, { 3, 66, 256 }, { 4, 67, 256 }, { 3, 68, 256 }, { 4, 69, 256 }, { 4, 70, 256 }, { 5, 71, 256 }, 
+   { 3, 72, 256 }, { 4, 73, 256 }, { 4, 74, 256 }, { 5, 75, 256 }, { 4, 76, 256 }, { 5, 77, 256 }, { 5, 78, 256 }, { 6, 79, 256 }, 
+   { 3, 80, 256 }, { 4, 81, 256 }, { 4, 82, 256 }, { 5, 83, 256 }, { 4, 84, 256 }, { 5, 85, 256 }, { 5, 86, 256 }, { 6, 87, 256 }, 
+   { 4, 88, 256 }, { 5, 89, 256 }, { 5, 90, 256 }, { 6, 91, 256 }, { 5, 92, 256 }, { 6, 93, 256 }, { 6, 94, 256 }, { 7, 95, 256 }, 
+   { 3, 96, 256 }, { 4, 97, 256 }, { 4, 98, 256 }, { 5, 99, 256 }, { 4, 100, 256 }, { 5, 101, 256 }, { 5, 102, 256 }, { 6, 103, 256 }, 
+   { 4, 104, 256 }, { 5, 105, 256 }, { 5, 106, 256 }, { 6, 107, 256 }, { 5, 108, 256 }, { 6, 109, 256 }, { 6, 110, 256 }, { 7, 111, 256 }, 
+   { 4, 112, 256 }, { 5, 113, 256 }, { 5, 114, 256 }, { 6, 115, 256 }, { 5, 116, 256 }, { 6, 117, 256 }, { 6, 118, 256 }, { 7, 119, 256 }, 
+   { 5, 120, 256 }, { 6, 121, 256 }, { 6, 122, 256 }, { 7, 123, 256 }, { 6, 124, 256 }, { 7, 125, 256 }, { 7, 126, 256 }, { 8, 127, 256 }, 
+   { 2, 128, 256 }, { 3, 129, 256 }, { 3, 130, 256 }, { 4, 131, 256 }, { 3, 132, 256 }, { 4, 133, 256 }, { 4, 134, 256 }, { 5, 135, 256 }, 
+   { 3, 136, 256 }, { 4, 137, 256 }, { 4, 138, 256 }, { 5, 139, 256 }, { 4, 140, 256 }, { 5, 141, 256 }, { 5, 142, 256 }, { 6, 143, 256 }, 
+   { 3, 144, 256 }, { 4, 145, 256 }, { 4, 146, 256 }, { 5, 147, 256 }, { 4, 148, 256 }, { 5, 149, 256 }, { 5, 150, 256 }, { 6, 151, 256 }, 
+   { 4, 152, 256 }, { 5, 153, 256 }, { 5, 154, 256 }, { 6, 155, 256 }, { 5, 156, 256 }, { 6, 157, 256 }, { 6, 158, 256 }, { 7, 159, 256 }, 
+   { 3, 160, 256 }, { 4, 161, 256 }, { 4, 162, 256 }, { 5, 163, 256 }, { 4, 164, 256 }, { 5, 165, 256 }, { 5, 166, 256 }, { 6, 167, 256 }, 
+   { 4, 168, 256 }, { 5, 169, 256 }, { 5, 170, 256 }, { 6, 171, 256 }, { 5, 172, 256 }, { 6, 173, 256 }, { 6, 174, 256 }, { 7, 175, 256 }, 
+   { 4, 176, 256 }, { 5, 177, 256 }, { 5, 178, 256 }, { 6, 179, 256 }, { 5, 180, 256 }, { 6, 181, 256 }, { 6, 182, 256 }, { 7, 183, 256 }, 
+   { 5, 184, 256 }, { 6, 185, 256 }, { 6, 186, 256 }, { 7, 187, 256 }, { 6, 188, 256 }, { 7, 189, 256 }, { 7, 190, 256 }, { 8, 191, 256 }, 
+   { 3, 192, 256 }, { 4, 193, 256 }, { 4, 194, 256 }, { 5, 195, 256 }, { 4, 196, 256 }, { 5, 197, 256 }, { 5, 198, 256 }, { 6, 199, 256 }, 
+   { 4, 200, 256 }, { 5, 201, 256 }, { 5, 202, 256 }, { 6, 203, 256 }, { 5, 204, 256 }, { 6, 205, 256 }, { 6, 206, 256 }, { 7, 207, 256 }, 
+   { 4, 208, 256 }, { 5, 209, 256 }, { 5, 210, 256 }, { 6, 211, 256 }, { 5, 212, 256 }, { 6, 213, 256 }, { 6, 214, 256 }, { 7, 215, 256 }, 
+   { 5, 216, 256 }, { 6, 217, 256 }, { 6, 218, 256 }, { 7, 219, 256 }, { 6, 220, 256 }, { 7, 221, 256 }, { 7, 222, 256 }, { 8, 223, 256 }, 
+   { 4, 224, 256 }, { 5, 225, 256 }, { 5, 226, 256 }, { 6, 227, 256 }, { 5, 228, 256 }, { 6, 229, 256 }, { 6, 230, 256 }, { 7, 231, 256 }, 
+   { 5, 232, 256 }, { 6, 233, 256 }, { 6, 234, 256 }, { 7, 235, 256 }, { 6, 236, 256 }, { 7, 237, 256 }, { 7, 238, 256 }, { 8, 239, 256 }, 
+   { 5, 240, 256 }, { 6, 241, 256 }, { 6, 242, 256 }, { 7, 243, 256 }, { 6, 244, 256 }, { 7, 245, 256 }, { 7, 246, 256 }, { 8, 247, 256 }, 
+   { 6, 248, 256 }, { 7, 249, 256 }, { 7, 250, 256 }, { 8, 251, 256 }, { 7, 252, 256 }, { 8, 253, 256 }, { 8, 254, 256 }, { 9, 255, 256 }, 
+#if FP_LUT > 9
+   { 1, 0, 0 }, { 2, 1, 512 }, { 2, 2, 512 }, { 3, 3, 512 }, { 2, 4, 512 }, { 3, 5, 512 }, { 3, 6, 512 }, { 4, 7, 512 }, 
+   { 2, 8, 512 }, { 3, 9, 512 }, { 3, 10, 512 }, { 4, 11, 512 }, { 3, 12, 512 }, { 4, 13, 512 }, { 4, 14, 512 }, { 5, 15, 512 }, 
+   { 2, 16, 512 }, { 3, 17, 512 }, { 3, 18, 512 }, { 4, 19, 512 }, { 3, 20, 512 }, { 4, 21, 512 }, { 4, 22, 512 }, { 5, 23, 512 }, 
+   { 3, 24, 512 }, { 4, 25, 512 }, { 4, 26, 512 }, { 5, 27, 512 }, { 4, 28, 512 }, { 5, 29, 512 }, { 5, 30, 512 }, { 6, 31, 512 }, 
+   { 2, 32, 512 }, { 3, 33, 512 }, { 3, 34, 512 }, { 4, 35, 512 }, { 3, 36, 512 }, { 4, 37, 512 }, { 4, 38, 512 }, { 5, 39, 512 }, 
+   { 3, 40, 512 }, { 4, 41, 512 }, { 4, 42, 512 }, { 5, 43, 512 }, { 4, 44, 512 }, { 5, 45, 512 }, { 5, 46, 512 }, { 6, 47, 512 }, 
+   { 3, 48, 512 }, { 4, 49, 512 }, { 4, 50, 512 }, { 5, 51, 512 }, { 4, 52, 512 }, { 5, 53, 512 }, { 5, 54, 512 }, { 6, 55, 512 }, 
+   { 4, 56, 512 }, { 5, 57, 512 }, { 5, 58, 512 }, { 6, 59, 512 }, { 5, 60, 512 }, { 6, 61, 512 }, { 6, 62, 512 }, { 7, 63, 512 }, 
+   { 2, 64, 512 }, { 3, 65, 512 }, { 3, 66, 512 }, { 4, 67, 512 }, { 3, 68, 512 }, { 4, 69, 512 }, { 4, 70, 512 }, { 5, 71, 512 }, 
+   { 3, 72, 512 }, { 4, 73, 512 }, { 4, 74, 512 }, { 5, 75, 512 }, { 4, 76, 512 }, { 5, 77, 512 }, { 5, 78, 512 }, { 6, 79, 512 }, 
+   { 3, 80, 512 }, { 4, 81, 512 }, { 4, 82, 512 }, { 5, 83, 512 }, { 4, 84, 512 }, { 5, 85, 512 }, { 5, 86, 512 }, { 6, 87, 512 }, 
+   { 4, 88, 512 }, { 5, 89, 512 }, { 5, 90, 512 }, { 6, 91, 512 }, { 5, 92, 512 }, { 6, 93, 512 }, { 6, 94, 512 }, { 7, 95, 512 }, 
+   { 3, 96, 512 }, { 4, 97, 512 }, { 4, 98, 512 }, { 5, 99, 512 }, { 4, 100, 512 }, { 5, 101, 512 }, { 5, 102, 512 }, { 6, 103, 512 }, 
+   { 4, 104, 512 }, { 5, 105, 512 }, { 5, 106, 512 }, { 6, 107, 512 }, { 5, 108, 512 }, { 6, 109, 512 }, { 6, 110, 512 }, { 7, 111, 512 }, 
+   { 4, 112, 512 }, { 5, 113, 512 }, { 5, 114, 512 }, { 6, 115, 512 }, { 5, 116, 512 }, { 6, 117, 512 }, { 6, 118, 512 }, { 7, 119, 512 }, 
+   { 5, 120, 512 }, { 6, 121, 512 }, { 6, 122, 512 }, { 7, 123, 512 }, { 6, 124, 512 }, { 7, 125, 512 }, { 7, 126, 512 }, { 8, 127, 512 }, 
+   { 2, 128, 512 }, { 3, 129, 512 }, { 3, 130, 512 }, { 4, 131, 512 }, { 3, 132, 512 }, { 4, 133, 512 }, { 4, 134, 512 }, { 5, 135, 512 }, 
+   { 3, 136, 512 }, { 4, 137, 512 }, { 4, 138, 512 }, { 5, 139, 512 }, { 4, 140, 512 }, { 5, 141, 512 }, { 5, 142, 512 }, { 6, 143, 512 }, 
+   { 3, 144, 512 }, { 4, 145, 512 }, { 4, 146, 512 }, { 5, 147, 512 }, { 4, 148, 512 }, { 5, 149, 512 }, { 5, 150, 512 }, { 6, 151, 512 }, 
+   { 4, 152, 512 }, { 5, 153, 512 }, { 5, 154, 512 }, { 6, 155, 512 }, { 5, 156, 512 }, { 6, 157, 512 }, { 6, 158, 512 }, { 7, 159, 512 }, 
+   { 3, 160, 512 }, { 4, 161, 512 }, { 4, 162, 512 }, { 5, 163, 512 }, { 4, 164, 512 }, { 5, 165, 512 }, { 5, 166, 512 }, { 6, 167, 512 }, 
+   { 4, 168, 512 }, { 5, 169, 512 }, { 5, 170, 512 }, { 6, 171, 512 }, { 5, 172, 512 }, { 6, 173, 512 }, { 6, 174, 512 }, { 7, 175, 512 }, 
+   { 4, 176, 512 }, { 5, 177, 512 }, { 5, 178, 512 }, { 6, 179, 512 }, { 5, 180, 512 }, { 6, 181, 512 }, { 6, 182, 512 }, { 7, 183, 512 }, 
+   { 5, 184, 512 }, { 6, 185, 512 }, { 6, 186, 512 }, { 7, 187, 512 }, { 6, 188, 512 }, { 7, 189, 512 }, { 7, 190, 512 }, { 8, 191, 512 }, 
+   { 3, 192, 512 }, { 4, 193, 512 }, { 4, 194, 512 }, { 5, 195, 512 }, { 4, 196, 512 }, { 5, 197, 512 }, { 5, 198, 512 }, { 6, 199, 512 }, 
+   { 4, 200, 512 }, { 5, 201, 512 }, { 5, 202, 512 }, { 6, 203, 512 }, { 5, 204, 512 }, { 6, 205, 512 }, { 6, 206, 512 }, { 7, 207, 512 }, 
+   { 4, 208, 512 }, { 5, 209, 512 }, { 5, 210, 512 }, { 6, 211, 512 }, { 5, 212, 512 }, { 6, 213, 512 }, { 6, 214, 512 }, { 7, 215, 512 }, 
+   { 5, 216, 512 }, { 6, 217, 512 }, { 6, 218, 512 }, { 7, 219, 512 }, { 6, 220, 512 }, { 7, 221, 512 }, { 7, 222, 512 }, { 8, 223, 512 }, 
+   { 4, 224, 512 }, { 5, 225, 512 }, { 5, 226, 512 }, { 6, 227, 512 }, { 5, 228, 512 }, { 6, 229, 512 }, { 6, 230, 512 }, { 7, 231, 512 }, 
+   { 5, 232, 512 }, { 6, 233, 512 }, { 6, 234, 512 }, { 7, 235, 512 }, { 6, 236, 512 }, { 7, 237, 512 }, { 7, 238, 512 }, { 8, 239, 512 }, 
+   { 5, 240, 512 }, { 6, 241, 512 }, { 6, 242, 512 }, { 7, 243, 512 }, { 6, 244, 512 }, { 7, 245, 512 }, { 7, 246, 512 }, { 8, 247, 512 }, 
+   { 6, 248, 512 }, { 7, 249, 512 }, { 7, 250, 512 }, { 8, 251, 512 }, { 7, 252, 512 }, { 8, 253, 512 }, { 8, 254, 512 }, { 9, 255, 512 }, 
+   { 2, 256, 512 }, { 3, 257, 512 }, { 3, 258, 512 }, { 4, 259, 512 }, { 3, 260, 512 }, { 4, 261, 512 }, { 4, 262, 512 }, { 5, 263, 512 }, 
+   { 3, 264, 512 }, { 4, 265, 512 }, { 4, 266, 512 }, { 5, 267, 512 }, { 4, 268, 512 }, { 5, 269, 512 }, { 5, 270, 512 }, { 6, 271, 512 }, 
+   { 3, 272, 512 }, { 4, 273, 512 }, { 4, 274, 512 }, { 5, 275, 512 }, { 4, 276, 512 }, { 5, 277, 512 }, { 5, 278, 512 }, { 6, 279, 512 }, 
+   { 4, 280, 512 }, { 5, 281, 512 }, { 5, 282, 512 }, { 6, 283, 512 }, { 5, 284, 512 }, { 6, 285, 512 }, { 6, 286, 512 }, { 7, 287, 512 }, 
+   { 3, 288, 512 }, { 4, 289, 512 }, { 4, 290, 512 }, { 5, 291, 512 }, { 4, 292, 512 }, { 5, 293, 512 }, { 5, 294, 512 }, { 6, 295, 512 }, 
+   { 4, 296, 512 }, { 5, 297, 512 }, { 5, 298, 512 }, { 6, 299, 512 }, { 5, 300, 512 }, { 6, 301, 512 }, { 6, 302, 512 }, { 7, 303, 512 }, 
+   { 4, 304, 512 }, { 5, 305, 512 }, { 5, 306, 512 }, { 6, 307, 512 }, { 5, 308, 512 }, { 6, 309, 512 }, { 6, 310, 512 }, { 7, 311, 512 }, 
+   { 5, 312, 512 }, { 6, 313, 512 }, { 6, 314, 512 }, { 7, 315, 512 }, { 6, 316, 512 }, { 7, 317, 512 }, { 7, 318, 512 }, { 8, 319, 512 }, 
+   { 3, 320, 512 }, { 4, 321, 512 }, { 4, 322, 512 }, { 5, 323, 512 }, { 4, 324, 512 }, { 5, 325, 512 }, { 5, 326, 512 }, { 6, 327, 512 }, 
+   { 4, 328, 512 }, { 5, 329, 512 }, { 5, 330, 512 }, { 6, 331, 512 }, { 5, 332, 512 }, { 6, 333, 512 }, { 6, 334, 512 }, { 7, 335, 512 }, 
+   { 4, 336, 512 }, { 5, 337, 512 }, { 5, 338, 512 }, { 6, 339, 512 }, { 5, 340, 512 }, { 6, 341, 512 }, { 6, 342, 512 }, { 7, 343, 512 }, 
+   { 5, 344, 512 }, { 6, 345, 512 }, { 6, 346, 512 }, { 7, 347, 512 }, { 6, 348, 512 }, { 7, 349, 512 }, { 7, 350, 512 }, { 8, 351, 512 }, 
+   { 4, 352, 512 }, { 5, 353, 512 }, { 5, 354, 512 }, { 6, 355, 512 }, { 5, 356, 512 }, { 6, 357, 512 }, { 6, 358, 512 }, { 7, 359, 512 }, 
+   { 5, 360, 512 }, { 6, 361, 512 }, { 6, 362, 512 }, { 7, 363, 512 }, { 6, 364, 512 }, { 7, 365, 512 }, { 7, 366, 512 }, { 8, 367, 512 }, 
+   { 5, 368, 512 }, { 6, 369, 512 }, { 6, 370, 512 }, { 7, 371, 512 }, { 6, 372, 512 }, { 7, 373, 512 }, { 7, 374, 512 }, { 8, 375, 512 }, 
+   { 6, 376, 512 }, { 7, 377, 512 }, { 7, 378, 512 }, { 8, 379, 512 }, { 7, 380, 512 }, { 8, 381, 512 }, { 8, 382, 512 }, { 9, 383, 512 }, 
+   { 3, 384, 512 }, { 4, 385, 512 }, { 4, 386, 512 }, { 5, 387, 512 }, { 4, 388, 512 }, { 5, 389, 512 }, { 5, 390, 512 }, { 6, 391, 512 }, 
+   { 4, 392, 512 }, { 5, 393, 512 }, { 5, 394, 512 }, { 6, 395, 512 }, { 5, 396, 512 }, { 6, 397, 512 }, { 6, 398, 512 }, { 7, 399, 512 }, 
+   { 4, 400, 512 }, { 5, 401, 512 }, { 5, 402, 512 }, { 6, 403, 512 }, { 5, 404, 512 }, { 6, 405, 512 }, { 6, 406, 512 }, { 7, 407, 512 }, 
+   { 5, 408, 512 }, { 6, 409, 512 }, { 6, 410, 512 }, { 7, 411, 512 }, { 6, 412, 512 }, { 7, 413, 512 }, { 7, 414, 512 }, { 8, 415, 512 }, 
+   { 4, 416, 512 }, { 5, 417, 512 }, { 5, 418, 512 }, { 6, 419, 512 }, { 5, 420, 512 }, { 6, 421, 512 }, { 6, 422, 512 }, { 7, 423, 512 }, 
+   { 5, 424, 512 }, { 6, 425, 512 }, { 6, 426, 512 }, { 7, 427, 512 }, { 6, 428, 512 }, { 7, 429, 512 }, { 7, 430, 512 }, { 8, 431, 512 }, 
+   { 5, 432, 512 }, { 6, 433, 512 }, { 6, 434, 512 }, { 7, 435, 512 }, { 6, 436, 512 }, { 7, 437, 512 }, { 7, 438, 512 }, { 8, 439, 512 }, 
+   { 6, 440, 512 }, { 7, 441, 512 }, { 7, 442, 512 }, { 8, 443, 512 }, { 7, 444, 512 }, { 8, 445, 512 }, { 8, 446, 512 }, { 9, 447, 512 }, 
+   { 4, 448, 512 }, { 5, 449, 512 }, { 5, 450, 512 }, { 6, 451, 512 }, { 5, 452, 512 }, { 6, 453, 512 }, { 6, 454, 512 }, { 7, 455, 512 }, 
+   { 5, 456, 512 }, { 6, 457, 512 }, { 6, 458, 512 }, { 7, 459, 512 }, { 6, 460, 512 }, { 7, 461, 512 }, { 7, 462, 512 }, { 8, 463, 512 }, 
+   { 5, 464, 512 }, { 6, 465, 512 }, { 6, 466, 512 }, { 7, 467, 512 }, { 6, 468, 512 }, { 7, 469, 512 }, { 7, 470, 512 }, { 8, 471, 512 }, 
+   { 6, 472, 512 }, { 7, 473, 512 }, { 7, 474, 512 }, { 8, 475, 512 }, { 7, 476, 512 }, { 8, 477, 512 }, { 8, 478, 512 }, { 9, 479, 512 }, 
+   { 5, 480, 512 }, { 6, 481, 512 }, { 6, 482, 512 }, { 7, 483, 512 }, { 6, 484, 512 }, { 7, 485, 512 }, { 7, 486, 512 }, { 8, 487, 512 }, 
+   { 6, 488, 512 }, { 7, 489, 512 }, { 7, 490, 512 }, { 8, 491, 512 }, { 7, 492, 512 }, { 8, 493, 512 }, { 8, 494, 512 }, { 9, 495, 512 }, 
+   { 6, 496, 512 }, { 7, 497, 512 }, { 7, 498, 512 }, { 8, 499, 512 }, { 7, 500, 512 }, { 8, 501, 512 }, { 8, 502, 512 }, { 9, 503, 512 }, 
+   { 7, 504, 512 }, { 8, 505, 512 }, { 8, 506, 512 }, { 9, 507, 512 }, { 8, 508, 512 }, { 9, 509, 512 }, { 9, 510, 512 }, { 10, 511, 512 }, 
+#if FP_LUT > 10
+   { 1, 0, 0 }, { 2, 1, 1024 }, { 2, 2, 1024 }, { 3, 3, 1024 }, { 2, 4, 1024 }, { 3, 5, 1024 }, { 3, 6, 1024 }, { 4, 7, 1024 }, 
+   { 2, 8, 1024 }, { 3, 9, 1024 }, { 3, 10, 1024 }, { 4, 11, 1024 }, { 3, 12, 1024 }, { 4, 13, 1024 }, { 4, 14, 1024 }, { 5, 15, 1024 }, 
+   { 2, 16, 1024 }, { 3, 17, 1024 }, { 3, 18, 1024 }, { 4, 19, 1024 }, { 3, 20, 1024 }, { 4, 21, 1024 }, { 4, 22, 1024 }, { 5, 23, 1024 }, 
+   { 3, 24, 1024 }, { 4, 25, 1024 }, { 4, 26, 1024 }, { 5, 27, 1024 }, { 4, 28, 1024 }, { 5, 29, 1024 }, { 5, 30, 1024 }, { 6, 31, 1024 }, 
+   { 2, 32, 1024 }, { 3, 33, 1024 }, { 3, 34, 1024 }, { 4, 35, 1024 }, { 3, 36, 1024 }, { 4, 37, 1024 }, { 4, 38, 1024 }, { 5, 39, 1024 }, 
+   { 3, 40, 1024 }, { 4, 41, 1024 }, { 4, 42, 1024 }, { 5, 43, 1024 }, { 4, 44, 1024 }, { 5, 45, 1024 }, { 5, 46, 1024 }, { 6, 47, 1024 }, 
+   { 3, 48, 1024 }, { 4, 49, 1024 }, { 4, 50, 1024 }, { 5, 51, 1024 }, { 4, 52, 1024 }, { 5, 53, 1024 }, { 5, 54, 1024 }, { 6, 55, 1024 }, 
+   { 4, 56, 1024 }, { 5, 57, 1024 }, { 5, 58, 1024 }, { 6, 59, 1024 }, { 5, 60, 1024 }, { 6, 61, 1024 }, { 6, 62, 1024 }, { 7, 63, 1024 }, 
+   { 2, 64, 1024 }, { 3, 65, 1024 }, { 3, 66, 1024 }, { 4, 67, 1024 }, { 3, 68, 1024 }, { 4, 69, 1024 }, { 4, 70, 1024 }, { 5, 71, 1024 }, 
+   { 3, 72, 1024 }, { 4, 73, 1024 }, { 4, 74, 1024 }, { 5, 75, 1024 }, { 4, 76, 1024 }, { 5, 77, 1024 }, { 5, 78, 1024 }, { 6, 79, 1024 }, 
+   { 3, 80, 1024 }, { 4, 81, 1024 }, { 4, 82, 1024 }, { 5, 83, 1024 }, { 4, 84, 1024 }, { 5, 85, 1024 }, { 5, 86, 1024 }, { 6, 87, 1024 }, 
+   { 4, 88, 1024 }, { 5, 89, 1024 }, { 5, 90, 1024 }, { 6, 91, 1024 }, { 5, 92, 1024 }, { 6, 93, 1024 }, { 6, 94, 1024 }, { 7, 95, 1024 }, 
+   { 3, 96, 1024 }, { 4, 97, 1024 }, { 4, 98, 1024 }, { 5, 99, 1024 }, { 4, 100, 1024 }, { 5, 101, 1024 }, { 5, 102, 1024 }, { 6, 103, 1024 }, 
+   { 4, 104, 1024 }, { 5, 105, 1024 }, { 5, 106, 1024 }, { 6, 107, 1024 }, { 5, 108, 1024 }, { 6, 109, 1024 }, { 6, 110, 1024 }, { 7, 111, 1024 }, 
+   { 4, 112, 1024 }, { 5, 113, 1024 }, { 5, 114, 1024 }, { 6, 115, 1024 }, { 5, 116, 1024 }, { 6, 117, 1024 }, { 6, 118, 1024 }, { 7, 119, 1024 }, 
+   { 5, 120, 1024 }, { 6, 121, 1024 }, { 6, 122, 1024 }, { 7, 123, 1024 }, { 6, 124, 1024 }, { 7, 125, 1024 }, { 7, 126, 1024 }, { 8, 127, 1024 }, 
+   { 2, 128, 1024 }, { 3, 129, 1024 }, { 3, 130, 1024 }, { 4, 131, 1024 }, { 3, 132, 1024 }, { 4, 133, 1024 }, { 4, 134, 1024 }, { 5, 135, 1024 }, 
+   { 3, 136, 1024 }, { 4, 137, 1024 }, { 4, 138, 1024 }, { 5, 139, 1024 }, { 4, 140, 1024 }, { 5, 141, 1024 }, { 5, 142, 1024 }, { 6, 143, 1024 }, 
+   { 3, 144, 1024 }, { 4, 145, 1024 }, { 4, 146, 1024 }, { 5, 147, 1024 }, { 4, 148, 1024 }, { 5, 149, 1024 }, { 5, 150, 1024 }, { 6, 151, 1024 }, 
+   { 4, 152, 1024 }, { 5, 153, 1024 }, { 5, 154, 1024 }, { 6, 155, 1024 }, { 5, 156, 1024 }, { 6, 157, 1024 }, { 6, 158, 1024 }, { 7, 159, 1024 }, 
+   { 3, 160, 1024 }, { 4, 161, 1024 }, { 4, 162, 1024 }, { 5, 163, 1024 }, { 4, 164, 1024 }, { 5, 165, 1024 }, { 5, 166, 1024 }, { 6, 167, 1024 }, 
+   { 4, 168, 1024 }, { 5, 169, 1024 }, { 5, 170, 1024 }, { 6, 171, 1024 }, { 5, 172, 1024 }, { 6, 173, 1024 }, { 6, 174, 1024 }, { 7, 175, 1024 }, 
+   { 4, 176, 1024 }, { 5, 177, 1024 }, { 5, 178, 1024 }, { 6, 179, 1024 }, { 5, 180, 1024 }, { 6, 181, 1024 }, { 6, 182, 1024 }, { 7, 183, 1024 }, 
+   { 5, 184, 1024 }, { 6, 185, 1024 }, { 6, 186, 1024 }, { 7, 187, 1024 }, { 6, 188, 1024 }, { 7, 189, 1024 }, { 7, 190, 1024 }, { 8, 191, 1024 }, 
+   { 3, 192, 1024 }, { 4, 193, 1024 }, { 4, 194, 1024 }, { 5, 195, 1024 }, { 4, 196, 1024 }, { 5, 197, 1024 }, { 5, 198, 1024 }, { 6, 199, 1024 }, 
+   { 4, 200, 1024 }, { 5, 201, 1024 }, { 5, 202, 1024 }, { 6, 203, 1024 }, { 5, 204, 1024 }, { 6, 205, 1024 }, { 6, 206, 1024 }, { 7, 207, 1024 }, 
+   { 4, 208, 1024 }, { 5, 209, 1024 }, { 5, 210, 1024 }, { 6, 211, 1024 }, { 5, 212, 1024 }, { 6, 213, 1024 }, { 6, 214, 1024 }, { 7, 215, 1024 }, 
+   { 5, 216, 1024 }, { 6, 217, 1024 }, { 6, 218, 1024 }, { 7, 219, 1024 }, { 6, 220, 1024 }, { 7, 221, 1024 }, { 7, 222, 1024 }, { 8, 223, 1024 }, 
+   { 4, 224, 1024 }, { 5, 225, 1024 }, { 5, 226, 1024 }, { 6, 227, 1024 }, { 5, 228, 1024 }, { 6, 229, 1024 }, { 6, 230, 1024 }, { 7, 231, 1024 }, 
+   { 5, 232, 1024 }, { 6, 233, 1024 }, { 6, 234, 1024 }, { 7, 235, 1024 }, { 6, 236, 1024 }, { 7, 237, 1024 }, { 7, 238, 1024 }, { 8, 239, 1024 }, 
+   { 5, 240, 1024 }, { 6, 241, 1024 }, { 6, 242, 1024 }, { 7, 243, 1024 }, { 6, 244, 1024 }, { 7, 245, 1024 }, { 7, 246, 1024 }, { 8, 247, 1024 }, 
+   { 6, 248, 1024 }, { 7, 249, 1024 }, { 7, 250, 1024 }, { 8, 251, 1024 }, { 7, 252, 1024 }, { 8, 253, 1024 }, { 8, 254, 1024 }, { 9, 255, 1024 }, 
+   { 2, 256, 1024 }, { 3, 257, 1024 }, { 3, 258, 1024 }, { 4, 259, 1024 }, { 3, 260, 1024 }, { 4, 261, 1024 }, { 4, 262, 1024 }, { 5, 263, 1024 }, 
+   { 3, 264, 1024 }, { 4, 265, 1024 }, { 4, 266, 1024 }, { 5, 267, 1024 }, { 4, 268, 1024 }, { 5, 269, 1024 }, { 5, 270, 1024 }, { 6, 271, 1024 }, 
+   { 3, 272, 1024 }, { 4, 273, 1024 }, { 4, 274, 1024 }, { 5, 275, 1024 }, { 4, 276, 1024 }, { 5, 277, 1024 }, { 5, 278, 1024 }, { 6, 279, 1024 }, 
+   { 4, 280, 1024 }, { 5, 281, 1024 }, { 5, 282, 1024 }, { 6, 283, 1024 }, { 5, 284, 1024 }, { 6, 285, 1024 }, { 6, 286, 1024 }, { 7, 287, 1024 }, 
+   { 3, 288, 1024 }, { 4, 289, 1024 }, { 4, 290, 1024 }, { 5, 291, 1024 }, { 4, 292, 1024 }, { 5, 293, 1024 }, { 5, 294, 1024 }, { 6, 295, 1024 }, 
+   { 4, 296, 1024 }, { 5, 297, 1024 }, { 5, 298, 1024 }, { 6, 299, 1024 }, { 5, 300, 1024 }, { 6, 301, 1024 }, { 6, 302, 1024 }, { 7, 303, 1024 }, 
+   { 4, 304, 1024 }, { 5, 305, 1024 }, { 5, 306, 1024 }, { 6, 307, 1024 }, { 5, 308, 1024 }, { 6, 309, 1024 }, { 6, 310, 1024 }, { 7, 311, 1024 }, 
+   { 5, 312, 1024 }, { 6, 313, 1024 }, { 6, 314, 1024 }, { 7, 315, 1024 }, { 6, 316, 1024 }, { 7, 317, 1024 }, { 7, 318, 1024 }, { 8, 319, 1024 }, 
+   { 3, 320, 1024 }, { 4, 321, 1024 }, { 4, 322, 1024 }, { 5, 323, 1024 }, { 4, 324, 1024 }, { 5, 325, 1024 }, { 5, 326, 1024 }, { 6, 327, 1024 }, 
+   { 4, 328, 1024 }, { 5, 329, 1024 }, { 5, 330, 1024 }, { 6, 331, 1024 }, { 5, 332, 1024 }, { 6, 333, 1024 }, { 6, 334, 1024 }, { 7, 335, 1024 }, 
+   { 4, 336, 1024 }, { 5, 337, 1024 }, { 5, 338, 1024 }, { 6, 339, 1024 }, { 5, 340, 1024 }, { 6, 341, 1024 }, { 6, 342, 1024 }, { 7, 343, 1024 }, 
+   { 5, 344, 1024 }, { 6, 345, 1024 }, { 6, 346, 1024 }, { 7, 347, 1024 }, { 6, 348, 1024 }, { 7, 349, 1024 }, { 7, 350, 1024 }, { 8, 351, 1024 }, 
+   { 4, 352, 1024 }, { 5, 353, 1024 }, { 5, 354, 1024 }, { 6, 355, 1024 }, { 5, 356, 1024 }, { 6, 357, 1024 }, { 6, 358, 1024 }, { 7, 359, 1024 }, 
+   { 5, 360, 1024 }, { 6, 361, 1024 }, { 6, 362, 1024 }, { 7, 363, 1024 }, { 6, 364, 1024 }, { 7, 365, 1024 }, { 7, 366, 1024 }, { 8, 367, 1024 }, 
+   { 5, 368, 1024 }, { 6, 369, 1024 }, { 6, 370, 1024 }, { 7, 371, 1024 }, { 6, 372, 1024 }, { 7, 373, 1024 }, { 7, 374, 1024 }, { 8, 375, 1024 }, 
+   { 6, 376, 1024 }, { 7, 377, 1024 }, { 7, 378, 1024 }, { 8, 379, 1024 }, { 7, 380, 1024 }, { 8, 381, 1024 }, { 8, 382, 1024 }, { 9, 383, 1024 }, 
+   { 3, 384, 1024 }, { 4, 385, 1024 }, { 4, 386, 1024 }, { 5, 387, 1024 }, { 4, 388, 1024 }, { 5, 389, 1024 }, { 5, 390, 1024 }, { 6, 391, 1024 }, 
+   { 4, 392, 1024 }, { 5, 393, 1024 }, { 5, 394, 1024 }, { 6, 395, 1024 }, { 5, 396, 1024 }, { 6, 397, 1024 }, { 6, 398, 1024 }, { 7, 399, 1024 }, 
+   { 4, 400, 1024 }, { 5, 401, 1024 }, { 5, 402, 1024 }, { 6, 403, 1024 }, { 5, 404, 1024 }, { 6, 405, 1024 }, { 6, 406, 1024 }, { 7, 407, 1024 }, 
+   { 5, 408, 1024 }, { 6, 409, 1024 }, { 6, 410, 1024 }, { 7, 411, 1024 }, { 6, 412, 1024 }, { 7, 413, 1024 }, { 7, 414, 1024 }, { 8, 415, 1024 }, 
+   { 4, 416, 1024 }, { 5, 417, 1024 }, { 5, 418, 1024 }, { 6, 419, 1024 }, { 5, 420, 1024 }, { 6, 421, 1024 }, { 6, 422, 1024 }, { 7, 423, 1024 }, 
+   { 5, 424, 1024 }, { 6, 425, 1024 }, { 6, 426, 1024 }, { 7, 427, 1024 }, { 6, 428, 1024 }, { 7, 429, 1024 }, { 7, 430, 1024 }, { 8, 431, 1024 }, 
+   { 5, 432, 1024 }, { 6, 433, 1024 }, { 6, 434, 1024 }, { 7, 435, 1024 }, { 6, 436, 1024 }, { 7, 437, 1024 }, { 7, 438, 1024 }, { 8, 439, 1024 }, 
+   { 6, 440, 1024 }, { 7, 441, 1024 }, { 7, 442, 1024 }, { 8, 443, 1024 }, { 7, 444, 1024 }, { 8, 445, 1024 }, { 8, 446, 1024 }, { 9, 447, 1024 }, 
+   { 4, 448, 1024 }, { 5, 449, 1024 }, { 5, 450, 1024 }, { 6, 451, 1024 }, { 5, 452, 1024 }, { 6, 453, 1024 }, { 6, 454, 1024 }, { 7, 455, 1024 }, 
+   { 5, 456, 1024 }, { 6, 457, 1024 }, { 6, 458, 1024 }, { 7, 459, 1024 }, { 6, 460, 1024 }, { 7, 461, 1024 }, { 7, 462, 1024 }, { 8, 463, 1024 }, 
+   { 5, 464, 1024 }, { 6, 465, 1024 }, { 6, 466, 1024 }, { 7, 467, 1024 }, { 6, 468, 1024 }, { 7, 469, 1024 }, { 7, 470, 1024 }, { 8, 471, 1024 }, 
+   { 6, 472, 1024 }, { 7, 473, 1024 }, { 7, 474, 1024 }, { 8, 475, 1024 }, { 7, 476, 1024 }, { 8, 477, 1024 }, { 8, 478, 1024 }, { 9, 479, 1024 }, 
+   { 5, 480, 1024 }, { 6, 481, 1024 }, { 6, 482, 1024 }, { 7, 483, 1024 }, { 6, 484, 1024 }, { 7, 485, 1024 }, { 7, 486, 1024 }, { 8, 487, 1024 }, 
+   { 6, 488, 1024 }, { 7, 489, 1024 }, { 7, 490, 1024 }, { 8, 491, 1024 }, { 7, 492, 1024 }, { 8, 493, 1024 }, { 8, 494, 1024 }, { 9, 495, 1024 }, 
+   { 6, 496, 1024 }, { 7, 497, 1024 }, { 7, 498, 1024 }, { 8, 499, 1024 }, { 7, 500, 1024 }, { 8, 501, 1024 }, { 8, 502, 1024 }, { 9, 503, 1024 }, 
+   { 7, 504, 1024 }, { 8, 505, 1024 }, { 8, 506, 1024 }, { 9, 507, 1024 }, { 8, 508, 1024 }, { 9, 509, 1024 }, { 9, 510, 1024 }, { 10, 511, 1024 }, 
+   { 2, 512, 1024 }, { 3, 513, 1024 }, { 3, 514, 1024 }, { 4, 515, 1024 }, { 3, 516, 1024 }, { 4, 517, 1024 }, { 4, 518, 1024 }, { 5, 519, 1024 }, 
+   { 3, 520, 1024 }, { 4, 521, 1024 }, { 4, 522, 1024 }, { 5, 523, 1024 }, { 4, 524, 1024 }, { 5, 525, 1024 }, { 5, 526, 1024 }, { 6, 527, 1024 }, 
+   { 3, 528, 1024 }, { 4, 529, 1024 }, { 4, 530, 1024 }, { 5, 531, 1024 }, { 4, 532, 1024 }, { 5, 533, 1024 }, { 5, 534, 1024 }, { 6, 535, 1024 }, 
+   { 4, 536, 1024 }, { 5, 537, 1024 }, { 5, 538, 1024 }, { 6, 539, 1024 }, { 5, 540, 1024 }, { 6, 541, 1024 }, { 6, 542, 1024 }, { 7, 543, 1024 }, 
+   { 3, 544, 1024 }, { 4, 545, 1024 }, { 4, 546, 1024 }, { 5, 547, 1024 }, { 4, 548, 1024 }, { 5, 549, 1024 }, { 5, 550, 1024 }, { 6, 551, 1024 }, 
+   { 4, 552, 1024 }, { 5, 553, 1024 }, { 5, 554, 1024 }, { 6, 555, 1024 }, { 5, 556, 1024 }, { 6, 557, 1024 }, { 6, 558, 1024 }, { 7, 559, 1024 }, 
+   { 4, 560, 1024 }, { 5, 561, 1024 }, { 5, 562, 1024 }, { 6, 563, 1024 }, { 5, 564, 1024 }, { 6, 565, 1024 }, { 6, 566, 1024 }, { 7, 567, 1024 }, 
+   { 5, 568, 1024 }, { 6, 569, 1024 }, { 6, 570, 1024 }, { 7, 571, 1024 }, { 6, 572, 1024 }, { 7, 573, 1024 }, { 7, 574, 1024 }, { 8, 575, 1024 }, 
+   { 3, 576, 1024 }, { 4, 577, 1024 }, { 4, 578, 1024 }, { 5, 579, 1024 }, { 4, 580, 1024 }, { 5, 581, 1024 }, { 5, 582, 1024 }, { 6, 583, 1024 }, 
+   { 4, 584, 1024 }, { 5, 585, 1024 }, { 5, 586, 1024 }, { 6, 587, 1024 }, { 5, 588, 1024 }, { 6, 589, 1024 }, { 6, 590, 1024 }, { 7, 591, 1024 }, 
+   { 4, 592, 1024 }, { 5, 593, 1024 }, { 5, 594, 1024 }, { 6, 595, 1024 }, { 5, 596, 1024 }, { 6, 597, 1024 }, { 6, 598, 1024 }, { 7, 599, 1024 }, 
+   { 5, 600, 1024 }, { 6, 601, 1024 }, { 6, 602, 1024 }, { 7, 603, 1024 }, { 6, 604, 1024 }, { 7, 605, 1024 }, { 7, 606, 1024 }, { 8, 607, 1024 }, 
+   { 4, 608, 1024 }, { 5, 609, 1024 }, { 5, 610, 1024 }, { 6, 611, 1024 }, { 5, 612, 1024 }, { 6, 613, 1024 }, { 6, 614, 1024 }, { 7, 615, 1024 }, 
+   { 5, 616, 1024 }, { 6, 617, 1024 }, { 6, 618, 1024 }, { 7, 619, 1024 }, { 6, 620, 1024 }, { 7, 621, 1024 }, { 7, 622, 1024 }, { 8, 623, 1024 }, 
+   { 5, 624, 1024 }, { 6, 625, 1024 }, { 6, 626, 1024 }, { 7, 627, 1024 }, { 6, 628, 1024 }, { 7, 629, 1024 }, { 7, 630, 1024 }, { 8, 631, 1024 }, 
+   { 6, 632, 1024 }, { 7, 633, 1024 }, { 7, 634, 1024 }, { 8, 635, 1024 }, { 7, 636, 1024 }, { 8, 637, 1024 }, { 8, 638, 1024 }, { 9, 639, 1024 }, 
+   { 3, 640, 1024 }, { 4, 641, 1024 }, { 4, 642, 1024 }, { 5, 643, 1024 }, { 4, 644, 1024 }, { 5, 645, 1024 }, { 5, 646, 1024 }, { 6, 647, 1024 }, 
+   { 4, 648, 1024 }, { 5, 649, 1024 }, { 5, 650, 1024 }, { 6, 651, 1024 }, { 5, 652, 1024 }, { 6, 653, 1024 }, { 6, 654, 1024 }, { 7, 655, 1024 }, 
+   { 4, 656, 1024 }, { 5, 657, 1024 }, { 5, 658, 1024 }, { 6, 659, 1024 }, { 5, 660, 1024 }, { 6, 661, 1024 }, { 6, 662, 1024 }, { 7, 663, 1024 }, 
+   { 5, 664, 1024 }, { 6, 665, 1024 }, { 6, 666, 1024 }, { 7, 667, 1024 }, { 6, 668, 1024 }, { 7, 669, 1024 }, { 7, 670, 1024 }, { 8, 671, 1024 }, 
+   { 4, 672, 1024 }, { 5, 673, 1024 }, { 5, 674, 1024 }, { 6, 675, 1024 }, { 5, 676, 1024 }, { 6, 677, 1024 }, { 6, 678, 1024 }, { 7, 679, 1024 }, 
+   { 5, 680, 1024 }, { 6, 681, 1024 }, { 6, 682, 1024 }, { 7, 683, 1024 }, { 6, 684, 1024 }, { 7, 685, 1024 }, { 7, 686, 1024 }, { 8, 687, 1024 }, 
+   { 5, 688, 1024 }, { 6, 689, 1024 }, { 6, 690, 1024 }, { 7, 691, 1024 }, { 6, 692, 1024 }, { 7, 693, 1024 }, { 7, 694, 1024 }, { 8, 695, 1024 }, 
+   { 6, 696, 1024 }, { 7, 697, 1024 }, { 7, 698, 1024 }, { 8, 699, 1024 }, { 7, 700, 1024 }, { 8, 701, 1024 }, { 8, 702, 1024 }, { 9, 703, 1024 }, 
+   { 4, 704, 1024 }, { 5, 705, 1024 }, { 5, 706, 1024 }, { 6, 707, 1024 }, { 5, 708, 1024 }, { 6, 709, 1024 }, { 6, 710, 1024 }, { 7, 711, 1024 }, 
+   { 5, 712, 1024 }, { 6, 713, 1024 }, { 6, 714, 1024 }, { 7, 715, 1024 }, { 6, 716, 1024 }, { 7, 717, 1024 }, { 7, 718, 1024 }, { 8, 719, 1024 }, 
+   { 5, 720, 1024 }, { 6, 721, 1024 }, { 6, 722, 1024 }, { 7, 723, 1024 }, { 6, 724, 1024 }, { 7, 725, 1024 }, { 7, 726, 1024 }, { 8, 727, 1024 }, 
+   { 6, 728, 1024 }, { 7, 729, 1024 }, { 7, 730, 1024 }, { 8, 731, 1024 }, { 7, 732, 1024 }, { 8, 733, 1024 }, { 8, 734, 1024 }, { 9, 735, 1024 }, 
+   { 5, 736, 1024 }, { 6, 737, 1024 }, { 6, 738, 1024 }, { 7, 739, 1024 }, { 6, 740, 1024 }, { 7, 741, 1024 }, { 7, 742, 1024 }, { 8, 743, 1024 }, 
+   { 6, 744, 1024 }, { 7, 745, 1024 }, { 7, 746, 1024 }, { 8, 747, 1024 }, { 7, 748, 1024 }, { 8, 749, 1024 }, { 8, 750, 1024 }, { 9, 751, 1024 }, 
+   { 6, 752, 1024 }, { 7, 753, 1024 }, { 7, 754, 1024 }, { 8, 755, 1024 }, { 7, 756, 1024 }, { 8, 757, 1024 }, { 8, 758, 1024 }, { 9, 759, 1024 }, 
+   { 7, 760, 1024 }, { 8, 761, 1024 }, { 8, 762, 1024 }, { 9, 763, 1024 }, { 8, 764, 1024 }, { 9, 765, 1024 }, { 9, 766, 1024 }, { 10, 767, 1024 }, 
+   { 3, 768, 1024 }, { 4, 769, 1024 }, { 4, 770, 1024 }, { 5, 771, 1024 }, { 4, 772, 1024 }, { 5, 773, 1024 }, { 5, 774, 1024 }, { 6, 775, 1024 }, 
+   { 4, 776, 1024 }, { 5, 777, 1024 }, { 5, 778, 1024 }, { 6, 779, 1024 }, { 5, 780, 1024 }, { 6, 781, 1024 }, { 6, 782, 1024 }, { 7, 783, 1024 }, 
+   { 4, 784, 1024 }, { 5, 785, 1024 }, { 5, 786, 1024 }, { 6, 787, 1024 }, { 5, 788, 1024 }, { 6, 789, 1024 }, { 6, 790, 1024 }, { 7, 791, 1024 }, 
+   { 5, 792, 1024 }, { 6, 793, 1024 }, { 6, 794, 1024 }, { 7, 795, 1024 }, { 6, 796, 1024 }, { 7, 797, 1024 }, { 7, 798, 1024 }, { 8, 799, 1024 }, 
+   { 4, 800, 1024 }, { 5, 801, 1024 }, { 5, 802, 1024 }, { 6, 803, 1024 }, { 5, 804, 1024 }, { 6, 805, 1024 }, { 6, 806, 1024 }, { 7, 807, 1024 }, 
+   { 5, 808, 1024 }, { 6, 809, 1024 }, { 6, 810, 1024 }, { 7, 811, 1024 }, { 6, 812, 1024 }, { 7, 813, 1024 }, { 7, 814, 1024 }, { 8, 815, 1024 }, 
+   { 5, 816, 1024 }, { 6, 817, 1024 }, { 6, 818, 1024 }, { 7, 819, 1024 }, { 6, 820, 1024 }, { 7, 821, 1024 }, { 7, 822, 1024 }, { 8, 823, 1024 }, 
+   { 6, 824, 1024 }, { 7, 825, 1024 }, { 7, 826, 1024 }, { 8, 827, 1024 }, { 7, 828, 1024 }, { 8, 829, 1024 }, { 8, 830, 1024 }, { 9, 831, 1024 }, 
+   { 4, 832, 1024 }, { 5, 833, 1024 }, { 5, 834, 1024 }, { 6, 835, 1024 }, { 5, 836, 1024 }, { 6, 837, 1024 }, { 6, 838, 1024 }, { 7, 839, 1024 }, 
+   { 5, 840, 1024 }, { 6, 841, 1024 }, { 6, 842, 1024 }, { 7, 843, 1024 }, { 6, 844, 1024 }, { 7, 845, 1024 }, { 7, 846, 1024 }, { 8, 847, 1024 }, 
+   { 5, 848, 1024 }, { 6, 849, 1024 }, { 6, 850, 1024 }, { 7, 851, 1024 }, { 6, 852, 1024 }, { 7, 853, 1024 }, { 7, 854, 1024 }, { 8, 855, 1024 }, 
+   { 6, 856, 1024 }, { 7, 857, 1024 }, { 7, 858, 1024 }, { 8, 859, 1024 }, { 7, 860, 1024 }, { 8, 861, 1024 }, { 8, 862, 1024 }, { 9, 863, 1024 }, 
+   { 5, 864, 1024 }, { 6, 865, 1024 }, { 6, 866, 1024 }, { 7, 867, 1024 }, { 6, 868, 1024 }, { 7, 869, 1024 }, { 7, 870, 1024 }, { 8, 871, 1024 }, 
+   { 6, 872, 1024 }, { 7, 873, 1024 }, { 7, 874, 1024 }, { 8, 875, 1024 }, { 7, 876, 1024 }, { 8, 877, 1024 }, { 8, 878, 1024 }, { 9, 879, 1024 }, 
+   { 6, 880, 1024 }, { 7, 881, 1024 }, { 7, 882, 1024 }, { 8, 883, 1024 }, { 7, 884, 1024 }, { 8, 885, 1024 }, { 8, 886, 1024 }, { 9, 887, 1024 }, 
+   { 7, 888, 1024 }, { 8, 889, 1024 }, { 8, 890, 1024 }, { 9, 891, 1024 }, { 8, 892, 1024 }, { 9, 893, 1024 }, { 9, 894, 1024 }, { 10, 895, 1024 }, 
+   { 4, 896, 1024 }, { 5, 897, 1024 }, { 5, 898, 1024 }, { 6, 899, 1024 }, { 5, 900, 1024 }, { 6, 901, 1024 }, { 6, 902, 1024 }, { 7, 903, 1024 }, 
+   { 5, 904, 1024 }, { 6, 905, 1024 }, { 6, 906, 1024 }, { 7, 907, 1024 }, { 6, 908, 1024 }, { 7, 909, 1024 }, { 7, 910, 1024 }, { 8, 911, 1024 }, 
+   { 5, 912, 1024 }, { 6, 913, 1024 }, { 6, 914, 1024 }, { 7, 915, 1024 }, { 6, 916, 1024 }, { 7, 917, 1024 }, { 7, 918, 1024 }, { 8, 919, 1024 }, 
+   { 6, 920, 1024 }, { 7, 921, 1024 }, { 7, 922, 1024 }, { 8, 923, 1024 }, { 7, 924, 1024 }, { 8, 925, 1024 }, { 8, 926, 1024 }, { 9, 927, 1024 }, 
+   { 5, 928, 1024 }, { 6, 929, 1024 }, { 6, 930, 1024 }, { 7, 931, 1024 }, { 6, 932, 1024 }, { 7, 933, 1024 }, { 7, 934, 1024 }, { 8, 935, 1024 }, 
+   { 6, 936, 1024 }, { 7, 937, 1024 }, { 7, 938, 1024 }, { 8, 939, 1024 }, { 7, 940, 1024 }, { 8, 941, 1024 }, { 8, 942, 1024 }, { 9, 943, 1024 }, 
+   { 6, 944, 1024 }, { 7, 945, 1024 }, { 7, 946, 1024 }, { 8, 947, 1024 }, { 7, 948, 1024 }, { 8, 949, 1024 }, { 8, 950, 1024 }, { 9, 951, 1024 }, 
+   { 7, 952, 1024 }, { 8, 953, 1024 }, { 8, 954, 1024 }, { 9, 955, 1024 }, { 8, 956, 1024 }, { 9, 957, 1024 }, { 9, 958, 1024 }, { 10, 959, 1024 }, 
+   { 5, 960, 1024 }, { 6, 961, 1024 }, { 6, 962, 1024 }, { 7, 963, 1024 }, { 6, 964, 1024 }, { 7, 965, 1024 }, { 7, 966, 1024 }, { 8, 967, 1024 }, 
+   { 6, 968, 1024 }, { 7, 969, 1024 }, { 7, 970, 1024 }, { 8, 971, 1024 }, { 7, 972, 1024 }, { 8, 973, 1024 }, { 8, 974, 1024 }, { 9, 975, 1024 }, 
+   { 6, 976, 1024 }, { 7, 977, 1024 }, { 7, 978, 1024 }, { 8, 979, 1024 }, { 7, 980, 1024 }, { 8, 981, 1024 }, { 8, 982, 1024 }, { 9, 983, 1024 }, 
+   { 7, 984, 1024 }, { 8, 985, 1024 }, { 8, 986, 1024 }, { 9, 987, 1024 }, { 8, 988, 1024 }, { 9, 989, 1024 }, { 9, 990, 1024 }, { 10, 991, 1024 }, 
+   { 6, 992, 1024 }, { 7, 993, 1024 }, { 7, 994, 1024 }, { 8, 995, 1024 }, { 7, 996, 1024 }, { 8, 997, 1024 }, { 8, 998, 1024 }, { 9, 999, 1024 }, 
+   { 7, 1000, 1024 }, { 8, 1001, 1024 }, { 8, 1002, 1024 }, { 9, 1003, 1024 }, { 8, 1004, 1024 }, { 9, 1005, 1024 }, { 9, 1006, 1024 }, { 10, 1007, 1024 }, 
+   { 7, 1008, 1024 }, { 8, 1009, 1024 }, { 8, 1010, 1024 }, { 9, 1011, 1024 }, { 8, 1012, 1024 }, { 9, 1013, 1024 }, { 9, 1014, 1024 }, { 10, 1015, 1024 }, 
+   { 8, 1016, 1024 }, { 9, 1017, 1024 }, { 9, 1018, 1024 }, { 10, 1019, 1024 }, { 9, 1020, 1024 }, { 10, 1021, 1024 }, { 10, 1022, 1024 }, { 11, 1023, 1024 }, 
+#if FP_LUT > 11
+   { 1, 0, 0 }, { 2, 1, 2048 }, { 2, 2, 2048 }, { 3, 3, 2048 }, { 2, 4, 2048 }, { 3, 5, 2048 }, { 3, 6, 2048 }, { 4, 7, 2048 }, 
+   { 2, 8, 2048 }, { 3, 9, 2048 }, { 3, 10, 2048 }, { 4, 11, 2048 }, { 3, 12, 2048 }, { 4, 13, 2048 }, { 4, 14, 2048 }, { 5, 15, 2048 }, 
+   { 2, 16, 2048 }, { 3, 17, 2048 }, { 3, 18, 2048 }, { 4, 19, 2048 }, { 3, 20, 2048 }, { 4, 21, 2048 }, { 4, 22, 2048 }, { 5, 23, 2048 }, 
+   { 3, 24, 2048 }, { 4, 25, 2048 }, { 4, 26, 2048 }, { 5, 27, 2048 }, { 4, 28, 2048 }, { 5, 29, 2048 }, { 5, 30, 2048 }, { 6, 31, 2048 }, 
+   { 2, 32, 2048 }, { 3, 33, 2048 }, { 3, 34, 2048 }, { 4, 35, 2048 }, { 3, 36, 2048 }, { 4, 37, 2048 }, { 4, 38, 2048 }, { 5, 39, 2048 }, 
+   { 3, 40, 2048 }, { 4, 41, 2048 }, { 4, 42, 2048 }, { 5, 43, 2048 }, { 4, 44, 2048 }, { 5, 45, 2048 }, { 5, 46, 2048 }, { 6, 47, 2048 }, 
+   { 3, 48, 2048 }, { 4, 49, 2048 }, { 4, 50, 2048 }, { 5, 51, 2048 }, { 4, 52, 2048 }, { 5, 53, 2048 }, { 5, 54, 2048 }, { 6, 55, 2048 }, 
+   { 4, 56, 2048 }, { 5, 57, 2048 }, { 5, 58, 2048 }, { 6, 59, 2048 }, { 5, 60, 2048 }, { 6, 61, 2048 }, { 6, 62, 2048 }, { 7, 63, 2048 }, 
+   { 2, 64, 2048 }, { 3, 65, 2048 }, { 3, 66, 2048 }, { 4, 67, 2048 }, { 3, 68, 2048 }, { 4, 69, 2048 }, { 4, 70, 2048 }, { 5, 71, 2048 }, 
+   { 3, 72, 2048 }, { 4, 73, 2048 }, { 4, 74, 2048 }, { 5, 75, 2048 }, { 4, 76, 2048 }, { 5, 77, 2048 }, { 5, 78, 2048 }, { 6, 79, 2048 }, 
+   { 3, 80, 2048 }, { 4, 81, 2048 }, { 4, 82, 2048 }, { 5, 83, 2048 }, { 4, 84, 2048 }, { 5, 85, 2048 }, { 5, 86, 2048 }, { 6, 87, 2048 }, 
+   { 4, 88, 2048 }, { 5, 89, 2048 }, { 5, 90, 2048 }, { 6, 91, 2048 }, { 5, 92, 2048 }, { 6, 93, 2048 }, { 6, 94, 2048 }, { 7, 95, 2048 }, 
+   { 3, 96, 2048 }, { 4, 97, 2048 }, { 4, 98, 2048 }, { 5, 99, 2048 }, { 4, 100, 2048 }, { 5, 101, 2048 }, { 5, 102, 2048 }, { 6, 103, 2048 }, 
+   { 4, 104, 2048 }, { 5, 105, 2048 }, { 5, 106, 2048 }, { 6, 107, 2048 }, { 5, 108, 2048 }, { 6, 109, 2048 }, { 6, 110, 2048 }, { 7, 111, 2048 }, 
+   { 4, 112, 2048 }, { 5, 113, 2048 }, { 5, 114, 2048 }, { 6, 115, 2048 }, { 5, 116, 2048 }, { 6, 117, 2048 }, { 6, 118, 2048 }, { 7, 119, 2048 }, 
+   { 5, 120, 2048 }, { 6, 121, 2048 }, { 6, 122, 2048 }, { 7, 123, 2048 }, { 6, 124, 2048 }, { 7, 125, 2048 }, { 7, 126, 2048 }, { 8, 127, 2048 }, 
+   { 2, 128, 2048 }, { 3, 129, 2048 }, { 3, 130, 2048 }, { 4, 131, 2048 }, { 3, 132, 2048 }, { 4, 133, 2048 }, { 4, 134, 2048 }, { 5, 135, 2048 }, 
+   { 3, 136, 2048 }, { 4, 137, 2048 }, { 4, 138, 2048 }, { 5, 139, 2048 }, { 4, 140, 2048 }, { 5, 141, 2048 }, { 5, 142, 2048 }, { 6, 143, 2048 }, 
+   { 3, 144, 2048 }, { 4, 145, 2048 }, { 4, 146, 2048 }, { 5, 147, 2048 }, { 4, 148, 2048 }, { 5, 149, 2048 }, { 5, 150, 2048 }, { 6, 151, 2048 }, 
+   { 4, 152, 2048 }, { 5, 153, 2048 }, { 5, 154, 2048 }, { 6, 155, 2048 }, { 5, 156, 2048 }, { 6, 157, 2048 }, { 6, 158, 2048 }, { 7, 159, 2048 }, 
+   { 3, 160, 2048 }, { 4, 161, 2048 }, { 4, 162, 2048 }, { 5, 163, 2048 }, { 4, 164, 2048 }, { 5, 165, 2048 }, { 5, 166, 2048 }, { 6, 167, 2048 }, 
+   { 4, 168, 2048 }, { 5, 169, 2048 }, { 5, 170, 2048 }, { 6, 171, 2048 }, { 5, 172, 2048 }, { 6, 173, 2048 }, { 6, 174, 2048 }, { 7, 175, 2048 }, 
+   { 4, 176, 2048 }, { 5, 177, 2048 }, { 5, 178, 2048 }, { 6, 179, 2048 }, { 5, 180, 2048 }, { 6, 181, 2048 }, { 6, 182, 2048 }, { 7, 183, 2048 }, 
+   { 5, 184, 2048 }, { 6, 185, 2048 }, { 6, 186, 2048 }, { 7, 187, 2048 }, { 6, 188, 2048 }, { 7, 189, 2048 }, { 7, 190, 2048 }, { 8, 191, 2048 }, 
+   { 3, 192, 2048 }, { 4, 193, 2048 }, { 4, 194, 2048 }, { 5, 195, 2048 }, { 4, 196, 2048 }, { 5, 197, 2048 }, { 5, 198, 2048 }, { 6, 199, 2048 }, 
+   { 4, 200, 2048 }, { 5, 201, 2048 }, { 5, 202, 2048 }, { 6, 203, 2048 }, { 5, 204, 2048 }, { 6, 205, 2048 }, { 6, 206, 2048 }, { 7, 207, 2048 }, 
+   { 4, 208, 2048 }, { 5, 209, 2048 }, { 5, 210, 2048 }, { 6, 211, 2048 }, { 5, 212, 2048 }, { 6, 213, 2048 }, { 6, 214, 2048 }, { 7, 215, 2048 }, 
+   { 5, 216, 2048 }, { 6, 217, 2048 }, { 6, 218, 2048 }, { 7, 219, 2048 }, { 6, 220, 2048 }, { 7, 221, 2048 }, { 7, 222, 2048 }, { 8, 223, 2048 }, 
+   { 4, 224, 2048 }, { 5, 225, 2048 }, { 5, 226, 2048 }, { 6, 227, 2048 }, { 5, 228, 2048 }, { 6, 229, 2048 }, { 6, 230, 2048 }, { 7, 231, 2048 }, 
+   { 5, 232, 2048 }, { 6, 233, 2048 }, { 6, 234, 2048 }, { 7, 235, 2048 }, { 6, 236, 2048 }, { 7, 237, 2048 }, { 7, 238, 2048 }, { 8, 239, 2048 }, 
+   { 5, 240, 2048 }, { 6, 241, 2048 }, { 6, 242, 2048 }, { 7, 243, 2048 }, { 6, 244, 2048 }, { 7, 245, 2048 }, { 7, 246, 2048 }, { 8, 247, 2048 }, 
+   { 6, 248, 2048 }, { 7, 249, 2048 }, { 7, 250, 2048 }, { 8, 251, 2048 }, { 7, 252, 2048 }, { 8, 253, 2048 }, { 8, 254, 2048 }, { 9, 255, 2048 }, 
+   { 2, 256, 2048 }, { 3, 257, 2048 }, { 3, 258, 2048 }, { 4, 259, 2048 }, { 3, 260, 2048 }, { 4, 261, 2048 }, { 4, 262, 2048 }, { 5, 263, 2048 }, 
+   { 3, 264, 2048 }, { 4, 265, 2048 }, { 4, 266, 2048 }, { 5, 267, 2048 }, { 4, 268, 2048 }, { 5, 269, 2048 }, { 5, 270, 2048 }, { 6, 271, 2048 }, 
+   { 3, 272, 2048 }, { 4, 273, 2048 }, { 4, 274, 2048 }, { 5, 275, 2048 }, { 4, 276, 2048 }, { 5, 277, 2048 }, { 5, 278, 2048 }, { 6, 279, 2048 }, 
+   { 4, 280, 2048 }, { 5, 281, 2048 }, { 5, 282, 2048 }, { 6, 283, 2048 }, { 5, 284, 2048 }, { 6, 285, 2048 }, { 6, 286, 2048 }, { 7, 287, 2048 }, 
+   { 3, 288, 2048 }, { 4, 289, 2048 }, { 4, 290, 2048 }, { 5, 291, 2048 }, { 4, 292, 2048 }, { 5, 293, 2048 }, { 5, 294, 2048 }, { 6, 295, 2048 }, 
+   { 4, 296, 2048 }, { 5, 297, 2048 }, { 5, 298, 2048 }, { 6, 299, 2048 }, { 5, 300, 2048 }, { 6, 301, 2048 }, { 6, 302, 2048 }, { 7, 303, 2048 }, 
+   { 4, 304, 2048 }, { 5, 305, 2048 }, { 5, 306, 2048 }, { 6, 307, 2048 }, { 5, 308, 2048 }, { 6, 309, 2048 }, { 6, 310, 2048 }, { 7, 311, 2048 }, 
+   { 5, 312, 2048 }, { 6, 313, 2048 }, { 6, 314, 2048 }, { 7, 315, 2048 }, { 6, 316, 2048 }, { 7, 317, 2048 }, { 7, 318, 2048 }, { 8, 319, 2048 }, 
+   { 3, 320, 2048 }, { 4, 321, 2048 }, { 4, 322, 2048 }, { 5, 323, 2048 }, { 4, 324, 2048 }, { 5, 325, 2048 }, { 5, 326, 2048 }, { 6, 327, 2048 }, 
+   { 4, 328, 2048 }, { 5, 329, 2048 }, { 5, 330, 2048 }, { 6, 331, 2048 }, { 5, 332, 2048 }, { 6, 333, 2048 }, { 6, 334, 2048 }, { 7, 335, 2048 }, 
+   { 4, 336, 2048 }, { 5, 337, 2048 }, { 5, 338, 2048 }, { 6, 339, 2048 }, { 5, 340, 2048 }, { 6, 341, 2048 }, { 6, 342, 2048 }, { 7, 343, 2048 }, 
+   { 5, 344, 2048 }, { 6, 345, 2048 }, { 6, 346, 2048 }, { 7, 347, 2048 }, { 6, 348, 2048 }, { 7, 349, 2048 }, { 7, 350, 2048 }, { 8, 351, 2048 }, 
+   { 4, 352, 2048 }, { 5, 353, 2048 }, { 5, 354, 2048 }, { 6, 355, 2048 }, { 5, 356, 2048 }, { 6, 357, 2048 }, { 6, 358, 2048 }, { 7, 359, 2048 }, 
+   { 5, 360, 2048 }, { 6, 361, 2048 }, { 6, 362, 2048 }, { 7, 363, 2048 }, { 6, 364, 2048 }, { 7, 365, 2048 }, { 7, 366, 2048 }, { 8, 367, 2048 }, 
+   { 5, 368, 2048 }, { 6, 369, 2048 }, { 6, 370, 2048 }, { 7, 371, 2048 }, { 6, 372, 2048 }, { 7, 373, 2048 }, { 7, 374, 2048 }, { 8, 375, 2048 }, 
+   { 6, 376, 2048 }, { 7, 377, 2048 }, { 7, 378, 2048 }, { 8, 379, 2048 }, { 7, 380, 2048 }, { 8, 381, 2048 }, { 8, 382, 2048 }, { 9, 383, 2048 }, 
+   { 3, 384, 2048 }, { 4, 385, 2048 }, { 4, 386, 2048 }, { 5, 387, 2048 }, { 4, 388, 2048 }, { 5, 389, 2048 }, { 5, 390, 2048 }, { 6, 391, 2048 }, 
+   { 4, 392, 2048 }, { 5, 393, 2048 }, { 5, 394, 2048 }, { 6, 395, 2048 }, { 5, 396, 2048 }, { 6, 397, 2048 }, { 6, 398, 2048 }, { 7, 399, 2048 }, 
+   { 4, 400, 2048 }, { 5, 401, 2048 }, { 5, 402, 2048 }, { 6, 403, 2048 }, { 5, 404, 2048 }, { 6, 405, 2048 }, { 6, 406, 2048 }, { 7, 407, 2048 }, 
+   { 5, 408, 2048 }, { 6, 409, 2048 }, { 6, 410, 2048 }, { 7, 411, 2048 }, { 6, 412, 2048 }, { 7, 413, 2048 }, { 7, 414, 2048 }, { 8, 415, 2048 }, 
+   { 4, 416, 2048 }, { 5, 417, 2048 }, { 5, 418, 2048 }, { 6, 419, 2048 }, { 5, 420, 2048 }, { 6, 421, 2048 }, { 6, 422, 2048 }, { 7, 423, 2048 }, 
+   { 5, 424, 2048 }, { 6, 425, 2048 }, { 6, 426, 2048 }, { 7, 427, 2048 }, { 6, 428, 2048 }, { 7, 429, 2048 }, { 7, 430, 2048 }, { 8, 431, 2048 }, 
+   { 5, 432, 2048 }, { 6, 433, 2048 }, { 6, 434, 2048 }, { 7, 435, 2048 }, { 6, 436, 2048 }, { 7, 437, 2048 }, { 7, 438, 2048 }, { 8, 439, 2048 }, 
+   { 6, 440, 2048 }, { 7, 441, 2048 }, { 7, 442, 2048 }, { 8, 443, 2048 }, { 7, 444, 2048 }, { 8, 445, 2048 }, { 8, 446, 2048 }, { 9, 447, 2048 }, 
+   { 4, 448, 2048 }, { 5, 449, 2048 }, { 5, 450, 2048 }, { 6, 451, 2048 }, { 5, 452, 2048 }, { 6, 453, 2048 }, { 6, 454, 2048 }, { 7, 455, 2048 }, 
+   { 5, 456, 2048 }, { 6, 457, 2048 }, { 6, 458, 2048 }, { 7, 459, 2048 }, { 6, 460, 2048 }, { 7, 461, 2048 }, { 7, 462, 2048 }, { 8, 463, 2048 }, 
+   { 5, 464, 2048 }, { 6, 465, 2048 }, { 6, 466, 2048 }, { 7, 467, 2048 }, { 6, 468, 2048 }, { 7, 469, 2048 }, { 7, 470, 2048 }, { 8, 471, 2048 }, 
+   { 6, 472, 2048 }, { 7, 473, 2048 }, { 7, 474, 2048 }, { 8, 475, 2048 }, { 7, 476, 2048 }, { 8, 477, 2048 }, { 8, 478, 2048 }, { 9, 479, 2048 }, 
+   { 5, 480, 2048 }, { 6, 481, 2048 }, { 6, 482, 2048 }, { 7, 483, 2048 }, { 6, 484, 2048 }, { 7, 485, 2048 }, { 7, 486, 2048 }, { 8, 487, 2048 }, 
+   { 6, 488, 2048 }, { 7, 489, 2048 }, { 7, 490, 2048 }, { 8, 491, 2048 }, { 7, 492, 2048 }, { 8, 493, 2048 }, { 8, 494, 2048 }, { 9, 495, 2048 }, 
+   { 6, 496, 2048 }, { 7, 497, 2048 }, { 7, 498, 2048 }, { 8, 499, 2048 }, { 7, 500, 2048 }, { 8, 501, 2048 }, { 8, 502, 2048 }, { 9, 503, 2048 }, 
+   { 7, 504, 2048 }, { 8, 505, 2048 }, { 8, 506, 2048 }, { 9, 507, 2048 }, { 8, 508, 2048 }, { 9, 509, 2048 }, { 9, 510, 2048 }, { 10, 511, 2048 }, 
+   { 2, 512, 2048 }, { 3, 513, 2048 }, { 3, 514, 2048 }, { 4, 515, 2048 }, { 3, 516, 2048 }, { 4, 517, 2048 }, { 4, 518, 2048 }, { 5, 519, 2048 }, 
+   { 3, 520, 2048 }, { 4, 521, 2048 }, { 4, 522, 2048 }, { 5, 523, 2048 }, { 4, 524, 2048 }, { 5, 525, 2048 }, { 5, 526, 2048 }, { 6, 527, 2048 }, 
+   { 3, 528, 2048 }, { 4, 529, 2048 }, { 4, 530, 2048 }, { 5, 531, 2048 }, { 4, 532, 2048 }, { 5, 533, 2048 }, { 5, 534, 2048 }, { 6, 535, 2048 }, 
+   { 4, 536, 2048 }, { 5, 537, 2048 }, { 5, 538, 2048 }, { 6, 539, 2048 }, { 5, 540, 2048 }, { 6, 541, 2048 }, { 6, 542, 2048 }, { 7, 543, 2048 }, 
+   { 3, 544, 2048 }, { 4, 545, 2048 }, { 4, 546, 2048 }, { 5, 547, 2048 }, { 4, 548, 2048 }, { 5, 549, 2048 }, { 5, 550, 2048 }, { 6, 551, 2048 }, 
+   { 4, 552, 2048 }, { 5, 553, 2048 }, { 5, 554, 2048 }, { 6, 555, 2048 }, { 5, 556, 2048 }, { 6, 557, 2048 }, { 6, 558, 2048 }, { 7, 559, 2048 }, 
+   { 4, 560, 2048 }, { 5, 561, 2048 }, { 5, 562, 2048 }, { 6, 563, 2048 }, { 5, 564, 2048 }, { 6, 565, 2048 }, { 6, 566, 2048 }, { 7, 567, 2048 }, 
+   { 5, 568, 2048 }, { 6, 569, 2048 }, { 6, 570, 2048 }, { 7, 571, 2048 }, { 6, 572, 2048 }, { 7, 573, 2048 }, { 7, 574, 2048 }, { 8, 575, 2048 }, 
+   { 3, 576, 2048 }, { 4, 577, 2048 }, { 4, 578, 2048 }, { 5, 579, 2048 }, { 4, 580, 2048 }, { 5, 581, 2048 }, { 5, 582, 2048 }, { 6, 583, 2048 }, 
+   { 4, 584, 2048 }, { 5, 585, 2048 }, { 5, 586, 2048 }, { 6, 587, 2048 }, { 5, 588, 2048 }, { 6, 589, 2048 }, { 6, 590, 2048 }, { 7, 591, 2048 }, 
+   { 4, 592, 2048 }, { 5, 593, 2048 }, { 5, 594, 2048 }, { 6, 595, 2048 }, { 5, 596, 2048 }, { 6, 597, 2048 }, { 6, 598, 2048 }, { 7, 599, 2048 }, 
+   { 5, 600, 2048 }, { 6, 601, 2048 }, { 6, 602, 2048 }, { 7, 603, 2048 }, { 6, 604, 2048 }, { 7, 605, 2048 }, { 7, 606, 2048 }, { 8, 607, 2048 }, 
+   { 4, 608, 2048 }, { 5, 609, 2048 }, { 5, 610, 2048 }, { 6, 611, 2048 }, { 5, 612, 2048 }, { 6, 613, 2048 }, { 6, 614, 2048 }, { 7, 615, 2048 }, 
+   { 5, 616, 2048 }, { 6, 617, 2048 }, { 6, 618, 2048 }, { 7, 619, 2048 }, { 6, 620, 2048 }, { 7, 621, 2048 }, { 7, 622, 2048 }, { 8, 623, 2048 }, 
+   { 5, 624, 2048 }, { 6, 625, 2048 }, { 6, 626, 2048 }, { 7, 627, 2048 }, { 6, 628, 2048 }, { 7, 629, 2048 }, { 7, 630, 2048 }, { 8, 631, 2048 }, 
+   { 6, 632, 2048 }, { 7, 633, 2048 }, { 7, 634, 2048 }, { 8, 635, 2048 }, { 7, 636, 2048 }, { 8, 637, 2048 }, { 8, 638, 2048 }, { 9, 639, 2048 }, 
+   { 3, 640, 2048 }, { 4, 641, 2048 }, { 4, 642, 2048 }, { 5, 643, 2048 }, { 4, 644, 2048 }, { 5, 645, 2048 }, { 5, 646, 2048 }, { 6, 647, 2048 }, 
+   { 4, 648, 2048 }, { 5, 649, 2048 }, { 5, 650, 2048 }, { 6, 651, 2048 }, { 5, 652, 2048 }, { 6, 653, 2048 }, { 6, 654, 2048 }, { 7, 655, 2048 }, 
+   { 4, 656, 2048 }, { 5, 657, 2048 }, { 5, 658, 2048 }, { 6, 659, 2048 }, { 5, 660, 2048 }, { 6, 661, 2048 }, { 6, 662, 2048 }, { 7, 663, 2048 }, 
+   { 5, 664, 2048 }, { 6, 665, 2048 }, { 6, 666, 2048 }, { 7, 667, 2048 }, { 6, 668, 2048 }, { 7, 669, 2048 }, { 7, 670, 2048 }, { 8, 671, 2048 }, 
+   { 4, 672, 2048 }, { 5, 673, 2048 }, { 5, 674, 2048 }, { 6, 675, 2048 }, { 5, 676, 2048 }, { 6, 677, 2048 }, { 6, 678, 2048 }, { 7, 679, 2048 }, 
+   { 5, 680, 2048 }, { 6, 681, 2048 }, { 6, 682, 2048 }, { 7, 683, 2048 }, { 6, 684, 2048 }, { 7, 685, 2048 }, { 7, 686, 2048 }, { 8, 687, 2048 }, 
+   { 5, 688, 2048 }, { 6, 689, 2048 }, { 6, 690, 2048 }, { 7, 691, 2048 }, { 6, 692, 2048 }, { 7, 693, 2048 }, { 7, 694, 2048 }, { 8, 695, 2048 }, 
+   { 6, 696, 2048 }, { 7, 697, 2048 }, { 7, 698, 2048 }, { 8, 699, 2048 }, { 7, 700, 2048 }, { 8, 701, 2048 }, { 8, 702, 2048 }, { 9, 703, 2048 }, 
+   { 4, 704, 2048 }, { 5, 705, 2048 }, { 5, 706, 2048 }, { 6, 707, 2048 }, { 5, 708, 2048 }, { 6, 709, 2048 }, { 6, 710, 2048 }, { 7, 711, 2048 }, 
+   { 5, 712, 2048 }, { 6, 713, 2048 }, { 6, 714, 2048 }, { 7, 715, 2048 }, { 6, 716, 2048 }, { 7, 717, 2048 }, { 7, 718, 2048 }, { 8, 719, 2048 }, 
+   { 5, 720, 2048 }, { 6, 721, 2048 }, { 6, 722, 2048 }, { 7, 723, 2048 }, { 6, 724, 2048 }, { 7, 725, 2048 }, { 7, 726, 2048 }, { 8, 727, 2048 }, 
+   { 6, 728, 2048 }, { 7, 729, 2048 }, { 7, 730, 2048 }, { 8, 731, 2048 }, { 7, 732, 2048 }, { 8, 733, 2048 }, { 8, 734, 2048 }, { 9, 735, 2048 }, 
+   { 5, 736, 2048 }, { 6, 737, 2048 }, { 6, 738, 2048 }, { 7, 739, 2048 }, { 6, 740, 2048 }, { 7, 741, 2048 }, { 7, 742, 2048 }, { 8, 743, 2048 }, 
+   { 6, 744, 2048 }, { 7, 745, 2048 }, { 7, 746, 2048 }, { 8, 747, 2048 }, { 7, 748, 2048 }, { 8, 749, 2048 }, { 8, 750, 2048 }, { 9, 751, 2048 }, 
+   { 6, 752, 2048 }, { 7, 753, 2048 }, { 7, 754, 2048 }, { 8, 755, 2048 }, { 7, 756, 2048 }, { 8, 757, 2048 }, { 8, 758, 2048 }, { 9, 759, 2048 }, 
+   { 7, 760, 2048 }, { 8, 761, 2048 }, { 8, 762, 2048 }, { 9, 763, 2048 }, { 8, 764, 2048 }, { 9, 765, 2048 }, { 9, 766, 2048 }, { 10, 767, 2048 }, 
+   { 3, 768, 2048 }, { 4, 769, 2048 }, { 4, 770, 2048 }, { 5, 771, 2048 }, { 4, 772, 2048 }, { 5, 773, 2048 }, { 5, 774, 2048 }, { 6, 775, 2048 }, 
+   { 4, 776, 2048 }, { 5, 777, 2048 }, { 5, 778, 2048 }, { 6, 779, 2048 }, { 5, 780, 2048 }, { 6, 781, 2048 }, { 6, 782, 2048 }, { 7, 783, 2048 }, 
+   { 4, 784, 2048 }, { 5, 785, 2048 }, { 5, 786, 2048 }, { 6, 787, 2048 }, { 5, 788, 2048 }, { 6, 789, 2048 }, { 6, 790, 2048 }, { 7, 791, 2048 }, 
+   { 5, 792, 2048 }, { 6, 793, 2048 }, { 6, 794, 2048 }, { 7, 795, 2048 }, { 6, 796, 2048 }, { 7, 797, 2048 }, { 7, 798, 2048 }, { 8, 799, 2048 }, 
+   { 4, 800, 2048 }, { 5, 801, 2048 }, { 5, 802, 2048 }, { 6, 803, 2048 }, { 5, 804, 2048 }, { 6, 805, 2048 }, { 6, 806, 2048 }, { 7, 807, 2048 }, 
+   { 5, 808, 2048 }, { 6, 809, 2048 }, { 6, 810, 2048 }, { 7, 811, 2048 }, { 6, 812, 2048 }, { 7, 813, 2048 }, { 7, 814, 2048 }, { 8, 815, 2048 }, 
+   { 5, 816, 2048 }, { 6, 817, 2048 }, { 6, 818, 2048 }, { 7, 819, 2048 }, { 6, 820, 2048 }, { 7, 821, 2048 }, { 7, 822, 2048 }, { 8, 823, 2048 }, 
+   { 6, 824, 2048 }, { 7, 825, 2048 }, { 7, 826, 2048 }, { 8, 827, 2048 }, { 7, 828, 2048 }, { 8, 829, 2048 }, { 8, 830, 2048 }, { 9, 831, 2048 }, 
+   { 4, 832, 2048 }, { 5, 833, 2048 }, { 5, 834, 2048 }, { 6, 835, 2048 }, { 5, 836, 2048 }, { 6, 837, 2048 }, { 6, 838, 2048 }, { 7, 839, 2048 }, 
+   { 5, 840, 2048 }, { 6, 841, 2048 }, { 6, 842, 2048 }, { 7, 843, 2048 }, { 6, 844, 2048 }, { 7, 845, 2048 }, { 7, 846, 2048 }, { 8, 847, 2048 }, 
+   { 5, 848, 2048 }, { 6, 849, 2048 }, { 6, 850, 2048 }, { 7, 851, 2048 }, { 6, 852, 2048 }, { 7, 853, 2048 }, { 7, 854, 2048 }, { 8, 855, 2048 }, 
+   { 6, 856, 2048 }, { 7, 857, 2048 }, { 7, 858, 2048 }, { 8, 859, 2048 }, { 7, 860, 2048 }, { 8, 861, 2048 }, { 8, 862, 2048 }, { 9, 863, 2048 }, 
+   { 5, 864, 2048 }, { 6, 865, 2048 }, { 6, 866, 2048 }, { 7, 867, 2048 }, { 6, 868, 2048 }, { 7, 869, 2048 }, { 7, 870, 2048 }, { 8, 871, 2048 }, 
+   { 6, 872, 2048 }, { 7, 873, 2048 }, { 7, 874, 2048 }, { 8, 875, 2048 }, { 7, 876, 2048 }, { 8, 877, 2048 }, { 8, 878, 2048 }, { 9, 879, 2048 }, 
+   { 6, 880, 2048 }, { 7, 881, 2048 }, { 7, 882, 2048 }, { 8, 883, 2048 }, { 7, 884, 2048 }, { 8, 885, 2048 }, { 8, 886, 2048 }, { 9, 887, 2048 }, 
+   { 7, 888, 2048 }, { 8, 889, 2048 }, { 8, 890, 2048 }, { 9, 891, 2048 }, { 8, 892, 2048 }, { 9, 893, 2048 }, { 9, 894, 2048 }, { 10, 895, 2048 }, 
+   { 4, 896, 2048 }, { 5, 897, 2048 }, { 5, 898, 2048 }, { 6, 899, 2048 }, { 5, 900, 2048 }, { 6, 901, 2048 }, { 6, 902, 2048 }, { 7, 903, 2048 }, 
+   { 5, 904, 2048 }, { 6, 905, 2048 }, { 6, 906, 2048 }, { 7, 907, 2048 }, { 6, 908, 2048 }, { 7, 909, 2048 }, { 7, 910, 2048 }, { 8, 911, 2048 }, 
+   { 5, 912, 2048 }, { 6, 913, 2048 }, { 6, 914, 2048 }, { 7, 915, 2048 }, { 6, 916, 2048 }, { 7, 917, 2048 }, { 7, 918, 2048 }, { 8, 919, 2048 }, 
+   { 6, 920, 2048 }, { 7, 921, 2048 }, { 7, 922, 2048 }, { 8, 923, 2048 }, { 7, 924, 2048 }, { 8, 925, 2048 }, { 8, 926, 2048 }, { 9, 927, 2048 }, 
+   { 5, 928, 2048 }, { 6, 929, 2048 }, { 6, 930, 2048 }, { 7, 931, 2048 }, { 6, 932, 2048 }, { 7, 933, 2048 }, { 7, 934, 2048 }, { 8, 935, 2048 }, 
+   { 6, 936, 2048 }, { 7, 937, 2048 }, { 7, 938, 2048 }, { 8, 939, 2048 }, { 7, 940, 2048 }, { 8, 941, 2048 }, { 8, 942, 2048 }, { 9, 943, 2048 }, 
+   { 6, 944, 2048 }, { 7, 945, 2048 }, { 7, 946, 2048 }, { 8, 947, 2048 }, { 7, 948, 2048 }, { 8, 949, 2048 }, { 8, 950, 2048 }, { 9, 951, 2048 }, 
+   { 7, 952, 2048 }, { 8, 953, 2048 }, { 8, 954, 2048 }, { 9, 955, 2048 }, { 8, 956, 2048 }, { 9, 957, 2048 }, { 9, 958, 2048 }, { 10, 959, 2048 }, 
+   { 5, 960, 2048 }, { 6, 961, 2048 }, { 6, 962, 2048 }, { 7, 963, 2048 }, { 6, 964, 2048 }, { 7, 965, 2048 }, { 7, 966, 2048 }, { 8, 967, 2048 }, 
+   { 6, 968, 2048 }, { 7, 969, 2048 }, { 7, 970, 2048 }, { 8, 971, 2048 }, { 7, 972, 2048 }, { 8, 973, 2048 }, { 8, 974, 2048 }, { 9, 975, 2048 }, 
+   { 6, 976, 2048 }, { 7, 977, 2048 }, { 7, 978, 2048 }, { 8, 979, 2048 }, { 7, 980, 2048 }, { 8, 981, 2048 }, { 8, 982, 2048 }, { 9, 983, 2048 }, 
+   { 7, 984, 2048 }, { 8, 985, 2048 }, { 8, 986, 2048 }, { 9, 987, 2048 }, { 8, 988, 2048 }, { 9, 989, 2048 }, { 9, 990, 2048 }, { 10, 991, 2048 }, 
+   { 6, 992, 2048 }, { 7, 993, 2048 }, { 7, 994, 2048 }, { 8, 995, 2048 }, { 7, 996, 2048 }, { 8, 997, 2048 }, { 8, 998, 2048 }, { 9, 999, 2048 }, 
+   { 7, 1000, 2048 }, { 8, 1001, 2048 }, { 8, 1002, 2048 }, { 9, 1003, 2048 }, { 8, 1004, 2048 }, { 9, 1005, 2048 }, { 9, 1006, 2048 }, { 10, 1007, 2048 }, 
+   { 7, 1008, 2048 }, { 8, 1009, 2048 }, { 8, 1010, 2048 }, { 9, 1011, 2048 }, { 8, 1012, 2048 }, { 9, 1013, 2048 }, { 9, 1014, 2048 }, { 10, 1015, 2048 }, 
+   { 8, 1016, 2048 }, { 9, 1017, 2048 }, { 9, 1018, 2048 }, { 10, 1019, 2048 }, { 9, 1020, 2048 }, { 10, 1021, 2048 }, { 10, 1022, 2048 }, { 11, 1023, 2048 }, 
+   { 2, 1024, 2048 }, { 3, 1025, 2048 }, { 3, 1026, 2048 }, { 4, 1027, 2048 }, { 3, 1028, 2048 }, { 4, 1029, 2048 }, { 4, 1030, 2048 }, { 5, 1031, 2048 }, 
+   { 3, 1032, 2048 }, { 4, 1033, 2048 }, { 4, 1034, 2048 }, { 5, 1035, 2048 }, { 4, 1036, 2048 }, { 5, 1037, 2048 }, { 5, 1038, 2048 }, { 6, 1039, 2048 }, 
+   { 3, 1040, 2048 }, { 4, 1041, 2048 }, { 4, 1042, 2048 }, { 5, 1043, 2048 }, { 4, 1044, 2048 }, { 5, 1045, 2048 }, { 5, 1046, 2048 }, { 6, 1047, 2048 }, 
+   { 4, 1048, 2048 }, { 5, 1049, 2048 }, { 5, 1050, 2048 }, { 6, 1051, 2048 }, { 5, 1052, 2048 }, { 6, 1053, 2048 }, { 6, 1054, 2048 }, { 7, 1055, 2048 }, 
+   { 3, 1056, 2048 }, { 4, 1057, 2048 }, { 4, 1058, 2048 }, { 5, 1059, 2048 }, { 4, 1060, 2048 }, { 5, 1061, 2048 }, { 5, 1062, 2048 }, { 6, 1063, 2048 }, 
+   { 4, 1064, 2048 }, { 5, 1065, 2048 }, { 5, 1066, 2048 }, { 6, 1067, 2048 }, { 5, 1068, 2048 }, { 6, 1069, 2048 }, { 6, 1070, 2048 }, { 7, 1071, 2048 }, 
+   { 4, 1072, 2048 }, { 5, 1073, 2048 }, { 5, 1074, 2048 }, { 6, 1075, 2048 }, { 5, 1076, 2048 }, { 6, 1077, 2048 }, { 6, 1078, 2048 }, { 7, 1079, 2048 }, 
+   { 5, 1080, 2048 }, { 6, 1081, 2048 }, { 6, 1082, 2048 }, { 7, 1083, 2048 }, { 6, 1084, 2048 }, { 7, 1085, 2048 }, { 7, 1086, 2048 }, { 8, 1087, 2048 }, 
+   { 3, 1088, 2048 }, { 4, 1089, 2048 }, { 4, 1090, 2048 }, { 5, 1091, 2048 }, { 4, 1092, 2048 }, { 5, 1093, 2048 }, { 5, 1094, 2048 }, { 6, 1095, 2048 }, 
+   { 4, 1096, 2048 }, { 5, 1097, 2048 }, { 5, 1098, 2048 }, { 6, 1099, 2048 }, { 5, 1100, 2048 }, { 6, 1101, 2048 }, { 6, 1102, 2048 }, { 7, 1103, 2048 }, 
+   { 4, 1104, 2048 }, { 5, 1105, 2048 }, { 5, 1106, 2048 }, { 6, 1107, 2048 }, { 5, 1108, 2048 }, { 6, 1109, 2048 }, { 6, 1110, 2048 }, { 7, 1111, 2048 }, 
+   { 5, 1112, 2048 }, { 6, 1113, 2048 }, { 6, 1114, 2048 }, { 7, 1115, 2048 }, { 6, 1116, 2048 }, { 7, 1117, 2048 }, { 7, 1118, 2048 }, { 8, 1119, 2048 }, 
+   { 4, 1120, 2048 }, { 5, 1121, 2048 }, { 5, 1122, 2048 }, { 6, 1123, 2048 }, { 5, 1124, 2048 }, { 6, 1125, 2048 }, { 6, 1126, 2048 }, { 7, 1127, 2048 }, 
+   { 5, 1128, 2048 }, { 6, 1129, 2048 }, { 6, 1130, 2048 }, { 7, 1131, 2048 }, { 6, 1132, 2048 }, { 7, 1133, 2048 }, { 7, 1134, 2048 }, { 8, 1135, 2048 }, 
+   { 5, 1136, 2048 }, { 6, 1137, 2048 }, { 6, 1138, 2048 }, { 7, 1139, 2048 }, { 6, 1140, 2048 }, { 7, 1141, 2048 }, { 7, 1142, 2048 }, { 8, 1143, 2048 }, 
+   { 6, 1144, 2048 }, { 7, 1145, 2048 }, { 7, 1146, 2048 }, { 8, 1147, 2048 }, { 7, 1148, 2048 }, { 8, 1149, 2048 }, { 8, 1150, 2048 }, { 9, 1151, 2048 }, 
+   { 3, 1152, 2048 }, { 4, 1153, 2048 }, { 4, 1154, 2048 }, { 5, 1155, 2048 }, { 4, 1156, 2048 }, { 5, 1157, 2048 }, { 5, 1158, 2048 }, { 6, 1159, 2048 }, 
+   { 4, 1160, 2048 }, { 5, 1161, 2048 }, { 5, 1162, 2048 }, { 6, 1163, 2048 }, { 5, 1164, 2048 }, { 6, 1165, 2048 }, { 6, 1166, 2048 }, { 7, 1167, 2048 }, 
+   { 4, 1168, 2048 }, { 5, 1169, 2048 }, { 5, 1170, 2048 }, { 6, 1171, 2048 }, { 5, 1172, 2048 }, { 6, 1173, 2048 }, { 6, 1174, 2048 }, { 7, 1175, 2048 }, 
+   { 5, 1176, 2048 }, { 6, 1177, 2048 }, { 6, 1178, 2048 }, { 7, 1179, 2048 }, { 6, 1180, 2048 }, { 7, 1181, 2048 }, { 7, 1182, 2048 }, { 8, 1183, 2048 }, 
+   { 4, 1184, 2048 }, { 5, 1185, 2048 }, { 5, 1186, 2048 }, { 6, 1187, 2048 }, { 5, 1188, 2048 }, { 6, 1189, 2048 }, { 6, 1190, 2048 }, { 7, 1191, 2048 }, 
+   { 5, 1192, 2048 }, { 6, 1193, 2048 }, { 6, 1194, 2048 }, { 7, 1195, 2048 }, { 6, 1196, 2048 }, { 7, 1197, 2048 }, { 7, 1198, 2048 }, { 8, 1199, 2048 }, 
+   { 5, 1200, 2048 }, { 6, 1201, 2048 }, { 6, 1202, 2048 }, { 7, 1203, 2048 }, { 6, 1204, 2048 }, { 7, 1205, 2048 }, { 7, 1206, 2048 }, { 8, 1207, 2048 }, 
+   { 6, 1208, 2048 }, { 7, 1209, 2048 }, { 7, 1210, 2048 }, { 8, 1211, 2048 }, { 7, 1212, 2048 }, { 8, 1213, 2048 }, { 8, 1214, 2048 }, { 9, 1215, 2048 }, 
+   { 4, 1216, 2048 }, { 5, 1217, 2048 }, { 5, 1218, 2048 }, { 6, 1219, 2048 }, { 5, 1220, 2048 }, { 6, 1221, 2048 }, { 6, 1222, 2048 }, { 7, 1223, 2048 }, 
+   { 5, 1224, 2048 }, { 6, 1225, 2048 }, { 6, 1226, 2048 }, { 7, 1227, 2048 }, { 6, 1228, 2048 }, { 7, 1229, 2048 }, { 7, 1230, 2048 }, { 8, 1231, 2048 }, 
+   { 5, 1232, 2048 }, { 6, 1233, 2048 }, { 6, 1234, 2048 }, { 7, 1235, 2048 }, { 6, 1236, 2048 }, { 7, 1237, 2048 }, { 7, 1238, 2048 }, { 8, 1239, 2048 }, 
+   { 6, 1240, 2048 }, { 7, 1241, 2048 }, { 7, 1242, 2048 }, { 8, 1243, 2048 }, { 7, 1244, 2048 }, { 8, 1245, 2048 }, { 8, 1246, 2048 }, { 9, 1247, 2048 }, 
+   { 5, 1248, 2048 }, { 6, 1249, 2048 }, { 6, 1250, 2048 }, { 7, 1251, 2048 }, { 6, 1252, 2048 }, { 7, 1253, 2048 }, { 7, 1254, 2048 }, { 8, 1255, 2048 }, 
+   { 6, 1256, 2048 }, { 7, 1257, 2048 }, { 7, 1258, 2048 }, { 8, 1259, 2048 }, { 7, 1260, 2048 }, { 8, 1261, 2048 }, { 8, 1262, 2048 }, { 9, 1263, 2048 }, 
+   { 6, 1264, 2048 }, { 7, 1265, 2048 }, { 7, 1266, 2048 }, { 8, 1267, 2048 }, { 7, 1268, 2048 }, { 8, 1269, 2048 }, { 8, 1270, 2048 }, { 9, 1271, 2048 }, 
+   { 7, 1272, 2048 }, { 8, 1273, 2048 }, { 8, 1274, 2048 }, { 9, 1275, 2048 }, { 8, 1276, 2048 }, { 9, 1277, 2048 }, { 9, 1278, 2048 }, { 10, 1279, 2048 }, 
+   { 3, 1280, 2048 }, { 4, 1281, 2048 }, { 4, 1282, 2048 }, { 5, 1283, 2048 }, { 4, 1284, 2048 }, { 5, 1285, 2048 }, { 5, 1286, 2048 }, { 6, 1287, 2048 }, 
+   { 4, 1288, 2048 }, { 5, 1289, 2048 }, { 5, 1290, 2048 }, { 6, 1291, 2048 }, { 5, 1292, 2048 }, { 6, 1293, 2048 }, { 6, 1294, 2048 }, { 7, 1295, 2048 }, 
+   { 4, 1296, 2048 }, { 5, 1297, 2048 }, { 5, 1298, 2048 }, { 6, 1299, 2048 }, { 5, 1300, 2048 }, { 6, 1301, 2048 }, { 6, 1302, 2048 }, { 7, 1303, 2048 }, 
+   { 5, 1304, 2048 }, { 6, 1305, 2048 }, { 6, 1306, 2048 }, { 7, 1307, 2048 }, { 6, 1308, 2048 }, { 7, 1309, 2048 }, { 7, 1310, 2048 }, { 8, 1311, 2048 }, 
+   { 4, 1312, 2048 }, { 5, 1313, 2048 }, { 5, 1314, 2048 }, { 6, 1315, 2048 }, { 5, 1316, 2048 }, { 6, 1317, 2048 }, { 6, 1318, 2048 }, { 7, 1319, 2048 }, 
+   { 5, 1320, 2048 }, { 6, 1321, 2048 }, { 6, 1322, 2048 }, { 7, 1323, 2048 }, { 6, 1324, 2048 }, { 7, 1325, 2048 }, { 7, 1326, 2048 }, { 8, 1327, 2048 }, 
+   { 5, 1328, 2048 }, { 6, 1329, 2048 }, { 6, 1330, 2048 }, { 7, 1331, 2048 }, { 6, 1332, 2048 }, { 7, 1333, 2048 }, { 7, 1334, 2048 }, { 8, 1335, 2048 }, 
+   { 6, 1336, 2048 }, { 7, 1337, 2048 }, { 7, 1338, 2048 }, { 8, 1339, 2048 }, { 7, 1340, 2048 }, { 8, 1341, 2048 }, { 8, 1342, 2048 }, { 9, 1343, 2048 }, 
+   { 4, 1344, 2048 }, { 5, 1345, 2048 }, { 5, 1346, 2048 }, { 6, 1347, 2048 }, { 5, 1348, 2048 }, { 6, 1349, 2048 }, { 6, 1350, 2048 }, { 7, 1351, 2048 }, 
+   { 5, 1352, 2048 }, { 6, 1353, 2048 }, { 6, 1354, 2048 }, { 7, 1355, 2048 }, { 6, 1356, 2048 }, { 7, 1357, 2048 }, { 7, 1358, 2048 }, { 8, 1359, 2048 }, 
+   { 5, 1360, 2048 }, { 6, 1361, 2048 }, { 6, 1362, 2048 }, { 7, 1363, 2048 }, { 6, 1364, 2048 }, { 7, 1365, 2048 }, { 7, 1366, 2048 }, { 8, 1367, 2048 }, 
+   { 6, 1368, 2048 }, { 7, 1369, 2048 }, { 7, 1370, 2048 }, { 8, 1371, 2048 }, { 7, 1372, 2048 }, { 8, 1373, 2048 }, { 8, 1374, 2048 }, { 9, 1375, 2048 }, 
+   { 5, 1376, 2048 }, { 6, 1377, 2048 }, { 6, 1378, 2048 }, { 7, 1379, 2048 }, { 6, 1380, 2048 }, { 7, 1381, 2048 }, { 7, 1382, 2048 }, { 8, 1383, 2048 }, 
+   { 6, 1384, 2048 }, { 7, 1385, 2048 }, { 7, 1386, 2048 }, { 8, 1387, 2048 }, { 7, 1388, 2048 }, { 8, 1389, 2048 }, { 8, 1390, 2048 }, { 9, 1391, 2048 }, 
+   { 6, 1392, 2048 }, { 7, 1393, 2048 }, { 7, 1394, 2048 }, { 8, 1395, 2048 }, { 7, 1396, 2048 }, { 8, 1397, 2048 }, { 8, 1398, 2048 }, { 9, 1399, 2048 }, 
+   { 7, 1400, 2048 }, { 8, 1401, 2048 }, { 8, 1402, 2048 }, { 9, 1403, 2048 }, { 8, 1404, 2048 }, { 9, 1405, 2048 }, { 9, 1406, 2048 }, { 10, 1407, 2048 }, 
+   { 4, 1408, 2048 }, { 5, 1409, 2048 }, { 5, 1410, 2048 }, { 6, 1411, 2048 }, { 5, 1412, 2048 }, { 6, 1413, 2048 }, { 6, 1414, 2048 }, { 7, 1415, 2048 }, 
+   { 5, 1416, 2048 }, { 6, 1417, 2048 }, { 6, 1418, 2048 }, { 7, 1419, 2048 }, { 6, 1420, 2048 }, { 7, 1421, 2048 }, { 7, 1422, 2048 }, { 8, 1423, 2048 }, 
+   { 5, 1424, 2048 }, { 6, 1425, 2048 }, { 6, 1426, 2048 }, { 7, 1427, 2048 }, { 6, 1428, 2048 }, { 7, 1429, 2048 }, { 7, 1430, 2048 }, { 8, 1431, 2048 }, 
+   { 6, 1432, 2048 }, { 7, 1433, 2048 }, { 7, 1434, 2048 }, { 8, 1435, 2048 }, { 7, 1436, 2048 }, { 8, 1437, 2048 }, { 8, 1438, 2048 }, { 9, 1439, 2048 }, 
+   { 5, 1440, 2048 }, { 6, 1441, 2048 }, { 6, 1442, 2048 }, { 7, 1443, 2048 }, { 6, 1444, 2048 }, { 7, 1445, 2048 }, { 7, 1446, 2048 }, { 8, 1447, 2048 }, 
+   { 6, 1448, 2048 }, { 7, 1449, 2048 }, { 7, 1450, 2048 }, { 8, 1451, 2048 }, { 7, 1452, 2048 }, { 8, 1453, 2048 }, { 8, 1454, 2048 }, { 9, 1455, 2048 }, 
+   { 6, 1456, 2048 }, { 7, 1457, 2048 }, { 7, 1458, 2048 }, { 8, 1459, 2048 }, { 7, 1460, 2048 }, { 8, 1461, 2048 }, { 8, 1462, 2048 }, { 9, 1463, 2048 }, 
+   { 7, 1464, 2048 }, { 8, 1465, 2048 }, { 8, 1466, 2048 }, { 9, 1467, 2048 }, { 8, 1468, 2048 }, { 9, 1469, 2048 }, { 9, 1470, 2048 }, { 10, 1471, 2048 }, 
+   { 5, 1472, 2048 }, { 6, 1473, 2048 }, { 6, 1474, 2048 }, { 7, 1475, 2048 }, { 6, 1476, 2048 }, { 7, 1477, 2048 }, { 7, 1478, 2048 }, { 8, 1479, 2048 }, 
+   { 6, 1480, 2048 }, { 7, 1481, 2048 }, { 7, 1482, 2048 }, { 8, 1483, 2048 }, { 7, 1484, 2048 }, { 8, 1485, 2048 }, { 8, 1486, 2048 }, { 9, 1487, 2048 }, 
+   { 6, 1488, 2048 }, { 7, 1489, 2048 }, { 7, 1490, 2048 }, { 8, 1491, 2048 }, { 7, 1492, 2048 }, { 8, 1493, 2048 }, { 8, 1494, 2048 }, { 9, 1495, 2048 }, 
+   { 7, 1496, 2048 }, { 8, 1497, 2048 }, { 8, 1498, 2048 }, { 9, 1499, 2048 }, { 8, 1500, 2048 }, { 9, 1501, 2048 }, { 9, 1502, 2048 }, { 10, 1503, 2048 }, 
+   { 6, 1504, 2048 }, { 7, 1505, 2048 }, { 7, 1506, 2048 }, { 8, 1507, 2048 }, { 7, 1508, 2048 }, { 8, 1509, 2048 }, { 8, 1510, 2048 }, { 9, 1511, 2048 }, 
+   { 7, 1512, 2048 }, { 8, 1513, 2048 }, { 8, 1514, 2048 }, { 9, 1515, 2048 }, { 8, 1516, 2048 }, { 9, 1517, 2048 }, { 9, 1518, 2048 }, { 10, 1519, 2048 }, 
+   { 7, 1520, 2048 }, { 8, 1521, 2048 }, { 8, 1522, 2048 }, { 9, 1523, 2048 }, { 8, 1524, 2048 }, { 9, 1525, 2048 }, { 9, 1526, 2048 }, { 10, 1527, 2048 }, 
+   { 8, 1528, 2048 }, { 9, 1529, 2048 }, { 9, 1530, 2048 }, { 10, 1531, 2048 }, { 9, 1532, 2048 }, { 10, 1533, 2048 }, { 10, 1534, 2048 }, { 11, 1535, 2048 }, 
+   { 3, 1536, 2048 }, { 4, 1537, 2048 }, { 4, 1538, 2048 }, { 5, 1539, 2048 }, { 4, 1540, 2048 }, { 5, 1541, 2048 }, { 5, 1542, 2048 }, { 6, 1543, 2048 }, 
+   { 4, 1544, 2048 }, { 5, 1545, 2048 }, { 5, 1546, 2048 }, { 6, 1547, 2048 }, { 5, 1548, 2048 }, { 6, 1549, 2048 }, { 6, 1550, 2048 }, { 7, 1551, 2048 }, 
+   { 4, 1552, 2048 }, { 5, 1553, 2048 }, { 5, 1554, 2048 }, { 6, 1555, 2048 }, { 5, 1556, 2048 }, { 6, 1557, 2048 }, { 6, 1558, 2048 }, { 7, 1559, 2048 }, 
+   { 5, 1560, 2048 }, { 6, 1561, 2048 }, { 6, 1562, 2048 }, { 7, 1563, 2048 }, { 6, 1564, 2048 }, { 7, 1565, 2048 }, { 7, 1566, 2048 }, { 8, 1567, 2048 }, 
+   { 4, 1568, 2048 }, { 5, 1569, 2048 }, { 5, 1570, 2048 }, { 6, 1571, 2048 }, { 5, 1572, 2048 }, { 6, 1573, 2048 }, { 6, 1574, 2048 }, { 7, 1575, 2048 }, 
+   { 5, 1576, 2048 }, { 6, 1577, 2048 }, { 6, 1578, 2048 }, { 7, 1579, 2048 }, { 6, 1580, 2048 }, { 7, 1581, 2048 }, { 7, 1582, 2048 }, { 8, 1583, 2048 }, 
+   { 5, 1584, 2048 }, { 6, 1585, 2048 }, { 6, 1586, 2048 }, { 7, 1587, 2048 }, { 6, 1588, 2048 }, { 7, 1589, 2048 }, { 7, 1590, 2048 }, { 8, 1591, 2048 }, 
+   { 6, 1592, 2048 }, { 7, 1593, 2048 }, { 7, 1594, 2048 }, { 8, 1595, 2048 }, { 7, 1596, 2048 }, { 8, 1597, 2048 }, { 8, 1598, 2048 }, { 9, 1599, 2048 }, 
+   { 4, 1600, 2048 }, { 5, 1601, 2048 }, { 5, 1602, 2048 }, { 6, 1603, 2048 }, { 5, 1604, 2048 }, { 6, 1605, 2048 }, { 6, 1606, 2048 }, { 7, 1607, 2048 }, 
+   { 5, 1608, 2048 }, { 6, 1609, 2048 }, { 6, 1610, 2048 }, { 7, 1611, 2048 }, { 6, 1612, 2048 }, { 7, 1613, 2048 }, { 7, 1614, 2048 }, { 8, 1615, 2048 }, 
+   { 5, 1616, 2048 }, { 6, 1617, 2048 }, { 6, 1618, 2048 }, { 7, 1619, 2048 }, { 6, 1620, 2048 }, { 7, 1621, 2048 }, { 7, 1622, 2048 }, { 8, 1623, 2048 }, 
+   { 6, 1624, 2048 }, { 7, 1625, 2048 }, { 7, 1626, 2048 }, { 8, 1627, 2048 }, { 7, 1628, 2048 }, { 8, 1629, 2048 }, { 8, 1630, 2048 }, { 9, 1631, 2048 }, 
+   { 5, 1632, 2048 }, { 6, 1633, 2048 }, { 6, 1634, 2048 }, { 7, 1635, 2048 }, { 6, 1636, 2048 }, { 7, 1637, 2048 }, { 7, 1638, 2048 }, { 8, 1639, 2048 }, 
+   { 6, 1640, 2048 }, { 7, 1641, 2048 }, { 7, 1642, 2048 }, { 8, 1643, 2048 }, { 7, 1644, 2048 }, { 8, 1645, 2048 }, { 8, 1646, 2048 }, { 9, 1647, 2048 }, 
+   { 6, 1648, 2048 }, { 7, 1649, 2048 }, { 7, 1650, 2048 }, { 8, 1651, 2048 }, { 7, 1652, 2048 }, { 8, 1653, 2048 }, { 8, 1654, 2048 }, { 9, 1655, 2048 }, 
+   { 7, 1656, 2048 }, { 8, 1657, 2048 }, { 8, 1658, 2048 }, { 9, 1659, 2048 }, { 8, 1660, 2048 }, { 9, 1661, 2048 }, { 9, 1662, 2048 }, { 10, 1663, 2048 }, 
+   { 4, 1664, 2048 }, { 5, 1665, 2048 }, { 5, 1666, 2048 }, { 6, 1667, 2048 }, { 5, 1668, 2048 }, { 6, 1669, 2048 }, { 6, 1670, 2048 }, { 7, 1671, 2048 }, 
+   { 5, 1672, 2048 }, { 6, 1673, 2048 }, { 6, 1674, 2048 }, { 7, 1675, 2048 }, { 6, 1676, 2048 }, { 7, 1677, 2048 }, { 7, 1678, 2048 }, { 8, 1679, 2048 }, 
+   { 5, 1680, 2048 }, { 6, 1681, 2048 }, { 6, 1682, 2048 }, { 7, 1683, 2048 }, { 6, 1684, 2048 }, { 7, 1685, 2048 }, { 7, 1686, 2048 }, { 8, 1687, 2048 }, 
+   { 6, 1688, 2048 }, { 7, 1689, 2048 }, { 7, 1690, 2048 }, { 8, 1691, 2048 }, { 7, 1692, 2048 }, { 8, 1693, 2048 }, { 8, 1694, 2048 }, { 9, 1695, 2048 }, 
+   { 5, 1696, 2048 }, { 6, 1697, 2048 }, { 6, 1698, 2048 }, { 7, 1699, 2048 }, { 6, 1700, 2048 }, { 7, 1701, 2048 }, { 7, 1702, 2048 }, { 8, 1703, 2048 }, 
+   { 6, 1704, 2048 }, { 7, 1705, 2048 }, { 7, 1706, 2048 }, { 8, 1707, 2048 }, { 7, 1708, 2048 }, { 8, 1709, 2048 }, { 8, 1710, 2048 }, { 9, 1711, 2048 }, 
+   { 6, 1712, 2048 }, { 7, 1713, 2048 }, { 7, 1714, 2048 }, { 8, 1715, 2048 }, { 7, 1716, 2048 }, { 8, 1717, 2048 }, { 8, 1718, 2048 }, { 9, 1719, 2048 }, 
+   { 7, 1720, 2048 }, { 8, 1721, 2048 }, { 8, 1722, 2048 }, { 9, 1723, 2048 }, { 8, 1724, 2048 }, { 9, 1725, 2048 }, { 9, 1726, 2048 }, { 10, 1727, 2048 }, 
+   { 5, 1728, 2048 }, { 6, 1729, 2048 }, { 6, 1730, 2048 }, { 7, 1731, 2048 }, { 6, 1732, 2048 }, { 7, 1733, 2048 }, { 7, 1734, 2048 }, { 8, 1735, 2048 }, 
+   { 6, 1736, 2048 }, { 7, 1737, 2048 }, { 7, 1738, 2048 }, { 8, 1739, 2048 }, { 7, 1740, 2048 }, { 8, 1741, 2048 }, { 8, 1742, 2048 }, { 9, 1743, 2048 }, 
+   { 6, 1744, 2048 }, { 7, 1745, 2048 }, { 7, 1746, 2048 }, { 8, 1747, 2048 }, { 7, 1748, 2048 }, { 8, 1749, 2048 }, { 8, 1750, 2048 }, { 9, 1751, 2048 }, 
+   { 7, 1752, 2048 }, { 8, 1753, 2048 }, { 8, 1754, 2048 }, { 9, 1755, 2048 }, { 8, 1756, 2048 }, { 9, 1757, 2048 }, { 9, 1758, 2048 }, { 10, 1759, 2048 }, 
+   { 6, 1760, 2048 }, { 7, 1761, 2048 }, { 7, 1762, 2048 }, { 8, 1763, 2048 }, { 7, 1764, 2048 }, { 8, 1765, 2048 }, { 8, 1766, 2048 }, { 9, 1767, 2048 }, 
+   { 7, 1768, 2048 }, { 8, 1769, 2048 }, { 8, 1770, 2048 }, { 9, 1771, 2048 }, { 8, 1772, 2048 }, { 9, 1773, 2048 }, { 9, 1774, 2048 }, { 10, 1775, 2048 }, 
+   { 7, 1776, 2048 }, { 8, 1777, 2048 }, { 8, 1778, 2048 }, { 9, 1779, 2048 }, { 8, 1780, 2048 }, { 9, 1781, 2048 }, { 9, 1782, 2048 }, { 10, 1783, 2048 }, 
+   { 8, 1784, 2048 }, { 9, 1785, 2048 }, { 9, 1786, 2048 }, { 10, 1787, 2048 }, { 9, 1788, 2048 }, { 10, 1789, 2048 }, { 10, 1790, 2048 }, { 11, 1791, 2048 }, 
+   { 4, 1792, 2048 }, { 5, 1793, 2048 }, { 5, 1794, 2048 }, { 6, 1795, 2048 }, { 5, 1796, 2048 }, { 6, 1797, 2048 }, { 6, 1798, 2048 }, { 7, 1799, 2048 }, 
+   { 5, 1800, 2048 }, { 6, 1801, 2048 }, { 6, 1802, 2048 }, { 7, 1803, 2048 }, { 6, 1804, 2048 }, { 7, 1805, 2048 }, { 7, 1806, 2048 }, { 8, 1807, 2048 }, 
+   { 5, 1808, 2048 }, { 6, 1809, 2048 }, { 6, 1810, 2048 }, { 7, 1811, 2048 }, { 6, 1812, 2048 }, { 7, 1813, 2048 }, { 7, 1814, 2048 }, { 8, 1815, 2048 }, 
+   { 6, 1816, 2048 }, { 7, 1817, 2048 }, { 7, 1818, 2048 }, { 8, 1819, 2048 }, { 7, 1820, 2048 }, { 8, 1821, 2048 }, { 8, 1822, 2048 }, { 9, 1823, 2048 }, 
+   { 5, 1824, 2048 }, { 6, 1825, 2048 }, { 6, 1826, 2048 }, { 7, 1827, 2048 }, { 6, 1828, 2048 }, { 7, 1829, 2048 }, { 7, 1830, 2048 }, { 8, 1831, 2048 }, 
+   { 6, 1832, 2048 }, { 7, 1833, 2048 }, { 7, 1834, 2048 }, { 8, 1835, 2048 }, { 7, 1836, 2048 }, { 8, 1837, 2048 }, { 8, 1838, 2048 }, { 9, 1839, 2048 }, 
+   { 6, 1840, 2048 }, { 7, 1841, 2048 }, { 7, 1842, 2048 }, { 8, 1843, 2048 }, { 7, 1844, 2048 }, { 8, 1845, 2048 }, { 8, 1846, 2048 }, { 9, 1847, 2048 }, 
+   { 7, 1848, 2048 }, { 8, 1849, 2048 }, { 8, 1850, 2048 }, { 9, 1851, 2048 }, { 8, 1852, 2048 }, { 9, 1853, 2048 }, { 9, 1854, 2048 }, { 10, 1855, 2048 }, 
+   { 5, 1856, 2048 }, { 6, 1857, 2048 }, { 6, 1858, 2048 }, { 7, 1859, 2048 }, { 6, 1860, 2048 }, { 7, 1861, 2048 }, { 7, 1862, 2048 }, { 8, 1863, 2048 }, 
+   { 6, 1864, 2048 }, { 7, 1865, 2048 }, { 7, 1866, 2048 }, { 8, 1867, 2048 }, { 7, 1868, 2048 }, { 8, 1869, 2048 }, { 8, 1870, 2048 }, { 9, 1871, 2048 }, 
+   { 6, 1872, 2048 }, { 7, 1873, 2048 }, { 7, 1874, 2048 }, { 8, 1875, 2048 }, { 7, 1876, 2048 }, { 8, 1877, 2048 }, { 8, 1878, 2048 }, { 9, 1879, 2048 }, 
+   { 7, 1880, 2048 }, { 8, 1881, 2048 }, { 8, 1882, 2048 }, { 9, 1883, 2048 }, { 8, 1884, 2048 }, { 9, 1885, 2048 }, { 9, 1886, 2048 }, { 10, 1887, 2048 }, 
+   { 6, 1888, 2048 }, { 7, 1889, 2048 }, { 7, 1890, 2048 }, { 8, 1891, 2048 }, { 7, 1892, 2048 }, { 8, 1893, 2048 }, { 8, 1894, 2048 }, { 9, 1895, 2048 }, 
+   { 7, 1896, 2048 }, { 8, 1897, 2048 }, { 8, 1898, 2048 }, { 9, 1899, 2048 }, { 8, 1900, 2048 }, { 9, 1901, 2048 }, { 9, 1902, 2048 }, { 10, 1903, 2048 }, 
+   { 7, 1904, 2048 }, { 8, 1905, 2048 }, { 8, 1906, 2048 }, { 9, 1907, 2048 }, { 8, 1908, 2048 }, { 9, 1909, 2048 }, { 9, 1910, 2048 }, { 10, 1911, 2048 }, 
+   { 8, 1912, 2048 }, { 9, 1913, 2048 }, { 9, 1914, 2048 }, { 10, 1915, 2048 }, { 9, 1916, 2048 }, { 10, 1917, 2048 }, { 10, 1918, 2048 }, { 11, 1919, 2048 }, 
+   { 5, 1920, 2048 }, { 6, 1921, 2048 }, { 6, 1922, 2048 }, { 7, 1923, 2048 }, { 6, 1924, 2048 }, { 7, 1925, 2048 }, { 7, 1926, 2048 }, { 8, 1927, 2048 }, 
+   { 6, 1928, 2048 }, { 7, 1929, 2048 }, { 7, 1930, 2048 }, { 8, 1931, 2048 }, { 7, 1932, 2048 }, { 8, 1933, 2048 }, { 8, 1934, 2048 }, { 9, 1935, 2048 }, 
+   { 6, 1936, 2048 }, { 7, 1937, 2048 }, { 7, 1938, 2048 }, { 8, 1939, 2048 }, { 7, 1940, 2048 }, { 8, 1941, 2048 }, { 8, 1942, 2048 }, { 9, 1943, 2048 }, 
+   { 7, 1944, 2048 }, { 8, 1945, 2048 }, { 8, 1946, 2048 }, { 9, 1947, 2048 }, { 8, 1948, 2048 }, { 9, 1949, 2048 }, { 9, 1950, 2048 }, { 10, 1951, 2048 }, 
+   { 6, 1952, 2048 }, { 7, 1953, 2048 }, { 7, 1954, 2048 }, { 8, 1955, 2048 }, { 7, 1956, 2048 }, { 8, 1957, 2048 }, { 8, 1958, 2048 }, { 9, 1959, 2048 }, 
+   { 7, 1960, 2048 }, { 8, 1961, 2048 }, { 8, 1962, 2048 }, { 9, 1963, 2048 }, { 8, 1964, 2048 }, { 9, 1965, 2048 }, { 9, 1966, 2048 }, { 10, 1967, 2048 }, 
+   { 7, 1968, 2048 }, { 8, 1969, 2048 }, { 8, 1970, 2048 }, { 9, 1971, 2048 }, { 8, 1972, 2048 }, { 9, 1973, 2048 }, { 9, 1974, 2048 }, { 10, 1975, 2048 }, 
+   { 8, 1976, 2048 }, { 9, 1977, 2048 }, { 9, 1978, 2048 }, { 10, 1979, 2048 }, { 9, 1980, 2048 }, { 10, 1981, 2048 }, { 10, 1982, 2048 }, { 11, 1983, 2048 }, 
+   { 6, 1984, 2048 }, { 7, 1985, 2048 }, { 7, 1986, 2048 }, { 8, 1987, 2048 }, { 7, 1988, 2048 }, { 8, 1989, 2048 }, { 8, 1990, 2048 }, { 9, 1991, 2048 }, 
+   { 7, 1992, 2048 }, { 8, 1993, 2048 }, { 8, 1994, 2048 }, { 9, 1995, 2048 }, { 8, 1996, 2048 }, { 9, 1997, 2048 }, { 9, 1998, 2048 }, { 10, 1999, 2048 }, 
+   { 7, 2000, 2048 }, { 8, 2001, 2048 }, { 8, 2002, 2048 }, { 9, 2003, 2048 }, { 8, 2004, 2048 }, { 9, 2005, 2048 }, { 9, 2006, 2048 }, { 10, 2007, 2048 }, 
+   { 8, 2008, 2048 }, { 9, 2009, 2048 }, { 9, 2010, 2048 }, { 10, 2011, 2048 }, { 9, 2012, 2048 }, { 10, 2013, 2048 }, { 10, 2014, 2048 }, { 11, 2015, 2048 }, 
+   { 7, 2016, 2048 }, { 8, 2017, 2048 }, { 8, 2018, 2048 }, { 9, 2019, 2048 }, { 8, 2020, 2048 }, { 9, 2021, 2048 }, { 9, 2022, 2048 }, { 10, 2023, 2048 }, 
+   { 8, 2024, 2048 }, { 9, 2025, 2048 }, { 9, 2026, 2048 }, { 10, 2027, 2048 }, { 9, 2028, 2048 }, { 10, 2029, 2048 }, { 10, 2030, 2048 }, { 11, 2031, 2048 }, 
+   { 8, 2032, 2048 }, { 9, 2033, 2048 }, { 9, 2034, 2048 }, { 10, 2035, 2048 }, { 9, 2036, 2048 }, { 10, 2037, 2048 }, { 10, 2038, 2048 }, { 11, 2039, 2048 }, 
+   { 9, 2040, 2048 }, { 10, 2041, 2048 }, { 10, 2042, 2048 }, { 11, 2043, 2048 }, { 10, 2044, 2048 }, { 11, 2045, 2048 }, { 11, 2046, 2048 }, { 12, 2047, 2048 }, 
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+};
+
+/* find a hole and free as required, return -1 if no hole found */
+static int find_hole(void)
+{
+   unsigned x;
+   int      y, z;
+   for (z = -1, y = INT_MAX, x = 0; x < FP_ENTRIES; x++) {
+       if (fp_cache[x].lru_count < y && fp_cache[x].lock == 0) {
+          z = x;
+          y = fp_cache[x].lru_count;
+       }
+   }
+
+   /* decrease all */
+   for (x = 0; x < FP_ENTRIES; x++) {
+      if (fp_cache[x].lru_count > 3) {
+         --(fp_cache[x].lru_count);
+      }
+   }
+
+   /* free entry z */
+   if (z >= 0 && fp_cache[z].g) {
+      mp_clear(&fp_cache[z].mu);
+      ecc_del_point(fp_cache[z].g);
+      fp_cache[z].g  = NULL;
+      for (x = 0; x < (1U<<FP_LUT); x++) {
+         ecc_del_point(fp_cache[z].LUT[x]);
+         fp_cache[z].LUT[x] = NULL;
+      }
+      fp_cache[z].lru_count = 0;
+   }
+   return z;
+}
+
+/* determine if a base is already in the cache and if so, where */
+static int find_base(ecc_point* g)
+{
+   int x;
+   for (x = 0; x < FP_ENTRIES; x++) {
+      if (fp_cache[x].g != NULL && 
+          mp_cmp(fp_cache[x].g->x, g->x) == MP_EQ && 
+          mp_cmp(fp_cache[x].g->y, g->y) == MP_EQ && 
+          mp_cmp(fp_cache[x].g->z, g->z) == MP_EQ) {
+         break;
+      }
+   }
+   if (x == FP_ENTRIES) {
+      x = -1;
+   }
+   return x;
+}
+
+/* add a new base to the cache */
+static int add_entry(int idx, ecc_point *g)
+{
+   unsigned x, y;
+
+   /* allocate base and LUT */
+   fp_cache[idx].g = ecc_new_point();
+   if (fp_cache[idx].g == NULL) {
+      return GEN_MEM_ERR;
+   }
+
+   /* copy x and y */
+   if ((mp_copy(g->x, fp_cache[idx].g->x) != MP_OKAY) ||
+       (mp_copy(g->y, fp_cache[idx].g->y) != MP_OKAY) ||
+       (mp_copy(g->z, fp_cache[idx].g->z) != MP_OKAY)) {
+      ecc_del_point(fp_cache[idx].g);
+      fp_cache[idx].g = NULL;
+      return GEN_MEM_ERR;
+   }              
+
+   for (x = 0; x < (1U<<FP_LUT); x++) {
+      fp_cache[idx].LUT[x] = ecc_new_point();
+      if (fp_cache[idx].LUT[x] == NULL) {
+         for (y = 0; y < x; y++) {
+            ecc_del_point(fp_cache[idx].LUT[y]);
+            fp_cache[idx].LUT[y] = NULL;
+         }
+         ecc_del_point(fp_cache[idx].g);
+         fp_cache[idx].g         = NULL;
+         fp_cache[idx].lru_count = 0;
+         return GEN_MEM_ERR;
+      }
+   }
+   
+   fp_cache[idx].lru_count = 0;
+
+   return MP_OKAY;
+}
+
+/* build the LUT by spacing the bits of the input by #modulus/FP_LUT bits apart 
+ * 
+ * The algorithm builds patterns in increasing bit order by first making all 
+ * single bit input patterns, then all two bit input patterns and so on
+ */
+static int build_lut(int idx, mp_int* modulus, mp_digit* mp, mp_int* mu)
+{ 
+   unsigned x, y, err, bitlen, lut_gap;
+   mp_int tmp;
+
+   if (mp_init(&tmp) != MP_OKAY)
+       return GEN_MEM_ERR;
+
+   /* sanity check to make sure lut_order table is of correct size,
+      should compile out to a NOP if true */
+   if ((sizeof(lut_orders) / sizeof(lut_orders[0])) < (1U<<FP_LUT)) {
+       err = BAD_FUNC_ARG;
+   }
+   else {   
+    /* get bitlen and round up to next multiple of FP_LUT */
+    bitlen  = mp_unsigned_bin_size(modulus) << 3;
+    x       = bitlen % FP_LUT;
+    if (x) {
+      bitlen += FP_LUT - x;
+    }  
+    lut_gap = bitlen / FP_LUT;
+
+    /* init the mu */
+    err = mp_init_copy(&fp_cache[idx].mu, mu);
+   }
+   
+   /* copy base */
+   if (err == MP_OKAY) {
+     if ((mp_mulmod(fp_cache[idx].g->x, mu, modulus,
+                  fp_cache[idx].LUT[1]->x) != MP_OKAY) || 
+         (mp_mulmod(fp_cache[idx].g->y, mu, modulus,
+                  fp_cache[idx].LUT[1]->y) != MP_OKAY) || 
+         (mp_mulmod(fp_cache[idx].g->z, mu, modulus,
+                  fp_cache[idx].LUT[1]->z) != MP_OKAY)) {
+       err = MP_MULMOD_E; 
+     }
+   }
+       
+   /* make all single bit entries */
+   for (x = 1; x < FP_LUT; x++) {
+      if (err != MP_OKAY)
+          break;
+      if ((mp_copy(fp_cache[idx].LUT[1<<(x-1)]->x,
+                   fp_cache[idx].LUT[1<<x]->x) != MP_OKAY) || 
+          (mp_copy(fp_cache[idx].LUT[1<<(x-1)]->y,
+                   fp_cache[idx].LUT[1<<x]->y) != MP_OKAY) || 
+          (mp_copy(fp_cache[idx].LUT[1<<(x-1)]->z,
+                   fp_cache[idx].LUT[1<<x]->z) != MP_OKAY)){
+          err = MP_INIT_E;
+          break;
+      } else {
+          
+         /* now double it bitlen/FP_LUT times */
+         for (y = 0; y < lut_gap; y++) {
+             if ((err = ecc_projective_dbl_point(fp_cache[idx].LUT[1<<x],
+                            fp_cache[idx].LUT[1<<x], modulus, mp)) != MP_OKAY) {
+                 break;
+             }
+         }
+     }
+  }
+      
+   /* now make all entries in increase order of hamming weight */
+   for (x = 2; x <= FP_LUT; x++) {
+       if (err != MP_OKAY)
+           break;
+       for (y = 0; y < (1UL<<FP_LUT); y++) {
+           if (err != MP_OKAY)
+             break;
+           if (lut_orders[y].ham != (int)x) continue;
+                     
+           /* perform the add */
+           if ((err = ecc_projective_add_point(
+                           fp_cache[idx].LUT[lut_orders[y].terma],
+                           fp_cache[idx].LUT[lut_orders[y].termb],
+                           fp_cache[idx].LUT[y], modulus, mp)) != MP_OKAY) {
+              break;
+           }
+       }
+   }
+      
+   /* now map all entries back to affine space to make point addition faster */
+   for (x = 1; x < (1UL<<FP_LUT); x++) {
+       if (err != MP_OKAY)
+           break;
+
+       /* convert z to normal from montgomery */
+       err = mp_montgomery_reduce(fp_cache[idx].LUT[x]->z, modulus, *mp);
+ 
+       /* invert it */
+       if (err == MP_OKAY)
+         err = mp_invmod(fp_cache[idx].LUT[x]->z, modulus,
+                         fp_cache[idx].LUT[x]->z);
+
+       if (err == MP_OKAY)
+         /* now square it */
+         err = mp_sqrmod(fp_cache[idx].LUT[x]->z, modulus, &tmp);
+       
+       if (err == MP_OKAY)
+         /* fix x */
+         err = mp_mulmod(fp_cache[idx].LUT[x]->x, &tmp, modulus,
+                         fp_cache[idx].LUT[x]->x);
+
+       if (err == MP_OKAY)
+         /* get 1/z^3 */
+         err = mp_mulmod(&tmp, fp_cache[idx].LUT[x]->z, modulus, &tmp);
+
+       if (err == MP_OKAY)
+         /* fix y */
+         err = mp_mulmod(fp_cache[idx].LUT[x]->y, &tmp, modulus,
+                         fp_cache[idx].LUT[x]->y);
+
+       if (err == MP_OKAY)
+         /* free z */
+         mp_clear(fp_cache[idx].LUT[x]->z);
+   }
+   mp_clear(&tmp);
+
+   if (err == MP_OKAY)
+     return MP_OKAY;
+
+   /* err cleanup */
+   for (y = 0; y < (1U<<FP_LUT); y++) {
+      ecc_del_point(fp_cache[idx].LUT[y]);
+      fp_cache[idx].LUT[y] = NULL;
+   }
+   ecc_del_point(fp_cache[idx].g);
+   fp_cache[idx].g         = NULL;
+   fp_cache[idx].lru_count = 0;
+   mp_clear(&fp_cache[idx].mu);
+   mp_clear(&tmp);
+
+   return err;
+}
+
+/* perform a fixed point ECC mulmod */
+static int accel_fp_mul(int idx, mp_int* k, ecc_point *R, mp_int* modulus,
+                        mp_digit* mp, int map)
+{
+#define KB_SIZE 128
+
+#ifdef WOLFSSL_SMALL_STACK
+   unsigned char* kb;
+#else
+   unsigned char kb[128];
+#endif
+   int      x;
+   unsigned y, z, err, bitlen, bitpos, lut_gap, first;
+   mp_int   tk;
+
+   if (mp_init(&tk) != MP_OKAY)
+       return MP_INIT_E;
+
+   /* if it's smaller than modulus we fine */
+   if (mp_unsigned_bin_size(k) > mp_unsigned_bin_size(modulus)) {
+      mp_int order;
+      if (mp_init(&order) != MP_OKAY) {
+        mp_clear(&tk);
+        return MP_INIT_E;
+      }
+
+      /* find order */
+      y = mp_unsigned_bin_size(modulus);
+      for (x = 0; ecc_sets[x].size; x++) {
+         if (y <= (unsigned)ecc_sets[x].size) break;
+      }
+   
+      /* back off if we are on the 521 bit curve */
+      if (y == 66) --x;
+      
+      if ((err = mp_read_radix(&order, ecc_sets[x].order, 16)) != MP_OKAY) {
+         mp_clear(&order);
+         mp_clear(&tk);
+         return err;
+      }
+
+      /* k must be less than modulus */
+      if (mp_cmp(k, &order) != MP_LT) {
+         if ((err = mp_mod(k, &order, &tk)) != MP_OKAY) {
+            mp_clear(&tk);
+            mp_clear(&order);
+            return err;
+         }
+      } else {
+         mp_copy(k, &tk);
+      }
+      mp_clear(&order);
+   } else {
+      mp_copy(k, &tk);
+   }       
+   
+   /* get bitlen and round up to next multiple of FP_LUT */
+   bitlen  = mp_unsigned_bin_size(modulus) << 3;
+   x       = bitlen % FP_LUT;
+   if (x) {
+      bitlen += FP_LUT - x;
+   }  
+   lut_gap = bitlen / FP_LUT;
+        
+   /* get the k value */
+   if (mp_unsigned_bin_size(&tk) > (int)(KB_SIZE - 2)) {
+      mp_clear(&tk);
+      return BUFFER_E;
+   }
+   
+   /* store k */
+#ifdef WOLFSSL_SMALL_STACK
+   kb = (unsigned char*)XMALLOC(KB_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+   if (kb == NULL)
+      return MEMORY_E;
+#endif
+
+   XMEMSET(kb, 0, KB_SIZE);
+   if ((err = mp_to_unsigned_bin(&tk, kb)) != MP_OKAY) {
+      mp_clear(&tk);
+   }
+   else {
+      /* let's reverse kb so it's little endian */
+      x = 0;
+      y = mp_unsigned_bin_size(&tk) - 1;
+      mp_clear(&tk);
+
+      while ((unsigned)x < y) {
+         z = kb[x]; kb[x] = kb[y]; kb[y] = z;
+         ++x; --y;
+      }
+
+      /* at this point we can start, yipee */
+      first = 1;
+      for (x = lut_gap-1; x >= 0; x--) {
+          /* extract FP_LUT bits from kb spread out by lut_gap bits and offset
+             by x bits from the start */
+          bitpos = x;
+          for (y = z = 0; y < FP_LUT; y++) {
+             z |= ((kb[bitpos>>3] >> (bitpos&7)) & 1) << y;
+             bitpos += lut_gap;  /* it's y*lut_gap + x, but here we can avoid
+                                    the mult in each loop */
+          }
+
+          /* double if not first */
+          if (!first) {
+             if ((err = ecc_projective_dbl_point(R, R, modulus,
+                                                              mp)) != MP_OKAY) {
+                break;
+             }
+          }
+
+          /* add if not first, otherwise copy */
+          if (!first && z) {
+             if ((err = ecc_projective_add_point(R, fp_cache[idx].LUT[z], R,
+                                                     modulus, mp)) != MP_OKAY) {
+                break;
+             }
+          } else if (z) {
+             if ((mp_copy(fp_cache[idx].LUT[z]->x, R->x) != MP_OKAY) ||
+                 (mp_copy(fp_cache[idx].LUT[z]->y, R->y) != MP_OKAY) ||
+                 (mp_copy(&fp_cache[idx].mu,       R->z) != MP_OKAY)) {
+                 err = GEN_MEM_ERR;
+                 break;
+             }
+                 first = 0;
+          }
+      }
+   }
+
+   if (err == MP_OKAY) {
+      z = 0;
+      ForceZero(kb, KB_SIZE);
+      /* map R back from projective space */
+      if (map) {
+         err = ecc_map(R, modulus, mp);
+      } else {
+         err = MP_OKAY;
+      }
+   }
+
+#ifdef WOLFSSL_SMALL_STACK
+   XFREE(kb, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+#undef KB_SIZE
+
+   return err;
+}
+
+#ifdef ECC_SHAMIR
+/* perform a fixed point ECC mulmod */
+static int accel_fp_mul2add(int idx1, int idx2, 
+                            mp_int* kA, mp_int* kB,
+                            ecc_point *R, mp_int* modulus, mp_digit* mp)
+{
+#define KB_SIZE 128
+
+#ifdef WOLFSSL_SMALL_STACK
+   unsigned char* kb[2];
+#else
+   unsigned char kb[2][128];
+#endif
+   int      x;
+   unsigned y, z, err, bitlen, bitpos, lut_gap, first, zA, zB;
+   mp_int tka;
+   mp_int tkb;
+   mp_int order;
+
+   if (mp_init_multi(&tka, &tkb, 0, 0, 0, 0) != MP_OKAY)
+       return MP_INIT_E;
+
+   /* if it's smaller than modulus we fine */
+   if (mp_unsigned_bin_size(kA) > mp_unsigned_bin_size(modulus)) {
+      /* find order */
+      y = mp_unsigned_bin_size(modulus);
+      for (x = 0; ecc_sets[x].size; x++) {
+         if (y <= (unsigned)ecc_sets[x].size) break;
+      }
+   
+      /* back off if we are on the 521 bit curve */
+      if (y == 66) --x;
+      
+      if ((err = mp_init(&order)) != MP_OKAY) {
+         mp_clear(&tkb);
+         mp_clear(&tka);
+         return err;
+      }      
+      if ((err = mp_read_radix(&order, ecc_sets[x].order, 16)) != MP_OKAY) {
+         mp_clear(&tkb);
+         mp_clear(&tka);
+         mp_clear(&order);
+         return err;
+      }
+
+      /* kA must be less than modulus */
+      if (mp_cmp(kA, &order) != MP_LT) {
+         if ((err = mp_mod(kA, &order, &tka)) != MP_OKAY) {
+            mp_clear(&tkb);
+            mp_clear(&tka);
+            mp_clear(&order);
+            return err;
+         }
+      } else {
+         mp_copy(kA, &tka);
+      }
+      mp_clear(&order);
+   } else {
+      mp_copy(kA, &tka);
+   }       
+
+   /* if it's smaller than modulus we fine */
+   if (mp_unsigned_bin_size(kB) > mp_unsigned_bin_size(modulus)) {
+      /* find order */
+      y = mp_unsigned_bin_size(modulus);
+      for (x = 0; ecc_sets[x].size; x++) {
+         if (y <= (unsigned)ecc_sets[x].size) break;
+      }
+   
+      /* back off if we are on the 521 bit curve */
+      if (y == 66) --x;
+      
+      if ((err = mp_init(&order)) != MP_OKAY) {
+         mp_clear(&tkb);
+         mp_clear(&tka);
+         return err;
+      }      
+      if ((err = mp_read_radix(&order, ecc_sets[x].order, 16)) != MP_OKAY) {
+         mp_clear(&tkb);
+         mp_clear(&tka);
+         mp_clear(&order);
+         return err;
+      }
+
+      /* kB must be less than modulus */
+      if (mp_cmp(kB, &order) != MP_LT) {
+         if ((err = mp_mod(kB, &order, &tkb)) != MP_OKAY) {
+            mp_clear(&tkb);
+            mp_clear(&tka);
+            mp_clear(&order);
+            return err;
+         }
+      } else {
+         mp_copy(kB, &tkb);
+      }
+      mp_clear(&order);
+   } else {
+      mp_copy(kB, &tkb);
+   }     
+
+   /* get bitlen and round up to next multiple of FP_LUT */
+   bitlen  = mp_unsigned_bin_size(modulus) << 3;
+   x       = bitlen % FP_LUT;
+   if (x) {
+      bitlen += FP_LUT - x;
+   }  
+   lut_gap = bitlen / FP_LUT;
+        
+   /* get the k value */
+   if ((mp_unsigned_bin_size(&tka) > (int)(KB_SIZE - 2)) ||
+       (mp_unsigned_bin_size(&tkb) > (int)(KB_SIZE - 2))  ) {
+      mp_clear(&tka);
+      mp_clear(&tkb);
+      return BUFFER_E;
+   }
+   
+   /* store k */
+#ifdef WOLFSSL_SMALL_STACK
+   kb[0] = (unsigned char*)XMALLOC(KB_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+   if (kb[0] == NULL)
+      return MEMORY_E;
+#endif
+
+   XMEMSET(kb[0], 0, KB_SIZE);
+   if ((err = mp_to_unsigned_bin(&tka, kb[0])) != MP_OKAY) {
+      mp_clear(&tka);
+      mp_clear(&tkb);
+      XFREE(kb[0], NULL, DYNAMIC_TYPE_TMP_BUFFER);
+      return err;
+   }
+   
+   /* let's reverse kb so it's little endian */
+   x = 0;
+   y = mp_unsigned_bin_size(&tka) - 1;
+   mp_clear(&tka);
+   while ((unsigned)x < y) {
+      z = kb[0][x]; kb[0][x] = kb[0][y]; kb[0][y] = z;
+      ++x; --y;
+   }      
+   
+   /* store b */
+#ifdef WOLFSSL_SMALL_STACK
+   kb[1] = (unsigned char*)XMALLOC(KB_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+   if (kb[1] == NULL) {
+      XFREE(kb[0], NULL, DYNAMIC_TYPE_TMP_BUFFER);
+      return MEMORY_E;
+   }
+#endif
+
+   XMEMSET(kb[1], 0, KB_SIZE);
+   if ((err = mp_to_unsigned_bin(&tkb, kb[1])) != MP_OKAY) {
+      mp_clear(&tkb);
+   }
+   else {
+      x = 0;
+      y = mp_unsigned_bin_size(&tkb) - 1;
+      mp_clear(&tkb);
+      while ((unsigned)x < y) {
+         z = kb[1][x]; kb[1][x] = kb[1][y]; kb[1][y] = z;
+         ++x; --y;
+      }
+
+      /* at this point we can start, yipee */
+      first = 1;
+      for (x = lut_gap-1; x >= 0; x--) {
+          /* extract FP_LUT bits from kb spread out by lut_gap bits and
+             offset by x bits from the start */
+          bitpos = x;
+          for (y = zA = zB = 0; y < FP_LUT; y++) {
+             zA |= ((kb[0][bitpos>>3] >> (bitpos&7)) & 1) << y;
+             zB |= ((kb[1][bitpos>>3] >> (bitpos&7)) & 1) << y;
+             bitpos += lut_gap;    /* it's y*lut_gap + x, but here we can avoid
+                                      the mult in each loop */
+          }
+
+          /* double if not first */
+          if (!first) {
+             if ((err = ecc_projective_dbl_point(R, R, modulus,
+                                                              mp)) != MP_OKAY) {
+                break;
+             }
+          }
+
+          /* add if not first, otherwise copy */
+          if (!first) {
+             if (zA) {
+                if ((err = ecc_projective_add_point(R, fp_cache[idx1].LUT[zA],
+                                                  R, modulus, mp)) != MP_OKAY) {
+                   break;
+                }
+             }
+             if (zB) {
+                if ((err = ecc_projective_add_point(R, fp_cache[idx2].LUT[zB],
+                                                  R, modulus, mp)) != MP_OKAY) {
+                   break;
+                }
+             }
+          } else {
+             if (zA) {
+                 if ((mp_copy(fp_cache[idx1].LUT[zA]->x, R->x) != MP_OKAY) ||
+                    (mp_copy(fp_cache[idx1].LUT[zA]->y,  R->y) != MP_OKAY) ||
+                    (mp_copy(&fp_cache[idx1].mu,         R->z) != MP_OKAY)) {
+                     err = GEN_MEM_ERR;
+                     break;
+                 }
+                    first = 0;
+             }
+             if (zB && first == 0) {
+                if (zB) {
+                   if ((err = ecc_projective_add_point(R,
+                           fp_cache[idx2].LUT[zB], R, modulus, mp)) != MP_OKAY){
+                      break;
+                   }
+                }
+             } else if (zB && first == 1) {
+                 if ((mp_copy(fp_cache[idx2].LUT[zB]->x, R->x) != MP_OKAY) ||
+                    (mp_copy(fp_cache[idx2].LUT[zB]->y, R->y) != MP_OKAY) ||
+                    (mp_copy(&fp_cache[idx2].mu,        R->z) != MP_OKAY)) {
+                     err = GEN_MEM_ERR;
+                     break;
+                 }
+                    first = 0;
+             }
+          }
+      }
+   }
+
+   ForceZero(kb[0], KB_SIZE);
+   ForceZero(kb[1], KB_SIZE);
+
+#ifdef WOLFSSL_SMALL_STACK
+   XFREE(kb[0], NULL, DYNAMIC_TYPE_TMP_BUFFER);
+   XFREE(kb[1], NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+#undef KB_SIZE
+
+   return ecc_map(R, modulus, mp);
+}
+
+/** ECC Fixed Point mulmod global
+  Computes kA*A + kB*B = C using Shamir's Trick
+  A        First point to multiply
+  kA       What to multiple A by
+  B        Second point to multiply
+  kB       What to multiple B by
+  C        [out] Destination point (can overlap with A or B)
+  modulus  Modulus for curve 
+  return MP_OKAY on success
+*/ 
+int ecc_mul2add(ecc_point* A, mp_int* kA,
+                ecc_point* B, mp_int* kB,
+                ecc_point* C, mp_int* modulus)
+{
+   int  idx1 = -1, idx2 = -1, err = MP_OKAY, mpInit = 0;
+   mp_digit mp;
+   mp_int   mu;
+  
+   err = mp_init(&mu);
+   if (err != MP_OKAY)
+       return err;
+
+#ifndef HAVE_THREAD_LS
+   if (initMutex == 0) {
+        InitMutex(&ecc_fp_lock);
+        initMutex = 1;
+   }
+   if (LockMutex(&ecc_fp_lock) != 0)
+      return BAD_MUTEX_E;
+#endif /* HAVE_THREAD_LS */
+
+      /* find point */
+      idx1 = find_base(A);
+
+      /* no entry? */
+      if (idx1 == -1) {
+         /* find hole and add it */
+         if ((idx1 = find_hole()) >= 0) {
+            err = add_entry(idx1, A);
+         }
+      }
+      if (err == MP_OKAY && idx1 != -1) {
+         /* increment LRU */
+         ++(fp_cache[idx1].lru_count);
+      }
+
+      if (err == MP_OKAY)
+        /* find point */
+        idx2 = find_base(B);
+
+      if (err == MP_OKAY) {
+        /* no entry? */
+        if (idx2 == -1) {
+           /* find hole and add it */
+           if ((idx2 = find_hole()) >= 0)
+              err = add_entry(idx2, B);
+         }
+      }
+
+      if (err == MP_OKAY && idx2 != -1) {
+         /* increment LRU */
+         ++(fp_cache[idx2].lru_count);
+      }
+
+      if (err == MP_OKAY) {
+        /* if it's 2 build the LUT, if it's higher just use the LUT */
+        if (idx1 >= 0 && fp_cache[idx1].lru_count == 2) {
+           /* compute mp */
+           err = mp_montgomery_setup(modulus, &mp);
+
+           if (err == MP_OKAY) {
+             mpInit = 1;
+             err = mp_montgomery_calc_normalization(&mu, modulus);
+           }
+                 
+           if (err == MP_OKAY)
+             /* build the LUT */
+               err = build_lut(idx1, modulus, &mp, &mu);
+        }
+      }
+
+      if (err == MP_OKAY) {
+        /* if it's 2 build the LUT, if it's higher just use the LUT */
+        if (idx2 >= 0 && fp_cache[idx2].lru_count == 2) {
+           if (mpInit == 0) {
+                /* compute mp */
+                err = mp_montgomery_setup(modulus, &mp);
+                if (err == MP_OKAY) {
+                    mpInit = 1;
+                    err = mp_montgomery_calc_normalization(&mu, modulus);
+                }
+            }
+                 
+            if (err == MP_OKAY) 
+            /* build the LUT */
+              err = build_lut(idx2, modulus, &mp, &mu);
+        }
+      }
+
+
+      if (err == MP_OKAY) {
+        if (idx1 >=0 && idx2 >= 0 && fp_cache[idx1].lru_count >= 2 &&
+                                     fp_cache[idx2].lru_count >= 2) {
+           if (mpInit == 0) {
+              /* compute mp */
+              err = mp_montgomery_setup(modulus, &mp);
+           }
+           if (err == MP_OKAY)
+             err = accel_fp_mul2add(idx1, idx2, kA, kB, C, modulus, &mp);
+        } else {
+           err = normal_ecc_mul2add(A, kA, B, kB, C, modulus);
+        }
+    }
+
+#ifndef HAVE_THREAD_LS
+    UnLockMutex(&ecc_fp_lock);
+#endif /* HAVE_THREAD_LS */
+    mp_clear(&mu);
+
+    return err;
+}
+#endif
+
+/** ECC Fixed Point mulmod global
+    k        The multiplicand
+    G        Base point to multiply
+    R        [out] Destination of product
+    modulus  The modulus for the curve
+    map      [boolean] If non-zero maps the point back to affine co-ordinates,
+             otherwise it's left in jacobian-montgomery form
+    return MP_OKAY if successful
+*/   
+int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus,
+               int map)
+{
+   int   idx, err = MP_OKAY;
+   mp_digit mp;
+   mp_int   mu;
+   int      mpSetup = 0;
+
+   if (mp_init(&mu) != MP_OKAY)
+       return MP_INIT_E;
+   
+#ifndef HAVE_THREAD_LS
+   if (initMutex == 0) {
+        InitMutex(&ecc_fp_lock);
+        initMutex = 1;
+   }
+   
+   if (LockMutex(&ecc_fp_lock) != 0)
+      return BAD_MUTEX_E;
+#endif /* HAVE_THREAD_LS */
+
+      /* find point */
+      idx = find_base(G);
+
+      /* no entry? */
+      if (idx == -1) {
+         /* find hole and add it */
+         idx = find_hole();
+
+         if (idx >= 0)
+            err = add_entry(idx, G);
+      }
+      if (err == MP_OKAY && idx >= 0) {
+         /* increment LRU */
+         ++(fp_cache[idx].lru_count);
+      }
+
+
+      if (err == MP_OKAY) { 
+        /* if it's 2 build the LUT, if it's higher just use the LUT */
+        if (idx >= 0 && fp_cache[idx].lru_count == 2) {
+           /* compute mp */
+           err = mp_montgomery_setup(modulus, &mp);
+
+           if (err == MP_OKAY) {
+             /* compute mu */
+             mpSetup = 1;
+             err = mp_montgomery_calc_normalization(&mu, modulus);
+           }
+                 
+           if (err == MP_OKAY) 
+             /* build the LUT */
+             err = build_lut(idx, modulus, &mp, &mu);
+        }
+      }
+
+      if (err == MP_OKAY) { 
+        if (idx >= 0 && fp_cache[idx].lru_count >= 2) {
+           if (mpSetup == 0) {
+              /* compute mp */
+              err = mp_montgomery_setup(modulus, &mp);
+           }
+           if (err == MP_OKAY)
+             err = accel_fp_mul(idx, k, R, modulus, &mp, map);
+        } else {
+           err = normal_ecc_mulmod(k, G, R, modulus, map);
+        }
+     }
+
+#ifndef HAVE_THREAD_LS
+    UnLockMutex(&ecc_fp_lock);
+#endif /* HAVE_THREAD_LS */
+    mp_clear(&mu);
+
+    return err;
+}
+
+/* helper function for freeing the cache ...
+   must be called with the cache mutex locked */
+static void wc_ecc_fp_free_cache(void)
+{
+   unsigned x, y;
+   for (x = 0; x < FP_ENTRIES; x++) {
+      if (fp_cache[x].g != NULL) {
+         for (y = 0; y < (1U<<FP_LUT); y++) {
+            ecc_del_point(fp_cache[x].LUT[y]);
+            fp_cache[x].LUT[y] = NULL;
+         }
+         ecc_del_point(fp_cache[x].g);
+         fp_cache[x].g         = NULL;
+         mp_clear(&fp_cache[x].mu);
+         fp_cache[x].lru_count = 0;
+         fp_cache[x].lock = 0;
+      }         
+   }
+}         
+
+/** Free the Fixed Point cache */
+void wc_ecc_fp_free(void)
+{
+#ifndef HAVE_THREAD_LS
+   if (initMutex == 0) {
+        InitMutex(&ecc_fp_lock);
+        initMutex = 1;
+   }
+   
+   if (LockMutex(&ecc_fp_lock) == 0) {
+#endif /* HAVE_THREAD_LS */
+
+       wc_ecc_fp_free_cache();
+
+#ifndef HAVE_THREAD_LS
+       UnLockMutex(&ecc_fp_lock);
+       FreeMutex(&ecc_fp_lock);
+       initMutex = 0;
+   }
+#endif /* HAVE_THREAD_LS */
+}
+
+
+#endif /* FP_ECC */
+
+#ifdef HAVE_ECC_ENCRYPT
+
+
+enum ecCliState {
+    ecCLI_INIT      = 1,    
+    ecCLI_SALT_GET  = 2,    
+    ecCLI_SALT_SET  = 3,    
+    ecCLI_SENT_REQ  = 4,    
+    ecCLI_RECV_RESP = 5,    
+    ecCLI_BAD_STATE = 99    
+};
+
+enum ecSrvState {
+    ecSRV_INIT      = 1,    
+    ecSRV_SALT_GET  = 2,    
+    ecSRV_SALT_SET  = 3,    
+    ecSRV_RECV_REQ  = 4,    
+    ecSRV_SENT_RESP = 5,    
+    ecSRV_BAD_STATE = 99    
+};
+
+
+struct ecEncCtx {
+    const byte* kdfSalt;   /* optional salt for kdf */
+    const byte* kdfInfo;   /* optional info for kdf */
+    const byte* macSalt;   /* optional salt for mac */
+    word32    kdfSaltSz;   /* size of kdfSalt */
+    word32    kdfInfoSz;   /* size of kdfInfo */
+    word32    macSaltSz;   /* size of macSalt */
+    byte      clientSalt[EXCHANGE_SALT_SZ];  /* for msg exchange */
+    byte      serverSalt[EXCHANGE_SALT_SZ];  /* for msg exchange */
+    byte      encAlgo;     /* which encryption type */
+    byte      kdfAlgo;     /* which key derivation function type */
+    byte      macAlgo;     /* which mac function type */
+    byte      protocol;    /* are we REQ_RESP client or server ? */
+    byte      cliSt;       /* protocol state, for sanity checks */
+    byte      srvSt;       /* protocol state, for sanity checks */
+};
+
+
+const byte* wc_ecc_ctx_get_own_salt(ecEncCtx* ctx)
+{
+    if (ctx == NULL || ctx->protocol == 0)
+        return NULL;
+
+    if (ctx->protocol == REQ_RESP_CLIENT) {
+        if (ctx->cliSt == ecCLI_INIT) {
+            ctx->cliSt =  ecCLI_SALT_GET;
+            return ctx->clientSalt;
+        }
+        else {
+            ctx->cliSt = ecCLI_BAD_STATE;
+            return NULL;
+        }
+    }
+    else if (ctx->protocol == REQ_RESP_SERVER) {
+        if (ctx->srvSt == ecSRV_INIT) {
+            ctx->srvSt =  ecSRV_SALT_GET;
+            return ctx->serverSalt;
+        }
+        else {
+            ctx->srvSt = ecSRV_BAD_STATE;
+            return NULL;
+        }
+    }
+
+    return NULL;
+}
+
+
+/* optional set info, can be called before or after set_peer_salt */
+int wc_ecc_ctx_set_info(ecEncCtx* ctx, const byte* info, int sz)
+{
+    if (ctx == NULL || info == 0 || sz < 0)
+        return BAD_FUNC_ARG;
+
+    ctx->kdfInfo   = info;
+    ctx->kdfInfoSz = sz;
+
+    return 0;
+}
+
+
+static const char* exchange_info = "Secure Message Exchange";
+
+int wc_ecc_ctx_set_peer_salt(ecEncCtx* ctx, const byte* salt)
+{
+    byte tmp[EXCHANGE_SALT_SZ/2];
+    int  halfSz = EXCHANGE_SALT_SZ/2;
+
+    if (ctx == NULL || ctx->protocol == 0 || salt == NULL)
+        return BAD_FUNC_ARG;
+
+    if (ctx->protocol == REQ_RESP_CLIENT) {
+        XMEMCPY(ctx->serverSalt, salt, EXCHANGE_SALT_SZ);
+        if (ctx->cliSt == ecCLI_SALT_GET)
+            ctx->cliSt =  ecCLI_SALT_SET;
+        else {
+            ctx->cliSt =  ecCLI_BAD_STATE;
+            return BAD_ENC_STATE_E;
+        }
+    }
+    else {
+        XMEMCPY(ctx->clientSalt, salt, EXCHANGE_SALT_SZ);
+        if (ctx->srvSt == ecSRV_SALT_GET)
+            ctx->srvSt =  ecSRV_SALT_SET;
+        else {
+            ctx->srvSt =  ecSRV_BAD_STATE;
+            return BAD_ENC_STATE_E;
+        }
+    }
+
+    /* mix half and half */
+    /* tmp stores 2nd half of client before overwrite */
+    XMEMCPY(tmp, ctx->clientSalt + halfSz, halfSz);
+    XMEMCPY(ctx->clientSalt + halfSz, ctx->serverSalt, halfSz);
+    XMEMCPY(ctx->serverSalt, tmp, halfSz);
+
+    ctx->kdfSalt   = ctx->clientSalt;
+    ctx->kdfSaltSz = EXCHANGE_SALT_SZ;
+
+    ctx->macSalt   = ctx->serverSalt;
+    ctx->macSaltSz = EXCHANGE_SALT_SZ;
+
+    if (ctx->kdfInfo == NULL) {
+        /* default info */
+        ctx->kdfInfo   = (const byte*)exchange_info;
+        ctx->kdfInfoSz = EXCHANGE_INFO_SZ;
+    }
+
+    return 0;
+}
+
+
+static int ecc_ctx_set_salt(ecEncCtx* ctx, int flags, RNG* rng)
+{
+    byte* saltBuffer = NULL;
+
+    if (ctx == NULL || rng == NULL || flags == 0) 
+        return BAD_FUNC_ARG;
+
+    saltBuffer = (flags == REQ_RESP_CLIENT) ? ctx->clientSalt : ctx->serverSalt;
+
+    return wc_RNG_GenerateBlock(rng, saltBuffer, EXCHANGE_SALT_SZ);
+}
+
+
+static void ecc_ctx_init(ecEncCtx* ctx, int flags)
+{
+    if (ctx) {
+        XMEMSET(ctx, 0, sizeof(ecEncCtx));
+
+        ctx->encAlgo  = ecAES_128_CBC;
+        ctx->kdfAlgo  = ecHKDF_SHA256;
+        ctx->macAlgo  = ecHMAC_SHA256;
+        ctx->protocol = (byte)flags;
+
+        if (flags == REQ_RESP_CLIENT)
+            ctx->cliSt = ecCLI_INIT;
+        if (flags == REQ_RESP_SERVER)
+            ctx->srvSt = ecSRV_INIT;
+    }
+}
+
+
+/* allow ecc context reset so user doesn't have to init/free for resue */
+int wc_ecc_ctx_reset(ecEncCtx* ctx, RNG* rng)
+{
+    if (ctx == NULL || rng == NULL)
+        return BAD_FUNC_ARG;
+
+    ecc_ctx_init(ctx, ctx->protocol);
+    return ecc_ctx_set_salt(ctx, ctx->protocol, rng);
+}
+
+
+/* alloc/init and set defaults, return new Context  */
+ecEncCtx* wc_ecc_ctx_new(int flags, RNG* rng)
+{
+    int       ret = 0;
+    ecEncCtx* ctx = (ecEncCtx*)XMALLOC(sizeof(ecEncCtx), 0, DYNAMIC_TYPE_ECC);
+
+    if (ctx)
+        ctx->protocol = (byte)flags;
+
+    ret = wc_ecc_ctx_reset(ctx, rng);
+    if (ret != 0) {
+        wc_ecc_ctx_free(ctx);
+        ctx = NULL;
+    }
+
+    return ctx;
+}
+
+
+/* free any resources, clear any keys */
+void wc_ecc_ctx_free(ecEncCtx* ctx)
+{
+    if (ctx) {
+        ForceZero(ctx, sizeof(ecEncCtx));
+        XFREE(ctx, 0, DYNAMIC_TYPE_ECC);
+    }
+}
+
+
+static int ecc_get_key_sizes(ecEncCtx* ctx, int* encKeySz, int* ivSz,
+                             int* keysLen, word32* digestSz, word32* blockSz)
+{
+    if (ctx) {
+        switch (ctx->encAlgo) {
+            case ecAES_128_CBC:
+                *encKeySz = KEY_SIZE_128;
+                *ivSz     = IV_SIZE_64;
+                *blockSz  = AES_BLOCK_SIZE;
+                break;
+            default:
+                return BAD_FUNC_ARG;
+        }
+
+        switch (ctx->macAlgo) {
+            case ecHMAC_SHA256:
+                *digestSz = SHA256_DIGEST_SIZE;
+                break;
+            default:
+                return BAD_FUNC_ARG;
+        }
+    } else
+        return BAD_FUNC_ARG;
+
+    *keysLen  = *encKeySz + *ivSz + *digestSz;
+
+    return 0;
+}
+
+
+/* ecc encrypt with shared secret run through kdf
+   ctx holds non default algos and inputs
+   msgSz should be the right size for encAlgo, i.e., already padded 
+   return 0 on success */
+int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
+                word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx)
+{
+    int          ret;
+    word32       blockSz;
+    word32       digestSz;
+    ecEncCtx     localCtx;
+#ifdef WOLFSSL_SMALL_STACK
+    byte*        sharedSecret;
+    byte*        keys;
+#else
+    byte         sharedSecret[ECC_MAXSIZE];  /* 521 max size */
+    byte         keys[ECC_BUFSIZE];         /* max size */
+#endif
+    word32       sharedSz = ECC_MAXSIZE;
+    int          keysLen;
+    int          encKeySz;
+    int          ivSz;
+    int          offset = 0;         /* keys offset if doing msg exchange */
+    byte*        encKey;
+    byte*        encIv;
+    byte*        macKey;
+
+    if (privKey == NULL || pubKey == NULL || msg == NULL || out == NULL ||
+                           outSz  == NULL)
+        return BAD_FUNC_ARG;
+
+    if (ctx == NULL) {  /* use defaults */
+        ecc_ctx_init(&localCtx, 0);
+        ctx = &localCtx;  
+    }
+        
+    ret = ecc_get_key_sizes(ctx, &encKeySz, &ivSz, &keysLen, &digestSz,
+                            &blockSz);
+    if (ret != 0)
+        return ret;
+
+    if (ctx->protocol == REQ_RESP_SERVER) {
+        offset = keysLen;
+        keysLen *= 2;
+
+        if (ctx->srvSt != ecSRV_RECV_REQ)
+            return BAD_ENC_STATE_E;
+
+        ctx->srvSt = ecSRV_BAD_STATE; /* we're done no more ops allowed */
+    }
+    else if (ctx->protocol == REQ_RESP_CLIENT) {
+        if (ctx->cliSt != ecCLI_SALT_SET)
+            return BAD_ENC_STATE_E;
+
+        ctx->cliSt = ecCLI_SENT_REQ; /* only do this once */
+    }
+        
+    if (keysLen > ECC_BUFSIZE) /* keys size */
+        return BUFFER_E;
+        
+    if ( (msgSz%blockSz) != 0)
+        return BAD_PADDING_E;
+
+    if (*outSz < (msgSz + digestSz))
+        return BUFFER_E;
+
+#ifdef WOLFSSL_SMALL_STACK
+    sharedSecret = (byte*)XMALLOC(ECC_MAXSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (sharedSecret == NULL)
+        return MEMORY_E;
+
+    keys = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (keys == NULL) {
+        XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    ret = wc_ecc_shared_secret(privKey, pubKey, sharedSecret, &sharedSz);
+
+    if (ret == 0) {
+       switch (ctx->kdfAlgo) {
+           case ecHKDF_SHA256 :
+               ret = wc_HKDF(SHA256, sharedSecret, sharedSz, ctx->kdfSalt,
+                          ctx->kdfSaltSz, ctx->kdfInfo, ctx->kdfInfoSz,
+                          keys, keysLen);
+               break;
+
+           default:
+               ret = BAD_FUNC_ARG;
+               break;
+       }
+    }
+
+    if (ret == 0) {
+       encKey = keys + offset;
+       encIv  = encKey + encKeySz;
+       macKey = encKey + encKeySz + ivSz;
+
+       switch (ctx->encAlgo) {
+           case ecAES_128_CBC:
+               {
+                   Aes aes;
+                   ret = wc_AesSetKey(&aes, encKey, KEY_SIZE_128, encIv,
+                                                                AES_ENCRYPTION);
+                   if (ret != 0)
+                       break;
+                   ret = wc_AesCbcEncrypt(&aes, out, msg, msgSz);
+               }
+               break;
+
+           default:
+               ret = BAD_FUNC_ARG;
+               break;
+       }
+    }
+
+    if (ret == 0) {
+       switch (ctx->macAlgo) {
+           case ecHMAC_SHA256:
+               {
+                   Hmac hmac;
+                   ret = wc_HmacSetKey(&hmac, SHA256, macKey, SHA256_DIGEST_SIZE);
+                   if (ret != 0)
+                       break;
+                   ret = wc_HmacUpdate(&hmac, out, msgSz);
+                   if (ret != 0)
+                       break;
+                   ret = wc_HmacUpdate(&hmac, ctx->macSalt, ctx->macSaltSz);
+                   if (ret != 0)
+                       break;
+                   ret = wc_HmacFinal(&hmac, out+msgSz);
+               }
+               break;
+
+           default:
+               ret = BAD_FUNC_ARG;
+               break;
+       }
+    }
+
+    if (ret == 0)
+       *outSz = msgSz + digestSz;
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(keys, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+/* ecc decrypt with shared secret run through kdf
+   ctx holds non default algos and inputs
+   return 0 on success */
+int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
+                word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx)
+{
+    int          ret;
+    word32       blockSz;
+    word32       digestSz;
+    ecEncCtx     localCtx;
+#ifdef WOLFSSL_SMALL_STACK
+    byte*        sharedSecret;
+    byte*        keys;
+#else
+    byte         sharedSecret[ECC_MAXSIZE];  /* 521 max size */
+    byte         keys[ECC_BUFSIZE];         /* max size */
+#endif
+    word32       sharedSz = ECC_MAXSIZE;
+    int          keysLen;
+    int          encKeySz;
+    int          ivSz;
+    int          offset = 0;       /* in case using msg exchange */
+    byte*        encKey;
+    byte*        encIv;
+    byte*        macKey;
+
+    if (privKey == NULL || pubKey == NULL || msg == NULL || out == NULL ||
+                           outSz  == NULL)
+        return BAD_FUNC_ARG;
+
+    if (ctx == NULL) {  /* use defaults */
+        ecc_ctx_init(&localCtx, 0);
+        ctx = &localCtx;  
+    }
+        
+    ret = ecc_get_key_sizes(ctx, &encKeySz, &ivSz, &keysLen, &digestSz,
+                            &blockSz);
+    if (ret != 0)
+        return ret;
+        
+    if (ctx->protocol == REQ_RESP_CLIENT) {
+        offset = keysLen;
+        keysLen *= 2;
+
+        if (ctx->cliSt != ecCLI_SENT_REQ)
+            return BAD_ENC_STATE_E;
+
+        ctx->cliSt = ecSRV_BAD_STATE; /* we're done no more ops allowed */
+    }
+    else if (ctx->protocol == REQ_RESP_SERVER) {
+        if (ctx->srvSt != ecSRV_SALT_SET)
+            return BAD_ENC_STATE_E;
+
+        ctx->srvSt = ecSRV_RECV_REQ; /* only do this once */
+    }
+        
+    if (keysLen > ECC_BUFSIZE) /* keys size */
+        return BUFFER_E;
+        
+    if ( ((msgSz-digestSz) % blockSz) != 0)
+        return BAD_PADDING_E;
+
+    if (*outSz < (msgSz - digestSz))
+        return BUFFER_E;
+
+#ifdef WOLFSSL_SMALL_STACK
+    sharedSecret = (byte*)XMALLOC(ECC_MAXSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (sharedSecret == NULL)
+        return MEMORY_E;
+
+    keys = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (keys == NULL) {
+        XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    ret = wc_ecc_shared_secret(privKey, pubKey, sharedSecret, &sharedSz);
+
+    if (ret == 0) {
+       switch (ctx->kdfAlgo) {
+           case ecHKDF_SHA256 :
+               ret = wc_HKDF(SHA256, sharedSecret, sharedSz, ctx->kdfSalt,
+                          ctx->kdfSaltSz, ctx->kdfInfo, ctx->kdfInfoSz,
+                          keys, keysLen);
+               break;
+
+           default:
+               ret = BAD_FUNC_ARG;
+               break;
+       }
+    }
+
+    if (ret == 0) {
+       encKey = keys + offset;
+       encIv  = encKey + encKeySz;
+       macKey = encKey + encKeySz + ivSz;
+
+       switch (ctx->macAlgo) {
+           case ecHMAC_SHA256:
+               {
+                   byte verify[SHA256_DIGEST_SIZE];
+                   Hmac hmac;
+                   ret = wc_HmacSetKey(&hmac, SHA256, macKey, SHA256_DIGEST_SIZE);
+                   if (ret != 0)
+                       break;
+                   ret = wc_HmacUpdate(&hmac, msg, msgSz-digestSz);
+                   if (ret != 0)
+                       break;
+                   ret = wc_HmacUpdate(&hmac, ctx->macSalt, ctx->macSaltSz);
+                   if (ret != 0)
+                       break;
+                   ret = wc_HmacFinal(&hmac, verify);
+                   if (ret != 0)
+                       break;
+                   if (memcmp(verify, msg + msgSz - digestSz, digestSz) != 0)
+                       ret = -1;
+               }
+               break;
+
+           default:
+               ret = BAD_FUNC_ARG;
+               break;
+       }
+    }
+
+    if (ret == 0) {
+       switch (ctx->encAlgo) {
+           case ecAES_128_CBC:
+               {
+                   Aes aes;
+                   ret = wc_AesSetKey(&aes, encKey, KEY_SIZE_128, encIv,
+                                                                AES_DECRYPTION);
+                   if (ret != 0)
+                       break;
+                   ret = wc_AesCbcDecrypt(&aes, out, msg, msgSz-digestSz);
+               }
+               break;
+
+           default:
+               ret = BAD_FUNC_ARG;
+               break;
+       }
+    }
+
+    if (ret == 0)
+       *outSz = msgSz - digestSz;
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(keys, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+
+#endif /* HAVE_ECC_ENCRYPT */
+
+
+#ifdef HAVE_COMP_KEY
+
+/* computes the jacobi c = (a | n) (or Legendre if n is prime)
+ * HAC pp. 73 Algorithm 2.149
+ */
+int mp_jacobi(mp_int* a, mp_int* p, int* c)
+{
+  mp_int   a1, p1;
+  int      k, s, r, res;
+  mp_digit residue;
+
+  /* if p <= 0 return MP_VAL */
+  if (mp_cmp_d(p, 0) != MP_GT) {
+     return MP_VAL;
+  }
+
+  /* step 1.  if a == 0, return 0 */
+  if (mp_iszero (a) == 1) {
+    *c = 0;
+    return MP_OKAY;
+  }
+
+  /* step 2.  if a == 1, return 1 */
+  if (mp_cmp_d (a, 1) == MP_EQ) {
+    *c = 1;
+    return MP_OKAY;
+  }
+
+  /* default */
+  s = 0;
+
+  /* step 3.  write a = a1 * 2**k  */
+  if ((res = mp_init_copy (&a1, a)) != MP_OKAY) {
+    return res;
+  }
+
+  if ((res = mp_init (&p1)) != MP_OKAY) {
+    mp_clear(&a1);
+    return res;
+  }
+
+  /* divide out larger power of two */
+  k = mp_cnt_lsb(&a1);
+  res = mp_div_2d(&a1, k, &a1, NULL);
+
+  if (res == MP_OKAY) {
+    /* step 4.  if e is even set s=1 */
+    if ((k & 1) == 0) {
+      s = 1;
+    } else {
+      /* else set s=1 if p = 1/7 (mod 8) or s=-1 if p = 3/5 (mod 8) */
+      residue = p->dp[0] & 7;
+
+      if (residue == 1 || residue == 7) {
+        s = 1;
+      } else if (residue == 3 || residue == 5) {
+        s = -1;
+      }
+    }
+
+    /* step 5.  if p == 3 (mod 4) *and* a1 == 3 (mod 4) then s = -s */
+    if ( ((p->dp[0] & 3) == 3) && ((a1.dp[0] & 3) == 3)) {
+      s = -s;
+    }
+  }
+
+  if (res == MP_OKAY) {
+    /* if a1 == 1 we're done */
+    if (mp_cmp_d (&a1, 1) == MP_EQ) {
+      *c = s;
+    } else {
+      /* n1 = n mod a1 */
+      res = mp_mod (p, &a1, &p1);
+      if (res == MP_OKAY)
+        res = mp_jacobi (&p1, &a1, &r);
+
+      if (res == MP_OKAY)
+      *c = s * r;
+    }
+  }
+
+  /* done */
+  mp_clear (&p1);
+  mp_clear (&a1);
+
+  return res;
+}
+
+
+int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret)
+{
+  int res, legendre, done = 0;
+  mp_int t1, C, Q, S, Z, M, T, R, two;
+  mp_digit i;
+
+  /* first handle the simple cases */
+  if (mp_cmp_d(n, 0) == MP_EQ) {
+    mp_zero(ret);
+    return MP_OKAY;
+  }
+  if (mp_cmp_d(prime, 2) == MP_EQ)       return MP_VAL; /* prime must be odd */
+  /* TAO removed
+  if ((res = mp_jacobi(n, prime, &legendre)) != MP_OKAY)      return res;
+  if (legendre == -1)  return MP_VAL; */ /* quadratic non-residue mod prime */
+
+  if ((res = mp_init_multi(&t1, &C, &Q, &S, &Z, &M)) != MP_OKAY)
+    return res;
+
+  if ((res = mp_init_multi(&T, &R, &two, NULL, NULL, NULL))
+                          != MP_OKAY) {
+    mp_clear(&t1); mp_clear(&C); mp_clear(&Q); mp_clear(&S); mp_clear(&Z);
+    mp_clear(&M);
+    return res;
+  }
+
+  /* SPECIAL CASE: if prime mod 4 == 3
+   * compute directly: res = n^(prime+1)/4 mod prime
+   * Handbook of Applied Cryptography algorithm 3.36
+   */
+  res = mp_mod_d(prime, 4, &i);
+  if (res == MP_OKAY && i == 3) {
+    res = mp_add_d(prime, 1, &t1);
+
+    if (res == MP_OKAY)
+      res = mp_div_2(&t1, &t1);
+    if (res == MP_OKAY)
+      res = mp_div_2(&t1, &t1);
+    if (res == MP_OKAY)
+      res = mp_exptmod(n, &t1, prime, ret);
+
+    done = 1;
+  }
+
+  /* NOW: TonelliShanks algorithm */
+
+ if (res == MP_OKAY && done == 0) {
+
+   /* factor out powers of 2 from prime-1, defining Q and S
+    *                                      as: prime-1 = Q*2^S */
+    res = mp_copy(prime, &Q);
+    if (res == MP_OKAY)
+      res = mp_sub_d(&Q, 1, &Q);
+    /* Q = prime - 1 */
+    if (res == MP_OKAY)
+      mp_zero(&S);
+    /* S = 0 */
+    while (res == MP_OKAY && mp_iseven(&Q)) {
+      res = mp_div_2(&Q, &Q);
+      /* Q = Q / 2 */
+      if (res == MP_OKAY)
+        res = mp_add_d(&S, 1, &S);
+        /* S = S + 1 */
+    }
+
+    /* find a Z such that the Legendre symbol (Z|prime) == -1 */
+    if (res == MP_OKAY)
+      res = mp_set_int(&Z, 2);
+    /* Z = 2 */
+    while (res == MP_OKAY) {
+      res = mp_jacobi(&Z, prime, &legendre);
+      if (res == MP_OKAY && legendre == -1)
+        break;
+      if (res == MP_OKAY)
+        res = mp_add_d(&Z, 1, &Z);
+        /* Z = Z + 1 */
+    }
+
+    if (res == MP_OKAY)
+      res = mp_exptmod(&Z, &Q, prime, &C);
+      /* C = Z ^ Q mod prime */
+    if (res == MP_OKAY)
+      res = mp_add_d(&Q, 1, &t1);
+    if (res == MP_OKAY)
+      res = mp_div_2(&t1, &t1);
+      /* t1 = (Q + 1) / 2 */
+    if (res == MP_OKAY)
+      res = mp_exptmod(n, &t1, prime, &R);
+    /* R = n ^ ((Q + 1) / 2) mod prime */
+    if (res == MP_OKAY)
+      res = mp_exptmod(n, &Q, prime, &T);
+    /* T = n ^ Q mod prime */
+    if (res == MP_OKAY)
+      res = mp_copy(&S, &M);
+    /* M = S */
+    if (res == MP_OKAY)
+      res = mp_set_int(&two, 2);
+
+    while (res == MP_OKAY && done == 0) {
+      res = mp_copy(&T, &t1);
+      i = 0;
+      while (res == MP_OKAY) {
+        if (mp_cmp_d(&t1, 1) == MP_EQ)
+            break;
+        res = mp_exptmod(&t1, &two, prime, &t1);
+        if (res == MP_OKAY)
+          i++;
+      }
+      if (res == MP_OKAY && i == 0) {
+        mp_copy(&R, ret);
+        res = MP_OKAY;
+        done = 1;
+      }
+
+      if (done == 0) {
+        if (res == MP_OKAY)
+          res = mp_sub_d(&M, i, &t1);
+        if (res == MP_OKAY)
+          res = mp_sub_d(&t1, 1, &t1);
+        if (res == MP_OKAY)
+          res = mp_exptmod(&two, &t1, prime, &t1);
+        /* t1 = 2 ^ (M - i - 1) */
+        if (res == MP_OKAY)
+          res = mp_exptmod(&C, &t1, prime, &t1);
+        /* t1 = C ^ (2 ^ (M - i - 1)) mod prime */
+        if (res == MP_OKAY)
+          res = mp_sqrmod(&t1, prime, &C);
+        /* C = (t1 * t1) mod prime */
+        if (res == MP_OKAY)
+          res = mp_mulmod(&R, &t1, prime, &R);
+        /* R = (R * t1) mod prime */
+        if (res == MP_OKAY)
+          res = mp_mulmod(&T, &C, prime, &T);
+        /* T = (T * C) mod prime */
+        if (res == MP_OKAY)
+          mp_set(&M, i);
+        /* M = i */
+      }
+    }
+  }
+
+  /* done */
+  mp_clear(&t1);
+  mp_clear(&C);
+  mp_clear(&Q);
+  mp_clear(&S);
+  mp_clear(&Z);
+  mp_clear(&M);
+  mp_clear(&T);
+  mp_clear(&R);
+  mp_clear(&two);
+
+  return res;
+}
+
+
+/* export public ECC key in ANSI X9.63 format compressed */
+int wc_ecc_export_x963_compressed(ecc_key* key, byte* out, word32* outLen)
+{
+   word32 numlen;
+   int    ret = MP_OKAY;
+
+   if (key == NULL || out == NULL || outLen == NULL)
+       return ECC_BAD_ARG_E;
+
+   if (ecc_is_valid_idx(key->idx) == 0) {
+      return ECC_BAD_ARG_E;
+   }
+   numlen = key->dp->size;
+
+   if (*outLen < (1 + numlen)) {
+      *outLen = 1 + numlen;
+      return BUFFER_E;
+   }
+
+   /* store first byte */
+   out[0] = mp_isodd(key->pubkey.y) ? 0x03 : 0x02;
+
+   /* pad and store x */
+   XMEMSET(out+1, 0, numlen);
+   ret = mp_to_unsigned_bin(key->pubkey.x,
+                       out+1 + (numlen - mp_unsigned_bin_size(key->pubkey.x)));
+   *outLen = 1 + numlen;
+   return ret;
+}
+
+
+/* d = a - b (mod c) */
+int mp_submod(mp_int* a, mp_int* b, mp_int* c, mp_int* d)
+{
+  int     res;
+  mp_int  t;
+
+  if ((res = mp_init (&t)) != MP_OKAY) {
+    return res;
+  }
+
+  if ((res = mp_sub (a, b, &t)) != MP_OKAY) {
+    mp_clear (&t);
+    return res;
+  }
+  res = mp_mod (&t, c, d);
+  mp_clear (&t);
+
+  return res;
+}
+
+
+#endif /* HAVE_COMP_KEY */
+
+#endif /* HAVE_ECC */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/ecc_fp.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,2 @@
+/* dummy ecc_fp.c for dist */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/ed25519.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,371 @@
+/* ed25519.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+ /* Based On Daniel J Bernstein's ed25519 Public Domain ref10 work. */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+/* in case user set HAVE_ED25519 there */
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_ED25519
+
+#include <wolfssl/wolfcrypt/ed25519.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+
+/*
+    generate an ed25519 key pair.
+    returns 0 on success
+ */
+int wc_ed25519_make_key(RNG* rng, int keySz, ed25519_key* key)
+{
+    byte  az[64];
+    int   ret;
+    ge_p3 A;
+
+    if (rng == NULL || key == NULL)
+        return BAD_FUNC_ARG;
+
+    /* ed25519 has 32 byte key sizes */
+    if (keySz != ED25519_KEY_SIZE)
+        return BAD_FUNC_ARG;
+
+    ret = 0;
+    ret |= wc_RNG_GenerateBlock(rng, key->k, 32);
+    ret |= wc_Sha512Hash(key->k, 32, az);
+    az[0] &= 248;
+    az[31] &= 63;
+    az[31] |= 64;
+
+    ge_scalarmult_base(&A, az);
+    ge_p3_tobytes(key->p, &A);
+    XMEMMOVE(key->k + 32, key->p, 32);
+
+    return ret;
+}
+
+
+/*
+    in     contains the message to sign
+    inlen  is the length of the message to sign
+    out    is the buffer to write the signature
+    outlen [in/out] input size of out buf
+                    output gets set as the final length of out
+    key    is the ed25519 key to use when signing
+    return 0 on success
+ */
+int wc_ed25519_sign_msg(const byte* in, word32 inlen, byte* out,
+                        word32 *outlen, ed25519_key* key)
+{
+    ge_p3  R;
+    byte   nonce[SHA512_DIGEST_SIZE];
+    byte   hram[SHA512_DIGEST_SIZE];
+    byte   az[64];
+    word32 sigSz;
+    Sha512 sha;
+    int    ret = 0;
+
+    /* sanity check on arguments */
+    if (in == NULL || out == NULL || outlen == NULL || key == NULL)
+        return BAD_FUNC_ARG;
+
+    /* check and set up out length */
+    ret   = 0;
+    sigSz = wc_ed25519_sig_size(key);
+    if (*outlen < sigSz)
+        return BAD_FUNC_ARG;
+    *outlen = sigSz;
+
+    /* step 1: create nonce to use where nonce is r in
+       r = H(h_b, ... ,h_2b-1,M) */
+    ret |= wc_Sha512Hash(key->k,32,az);
+    az[0]  &= 248;
+    az[31] &= 63;
+    az[31] |= 64;
+    ret |= wc_InitSha512(&sha);
+    ret |= wc_Sha512Update(&sha, az + 32, 32);
+    ret |= wc_Sha512Update(&sha, in, inlen);
+    ret |= wc_Sha512Final(&sha, nonce);
+    sc_reduce(nonce);
+
+    /* step 2: computing R = rB where rB is the scalar multiplication of
+       r and B */
+    ge_scalarmult_base(&R,nonce);
+    ge_p3_tobytes(out,&R);
+
+    /* step 3: hash R + public key + message getting H(R,A,M) then
+       creating S = (r + H(R,A,M)a) mod l */
+    ret |= wc_InitSha512(&sha);
+    ret |= wc_Sha512Update(&sha, out, 32);
+    ret |= wc_Sha512Update(&sha, key->p, 32);
+    ret |= wc_Sha512Update(&sha, in, inlen);
+    ret |= wc_Sha512Final(&sha, hram);
+    sc_reduce(hram);
+    sc_muladd(out + 32, hram, az, nonce);
+
+    return ret;
+}
+
+
+/*
+   sig     is array of bytes containing the signature
+   siglen  is the length of sig byte array
+   msg     the array of bytes containing the message
+   msglen  length of msg array
+   stat    will be 1 on successful verify and 0 on unsuccessful
+*/
+int wc_ed25519_verify_msg(byte* sig, word32 siglen, const byte* msg,
+                          word32 msglen, int* stat, ed25519_key* key)
+{
+    byte   rcheck[32];
+    byte   h[SHA512_DIGEST_SIZE];
+    ge_p3  A;
+    ge_p2  R;
+    word32 sigSz;
+    int    ret;
+    Sha512 sha;
+
+    /* sanity check on arguments */
+    if (sig == NULL || msg == NULL || stat == NULL || key == NULL)
+        return BAD_FUNC_ARG;
+
+    ret   = 0;
+    *stat = 0;
+    sigSz = wc_ed25519_size(key);
+
+    /* check on basics needed to verify signature */
+    if (siglen < sigSz)
+        return BAD_FUNC_ARG;
+    if (sig[63] & 224)
+        return BAD_FUNC_ARG;
+
+    /* uncompress A (public key), test if valid, and negate it */
+    if (ge_frombytes_negate_vartime(&A, key->p) != 0)
+        return BAD_FUNC_ARG;
+
+    /* find H(R,A,M) and store it as h */
+    ret |= wc_InitSha512(&sha);
+    ret |= wc_Sha512Update(&sha, sig,    32);
+    ret |= wc_Sha512Update(&sha, key->p, 32);
+    ret |= wc_Sha512Update(&sha, msg,    msglen);
+    ret |= wc_Sha512Final(&sha,  h);
+    sc_reduce(h);
+
+    /*
+       Uses a fast single-signature verification SB = R + H(R,A,M)A becomes
+       SB - H(R,A,M)A saving decompression of R
+    */
+    ret |= ge_double_scalarmult_vartime(&R, h, &A, sig + 32);
+    ge_tobytes(rcheck, &R);
+
+    /* comparison of R created to R in sig */
+    ret  |= ConstantCompare(rcheck, sig, 32);
+
+    *stat = (ret == 0)? 1: 0;
+
+    return ret;
+}
+
+
+/* initialize information and memory for key */
+int wc_ed25519_init(ed25519_key* key)
+{
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    XMEMSET(key, 0, sizeof(ed25519_key));
+
+    return 0;
+}
+
+
+/* clear memory of key */
+void wc_ed25519_free(ed25519_key* key)
+{
+    if (key == NULL)
+        return;
+
+    ForceZero(key, sizeof(ed25519_key));
+}
+
+
+/*
+    outLen should contain the size of out buffer when input. outLen is than set
+    to the final output length.
+    returns 0 on success
+ */
+int wc_ed25519_export_public(ed25519_key* key, byte* out, word32* outLen)
+{
+    word32 keySz;
+
+    /* sanity check on arguments */
+    if (key == NULL || out == NULL || outLen == NULL)
+        return BAD_FUNC_ARG;
+
+    keySz = wc_ed25519_size(key);
+    if (*outLen < keySz) {
+        *outLen = keySz;
+        return BUFFER_E;
+    }
+    *outLen = keySz;
+    XMEMCPY(out, key->p, keySz);
+
+    return 0;
+}
+
+
+/*
+    Imports a compressed/uncompressed public key.
+    in    the byte array containing the public key
+    inLen the length of the byte array being passed in
+    key   ed25519 key struct to put the public key in
+ */
+int wc_ed25519_import_public(const byte* in, word32 inLen, ed25519_key* key)
+{
+    word32 keySz;
+    int    ret;
+
+    /* sanity check on arguments */
+    if (in == NULL || key == NULL)
+        return BAD_FUNC_ARG;
+
+    keySz = wc_ed25519_size(key);
+
+    if (inLen < keySz)
+        return BAD_FUNC_ARG;
+
+    /* compressed prefix according to draft
+       http://www.ietf.org/id/draft-koch-eddsa-for-openpgp-02.txt */
+    if (in[0] == 0x40) {
+        /* key is stored in compressed format so just copy in */
+        XMEMCPY(key->p, (in + 1), keySz);
+        return 0;
+    }
+
+    /* importing uncompressed public key */
+    if (in[0] == 0x04) {
+        /* pass in (x,y) and store compressed key */
+        ret = ge_compress_key(key->p, (in+1), (in+1+keySz), keySz);
+        return ret;
+    }
+
+    /* if not specified compressed or uncompressed check key size
+       if key size is equal to compressed key size copy in key */
+    if (inLen == keySz) {
+        XMEMCPY(key->p, in, keySz);
+        return 0;
+    }
+
+    /* bad public key format */
+    return BAD_FUNC_ARG;
+}
+
+
+/*
+    For importing a private key and its associated public key.
+ */
+int wc_ed25519_import_private_key(const byte* priv, word32 privSz,
+                                const byte* pub, word32 pubSz, ed25519_key* key)
+{
+    word32 keySz;
+    int    ret;
+
+    /* sanity check on arguments */
+    if (priv == NULL || pub == NULL || key == NULL)
+        return BAD_FUNC_ARG;
+
+    keySz = wc_ed25519_size(key);
+
+    /* key size check */
+    if (privSz < keySz || pubSz < keySz)
+        return BAD_FUNC_ARG;
+
+    XMEMCPY(key->k, priv, keySz);
+    ret = wc_ed25519_import_public(pub, pubSz, key);
+    XMEMCPY((key->k + keySz), key->p, keySz);
+
+    return ret;
+}
+
+
+/*
+    outLen should contain the size of out buffer when input. outLen is than set
+    to the final output length.
+    returns 0 on success
+ */
+int wc_ed25519_export_private_only(ed25519_key* key, byte* out, word32* outLen)
+{
+    word32 keySz;
+
+    /* sanity checks on arguments */
+    if (key == NULL || out == NULL || outLen == NULL)
+        return BAD_FUNC_ARG;
+
+    keySz = wc_ed25519_size(key);
+    if (*outLen < keySz) {
+        *outLen = keySz;
+        return BUFFER_E;
+    }
+    *outLen = keySz;
+    XMEMCPY(out, key->k, keySz);
+
+    return 0;
+}
+
+
+/* is the compressed key size in bytes */
+int wc_ed25519_size(ed25519_key* key)
+{
+    word32 keySz;
+
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    keySz = ED25519_KEY_SIZE;
+
+    return keySz;
+}
+
+
+/* returns the size of signature in bytes */
+int wc_ed25519_sig_size(ed25519_key* key)
+{
+    word32 sigSz;
+
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    sigSz = ED25519_SIG_SIZE;
+
+    return sigSz;
+}
+
+#endif /* HAVE_ED25519 */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/error.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,344 @@
+/* error.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+#ifdef _MSC_VER
+    /* 4996 warning to use MS extensions e.g., strcpy_s instead of XSTRNCPY */
+    #pragma warning(disable: 4996)
+#endif
+
+const char* wc_GetErrorString(int error)
+{
+#ifdef NO_ERROR_STRINGS
+
+    (void)error;
+    return "no support for error strings built in";
+
+#else
+
+    switch (error) {
+
+    case OPEN_RAN_E :
+        return "opening random device error";
+
+    case READ_RAN_E :
+        return "reading random device error";
+
+    case WINCRYPT_E :
+        return "windows crypt init error";
+
+    case CRYPTGEN_E :
+        return "windows crypt generation error";
+
+    case RAN_BLOCK_E :
+        return "random device read would block error";
+
+    case BAD_MUTEX_E :
+        return "Bad mutex, operation failed";
+
+    case MP_INIT_E :
+        return "mp_init error state";
+
+    case MP_READ_E :
+        return "mp_read error state";
+
+    case MP_EXPTMOD_E :
+        return "mp_exptmod error state";
+
+    case MP_TO_E :
+        return "mp_to_xxx error state, can't convert";
+
+    case MP_SUB_E :
+        return "mp_sub error state, can't subtract";
+
+    case MP_ADD_E :
+        return "mp_add error state, can't add";
+
+    case MP_MUL_E :
+        return "mp_mul error state, can't multiply";
+
+    case MP_MULMOD_E :
+        return "mp_mulmod error state, can't multiply mod";
+
+    case MP_MOD_E :
+        return "mp_mod error state, can't mod";
+
+    case MP_INVMOD_E :
+        return "mp_invmod error state, can't inv mod";
+
+    case MP_CMP_E :
+        return "mp_cmp error state";
+
+    case MP_ZERO_E :
+        return "mp zero result, not expected";
+
+    case MEMORY_E :
+        return "out of memory error";
+
+    case RSA_WRONG_TYPE_E :
+        return "RSA wrong block type for RSA function";
+
+    case RSA_BUFFER_E :
+        return "RSA buffer error, output too small or input too big";
+
+    case BUFFER_E :
+        return "Buffer error, output too small or input too big";
+
+    case ALGO_ID_E :
+        return "Setting Cert AlogID error";
+
+    case PUBLIC_KEY_E :
+        return "Setting Cert Public Key error";
+
+    case DATE_E :
+        return "Setting Cert Date validity error";
+
+    case SUBJECT_E :
+        return "Setting Cert Subject name error";
+
+    case ISSUER_E :
+        return "Setting Cert Issuer name error";
+
+    case CA_TRUE_E :
+        return "Setting basic constraint CA true error";
+
+    case EXTENSIONS_E :
+        return "Setting extensions error";
+
+    case ASN_PARSE_E :
+        return "ASN parsing error, invalid input";
+
+    case ASN_VERSION_E :
+        return "ASN version error, invalid number";
+
+    case ASN_GETINT_E :
+        return "ASN get big int error, invalid data";
+
+    case ASN_RSA_KEY_E :
+        return "ASN key init error, invalid input";
+
+    case ASN_OBJECT_ID_E :
+        return "ASN object id error, invalid id";
+
+    case ASN_TAG_NULL_E :
+        return "ASN tag error, not null";
+
+    case ASN_EXPECT_0_E :
+        return "ASN expect error, not zero";
+
+    case ASN_BITSTR_E :
+        return "ASN bit string error, wrong id";
+
+    case ASN_UNKNOWN_OID_E :
+        return "ASN oid error, unknown sum id";
+
+    case ASN_DATE_SZ_E :
+        return "ASN date error, bad size";
+
+    case ASN_BEFORE_DATE_E :
+        return "ASN date error, current date before";
+
+    case ASN_AFTER_DATE_E :
+        return "ASN date error, current date after";
+
+    case ASN_SIG_OID_E :
+        return "ASN signature error, mismatched oid";
+
+    case ASN_TIME_E :
+        return "ASN time error, unkown time type";
+
+    case ASN_INPUT_E :
+        return "ASN input error, not enough data";
+
+    case ASN_SIG_CONFIRM_E :
+        return "ASN sig error, confirm failure";
+
+    case ASN_SIG_HASH_E :
+        return "ASN sig error, unsupported hash type";
+
+    case ASN_SIG_KEY_E :
+        return "ASN sig error, unsupported key type";
+
+    case ASN_DH_KEY_E :
+        return "ASN key init error, invalid input";
+
+    case ASN_NTRU_KEY_E :
+        return "ASN NTRU key decode error, invalid input";
+
+    case ASN_CRIT_EXT_E:
+        return "X.509 Critical extension ignored";
+
+    case ECC_BAD_ARG_E :
+        return "ECC input argument wrong type, invalid input";
+
+    case ASN_ECC_KEY_E :
+        return "ECC ASN1 bad key data, invalid input";
+
+    case ECC_CURVE_OID_E :
+        return "ECC curve sum OID unsupported, invalid input";
+
+    case BAD_FUNC_ARG :
+        return "Bad function argument";
+
+    case NOT_COMPILED_IN :
+        return "Feature not compiled in";
+
+    case UNICODE_SIZE_E :
+        return "Unicode password too big";
+
+    case NO_PASSWORD :
+        return "No password provided by user";
+
+    case ALT_NAME_E :
+        return "Alt Name problem, too big";
+
+    case AES_GCM_AUTH_E:
+        return "AES-GCM Authentication check fail";
+
+    case AES_CCM_AUTH_E:
+        return "AES-CCM Authentication check fail";
+
+    case CAVIUM_INIT_E:
+        return "Cavium Init type error";
+
+    case COMPRESS_INIT_E:
+        return "Compress Init error";
+
+    case COMPRESS_E:
+        return "Compress error";
+
+    case DECOMPRESS_INIT_E:
+        return "DeCompress Init error";
+
+    case DECOMPRESS_E:
+        return "DeCompress error";
+
+    case BAD_ALIGN_E:
+        return "Bad alignment error, no alloc help";
+
+    case ASN_NO_SIGNER_E :
+        return "ASN no signer error to confirm failure";
+
+    case ASN_CRL_CONFIRM_E :
+        return "ASN CRL sig error, confirm failure";
+
+    case ASN_CRL_NO_SIGNER_E :
+        return "ASN CRL no signer error to confirm failure";
+
+    case ASN_OCSP_CONFIRM_E :
+        return "ASN OCSP sig error, confirm failure";
+
+    case BAD_ENC_STATE_E:
+        return "Bad ecc encrypt state operation";
+
+    case BAD_PADDING_E:
+        return "Bad padding, message wrong length";
+
+    case REQ_ATTRIBUTE_E:
+        return "Setting cert request attributes error";
+
+    case PKCS7_OID_E:
+        return "PKCS#7 error: mismatched OID value";
+
+    case PKCS7_RECIP_E:
+        return "PKCS#7 error: no matching recipient found";
+
+    case FIPS_NOT_ALLOWED_E:
+        return "FIPS mode not allowed error";
+
+    case ASN_NAME_INVALID_E:
+        return "Name Constraint error";
+
+    case RNG_FAILURE_E:
+        return "Random Number Generator failed";
+
+    case HMAC_MIN_KEYLEN_E:
+        return "FIPS Mode HMAC Minimum Key Length error";
+
+    case RSA_PAD_E:
+        return "Rsa Padding error";
+
+    case LENGTH_ONLY_E:
+        return "Output length only set, not for other use error";
+
+    case IN_CORE_FIPS_E:
+        return "In Core Integrity check FIPS error";
+
+    case AES_KAT_FIPS_E:
+        return "AES Known Answer Test check FIPS error";
+
+    case DES3_KAT_FIPS_E:
+        return "DES3 Known Answer Test check FIPS error";
+
+    case HMAC_KAT_FIPS_E:
+        return "HMAC Known Answer Test check FIPS error";
+
+    case RSA_KAT_FIPS_E:
+        return "RSA Known Answer Test check FIPS error";
+
+    case DRBG_KAT_FIPS_E:
+        return "DRBG Known Answer Test check FIPS error";
+
+    case DRBG_CONT_FIPS_E:
+        return "DRBG Continuous Test FIPS error";
+
+    case AESGCM_KAT_FIPS_E:
+        return "AESGCM Known Answer Test check FIPS error";
+
+    case THREAD_STORE_KEY_E:
+        return "Thread Storage Key Create error";
+
+    case THREAD_STORE_SET_E:
+        return "Thread Storage Set error";
+
+    case MAC_CMP_FAILED_E:
+        return "MAC comparison failed";
+
+    case IS_POINT_E:
+        return "ECC is point on curve failed";
+
+    case ECC_INF_E:
+        return " ECC point at infinity error";
+
+    case ECC_PRIV_KEY_E:
+        return " ECC private key is not valid error";
+
+    default:
+        return "unknown error number";
+
+    }
+
+#endif /* NO_ERROR_STRINGS */
+
+}
+
+void wc_ErrorString(int error, char* buffer)
+{
+    XSTRNCPY(buffer, wc_GetErrorString(error), WOLFSSL_MAX_ERROR_SZ);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/fe_low_mem.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,597 @@
+/* fe_low_mem.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+/* Based from Daniel Beer's public domain word. */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#if defined(HAVE_ED25519) || defined(HAVE_CURVE25519)
+
+#include <wolfssl/wolfcrypt/fe_operations.h>
+
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+
+void fprime_copy(byte *x, const byte *a)
+{
+    int i;
+    for (i = 0; i < F25519_SIZE; i++)
+        x[i] = a[i];
+}
+
+
+void fe_copy(fe x, const fe a)
+{
+    int i;
+    for (i = 0; i < F25519_SIZE; i++)
+        x[i] = a[i];
+}
+
+
+/* Double an X-coordinate */
+static void xc_double(byte *x3, byte *z3,
+		      const byte *x1, const byte *z1)
+{
+	/* Explicit formulas database: dbl-1987-m
+	 *
+	 * source 1987 Montgomery "Speeding the Pollard and elliptic
+	 *   curve methods of factorization", page 261, fourth display
+	 * compute X3 = (X1^2-Z1^2)^2
+	 * compute Z3 = 4 X1 Z1 (X1^2 + a X1 Z1 + Z1^2)
+	 */
+	byte x1sq[F25519_SIZE];
+	byte z1sq[F25519_SIZE];
+	byte x1z1[F25519_SIZE];
+	byte a[F25519_SIZE];
+
+	fe_mul__distinct(x1sq, x1, x1);
+	fe_mul__distinct(z1sq, z1, z1);
+	fe_mul__distinct(x1z1, x1, z1);
+
+	fe_sub(a, x1sq, z1sq);
+	fe_mul__distinct(x3, a, a);
+
+	fe_mul_c(a, x1z1, 486662);
+	fe_add(a, x1sq, a);
+	fe_add(a, z1sq, a);
+	fe_mul__distinct(x1sq, x1z1, a);
+	fe_mul_c(z3, x1sq, 4);
+}
+
+
+/* Differential addition */
+static void xc_diffadd(byte *x5, byte *z5,
+		       const byte *x1, const byte *z1,
+		       const byte *x2, const byte *z2,
+		       const byte *x3, const byte *z3)
+{
+	/* Explicit formulas database: dbl-1987-m3
+	 *
+	 * source 1987 Montgomery "Speeding the Pollard and elliptic curve
+	 *   methods of factorization", page 261, fifth display, plus
+	 *   common-subexpression elimination
+	 * compute A = X2+Z2
+	 * compute B = X2-Z2
+	 * compute C = X3+Z3
+	 * compute D = X3-Z3
+	 * compute DA = D A
+	 * compute CB = C B
+	 * compute X5 = Z1(DA+CB)^2
+	 * compute Z5 = X1(DA-CB)^2
+	 */
+	byte da[F25519_SIZE];
+	byte cb[F25519_SIZE];
+	byte a[F25519_SIZE];
+	byte b[F25519_SIZE];
+
+	fe_add(a, x2, z2);
+	fe_sub(b, x3, z3); /* D */
+	fe_mul__distinct(da, a, b);
+
+	fe_sub(b, x2, z2);
+	fe_add(a, x3, z3); /* C */
+	fe_mul__distinct(cb, a, b);
+
+	fe_add(a, da, cb);
+	fe_mul__distinct(b, a, a);
+	fe_mul__distinct(x5, z1, b);
+
+	fe_sub(a, da, cb);
+	fe_mul__distinct(b, a, a);
+	fe_mul__distinct(z5, x1, b);
+}
+
+
+int curve25519(byte *result, byte *e, byte *q)
+{
+	/* Current point: P_m */
+	byte xm[F25519_SIZE];
+	byte zm[F25519_SIZE] = {1};
+
+	/* Predecessor: P_(m-1) */
+	byte xm1[F25519_SIZE] = {1};
+	byte zm1[F25519_SIZE] = {0};
+
+	int i;
+
+	/* Note: bit 254 is assumed to be 1 */
+	fe_copy(xm, q);
+
+	for (i = 253; i >= 0; i--) {
+		const int bit = (e[i >> 3] >> (i & 7)) & 1;
+		byte xms[F25519_SIZE];
+		byte zms[F25519_SIZE];
+
+		/* From P_m and P_(m-1), compute P_(2m) and P_(2m-1) */
+		xc_diffadd(xm1, zm1, q, f25519_one, xm, zm, xm1, zm1);
+		xc_double(xm, zm, xm, zm);
+
+		/* Compute P_(2m+1) */
+		xc_diffadd(xms, zms, xm1, zm1, xm, zm, q, f25519_one);
+
+		/* Select:
+		 *   bit = 1 --> (P_(2m+1), P_(2m))
+		 *   bit = 0 --> (P_(2m), P_(2m-1))
+		 */
+		fe_select(xm1, xm1, xm, bit);
+		fe_select(zm1, zm1, zm, bit);
+		fe_select(xm, xm, xms, bit);
+		fe_select(zm, zm, zms, bit);
+	}
+
+	/* Freeze out of projective coordinates */
+	fe_inv__distinct(zm1, zm);
+	fe_mul__distinct(result, zm1, xm);
+	fe_normalize(result);
+    return 0;
+}
+
+
+static void raw_add(byte *x, const byte *p)
+{
+	word16 c = 0;
+	int i;
+
+	for (i = 0; i < F25519_SIZE; i++) {
+		c += ((word16)x[i]) + ((word16)p[i]);
+		x[i] = c;
+		c >>= 8;
+	}
+}
+
+
+static void raw_try_sub(byte *x, const byte *p)
+{
+	byte minusp[F25519_SIZE];
+	word16 c = 0;
+	int i;
+
+	for (i = 0; i < F25519_SIZE; i++) {
+		c = ((word16)x[i]) - ((word16)p[i]) - c;
+		minusp[i] = c;
+		c = (c >> 8) & 1;
+	}
+
+	fprime_select(x, minusp, x, c);
+}
+
+
+static int prime_msb(const byte *p)
+{
+    int i;
+    byte x;
+    int shift = 1;
+    int z     = F25519_SIZE - 1;
+
+   /*
+       Test for any hot bits.
+       As soon as one instance is incountered set shift to 0.
+    */
+	for (i = F25519_SIZE - 1; i >= 0; i--) {
+        shift &= ((shift ^ ((-p[i] | p[i]) >> 7)) & 1);
+        z -= shift;
+    }
+	x = p[z];
+	z <<= 3;
+    shift = 1;
+    for (i = 0; i < 8; i++) {
+        shift &= ((-(x >> i) | (x >> i)) >> (7 - i) & 1);
+        z += shift;
+    }
+
+	return z - 1;
+}
+
+
+void fprime_select(byte *dst, const byte *zero, const byte *one, byte condition)
+{
+	const byte mask = -condition;
+	int i;
+
+	for (i = 0; i < F25519_SIZE; i++)
+		dst[i] = zero[i] ^ (mask & (one[i] ^ zero[i]));
+}
+
+
+void fprime_add(byte *r, const byte *a, const byte *modulus)
+{
+	raw_add(r, a);
+	raw_try_sub(r, modulus);
+}
+
+
+void fprime_sub(byte *r, const byte *a, const byte *modulus)
+{
+	raw_add(r, modulus);
+	raw_try_sub(r, a);
+	raw_try_sub(r, modulus);
+}
+
+
+void fprime_mul(byte *r, const byte *a, const byte *b,
+		const byte *modulus)
+{
+	word16 c = 0;
+	int i,j;
+
+	XMEMSET(r, 0, F25519_SIZE);
+
+	for (i = prime_msb(modulus); i >= 0; i--) {
+		const byte bit = (b[i >> 3] >> (i & 7)) & 1;
+		byte plusa[F25519_SIZE];
+
+	    for (j = 0; j < F25519_SIZE; j++) {
+		    c |= ((word16)r[j]) << 1;
+		    r[j] = c;
+		    c >>= 8;
+	    }
+		raw_try_sub(r, modulus);
+
+		fprime_copy(plusa, r);
+		fprime_add(plusa, a, modulus);
+
+		fprime_select(r, r, plusa, bit);
+	}
+}
+
+
+void fe_load(byte *x, word32 c)
+{
+	word32 i;
+
+	for (i = 0; i < sizeof(c); i++) {
+		x[i] = c;
+		c >>= 8;
+	}
+
+	for (; i < F25519_SIZE; i++)
+		x[i] = 0;
+}
+
+
+void fe_normalize(byte *x)
+{
+	byte minusp[F25519_SIZE];
+	word16 c;
+	int i;
+
+	/* Reduce using 2^255 = 19 mod p */
+	c = (x[31] >> 7) * 19;
+	x[31] &= 127;
+
+	for (i = 0; i < F25519_SIZE; i++) {
+		c += x[i];
+		x[i] = c;
+		c >>= 8;
+	}
+
+	/* The number is now less than 2^255 + 18, and therefore less than
+	 * 2p. Try subtracting p, and conditionally load the subtracted
+	 * value if underflow did not occur.
+	 */
+	c = 19;
+
+	for (i = 0; i + 1 < F25519_SIZE; i++) {
+		c += x[i];
+		minusp[i] = c;
+		c >>= 8;
+	}
+
+	c += ((word16)x[i]) - 128;
+	minusp[31] = c;
+
+	/* Load x-p if no underflow */
+	fe_select(x, minusp, x, (c >> 15) & 1);
+}
+
+
+void fe_select(byte *dst,
+		   const byte *zero, const byte *one,
+		   byte condition)
+{
+	const byte mask = -condition;
+	int i;
+
+	for (i = 0; i < F25519_SIZE; i++)
+		dst[i] = zero[i] ^ (mask & (one[i] ^ zero[i]));
+}
+
+
+void fe_add(fe r, const fe a, const fe b)
+{
+	word16 c = 0;
+	int i;
+
+	/* Add */
+	for (i = 0; i < F25519_SIZE; i++) {
+		c >>= 8;
+		c += ((word16)a[i]) + ((word16)b[i]);
+		r[i] = c;
+	}
+
+	/* Reduce with 2^255 = 19 mod p */
+	r[31] &= 127;
+	c = (c >> 7) * 19;
+
+	for (i = 0; i < F25519_SIZE; i++) {
+		c += r[i];
+		r[i] = c;
+		c >>= 8;
+	}
+}
+
+
+void fe_sub(fe r, const fe a, const fe b)
+{
+	word32 c = 0;
+	int i;
+
+	/* Calculate a + 2p - b, to avoid underflow */
+	c = 218;
+	for (i = 0; i + 1 < F25519_SIZE; i++) {
+		c += 65280 + ((word32)a[i]) - ((word32)b[i]);
+		r[i] = c;
+		c >>= 8;
+	}
+
+	c += ((word32)a[31]) - ((word32)b[31]);
+	r[31] = c & 127;
+	c = (c >> 7) * 19;
+
+	for (i = 0; i < F25519_SIZE; i++) {
+		c += r[i];
+		r[i] = c;
+		c >>= 8;
+	}
+}
+
+
+void fe_neg(fe r, const fe a)
+{
+	word32 c = 0;
+	int i;
+
+	/* Calculate 2p - a, to avoid underflow */
+	c = 218;
+	for (i = 0; i + 1 < F25519_SIZE; i++) {
+		c += 65280 - ((word32)a[i]);
+		r[i] = c;
+		c >>= 8;
+	}
+
+	c -= ((word32)a[31]);
+	r[31] = c & 127;
+	c = (c >> 7) * 19;
+
+	for (i = 0; i < F25519_SIZE; i++) {
+		c += r[i];
+		r[i] = c;
+		c >>= 8;
+	}
+}
+
+
+void fe_mul__distinct(byte *r, const byte *a, const byte *b)
+{
+	word32 c = 0;
+	int i;
+
+	for (i = 0; i < F25519_SIZE; i++) {
+		int j;
+
+		c >>= 8;
+		for (j = 0; j <= i; j++)
+			c += ((word32)a[j]) * ((word32)b[i - j]);
+
+		for (; j < F25519_SIZE; j++)
+			c += ((word32)a[j]) *
+			     ((word32)b[i + F25519_SIZE - j]) * 38;
+
+		r[i] = c;
+	}
+
+	r[31] &= 127;
+	c = (c >> 7) * 19;
+
+	for (i = 0; i < F25519_SIZE; i++) {
+		c += r[i];
+		r[i] = c;
+		c >>= 8;
+	}
+}
+
+
+void fe_mul(fe r, const fe a, const fe b)
+{
+	byte tmp[F25519_SIZE];
+
+	fe_mul__distinct(tmp, a, b);
+	fe_copy(r, tmp);
+}
+
+
+void fe_mul_c(byte *r, const byte *a, word32 b)
+{
+	word32 c = 0;
+	int i;
+
+	for (i = 0; i < F25519_SIZE; i++) {
+		c >>= 8;
+		c += b * ((word32)a[i]);
+		r[i] = c;
+	}
+
+	r[31] &= 127;
+	c >>= 7;
+	c *= 19;
+
+	for (i = 0; i < F25519_SIZE; i++) {
+		c += r[i];
+		r[i] = c;
+		c >>= 8;
+	}
+}
+
+
+void fe_inv__distinct(byte *r, const byte *x)
+{
+	byte s[F25519_SIZE];
+	int i;
+
+	/* This is a prime field, so by Fermat's little theorem:
+	 *
+	 *     x^(p-1) = 1 mod p
+	 *
+	 * Therefore, raise to (p-2) = 2^255-21 to get a multiplicative
+	 * inverse.
+	 *
+	 * This is a 255-bit binary number with the digits:
+	 *
+	 *     11111111... 01011
+	 *
+	 * We compute the result by the usual binary chain, but
+	 * alternate between keeping the accumulator in r and s, so as
+	 * to avoid copying temporaries.
+	 */
+
+	/* 1 1 */
+	fe_mul__distinct(s, x, x);
+	fe_mul__distinct(r, s, x);
+
+	/* 1 x 248 */
+	for (i = 0; i < 248; i++) {
+		fe_mul__distinct(s, r, r);
+		fe_mul__distinct(r, s, x);
+	}
+
+	/* 0 */
+	fe_mul__distinct(s, r, r);
+
+	/* 1 */
+	fe_mul__distinct(r, s, s);
+	fe_mul__distinct(s, r, x);
+
+	/* 0 */
+	fe_mul__distinct(r, s, s);
+
+	/* 1 */
+	fe_mul__distinct(s, r, r);
+	fe_mul__distinct(r, s, x);
+
+	/* 1 */
+	fe_mul__distinct(s, r, r);
+	fe_mul__distinct(r, s, x);
+}
+
+
+void fe_invert(fe r, const fe x)
+{
+	byte tmp[F25519_SIZE];
+
+	fe_inv__distinct(tmp, x);
+	fe_copy(r, tmp);
+}
+
+
+/* Raise x to the power of (p-5)/8 = 2^252-3, using s for temporary
+ * storage.
+ */
+static void exp2523(byte *r, const byte *x, byte *s)
+{
+	int i;
+
+	/* This number is a 252-bit number with the binary expansion:
+	 *
+	 *     111111... 01
+	 */
+
+	/* 1 1 */
+	fe_mul__distinct(r, x, x);
+	fe_mul__distinct(s, r, x);
+
+	/* 1 x 248 */
+	for (i = 0; i < 248; i++) {
+		fe_mul__distinct(r, s, s);
+		fe_mul__distinct(s, r, x);
+	}
+
+	/* 0 */
+	fe_mul__distinct(r, s, s);
+
+	/* 1 */
+	fe_mul__distinct(s, r, r);
+	fe_mul__distinct(r, s, x);
+}
+
+
+void fe_sqrt(byte *r, const byte *a)
+{
+	byte v[F25519_SIZE];
+	byte i[F25519_SIZE];
+	byte x[F25519_SIZE];
+	byte y[F25519_SIZE];
+
+	/* v = (2a)^((p-5)/8) [x = 2a] */
+	fe_mul_c(x, a, 2);
+	exp2523(v, x, y);
+
+	/* i = 2av^2 - 1 */
+	fe_mul__distinct(y, v, v);
+	fe_mul__distinct(i, x, y);
+	fe_load(y, 1);
+	fe_sub(i, i, y);
+
+	/* r = avi */
+	fe_mul__distinct(x, v, a);
+	fe_mul__distinct(r, x, i);
+}
+
+#endif /* HAVE_CURVE25519 or HAVE_ED25519 */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/fe_operations.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,1398 @@
+/* fe_operations.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+ /* Based On Daniel J Bernstein's curve25519 Public Domain ref10 work. */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#if defined(HAVE_ED25519) || defined(HAVE_CURVE25519)
+
+#include <wolfssl/wolfcrypt/fe_operations.h>
+#include <stdint.h>
+
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+/*
+fe means field element.
+Here the field is \Z/(2^255-19).
+An element t, entries t[0]...t[9], represents the integer
+t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
+Bounds on each t[i] vary depending on context.
+*/
+
+uint64_t load_3(const unsigned char *in)
+{
+  uint64_t result;
+  result = (uint64_t) in[0];
+  result |= ((uint64_t) in[1]) << 8;
+  result |= ((uint64_t) in[2]) << 16;
+  return result;
+}
+
+
+uint64_t load_4(const unsigned char *in)
+{
+  uint64_t result;
+  result = (uint64_t) in[0];
+  result |= ((uint64_t) in[1]) << 8;
+  result |= ((uint64_t) in[2]) << 16;
+  result |= ((uint64_t) in[3]) << 24;
+  return result;
+}
+
+
+/*
+h = 1
+*/
+
+void fe_1(fe h)
+{
+  h[0] = 1;
+  h[1] = 0;
+  h[2] = 0;
+  h[3] = 0;
+  h[4] = 0;
+  h[5] = 0;
+  h[6] = 0;
+  h[7] = 0;
+  h[8] = 0;
+  h[9] = 0;
+}
+
+
+/*
+h = 0
+*/
+
+void fe_0(fe h)
+{
+  h[0] = 0;
+  h[1] = 0;
+  h[2] = 0;
+  h[3] = 0;
+  h[4] = 0;
+  h[5] = 0;
+  h[6] = 0;
+  h[7] = 0;
+  h[8] = 0;
+  h[9] = 0;
+}
+
+
+int curve25519(byte* q, byte* n, byte* p)
+{
+  unsigned char e[32];
+  unsigned int i;
+  fe x1;
+  fe x2;
+  fe z2;
+  fe x3;
+  fe z3;
+  fe tmp0;
+  fe tmp1;
+  int pos;
+  unsigned int swap;
+  unsigned int b;
+
+  for (i = 0;i < 32;++i) e[i] = n[i];
+  e[0] &= 248;
+  e[31] &= 127;
+  e[31] |= 64;
+
+  fe_frombytes(x1,p);
+  fe_1(x2);
+  fe_0(z2);
+  fe_copy(x3,x1);
+  fe_1(z3);
+
+  swap = 0;
+  for (pos = 254;pos >= 0;--pos) {
+    b = e[pos / 8] >> (pos & 7);
+    b &= 1;
+    swap ^= b;
+    fe_cswap(x2,x3,swap);
+    fe_cswap(z2,z3,swap);
+    swap = b;
+
+    /* montgomery */
+	fe_sub(tmp0,x3,z3);
+	fe_sub(tmp1,x2,z2);
+	fe_add(x2,x2,z2);
+	fe_add(z2,x3,z3);
+	fe_mul(z3,tmp0,x2);
+	fe_mul(z2,z2,tmp1);
+	fe_sq(tmp0,tmp1);
+	fe_sq(tmp1,x2);
+	fe_add(x3,z3,z2);
+	fe_sub(z2,z3,z2);
+	fe_mul(x2,tmp1,tmp0);
+	fe_sub(tmp1,tmp1,tmp0);
+	fe_sq(z2,z2);
+	fe_mul121666(z3,tmp1);
+	fe_sq(x3,x3);
+	fe_add(tmp0,tmp0,z3);
+	fe_mul(z3,x1,z2);
+	fe_mul(z2,tmp1,tmp0);
+  }
+  fe_cswap(x2,x3,swap);
+  fe_cswap(z2,z3,swap);
+
+  fe_invert(z2,z2);
+  fe_mul(x2,x2,z2);
+  fe_tobytes(q,x2);
+
+  return 0;
+}
+
+
+/*
+h = f * f
+Can overlap h with f.
+
+Preconditions:
+   |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+void fe_sq(fe h,const fe f)
+{
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t f0_2 = 2 * f0;
+  int32_t f1_2 = 2 * f1;
+  int32_t f2_2 = 2 * f2;
+  int32_t f3_2 = 2 * f3;
+  int32_t f4_2 = 2 * f4;
+  int32_t f5_2 = 2 * f5;
+  int32_t f6_2 = 2 * f6;
+  int32_t f7_2 = 2 * f7;
+  int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */
+  int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */
+  int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */
+  int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */
+  int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */
+  int64_t f0f0    = f0   * (int64_t) f0;
+  int64_t f0f1_2  = f0_2 * (int64_t) f1;
+  int64_t f0f2_2  = f0_2 * (int64_t) f2;
+  int64_t f0f3_2  = f0_2 * (int64_t) f3;
+  int64_t f0f4_2  = f0_2 * (int64_t) f4;
+  int64_t f0f5_2  = f0_2 * (int64_t) f5;
+  int64_t f0f6_2  = f0_2 * (int64_t) f6;
+  int64_t f0f7_2  = f0_2 * (int64_t) f7;
+  int64_t f0f8_2  = f0_2 * (int64_t) f8;
+  int64_t f0f9_2  = f0_2 * (int64_t) f9;
+  int64_t f1f1_2  = f1_2 * (int64_t) f1;
+  int64_t f1f2_2  = f1_2 * (int64_t) f2;
+  int64_t f1f3_4  = f1_2 * (int64_t) f3_2;
+  int64_t f1f4_2  = f1_2 * (int64_t) f4;
+  int64_t f1f5_4  = f1_2 * (int64_t) f5_2;
+  int64_t f1f6_2  = f1_2 * (int64_t) f6;
+  int64_t f1f7_4  = f1_2 * (int64_t) f7_2;
+  int64_t f1f8_2  = f1_2 * (int64_t) f8;
+  int64_t f1f9_76 = f1_2 * (int64_t) f9_38;
+  int64_t f2f2    = f2   * (int64_t) f2;
+  int64_t f2f3_2  = f2_2 * (int64_t) f3;
+  int64_t f2f4_2  = f2_2 * (int64_t) f4;
+  int64_t f2f5_2  = f2_2 * (int64_t) f5;
+  int64_t f2f6_2  = f2_2 * (int64_t) f6;
+  int64_t f2f7_2  = f2_2 * (int64_t) f7;
+  int64_t f2f8_38 = f2_2 * (int64_t) f8_19;
+  int64_t f2f9_38 = f2   * (int64_t) f9_38;
+  int64_t f3f3_2  = f3_2 * (int64_t) f3;
+  int64_t f3f4_2  = f3_2 * (int64_t) f4;
+  int64_t f3f5_4  = f3_2 * (int64_t) f5_2;
+  int64_t f3f6_2  = f3_2 * (int64_t) f6;
+  int64_t f3f7_76 = f3_2 * (int64_t) f7_38;
+  int64_t f3f8_38 = f3_2 * (int64_t) f8_19;
+  int64_t f3f9_76 = f3_2 * (int64_t) f9_38;
+  int64_t f4f4    = f4   * (int64_t) f4;
+  int64_t f4f5_2  = f4_2 * (int64_t) f5;
+  int64_t f4f6_38 = f4_2 * (int64_t) f6_19;
+  int64_t f4f7_38 = f4   * (int64_t) f7_38;
+  int64_t f4f8_38 = f4_2 * (int64_t) f8_19;
+  int64_t f4f9_38 = f4   * (int64_t) f9_38;
+  int64_t f5f5_38 = f5   * (int64_t) f5_38;
+  int64_t f5f6_38 = f5_2 * (int64_t) f6_19;
+  int64_t f5f7_76 = f5_2 * (int64_t) f7_38;
+  int64_t f5f8_38 = f5_2 * (int64_t) f8_19;
+  int64_t f5f9_76 = f5_2 * (int64_t) f9_38;
+  int64_t f6f6_19 = f6   * (int64_t) f6_19;
+  int64_t f6f7_38 = f6   * (int64_t) f7_38;
+  int64_t f6f8_38 = f6_2 * (int64_t) f8_19;
+  int64_t f6f9_38 = f6   * (int64_t) f9_38;
+  int64_t f7f7_38 = f7   * (int64_t) f7_38;
+  int64_t f7f8_38 = f7_2 * (int64_t) f8_19;
+  int64_t f7f9_76 = f7_2 * (int64_t) f9_38;
+  int64_t f8f8_19 = f8   * (int64_t) f8_19;
+  int64_t f8f9_38 = f8   * (int64_t) f9_38;
+  int64_t f9f9_38 = f9   * (int64_t) f9_38;
+  int64_t h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+  int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+  int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+  int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+  int64_t h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
+  int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+  int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+  int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+  int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
+  int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+  h[0] = (int32_t)h0;
+  h[1] = (int32_t)h1;
+  h[2] = (int32_t)h2;
+  h[3] = (int32_t)h3;
+  h[4] = (int32_t)h4;
+  h[5] = (int32_t)h5;
+  h[6] = (int32_t)h6;
+  h[7] = (int32_t)h7;
+  h[8] = (int32_t)h8;
+  h[9] = (int32_t)h9;
+}
+
+
+/*
+h = f + g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+   |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_add(fe h,const fe f,const fe g)
+{
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t g0 = g[0];
+  int32_t g1 = g[1];
+  int32_t g2 = g[2];
+  int32_t g3 = g[3];
+  int32_t g4 = g[4];
+  int32_t g5 = g[5];
+  int32_t g6 = g[6];
+  int32_t g7 = g[7];
+  int32_t g8 = g[8];
+  int32_t g9 = g[9];
+  int32_t h0 = f0 + g0;
+  int32_t h1 = f1 + g1;
+  int32_t h2 = f2 + g2;
+  int32_t h3 = f3 + g3;
+  int32_t h4 = f4 + g4;
+  int32_t h5 = f5 + g5;
+  int32_t h6 = f6 + g6;
+  int32_t h7 = f7 + g7;
+  int32_t h8 = f8 + g8;
+  int32_t h9 = f9 + g9;
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+
+/*
+Preconditions:
+  |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Write p=2^255-19; q=floor(h/p).
+Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+
+Proof:
+  Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+  Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4.
+
+  Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+  Then 0<y<1.
+
+  Write r=h-pq.
+  Have 0<=r<=p-1=2^255-20.
+  Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+
+  Write x=r+19(2^-255)r+y.
+  Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+
+  Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+  so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+*/
+
+void fe_tobytes(unsigned char *s,const fe h)
+{
+  int32_t h0 = h[0];
+  int32_t h1 = h[1];
+  int32_t h2 = h[2];
+  int32_t h3 = h[3];
+  int32_t h4 = h[4];
+  int32_t h5 = h[5];
+  int32_t h6 = h[6];
+  int32_t h7 = h[7];
+  int32_t h8 = h[8];
+  int32_t h9 = h[9];
+  int32_t q;
+  int32_t carry0;
+  int32_t carry1;
+  int32_t carry2;
+  int32_t carry3;
+  int32_t carry4;
+  int32_t carry5;
+  int32_t carry6;
+  int32_t carry7;
+  int32_t carry8;
+  int32_t carry9;
+
+  q = (19 * h9 + (((int32_t) 1) << 24)) >> 25;
+  q = (h0 + q) >> 26;
+  q = (h1 + q) >> 25;
+  q = (h2 + q) >> 26;
+  q = (h3 + q) >> 25;
+  q = (h4 + q) >> 26;
+  q = (h5 + q) >> 25;
+  q = (h6 + q) >> 26;
+  q = (h7 + q) >> 25;
+  q = (h8 + q) >> 26;
+  q = (h9 + q) >> 25;
+
+  /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
+  h0 += 19 * q;
+  /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
+
+  carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25;
+  carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26;
+  carry9 = h9 >> 25;               h9 -= carry9 << 25;
+                  /* h10 = carry9 */
+
+  /*
+  Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+  Have h0+...+2^230 h9 between 0 and 2^255-1;
+  evidently 2^255 h10-2^255 q = 0.
+  Goal: Output h0+...+2^230 h9.
+  */
+
+  s[0] = h0 >> 0;
+  s[1] = h0 >> 8;
+  s[2] = h0 >> 16;
+  s[3] = (h0 >> 24) | (h1 << 2);
+  s[4] = h1 >> 6;
+  s[5] = h1 >> 14;
+  s[6] = (h1 >> 22) | (h2 << 3);
+  s[7] = h2 >> 5;
+  s[8] = h2 >> 13;
+  s[9] = (h2 >> 21) | (h3 << 5);
+  s[10] = h3 >> 3;
+  s[11] = h3 >> 11;
+  s[12] = (h3 >> 19) | (h4 << 6);
+  s[13] = h4 >> 2;
+  s[14] = h4 >> 10;
+  s[15] = h4 >> 18;
+  s[16] = h5 >> 0;
+  s[17] = h5 >> 8;
+  s[18] = h5 >> 16;
+  s[19] = (h5 >> 24) | (h6 << 1);
+  s[20] = h6 >> 7;
+  s[21] = h6 >> 15;
+  s[22] = (h6 >> 23) | (h7 << 3);
+  s[23] = h7 >> 5;
+  s[24] = h7 >> 13;
+  s[25] = (h7 >> 21) | (h8 << 4);
+  s[26] = h8 >> 4;
+  s[27] = h8 >> 12;
+  s[28] = (h8 >> 20) | (h9 << 6);
+  s[29] = h9 >> 2;
+  s[30] = h9 >> 10;
+  s[31] = h9 >> 18;
+}
+
+
+/*
+h = f - g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+   |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_sub(fe h,const fe f,const fe g)
+{
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t g0 = g[0];
+  int32_t g1 = g[1];
+  int32_t g2 = g[2];
+  int32_t g3 = g[3];
+  int32_t g4 = g[4];
+  int32_t g5 = g[5];
+  int32_t g6 = g[6];
+  int32_t g7 = g[7];
+  int32_t g8 = g[8];
+  int32_t g9 = g[9];
+  int32_t h0 = f0 - g0;
+  int32_t h1 = f1 - g1;
+  int32_t h2 = f2 - g2;
+  int32_t h3 = f3 - g3;
+  int32_t h4 = f4 - g4;
+  int32_t h5 = f5 - g5;
+  int32_t h6 = f6 - g6;
+  int32_t h7 = f7 - g7;
+  int32_t h8 = f8 - g8;
+  int32_t h9 = f9 - g9;
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+
+/*
+Ignores top bit of h.
+*/
+
+void fe_frombytes(fe h,const unsigned char *s)
+{
+  int64_t h0 = load_4(s);
+  int64_t h1 = load_3(s + 4) << 6;
+  int64_t h2 = load_3(s + 7) << 5;
+  int64_t h3 = load_3(s + 10) << 3;
+  int64_t h4 = load_3(s + 13) << 2;
+  int64_t h5 = load_4(s + 16);
+  int64_t h6 = load_3(s + 20) << 7;
+  int64_t h7 = load_3(s + 23) << 5;
+  int64_t h8 = load_3(s + 26) << 4;
+  int64_t h9 = (load_3(s + 29) & 8388607) << 2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  h[0] = (int32_t)h0;
+  h[1] = (int32_t)h1;
+  h[2] = (int32_t)h2;
+  h[3] = (int32_t)h3;
+  h[4] = (int32_t)h4;
+  h[5] = (int32_t)h5;
+  h[6] = (int32_t)h6;
+  h[7] = (int32_t)h7;
+  h[8] = (int32_t)h8;
+  h[9] = (int32_t)h9;
+}
+
+
+void fe_invert(fe out,const fe z)
+{
+  fe t0;
+  fe t1;
+  fe t2;
+  fe t3;
+  int i;
+
+  /* pow225521 */
+  fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+  fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1);
+  fe_mul(t1,z,t1);
+  fe_mul(t0,t0,t1);
+  fe_sq(t2,t0); for (i = 1;i < 1;++i) fe_sq(t2,t2);
+  fe_mul(t1,t1,t2);
+  fe_sq(t2,t1); for (i = 1;i < 5;++i) fe_sq(t2,t2);
+  fe_mul(t1,t2,t1);
+  fe_sq(t2,t1); for (i = 1;i < 10;++i) fe_sq(t2,t2);
+  fe_mul(t2,t2,t1);
+  fe_sq(t3,t2); for (i = 1;i < 20;++i) fe_sq(t3,t3);
+  fe_mul(t2,t3,t2);
+  fe_sq(t2,t2); for (i = 1;i < 10;++i) fe_sq(t2,t2);
+  fe_mul(t1,t2,t1);
+  fe_sq(t2,t1); for (i = 1;i < 50;++i) fe_sq(t2,t2);
+  fe_mul(t2,t2,t1);
+  fe_sq(t3,t2); for (i = 1;i < 100;++i) fe_sq(t3,t3);
+  fe_mul(t2,t3,t2);
+  fe_sq(t2,t2); for (i = 1;i < 50;++i) fe_sq(t2,t2);
+  fe_mul(t1,t2,t1);
+  fe_sq(t1,t1); for (i = 1;i < 5;++i) fe_sq(t1,t1);
+  fe_mul(out,t1,t0);
+
+  return;
+}
+
+
+/*
+h = f
+*/
+
+void fe_copy(fe h,const fe f)
+{
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  h[0] = f0;
+  h[1] = f1;
+  h[2] = f2;
+  h[3] = f3;
+  h[4] = f4;
+  h[5] = f5;
+  h[6] = f6;
+  h[7] = f7;
+  h[8] = f8;
+  h[9] = f9;
+}
+
+
+/*
+h = f * g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+   |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+Notes on implementation strategy:
+
+Using schoolbook multiplication.
+Karatsuba would save a little in some cost models.
+
+Most multiplications by 2 and 19 are 32-bit precomputations;
+cheaper than 64-bit postcomputations.
+
+There is one remaining multiplication by 19 in the carry chain;
+one *19 precomputation can be merged into this,
+but the resulting data flow is considerably less clean.
+
+There are 12 carries below.
+10 of them are 2-way parallelizable and vectorizable.
+Can get away with 11 carries, but then data flow is much deeper.
+
+With tighter constraints on inputs can squeeze carries into int32.
+*/
+
+void fe_mul(fe h,const fe f,const fe g)
+{
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t g0 = g[0];
+  int32_t g1 = g[1];
+  int32_t g2 = g[2];
+  int32_t g3 = g[3];
+  int32_t g4 = g[4];
+  int32_t g5 = g[5];
+  int32_t g6 = g[6];
+  int32_t g7 = g[7];
+  int32_t g8 = g[8];
+  int32_t g9 = g[9];
+  int32_t g1_19 = 19 * g1; /* 1.959375*2^29 */
+  int32_t g2_19 = 19 * g2; /* 1.959375*2^30; still ok */
+  int32_t g3_19 = 19 * g3;
+  int32_t g4_19 = 19 * g4;
+  int32_t g5_19 = 19 * g5;
+  int32_t g6_19 = 19 * g6;
+  int32_t g7_19 = 19 * g7;
+  int32_t g8_19 = 19 * g8;
+  int32_t g9_19 = 19 * g9;
+  int32_t f1_2 = 2 * f1;
+  int32_t f3_2 = 2 * f3;
+  int32_t f5_2 = 2 * f5;
+  int32_t f7_2 = 2 * f7;
+  int32_t f9_2 = 2 * f9;
+  int64_t f0g0    = f0   * (int64_t) g0;
+  int64_t f0g1    = f0   * (int64_t) g1;
+  int64_t f0g2    = f0   * (int64_t) g2;
+  int64_t f0g3    = f0   * (int64_t) g3;
+  int64_t f0g4    = f0   * (int64_t) g4;
+  int64_t f0g5    = f0   * (int64_t) g5;
+  int64_t f0g6    = f0   * (int64_t) g6;
+  int64_t f0g7    = f0   * (int64_t) g7;
+  int64_t f0g8    = f0   * (int64_t) g8;
+  int64_t f0g9    = f0   * (int64_t) g9;
+  int64_t f1g0    = f1   * (int64_t) g0;
+  int64_t f1g1_2  = f1_2 * (int64_t) g1;
+  int64_t f1g2    = f1   * (int64_t) g2;
+  int64_t f1g3_2  = f1_2 * (int64_t) g3;
+  int64_t f1g4    = f1   * (int64_t) g4;
+  int64_t f1g5_2  = f1_2 * (int64_t) g5;
+  int64_t f1g6    = f1   * (int64_t) g6;
+  int64_t f1g7_2  = f1_2 * (int64_t) g7;
+  int64_t f1g8    = f1   * (int64_t) g8;
+  int64_t f1g9_38 = f1_2 * (int64_t) g9_19;
+  int64_t f2g0    = f2   * (int64_t) g0;
+  int64_t f2g1    = f2   * (int64_t) g1;
+  int64_t f2g2    = f2   * (int64_t) g2;
+  int64_t f2g3    = f2   * (int64_t) g3;
+  int64_t f2g4    = f2   * (int64_t) g4;
+  int64_t f2g5    = f2   * (int64_t) g5;
+  int64_t f2g6    = f2   * (int64_t) g6;
+  int64_t f2g7    = f2   * (int64_t) g7;
+  int64_t f2g8_19 = f2   * (int64_t) g8_19;
+  int64_t f2g9_19 = f2   * (int64_t) g9_19;
+  int64_t f3g0    = f3   * (int64_t) g0;
+  int64_t f3g1_2  = f3_2 * (int64_t) g1;
+  int64_t f3g2    = f3   * (int64_t) g2;
+  int64_t f3g3_2  = f3_2 * (int64_t) g3;
+  int64_t f3g4    = f3   * (int64_t) g4;
+  int64_t f3g5_2  = f3_2 * (int64_t) g5;
+  int64_t f3g6    = f3   * (int64_t) g6;
+  int64_t f3g7_38 = f3_2 * (int64_t) g7_19;
+  int64_t f3g8_19 = f3   * (int64_t) g8_19;
+  int64_t f3g9_38 = f3_2 * (int64_t) g9_19;
+  int64_t f4g0    = f4   * (int64_t) g0;
+  int64_t f4g1    = f4   * (int64_t) g1;
+  int64_t f4g2    = f4   * (int64_t) g2;
+  int64_t f4g3    = f4   * (int64_t) g3;
+  int64_t f4g4    = f4   * (int64_t) g4;
+  int64_t f4g5    = f4   * (int64_t) g5;
+  int64_t f4g6_19 = f4   * (int64_t) g6_19;
+  int64_t f4g7_19 = f4   * (int64_t) g7_19;
+  int64_t f4g8_19 = f4   * (int64_t) g8_19;
+  int64_t f4g9_19 = f4   * (int64_t) g9_19;
+  int64_t f5g0    = f5   * (int64_t) g0;
+  int64_t f5g1_2  = f5_2 * (int64_t) g1;
+  int64_t f5g2    = f5   * (int64_t) g2;
+  int64_t f5g3_2  = f5_2 * (int64_t) g3;
+  int64_t f5g4    = f5   * (int64_t) g4;
+  int64_t f5g5_38 = f5_2 * (int64_t) g5_19;
+  int64_t f5g6_19 = f5   * (int64_t) g6_19;
+  int64_t f5g7_38 = f5_2 * (int64_t) g7_19;
+  int64_t f5g8_19 = f5   * (int64_t) g8_19;
+  int64_t f5g9_38 = f5_2 * (int64_t) g9_19;
+  int64_t f6g0    = f6   * (int64_t) g0;
+  int64_t f6g1    = f6   * (int64_t) g1;
+  int64_t f6g2    = f6   * (int64_t) g2;
+  int64_t f6g3    = f6   * (int64_t) g3;
+  int64_t f6g4_19 = f6   * (int64_t) g4_19;
+  int64_t f6g5_19 = f6   * (int64_t) g5_19;
+  int64_t f6g6_19 = f6   * (int64_t) g6_19;
+  int64_t f6g7_19 = f6   * (int64_t) g7_19;
+  int64_t f6g8_19 = f6   * (int64_t) g8_19;
+  int64_t f6g9_19 = f6   * (int64_t) g9_19;
+  int64_t f7g0    = f7   * (int64_t) g0;
+  int64_t f7g1_2  = f7_2 * (int64_t) g1;
+  int64_t f7g2    = f7   * (int64_t) g2;
+  int64_t f7g3_38 = f7_2 * (int64_t) g3_19;
+  int64_t f7g4_19 = f7   * (int64_t) g4_19;
+  int64_t f7g5_38 = f7_2 * (int64_t) g5_19;
+  int64_t f7g6_19 = f7   * (int64_t) g6_19;
+  int64_t f7g7_38 = f7_2 * (int64_t) g7_19;
+  int64_t f7g8_19 = f7   * (int64_t) g8_19;
+  int64_t f7g9_38 = f7_2 * (int64_t) g9_19;
+  int64_t f8g0    = f8   * (int64_t) g0;
+  int64_t f8g1    = f8   * (int64_t) g1;
+  int64_t f8g2_19 = f8   * (int64_t) g2_19;
+  int64_t f8g3_19 = f8   * (int64_t) g3_19;
+  int64_t f8g4_19 = f8   * (int64_t) g4_19;
+  int64_t f8g5_19 = f8   * (int64_t) g5_19;
+  int64_t f8g6_19 = f8   * (int64_t) g6_19;
+  int64_t f8g7_19 = f8   * (int64_t) g7_19;
+  int64_t f8g8_19 = f8   * (int64_t) g8_19;
+  int64_t f8g9_19 = f8   * (int64_t) g9_19;
+  int64_t f9g0    = f9   * (int64_t) g0;
+  int64_t f9g1_38 = f9_2 * (int64_t) g1_19;
+  int64_t f9g2_19 = f9   * (int64_t) g2_19;
+  int64_t f9g3_38 = f9_2 * (int64_t) g3_19;
+  int64_t f9g4_19 = f9   * (int64_t) g4_19;
+  int64_t f9g5_38 = f9_2 * (int64_t) g5_19;
+  int64_t f9g6_19 = f9   * (int64_t) g6_19;
+  int64_t f9g7_38 = f9_2 * (int64_t) g7_19;
+  int64_t f9g8_19 = f9   * (int64_t) g8_19;
+  int64_t f9g9_38 = f9_2 * (int64_t) g9_19;
+  int64_t h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38;
+  int64_t h1 = f0g1+f1g0   +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19;
+  int64_t h2 = f0g2+f1g1_2 +f2g0   +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38;
+  int64_t h3 = f0g3+f1g2   +f2g1   +f3g0   +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19;
+  int64_t h4 = f0g4+f1g3_2 +f2g2   +f3g1_2 +f4g0   +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38;
+  int64_t h5 = f0g5+f1g4   +f2g3   +f3g2   +f4g1   +f5g0   +f6g9_19+f7g8_19+f8g7_19+f9g6_19;
+  int64_t h6 = f0g6+f1g5_2 +f2g4   +f3g3_2 +f4g2   +f5g1_2 +f6g0   +f7g9_38+f8g8_19+f9g7_38;
+  int64_t h7 = f0g7+f1g6   +f2g5   +f3g4   +f4g3   +f5g2   +f6g1   +f7g0   +f8g9_19+f9g8_19;
+  int64_t h8 = f0g8+f1g7_2 +f2g6   +f3g5_2 +f4g4   +f5g3_2 +f6g2   +f7g1_2 +f8g0   +f9g9_38;
+  int64_t h9 = f0g9+f1g8   +f2g7   +f3g6   +f4g5   +f5g4   +f6g3   +f7g2   +f8g1   +f9g0   ;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  /*
+  |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38))
+    i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8
+  |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19))
+    i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9
+  */
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  /* |h0| <= 2^25 */
+  /* |h4| <= 2^25 */
+  /* |h1| <= 1.71*2^59 */
+  /* |h5| <= 1.71*2^59 */
+
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  /* |h1| <= 2^24; from now on fits into int32 */
+  /* |h5| <= 2^24; from now on fits into int32 */
+  /* |h2| <= 1.41*2^60 */
+  /* |h6| <= 1.41*2^60 */
+
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  /* |h2| <= 2^25; from now on fits into int32 unchanged */
+  /* |h6| <= 2^25; from now on fits into int32 unchanged */
+  /* |h3| <= 1.71*2^59 */
+  /* |h7| <= 1.71*2^59 */
+
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+  /* |h3| <= 2^24; from now on fits into int32 unchanged */
+  /* |h7| <= 2^24; from now on fits into int32 unchanged */
+  /* |h4| <= 1.72*2^34 */
+  /* |h8| <= 1.41*2^60 */
+
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+  /* |h4| <= 2^25; from now on fits into int32 unchanged */
+  /* |h8| <= 2^25; from now on fits into int32 unchanged */
+  /* |h5| <= 1.01*2^24 */
+  /* |h9| <= 1.71*2^59 */
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  /* |h9| <= 2^24; from now on fits into int32 unchanged */
+  /* |h0| <= 1.1*2^39 */
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  /* |h0| <= 2^25; from now on fits into int32 unchanged */
+  /* |h1| <= 1.01*2^24 */
+
+  h[0] = (int32_t)h0;
+  h[1] = (int32_t)h1;
+  h[2] = (int32_t)h2;
+  h[3] = (int32_t)h3;
+  h[4] = (int32_t)h4;
+  h[5] = (int32_t)h5;
+  h[6] = (int32_t)h6;
+  h[7] = (int32_t)h7;
+  h[8] = (int32_t)h8;
+  h[9] = (int32_t)h9;
+}
+
+
+/*
+Replace (f,g) with (g,f) if b == 1;
+replace (f,g) with (f,g) if b == 0.
+
+Preconditions: b in {0,1}.
+*/
+
+void fe_cswap(fe f,fe g,unsigned int b)
+{
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t g0 = g[0];
+  int32_t g1 = g[1];
+  int32_t g2 = g[2];
+  int32_t g3 = g[3];
+  int32_t g4 = g[4];
+  int32_t g5 = g[5];
+  int32_t g6 = g[6];
+  int32_t g7 = g[7];
+  int32_t g8 = g[8];
+  int32_t g9 = g[9];
+  int32_t x0 = f0 ^ g0;
+  int32_t x1 = f1 ^ g1;
+  int32_t x2 = f2 ^ g2;
+  int32_t x3 = f3 ^ g3;
+  int32_t x4 = f4 ^ g4;
+  int32_t x5 = f5 ^ g5;
+  int32_t x6 = f6 ^ g6;
+  int32_t x7 = f7 ^ g7;
+  int32_t x8 = f8 ^ g8;
+  int32_t x9 = f9 ^ g9;
+  b = -b;
+  x0 &= b;
+  x1 &= b;
+  x2 &= b;
+  x3 &= b;
+  x4 &= b;
+  x5 &= b;
+  x6 &= b;
+  x7 &= b;
+  x8 &= b;
+  x9 &= b;
+  f[0] = f0 ^ x0;
+  f[1] = f1 ^ x1;
+  f[2] = f2 ^ x2;
+  f[3] = f3 ^ x3;
+  f[4] = f4 ^ x4;
+  f[5] = f5 ^ x5;
+  f[6] = f6 ^ x6;
+  f[7] = f7 ^ x7;
+  f[8] = f8 ^ x8;
+  f[9] = f9 ^ x9;
+  g[0] = g0 ^ x0;
+  g[1] = g1 ^ x1;
+  g[2] = g2 ^ x2;
+  g[3] = g3 ^ x3;
+  g[4] = g4 ^ x4;
+  g[5] = g5 ^ x5;
+  g[6] = g6 ^ x6;
+  g[7] = g7 ^ x7;
+  g[8] = g8 ^ x8;
+  g[9] = g9 ^ x9;
+}
+
+
+/*
+h = f * 121666
+Can overlap h with f.
+
+Preconditions:
+   |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+void fe_mul121666(fe h,fe f)
+{
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int64_t h0 = f0 * (int64_t) 121666;
+  int64_t h1 = f1 * (int64_t) 121666;
+  int64_t h2 = f2 * (int64_t) 121666;
+  int64_t h3 = f3 * (int64_t) 121666;
+  int64_t h4 = f4 * (int64_t) 121666;
+  int64_t h5 = f5 * (int64_t) 121666;
+  int64_t h6 = f6 * (int64_t) 121666;
+  int64_t h7 = f7 * (int64_t) 121666;
+  int64_t h8 = f8 * (int64_t) 121666;
+  int64_t h9 = f9 * (int64_t) 121666;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  h[0] = (int32_t)h0;
+  h[1] = (int32_t)h1;
+  h[2] = (int32_t)h2;
+  h[3] = (int32_t)h3;
+  h[4] = (int32_t)h4;
+  h[5] = (int32_t)h5;
+  h[6] = (int32_t)h6;
+  h[7] = (int32_t)h7;
+  h[8] = (int32_t)h8;
+  h[9] = (int32_t)h9;
+}
+
+
+/*
+h = 2 * f * f
+Can overlap h with f.
+
+Preconditions:
+   |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+void fe_sq2(fe h,const fe f)
+{
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t f0_2 = 2 * f0;
+  int32_t f1_2 = 2 * f1;
+  int32_t f2_2 = 2 * f2;
+  int32_t f3_2 = 2 * f3;
+  int32_t f4_2 = 2 * f4;
+  int32_t f5_2 = 2 * f5;
+  int32_t f6_2 = 2 * f6;
+  int32_t f7_2 = 2 * f7;
+  int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */
+  int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */
+  int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */
+  int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */
+  int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */
+  int64_t f0f0    = f0   * (int64_t) f0;
+  int64_t f0f1_2  = f0_2 * (int64_t) f1;
+  int64_t f0f2_2  = f0_2 * (int64_t) f2;
+  int64_t f0f3_2  = f0_2 * (int64_t) f3;
+  int64_t f0f4_2  = f0_2 * (int64_t) f4;
+  int64_t f0f5_2  = f0_2 * (int64_t) f5;
+  int64_t f0f6_2  = f0_2 * (int64_t) f6;
+  int64_t f0f7_2  = f0_2 * (int64_t) f7;
+  int64_t f0f8_2  = f0_2 * (int64_t) f8;
+  int64_t f0f9_2  = f0_2 * (int64_t) f9;
+  int64_t f1f1_2  = f1_2 * (int64_t) f1;
+  int64_t f1f2_2  = f1_2 * (int64_t) f2;
+  int64_t f1f3_4  = f1_2 * (int64_t) f3_2;
+  int64_t f1f4_2  = f1_2 * (int64_t) f4;
+  int64_t f1f5_4  = f1_2 * (int64_t) f5_2;
+  int64_t f1f6_2  = f1_2 * (int64_t) f6;
+  int64_t f1f7_4  = f1_2 * (int64_t) f7_2;
+  int64_t f1f8_2  = f1_2 * (int64_t) f8;
+  int64_t f1f9_76 = f1_2 * (int64_t) f9_38;
+  int64_t f2f2    = f2   * (int64_t) f2;
+  int64_t f2f3_2  = f2_2 * (int64_t) f3;
+  int64_t f2f4_2  = f2_2 * (int64_t) f4;
+  int64_t f2f5_2  = f2_2 * (int64_t) f5;
+  int64_t f2f6_2  = f2_2 * (int64_t) f6;
+  int64_t f2f7_2  = f2_2 * (int64_t) f7;
+  int64_t f2f8_38 = f2_2 * (int64_t) f8_19;
+  int64_t f2f9_38 = f2   * (int64_t) f9_38;
+  int64_t f3f3_2  = f3_2 * (int64_t) f3;
+  int64_t f3f4_2  = f3_2 * (int64_t) f4;
+  int64_t f3f5_4  = f3_2 * (int64_t) f5_2;
+  int64_t f3f6_2  = f3_2 * (int64_t) f6;
+  int64_t f3f7_76 = f3_2 * (int64_t) f7_38;
+  int64_t f3f8_38 = f3_2 * (int64_t) f8_19;
+  int64_t f3f9_76 = f3_2 * (int64_t) f9_38;
+  int64_t f4f4    = f4   * (int64_t) f4;
+  int64_t f4f5_2  = f4_2 * (int64_t) f5;
+  int64_t f4f6_38 = f4_2 * (int64_t) f6_19;
+  int64_t f4f7_38 = f4   * (int64_t) f7_38;
+  int64_t f4f8_38 = f4_2 * (int64_t) f8_19;
+  int64_t f4f9_38 = f4   * (int64_t) f9_38;
+  int64_t f5f5_38 = f5   * (int64_t) f5_38;
+  int64_t f5f6_38 = f5_2 * (int64_t) f6_19;
+  int64_t f5f7_76 = f5_2 * (int64_t) f7_38;
+  int64_t f5f8_38 = f5_2 * (int64_t) f8_19;
+  int64_t f5f9_76 = f5_2 * (int64_t) f9_38;
+  int64_t f6f6_19 = f6   * (int64_t) f6_19;
+  int64_t f6f7_38 = f6   * (int64_t) f7_38;
+  int64_t f6f8_38 = f6_2 * (int64_t) f8_19;
+  int64_t f6f9_38 = f6   * (int64_t) f9_38;
+  int64_t f7f7_38 = f7   * (int64_t) f7_38;
+  int64_t f7f8_38 = f7_2 * (int64_t) f8_19;
+  int64_t f7f9_76 = f7_2 * (int64_t) f9_38;
+  int64_t f8f8_19 = f8   * (int64_t) f8_19;
+  int64_t f8f9_38 = f8   * (int64_t) f9_38;
+  int64_t f9f9_38 = f9   * (int64_t) f9_38;
+  int64_t h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+  int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+  int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+  int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+  int64_t h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
+  int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+  int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+  int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+  int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
+  int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  h0 += h0;
+  h1 += h1;
+  h2 += h2;
+  h3 += h3;
+  h4 += h4;
+  h5 += h5;
+  h6 += h6;
+  h7 += h7;
+  h8 += h8;
+  h9 += h9;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+  h[0] = (int32_t)h0;
+  h[1] = (int32_t)h1;
+  h[2] = (int32_t)h2;
+  h[3] = (int32_t)h3;
+  h[4] = (int32_t)h4;
+  h[5] = (int32_t)h5;
+  h[6] = (int32_t)h6;
+  h[7] = (int32_t)h7;
+  h[8] = (int32_t)h8;
+  h[9] = (int32_t)h9;
+}
+
+
+void fe_pow22523(fe out,const fe z)
+{
+  fe t0;
+  fe t1;
+  fe t2;
+  int i;
+
+  fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+  fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1);
+  fe_mul(t1,z,t1);
+  fe_mul(t0,t0,t1);
+  fe_sq(t0,t0); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+  fe_mul(t0,t1,t0);
+  fe_sq(t1,t0); for (i = 1;i < 5;++i) fe_sq(t1,t1);
+  fe_mul(t0,t1,t0);
+  fe_sq(t1,t0); for (i = 1;i < 10;++i) fe_sq(t1,t1);
+  fe_mul(t1,t1,t0);
+  fe_sq(t2,t1); for (i = 1;i < 20;++i) fe_sq(t2,t2);
+  fe_mul(t1,t2,t1);
+  fe_sq(t1,t1); for (i = 1;i < 10;++i) fe_sq(t1,t1);
+  fe_mul(t0,t1,t0);
+  fe_sq(t1,t0); for (i = 1;i < 50;++i) fe_sq(t1,t1);
+  fe_mul(t1,t1,t0);
+  fe_sq(t2,t1); for (i = 1;i < 100;++i) fe_sq(t2,t2);
+  fe_mul(t1,t2,t1);
+  fe_sq(t1,t1); for (i = 1;i < 50;++i) fe_sq(t1,t1);
+  fe_mul(t0,t1,t0);
+  fe_sq(t0,t0); for (i = 1;i < 2;++i) fe_sq(t0,t0);
+  fe_mul(out,t0,z);
+
+  return;
+}
+
+
+/*
+h = -f
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+void fe_neg(fe h,const fe f)
+{
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t h0 = -f0;
+  int32_t h1 = -f1;
+  int32_t h2 = -f2;
+  int32_t h3 = -f3;
+  int32_t h4 = -f4;
+  int32_t h5 = -f5;
+  int32_t h6 = -f6;
+  int32_t h7 = -f7;
+  int32_t h8 = -f8;
+  int32_t h9 = -f9;
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+
+/*
+Preconditions:
+   |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+static const unsigned char zero[32];
+
+int fe_isnonzero(const fe f)
+{
+  unsigned char s[32];
+  fe_tobytes(s,f);
+  return ConstantCompare(s,zero,32);
+}
+
+
+/*
+return 1 if f is in {1,3,5,...,q-2}
+return 0 if f is in {0,2,4,...,q-1}
+
+Preconditions:
+   |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+int fe_isnegative(const fe f)
+{
+  unsigned char s[32];
+  fe_tobytes(s,f);
+  return s[0] & 1;
+}
+
+
+/*
+Replace (f,g) with (g,g) if b == 1;
+replace (f,g) with (f,g) if b == 0.
+
+Preconditions: b in {0,1}.
+*/
+
+void fe_cmov(fe f,const fe g,unsigned int b)
+{
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t g0 = g[0];
+  int32_t g1 = g[1];
+  int32_t g2 = g[2];
+  int32_t g3 = g[3];
+  int32_t g4 = g[4];
+  int32_t g5 = g[5];
+  int32_t g6 = g[6];
+  int32_t g7 = g[7];
+  int32_t g8 = g[8];
+  int32_t g9 = g[9];
+  int32_t x0 = f0 ^ g0;
+  int32_t x1 = f1 ^ g1;
+  int32_t x2 = f2 ^ g2;
+  int32_t x3 = f3 ^ g3;
+  int32_t x4 = f4 ^ g4;
+  int32_t x5 = f5 ^ g5;
+  int32_t x6 = f6 ^ g6;
+  int32_t x7 = f7 ^ g7;
+  int32_t x8 = f8 ^ g8;
+  int32_t x9 = f9 ^ g9;
+  b = -b;
+  x0 &= b;
+  x1 &= b;
+  x2 &= b;
+  x3 &= b;
+  x4 &= b;
+  x5 &= b;
+  x6 &= b;
+  x7 &= b;
+  x8 &= b;
+  x9 &= b;
+  f[0] = f0 ^ x0;
+  f[1] = f1 ^ x1;
+  f[2] = f2 ^ x2;
+  f[3] = f3 ^ x3;
+  f[4] = f4 ^ x4;
+  f[5] = f5 ^ x5;
+  f[6] = f6 ^ x6;
+  f[7] = f7 ^ x7;
+  f[8] = f8 ^ x8;
+  f[9] = f9 ^ x9;
+}
+#endif /* HAVE ED25519 or CURVE25519 */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/fp_mul_comba_7.i	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,91 @@
+/* fp_mul_comba_7.i
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifdef TFM_MUL7
+void fp_mul_comba7(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[14];
+
+   memcpy(at, A->dp, 7 * sizeof(fp_digit));
+   memcpy(at+7, B->dp, 7 * sizeof(fp_digit));
+   COMBA_START;
+
+   COMBA_CLEAR;
+   /* 0 */
+   MULADD(at[0], at[7]); 
+   COMBA_STORE(C->dp[0]);
+   /* 1 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[8]);    MULADD(at[1], at[7]); 
+   COMBA_STORE(C->dp[1]);
+   /* 2 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[9]);    MULADD(at[1], at[8]);    MULADD(at[2], at[7]); 
+   COMBA_STORE(C->dp[2]);
+   /* 3 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[10]);    MULADD(at[1], at[9]);    MULADD(at[2], at[8]);    MULADD(at[3], at[7]); 
+   COMBA_STORE(C->dp[3]);
+   /* 4 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[11]);    MULADD(at[1], at[10]);    MULADD(at[2], at[9]);    MULADD(at[3], at[8]);    MULADD(at[4], at[7]); 
+   COMBA_STORE(C->dp[4]);
+   /* 5 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[12]);    MULADD(at[1], at[11]);    MULADD(at[2], at[10]);    MULADD(at[3], at[9]);    MULADD(at[4], at[8]);    MULADD(at[5], at[7]); 
+   COMBA_STORE(C->dp[5]);
+   /* 6 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[13]);    MULADD(at[1], at[12]);    MULADD(at[2], at[11]);    MULADD(at[3], at[10]);    MULADD(at[4], at[9]);    MULADD(at[5], at[8]);    MULADD(at[6], at[7]); 
+   COMBA_STORE(C->dp[6]);
+   /* 7 */
+   COMBA_FORWARD;
+   MULADD(at[1], at[13]);    MULADD(at[2], at[12]);    MULADD(at[3], at[11]);    MULADD(at[4], at[10]);    MULADD(at[5], at[9]);    MULADD(at[6], at[8]); 
+   COMBA_STORE(C->dp[7]);
+   /* 8 */
+   COMBA_FORWARD;
+   MULADD(at[2], at[13]);    MULADD(at[3], at[12]);    MULADD(at[4], at[11]);    MULADD(at[5], at[10]);    MULADD(at[6], at[9]); 
+   COMBA_STORE(C->dp[8]);
+   /* 9 */
+   COMBA_FORWARD;
+   MULADD(at[3], at[13]);    MULADD(at[4], at[12]);    MULADD(at[5], at[11]);    MULADD(at[6], at[10]); 
+   COMBA_STORE(C->dp[9]);
+   /* 10 */
+   COMBA_FORWARD;
+   MULADD(at[4], at[13]);    MULADD(at[5], at[12]);    MULADD(at[6], at[11]); 
+   COMBA_STORE(C->dp[10]);
+   /* 11 */
+   COMBA_FORWARD;
+   MULADD(at[5], at[13]);    MULADD(at[6], at[12]); 
+   COMBA_STORE(C->dp[11]);
+   /* 12 */
+   COMBA_FORWARD;
+   MULADD(at[6], at[13]); 
+   COMBA_STORE(C->dp[12]);
+   COMBA_STORE2(C->dp[13]);
+   C->used = 14;
+   C->sign = A->sign ^ B->sign;
+   fp_clamp(C);
+   COMBA_FINI;
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/ge_low_mem.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,559 @@
+/* ge_low_mem.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+ /* Based from Daniel Beer's public domain work. */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_ED25519
+
+#include <wolfssl/wolfcrypt/ge_operations.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+void ed25519_smult(ge_p3 *r, const ge_p3 *a, const byte *e);
+void ed25519_add(ge_p3 *r, const ge_p3 *a, const ge_p3 *b);
+void ed25519_double(ge_p3 *r, const ge_p3 *a);
+
+
+static const byte ed25519_order[F25519_SIZE] = {
+	0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
+	0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
+};
+
+/*Arithmetic modulo the group order m = 2^252 +
+ 27742317777372353535851937790883648493 =
+ 7237005577332262213973186563042994240857116359379907606001950938285454250989 */
+
+static const word32 m[32] = {
+    0xED,0xD3,0xF5,0x5C,0x1A,0x63,0x12,0x58,0xD6,0x9C,0xF7,0xA2,0xDE,0xF9,
+    0xDE,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x10
+};
+
+static const word32 mu[33] = {
+    0x1B,0x13,0x2C,0x0A,0xA3,0xE5,0x9C,0xED,0xA7,0x29,0x63,0x08,0x5D,0x21,
+    0x06,0x21,0xEB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0xFF,0xFF,0xFF,0xFF,0x0F
+};
+
+
+int ge_compress_key(byte* out, const byte* xIn, const byte* yIn,
+                        word32 keySz)
+{
+	byte tmp[F25519_SIZE];
+	byte parity;
+    int     i;
+
+	fe_copy(tmp, xIn);
+	parity = (tmp[0] & 1) << 7;
+
+    byte pt[32];
+	fe_copy(pt, yIn);
+	pt[31] |= parity;
+
+    for(i = 0; i < 32; i++) {
+        out[32-i-1] = pt[i];
+    }
+    (void)keySz;
+    return 0;
+}
+
+
+static word32 lt(word32 a,word32 b) /* 16-bit inputs */
+{
+  unsigned int x = a;
+  x -= (unsigned int) b; /* 0..65535: no; 4294901761..4294967295: yes */
+  x >>= 31; /* 0: no; 1: yes */
+  return x;
+}
+
+
+/* Reduce coefficients of r before calling reduce_add_sub */
+static void reduce_add_sub(word32 *r)
+{
+  word32 pb = 0;
+  word32 b;
+  word32 mask;
+  int i;
+  unsigned char t[32];
+
+  for(i=0;i<32;i++)
+  {
+    pb += m[i];
+    b = lt(r[i],pb);
+    t[i] = r[i]-pb+(b<<8);
+    pb = b;
+  }
+  mask = b - 1;
+  for(i=0;i<32;i++)
+    r[i] ^= mask & (r[i] ^ t[i]);
+}
+
+
+/* Reduce coefficients of x before calling barrett_reduce */
+static void barrett_reduce(word32* r, word32 x[64])
+{
+  /* See HAC, Alg. 14.42 */
+  int i,j;
+  word32 q2[66];
+  word32 *q3 = q2 + 33;
+  word32 r1[33];
+  word32 r2[33];
+  word32 carry;
+  word32 pb = 0;
+  word32 b;
+
+  for (i = 0;i < 66;++i) q2[i] = 0;
+  for (i = 0;i < 33;++i) r2[i] = 0;
+
+  for(i=0;i<33;i++)
+    for(j=0;j<33;j++)
+      if(i+j >= 31) q2[i+j] += mu[i]*x[j+31];
+  carry = q2[31] >> 8;
+  q2[32] += carry;
+  carry = q2[32] >> 8;
+  q2[33] += carry;
+
+  for(i=0;i<33;i++)r1[i] = x[i];
+  for(i=0;i<32;i++)
+    for(j=0;j<33;j++)
+      if(i+j < 33) r2[i+j] += m[i]*q3[j];
+
+  for(i=0;i<32;i++)
+  {
+    carry = r2[i] >> 8;
+    r2[i+1] += carry;
+    r2[i] &= 0xff;
+  }
+
+  for(i=0;i<32;i++)
+  {
+    pb += r2[i];
+    b = lt(r1[i],pb);
+    r[i] = r1[i]-pb+(b<<8);
+    pb = b;
+  }
+
+  /* XXX: Can it really happen that r<0?, See HAC, Alg 14.42, Step 3
+   * r is an unsigned type.
+   * If so: Handle  it here!
+   */
+
+  reduce_add_sub(r);
+  reduce_add_sub(r);
+}
+
+
+void sc_reduce(unsigned char x[64])
+{
+  int i;
+  word32 t[64];
+  word32 r[32];
+  for(i=0;i<64;i++) t[i] = x[i];
+  barrett_reduce(r, t);
+  for(i=0;i<32;i++) x[i] = (r[i] & 0xFF);
+}
+
+
+void sc_muladd(byte* out, const byte* a, const byte* b, const byte* c)
+{
+
+	byte s[32];
+    byte e[64];
+
+    XMEMSET(e, 0, sizeof(e));
+    XMEMCPY(e, b, 32);
+
+	/* Obtain e */
+	sc_reduce(e);
+
+	/* Compute s = ze + k */
+	fprime_mul(s, a, e, ed25519_order);
+	fprime_add(s, c, ed25519_order);
+
+	XMEMCPY(out, s, 32);
+}
+
+
+/* Base point is (numbers wrapped):
+ *
+ *     x = 151122213495354007725011514095885315114
+ *         54012693041857206046113283949847762202
+ *     y = 463168356949264781694283940034751631413
+ *         07993866256225615783033603165251855960
+ *
+ * y is derived by transforming the original Montgomery base (u=9). x
+ * is the corresponding positive coordinate for the new curve equation.
+ * t is x*y.
+ */
+const ge_p3 ed25519_base = {
+	.X = {
+		0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9,
+		0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69,
+		0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0,
+		0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21
+	},
+	.Y = {
+		0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+		0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+		0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+		0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66
+	},
+	.T = {
+		0xa3, 0xdd, 0xb7, 0xa5, 0xb3, 0x8a, 0xde, 0x6d,
+		0xf5, 0x52, 0x51, 0x77, 0x80, 0x9f, 0xf0, 0x20,
+		0x7d, 0xe3, 0xab, 0x64, 0x8e, 0x4e, 0xea, 0x66,
+		0x65, 0x76, 0x8b, 0xd7, 0x0f, 0x5f, 0x87, 0x67
+	},
+	.Z = {1, 0}
+};
+
+
+const ge_p3 ed25519_neutral = {
+	.X = {0},
+	.Y = {1, 0},
+	.T = {0},
+	.Z = {1, 0}
+};
+
+
+static const byte ed25519_d[F25519_SIZE] = {
+	0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75,
+	0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00,
+	0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c,
+	0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52
+};
+
+
+/* k = 2d */
+static const byte ed25519_k[F25519_SIZE] = {
+	0x59, 0xf1, 0xb2, 0x26, 0x94, 0x9b, 0xd6, 0xeb,
+	0x56, 0xb1, 0x83, 0x82, 0x9a, 0x14, 0xe0, 0x00,
+	0x30, 0xd1, 0xf3, 0xee, 0xf2, 0x80, 0x8e, 0x19,
+	0xe7, 0xfc, 0xdf, 0x56, 0xdc, 0xd9, 0x06, 0x24
+};
+
+
+void ed25519_add(ge_p3 *r,
+		 const ge_p3 *p1, const ge_p3 *p2)
+{
+	/* Explicit formulas database: add-2008-hwcd-3
+	 *
+	 * source 2008 Hisil--Wong--Carter--Dawson,
+	 *     http://eprint.iacr.org/2008/522, Section 3.1
+	 * appliesto extended-1
+	 * parameter k
+	 * assume k = 2 d
+	 * compute A = (Y1-X1)(Y2-X2)
+	 * compute B = (Y1+X1)(Y2+X2)
+	 * compute C = T1 k T2
+	 * compute D = Z1 2 Z2
+	 * compute E = B - A
+	 * compute F = D - C
+	 * compute G = D + C
+	 * compute H = B + A
+	 * compute X3 = E F
+	 * compute Y3 = G H
+	 * compute T3 = E H
+	 * compute Z3 = F G
+	 */
+	byte a[F25519_SIZE];
+	byte b[F25519_SIZE];
+	byte c[F25519_SIZE];
+	byte d[F25519_SIZE];
+	byte e[F25519_SIZE];
+	byte f[F25519_SIZE];
+	byte g[F25519_SIZE];
+	byte h[F25519_SIZE];
+
+	/* A = (Y1-X1)(Y2-X2) */
+	fe_sub(c, p1->Y, p1->X);
+	fe_sub(d, p2->Y, p2->X);
+	fe_mul__distinct(a, c, d);
+
+	/* B = (Y1+X1)(Y2+X2) */
+	fe_add(c, p1->Y, p1->X);
+	fe_add(d, p2->Y, p2->X);
+	fe_mul__distinct(b, c, d);
+
+	/* C = T1 k T2 */
+	fe_mul__distinct(d, p1->T, p2->T);
+	fe_mul__distinct(c, d, ed25519_k);
+
+	/* D = Z1 2 Z2 */
+	fe_mul__distinct(d, p1->Z, p2->Z);
+	fe_add(d, d, d);
+
+	/* E = B - A */
+	fe_sub(e, b, a);
+
+	/* F = D - C */
+	fe_sub(f, d, c);
+
+	/* G = D + C */
+	fe_add(g, d, c);
+
+	/* H = B + A */
+	fe_add(h, b, a);
+
+	/* X3 = E F */
+	fe_mul__distinct(r->X, e, f);
+
+	/* Y3 = G H */
+	fe_mul__distinct(r->Y, g, h);
+
+	/* T3 = E H */
+	fe_mul__distinct(r->T, e, h);
+
+	/* Z3 = F G */
+	fe_mul__distinct(r->Z, f, g);
+}
+
+
+void ed25519_double(ge_p3 *r, const ge_p3 *p)
+{
+	/* Explicit formulas database: dbl-2008-hwcd
+	 *
+	 * source 2008 Hisil--Wong--Carter--Dawson,
+	 *     http://eprint.iacr.org/2008/522, Section 3.3
+	 * compute A = X1^2
+	 * compute B = Y1^2
+	 * compute C = 2 Z1^2
+	 * compute D = a A
+	 * compute E = (X1+Y1)^2-A-B
+	 * compute G = D + B
+	 * compute F = G - C
+	 * compute H = D - B
+	 * compute X3 = E F
+	 * compute Y3 = G H
+	 * compute T3 = E H
+	 * compute Z3 = F G
+	 */
+	byte a[F25519_SIZE];
+	byte b[F25519_SIZE];
+	byte c[F25519_SIZE];
+	byte e[F25519_SIZE];
+	byte f[F25519_SIZE];
+	byte g[F25519_SIZE];
+	byte h[F25519_SIZE];
+
+	/* A = X1^2 */
+	fe_mul__distinct(a, p->X, p->X);
+
+	/* B = Y1^2 */
+	fe_mul__distinct(b, p->Y, p->Y);
+
+	/* C = 2 Z1^2 */
+	fe_mul__distinct(c, p->Z, p->Z);
+	fe_add(c, c, c);
+
+	/* D = a A (alter sign) */
+	/* E = (X1+Y1)^2-A-B */
+	fe_add(f, p->X, p->Y);
+	fe_mul__distinct(e, f, f);
+	fe_sub(e, e, a);
+	fe_sub(e, e, b);
+
+	/* G = D + B */
+	fe_sub(g, b, a);
+
+	/* F = G - C */
+	fe_sub(f, g, c);
+
+	/* H = D - B */
+	fe_neg(h, b);
+	fe_sub(h, h, a);
+
+	/* X3 = E F */
+	fe_mul__distinct(r->X, e, f);
+
+	/* Y3 = G H */
+	fe_mul__distinct(r->Y, g, h);
+
+	/* T3 = E H */
+	fe_mul__distinct(r->T, e, h);
+
+	/* Z3 = F G */
+	fe_mul__distinct(r->Z, f, g);
+}
+
+
+void ed25519_smult(ge_p3 *r_out, const ge_p3 *p, const byte *e)
+{
+	ge_p3 r;
+	int   i;
+
+    XMEMCPY(&r, &ed25519_neutral, sizeof(r));
+
+	for (i = 255; i >= 0; i--) {
+		const byte bit = (e[i >> 3] >> (i & 7)) & 1;
+		ge_p3 s;
+
+		ed25519_double(&r, &r);
+		ed25519_add(&s, &r, p);
+
+		fe_select(r.X, r.X, s.X, bit);
+		fe_select(r.Y, r.Y, s.Y, bit);
+		fe_select(r.Z, r.Z, s.Z, bit);
+		fe_select(r.T, r.T, s.T, bit);
+	}
+    XMEMCPY(r_out, &r, sizeof(r));
+}
+
+
+void ge_scalarmult_base(ge_p3 *R,const unsigned char *nonce)
+{
+	ed25519_smult(R, &ed25519_base, nonce);
+}
+
+
+/* pack the point h into array s */
+void ge_p3_tobytes(unsigned char *s,const ge_p3 *h)
+{
+	byte x[F25519_SIZE];
+	byte y[F25519_SIZE];
+	byte z1[F25519_SIZE];
+	byte parity;
+
+	fe_inv__distinct(z1, h->Z);
+	fe_mul__distinct(x, h->X, z1);
+	fe_mul__distinct(y, h->Y, z1);
+
+	fe_normalize(x);
+	fe_normalize(y);
+
+	parity = (x[0] & 1) << 7;
+	fe_copy(s, y);
+	fe_normalize(s);
+	s[31] |= parity;
+}
+
+
+/* pack the point h into array s */
+void ge_tobytes(unsigned char *s,const ge_p2 *h)
+{
+	byte x[F25519_SIZE];
+	byte y[F25519_SIZE];
+	byte z1[F25519_SIZE];
+	byte parity;
+
+	fe_inv__distinct(z1, h->Z);
+	fe_mul__distinct(x, h->X, z1);
+	fe_mul__distinct(y, h->Y, z1);
+
+	fe_normalize(x);
+	fe_normalize(y);
+
+	parity = (x[0] & 1) << 7;
+	fe_copy(s, y);
+	fe_normalize(s);
+	s[31] |= parity;
+}
+
+
+/*
+   Test if the public key can be uncommpressed and negate it (-X,Y,Z,-T)
+   return 0 on success
+ */
+int ge_frombytes_negate_vartime(ge_p3 *p,const unsigned char *s)
+{
+
+	byte parity;
+    byte x[F25519_SIZE];
+	byte y[F25519_SIZE];
+	byte a[F25519_SIZE];
+	byte b[F25519_SIZE];
+	byte c[F25519_SIZE];
+    int ret = 0;
+
+    /* unpack the key s */
+    parity = s[31] >> 7;
+    fe_copy(y, s);
+	y[31] &= 127;
+
+	fe_mul__distinct(c, y, y);
+    fe_mul__distinct(b, c, ed25519_d);
+	fe_add(a, b, f25519_one);
+	fe_inv__distinct(b, a);
+	fe_sub(a, c, f25519_one);
+	fe_mul__distinct(c, a, b);
+	fe_sqrt(a, c);
+	fe_neg(b, a);
+	fe_select(x, a, b, (a[0] ^ parity) & 1);
+
+    /* test that x^2 is equal to c */
+    fe_mul__distinct(a, x, x);
+	fe_normalize(a);
+	fe_normalize(c);
+	ret |= ConstantCompare(a, c, F25519_SIZE);
+
+    /* project the key s onto p */
+	fe_copy(p->X, x);
+	fe_copy(p->Y, y);
+	fe_load(p->Z, 1);
+	fe_mul__distinct(p->T, x, y);
+
+    /* negate, the point becomes (-X,Y,Z,-T) */
+    fe_neg(p->X,p->X);
+    fe_neg(p->T,p->T);
+
+    return ret;
+}
+
+
+int ge_double_scalarmult_vartime(ge_p2* R, const unsigned char *h,
+                                 const ge_p3 *inA,const unsigned char *sig)
+{
+    ge_p3 p, A;
+    int ret = 0;
+
+    XMEMCPY(&A, inA, sizeof(ge_p3));
+
+    /* find SB */
+    ed25519_smult(&p, &ed25519_base, sig);
+
+    /* find H(R,A,M) * -A */
+	ed25519_smult(&A, &A, h);
+
+    /* SB + -H(R,A,M)A */
+	ed25519_add(&A, &p, &A);
+
+    fe_copy(R->X, A.X);
+    fe_copy(R->Y, A.Y);
+    fe_copy(R->Z, A.Z);
+
+    return ret;
+}
+
+#endif /* HAVE_ED25519 */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/ge_operations.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,2604 @@
+/* ge_operations.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+ /* Based On Daniel J Bernstein's ed25519 Public Domain ref10 work. */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_ED25519
+
+#include <wolfssl/wolfcrypt/ge_operations.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+/*
+ge means group element.
+
+Here the group is the set of pairs (x,y) of field elements (see fe.h)
+satisfying -x^2 + y^2 = 1 + d x^2y^2
+where d = -121665/121666.
+
+Representations:
+  ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
+  ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
+  ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
+  ge_precomp (Duif): (y+x,y-x,2dxy)
+*/
+
+
+/*
+Input:
+  s[0]+256*s[1]+...+256^63*s[63] = s
+
+Output:
+  s[0]+256*s[1]+...+256^31*s[31] = s mod l
+  where l = 2^252 + 27742317777372353535851937790883648493.
+  Overwrites s in place.
+*/
+void sc_reduce(byte* s)
+{
+  int64_t s0 = 2097151 & load_3(s);
+  int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
+  int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
+  int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
+  int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
+  int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
+  int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
+  int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
+  int64_t s8 = 2097151 & load_3(s + 21);
+  int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
+  int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
+  int64_t s11 = 2097151 & (load_4(s + 28) >> 7);
+  int64_t s12 = 2097151 & (load_4(s + 31) >> 4);
+  int64_t s13 = 2097151 & (load_3(s + 34) >> 1);
+  int64_t s14 = 2097151 & (load_4(s + 36) >> 6);
+  int64_t s15 = 2097151 & (load_3(s + 39) >> 3);
+  int64_t s16 = 2097151 & load_3(s + 42);
+  int64_t s17 = 2097151 & (load_4(s + 44) >> 5);
+  int64_t s18 = 2097151 & (load_3(s + 47) >> 2);
+  int64_t s19 = 2097151 & (load_4(s + 49) >> 7);
+  int64_t s20 = 2097151 & (load_4(s + 52) >> 4);
+  int64_t s21 = 2097151 & (load_3(s + 55) >> 1);
+  int64_t s22 = 2097151 & (load_4(s + 57) >> 6);
+  int64_t s23 = (load_4(s + 60) >> 3);
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+  int64_t carry12;
+  int64_t carry13;
+  int64_t carry14;
+  int64_t carry15;
+  int64_t carry16;
+
+  s11 += s23 * 666643;
+  s12 += s23 * 470296;
+  s13 += s23 * 654183;
+  s14 -= s23 * 997805;
+  s15 += s23 * 136657;
+  s16 -= s23 * 683901;
+  s23 = 0;
+
+  s10 += s22 * 666643;
+  s11 += s22 * 470296;
+  s12 += s22 * 654183;
+  s13 -= s22 * 997805;
+  s14 += s22 * 136657;
+  s15 -= s22 * 683901;
+  s22 = 0;
+
+  s9 += s21 * 666643;
+  s10 += s21 * 470296;
+  s11 += s21 * 654183;
+  s12 -= s21 * 997805;
+  s13 += s21 * 136657;
+  s14 -= s21 * 683901;
+  s21 = 0;
+
+  s8 += s20 * 666643;
+  s9 += s20 * 470296;
+  s10 += s20 * 654183;
+  s11 -= s20 * 997805;
+  s12 += s20 * 136657;
+  s13 -= s20 * 683901;
+  s20 = 0;
+
+  s7 += s19 * 666643;
+  s8 += s19 * 470296;
+  s9 += s19 * 654183;
+  s10 -= s19 * 997805;
+  s11 += s19 * 136657;
+  s12 -= s19 * 683901;
+  s19 = 0;
+
+  s6 += s18 * 666643;
+  s7 += s18 * 470296;
+  s8 += s18 * 654183;
+  s9 -= s18 * 997805;
+  s10 += s18 * 136657;
+  s11 -= s18 * 683901;
+  s18 = 0;
+
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+  s5 += s17 * 666643;
+  s6 += s17 * 470296;
+  s7 += s17 * 654183;
+  s8 -= s17 * 997805;
+  s9 += s17 * 136657;
+  s10 -= s17 * 683901;
+  s17 = 0;
+
+  s4 += s16 * 666643;
+  s5 += s16 * 470296;
+  s6 += s16 * 654183;
+  s7 -= s16 * 997805;
+  s8 += s16 * 136657;
+  s9 -= s16 * 683901;
+  s16 = 0;
+
+  s3 += s15 * 666643;
+  s4 += s15 * 470296;
+  s5 += s15 * 654183;
+  s6 -= s15 * 997805;
+  s7 += s15 * 136657;
+  s8 -= s15 * 683901;
+  s15 = 0;
+
+  s2 += s14 * 666643;
+  s3 += s14 * 470296;
+  s4 += s14 * 654183;
+  s5 -= s14 * 997805;
+  s6 += s14 * 136657;
+  s7 -= s14 * 683901;
+  s14 = 0;
+
+  s1 += s13 * 666643;
+  s2 += s13 * 470296;
+  s3 += s13 * 654183;
+  s4 -= s13 * 997805;
+  s5 += s13 * 136657;
+  s6 -= s13 * 683901;
+  s13 = 0;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+
+  /* hush warnings after setting values to 0 */
+  (void)s12;
+  (void)s13;
+  (void)s14;
+  (void)s15;
+  (void)s16;
+  (void)s17;
+  (void)s18;
+  (void)s19;
+  (void)s20;
+  (void)s21;
+  (void)s22;
+  (void)s23;
+}
+
+
+/*
+Input:
+  a[0]+256*a[1]+...+256^31*a[31] = a
+  b[0]+256*b[1]+...+256^31*b[31] = b
+  c[0]+256*c[1]+...+256^31*c[31] = c
+
+Output:
+  s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
+  where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+void sc_muladd(byte* s, const byte* a, const byte* b, const byte* c)
+{
+  int64_t a0 = 2097151 & load_3(a);
+  int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
+  int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
+  int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
+  int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
+  int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
+  int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
+  int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
+  int64_t a8 = 2097151 & load_3(a + 21);
+  int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
+  int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
+  int64_t a11 = (load_4(a + 28) >> 7);
+  int64_t b0 = 2097151 & load_3(b);
+  int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
+  int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
+  int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
+  int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
+  int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
+  int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
+  int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
+  int64_t b8 = 2097151 & load_3(b + 21);
+  int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
+  int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
+  int64_t b11 = (load_4(b + 28) >> 7);
+  int64_t c0 = 2097151 & load_3(c);
+  int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
+  int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
+  int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
+  int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
+  int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
+  int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
+  int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
+  int64_t c8 = 2097151 & load_3(c + 21);
+  int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
+  int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
+  int64_t c11 = (load_4(c + 28) >> 7);
+  int64_t s0;
+  int64_t s1;
+  int64_t s2;
+  int64_t s3;
+  int64_t s4;
+  int64_t s5;
+  int64_t s6;
+  int64_t s7;
+  int64_t s8;
+  int64_t s9;
+  int64_t s10;
+  int64_t s11;
+  int64_t s12;
+  int64_t s13;
+  int64_t s14;
+  int64_t s15;
+  int64_t s16;
+  int64_t s17;
+  int64_t s18;
+  int64_t s19;
+  int64_t s20;
+  int64_t s21;
+  int64_t s22;
+  int64_t s23;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+  int64_t carry10;
+  int64_t carry11;
+  int64_t carry12;
+  int64_t carry13;
+  int64_t carry14;
+  int64_t carry15;
+  int64_t carry16;
+  int64_t carry17;
+  int64_t carry18;
+  int64_t carry19;
+  int64_t carry20;
+  int64_t carry21;
+  int64_t carry22;
+
+  s0 = c0 + a0*b0;
+  s1 = c1 + a0*b1 + a1*b0;
+  s2 = c2 + a0*b2 + a1*b1 + a2*b0;
+  s3 = c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0;
+  s4 = c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0;
+  s5 = c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0;
+  s6 = c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0;
+  s7 = c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0;
+  s8 = c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1
+          + a8*b0;
+  s9 = c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2
+          + a8*b1 + a9*b0;
+  s10 = c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3
+            + a8*b2 + a9*b1 + a10*b0;
+  s11 = c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4
+            + a8*b3 + a9*b2 + a10*b1 + a11*b0;
+  s12 = a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3
+               + a10*b2 + a11*b1;
+  s13 = a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3
+               + a11*b2;
+  s14 = a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4
+               + a11*b3;
+  s15 = a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4;
+  s16 = a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5;
+  s17 = a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6;
+  s18 = a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7;
+  s19 = a8*b11 + a9*b10 + a10*b9 + a11*b8;
+  s20 = a9*b11 + a10*b10 + a11*b9;
+  s21 = a10*b11 + a11*b10;
+  s22 = a11*b11;
+  s23 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+  carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
+  carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
+  carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+  carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
+  carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
+  carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
+
+  s11 += s23 * 666643;
+  s12 += s23 * 470296;
+  s13 += s23 * 654183;
+  s14 -= s23 * 997805;
+  s15 += s23 * 136657;
+  s16 -= s23 * 683901;
+  s23 = 0;
+
+  s10 += s22 * 666643;
+  s11 += s22 * 470296;
+  s12 += s22 * 654183;
+  s13 -= s22 * 997805;
+  s14 += s22 * 136657;
+  s15 -= s22 * 683901;
+  s22 = 0;
+
+  s9 += s21 * 666643;
+  s10 += s21 * 470296;
+  s11 += s21 * 654183;
+  s12 -= s21 * 997805;
+  s13 += s21 * 136657;
+  s14 -= s21 * 683901;
+  s21 = 0;
+
+  s8 += s20 * 666643;
+  s9 += s20 * 470296;
+  s10 += s20 * 654183;
+  s11 -= s20 * 997805;
+  s12 += s20 * 136657;
+  s13 -= s20 * 683901;
+  s20 = 0;
+
+  s7 += s19 * 666643;
+  s8 += s19 * 470296;
+  s9 += s19 * 654183;
+  s10 -= s19 * 997805;
+  s11 += s19 * 136657;
+  s12 -= s19 * 683901;
+  s19 = 0;
+
+  s6 += s18 * 666643;
+  s7 += s18 * 470296;
+  s8 += s18 * 654183;
+  s9 -= s18 * 997805;
+  s10 += s18 * 136657;
+  s11 -= s18 * 683901;
+  s18 = 0;
+
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+  carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+  carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+  carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+  carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+  s5 += s17 * 666643;
+  s6 += s17 * 470296;
+  s7 += s17 * 654183;
+  s8 -= s17 * 997805;
+  s9 += s17 * 136657;
+  s10 -= s17 * 683901;
+  s17 = 0;
+
+  s4 += s16 * 666643;
+  s5 += s16 * 470296;
+  s6 += s16 * 654183;
+  s7 -= s16 * 997805;
+  s8 += s16 * 136657;
+  s9 -= s16 * 683901;
+  s16 = 0;
+
+  s3 += s15 * 666643;
+  s4 += s15 * 470296;
+  s5 += s15 * 654183;
+  s6 -= s15 * 997805;
+  s7 += s15 * 136657;
+  s8 -= s15 * 683901;
+  s15 = 0;
+
+  s2 += s14 * 666643;
+  s3 += s14 * 470296;
+  s4 += s14 * 654183;
+  s5 -= s14 * 997805;
+  s6 += s14 * 136657;
+  s7 -= s14 * 683901;
+  s14 = 0;
+
+  s1 += s13 * 666643;
+  s2 += s13 * 470296;
+  s3 += s13 * 654183;
+  s4 -= s13 * 997805;
+  s5 += s13 * 136657;
+  s6 -= s13 * 683901;
+  s13 = 0;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+  carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+  s0 += s12 * 666643;
+  s1 += s12 * 470296;
+  s2 += s12 * 654183;
+  s3 -= s12 * 997805;
+  s4 += s12 * 136657;
+  s5 -= s12 * 683901;
+  s12 = 0;
+
+  carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+  carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+  carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+  carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+  carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+  carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+  carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+  carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+  carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+  carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+  carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+  s[0] = s0 >> 0;
+  s[1] = s0 >> 8;
+  s[2] = (s0 >> 16) | (s1 << 5);
+  s[3] = s1 >> 3;
+  s[4] = s1 >> 11;
+  s[5] = (s1 >> 19) | (s2 << 2);
+  s[6] = s2 >> 6;
+  s[7] = (s2 >> 14) | (s3 << 7);
+  s[8] = s3 >> 1;
+  s[9] = s3 >> 9;
+  s[10] = (s3 >> 17) | (s4 << 4);
+  s[11] = s4 >> 4;
+  s[12] = s4 >> 12;
+  s[13] = (s4 >> 20) | (s5 << 1);
+  s[14] = s5 >> 7;
+  s[15] = (s5 >> 15) | (s6 << 6);
+  s[16] = s6 >> 2;
+  s[17] = s6 >> 10;
+  s[18] = (s6 >> 18) | (s7 << 3);
+  s[19] = s7 >> 5;
+  s[20] = s7 >> 13;
+  s[21] = s8 >> 0;
+  s[22] = s8 >> 8;
+  s[23] = (s8 >> 16) | (s9 << 5);
+  s[24] = s9 >> 3;
+  s[25] = s9 >> 11;
+  s[26] = (s9 >> 19) | (s10 << 2);
+  s[27] = s10 >> 6;
+  s[28] = (s10 >> 14) | (s11 << 7);
+  s[29] = s11 >> 1;
+  s[30] = s11 >> 9;
+  s[31] = s11 >> 17;
+
+  /* hush warnings after setting values to 0 */
+  (void)s12;
+  (void)s13;
+  (void)s14;
+  (void)s15;
+  (void)s16;
+  (void)s17;
+  (void)s18;
+  (void)s19;
+  (void)s20;
+  (void)s21;
+  (void)s22;
+  (void)s23;
+}
+
+
+int ge_compress_key(byte* out, const byte* xIn, const byte* yIn, word32 keySz)
+{
+    fe     x,y,z;
+    ge_p3  g;
+    byte   bArray[keySz];
+    word32 i;
+
+    fe_0(x);
+    fe_0(y);
+    fe_1(z);
+    fe_frombytes(x, xIn);
+    fe_frombytes(y, yIn);
+
+    fe_copy(g.X, x);
+    fe_copy(g.Y, y);
+    fe_copy(g.Z, z);
+
+    ge_p3_tobytes(bArray, &g);
+
+    for (i = 0; i < keySz; i++) {
+        out[keySz - 1 - i] = bArray[i];
+    }
+
+    return 0;
+}
+
+
+/*
+r = p + q
+*/
+void ge_add(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q)
+{
+	fe t0;
+	fe_add(r->X,p->Y,p->X);
+	fe_sub(r->Y,p->Y,p->X);
+	fe_mul(r->Z,r->X,q->YplusX);
+	fe_mul(r->Y,r->Y,q->YminusX);
+	fe_mul(r->T,q->T2d,p->T);
+	fe_mul(r->X,p->Z,q->Z);
+	fe_add(t0,r->X,r->X);
+	fe_sub(r->X,r->Z,r->Y);
+	fe_add(r->Y,r->Z,r->Y);
+	fe_add(r->Z,t0,r->T);
+	fe_sub(r->T,t0,r->T);
+}
+
+
+/* ge_scalar mult base */
+static unsigned char equal(signed char b,signed char c)
+{
+  unsigned char ub = b;
+  unsigned char uc = c;
+  unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
+  uint32_t y = x; /* 0: yes; 1..255: no */
+  y -= 1; /* 4294967295: yes; 0..254: no */
+  y >>= 31; /* 1: yes; 0: no */
+  return y;
+}
+
+
+static unsigned char negative(signed char b)
+{
+  unsigned long long x = b; /* 18446744073709551361..18446744073709551615:
+                               yes; 0..255: no */
+  x >>= 63; /* 1: yes; 0: no */
+  return x;
+}
+
+
+static void cmov(ge_precomp *t,ge_precomp *u,unsigned char b)
+{
+  fe_cmov(t->yplusx,u->yplusx,b);
+  fe_cmov(t->yminusx,u->yminusx,b);
+  fe_cmov(t->xy2d,u->xy2d,b);
+}
+
+
+/* base[i][j] = (j+1)*256^i*B */
+static ge_precomp base[32][8] = {
+{
+ {
+  { 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 },
+  { -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 },
+  { -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 },
+ },
+ {
+  { -12815894,-12976347,-21581243,11784320,-25355658,-2750717,-11717903,-3814571,-358445,-10211303 },
+  { -21703237,6903825,27185491,6451973,-29577724,-9554005,-15616551,11189268,-26829678,-5319081 },
+  { 26966642,11152617,32442495,15396054,14353839,-12752335,-3128826,-9541118,-15472047,-4166697 },
+ },
+ {
+  { 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 },
+  { 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 },
+  { 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 },
+ },
+ {
+  { -17036878,13921892,10945806,-6033431,27105052,-16084379,-28926210,15006023,3284568,-6276540 },
+  { 23599295,-8306047,-11193664,-7687416,13236774,10506355,7464579,9656445,13059162,10374397 },
+  { 7798556,16710257,3033922,2874086,28997861,2835604,32406664,-3839045,-641708,-101325 },
+ },
+ {
+  { 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 },
+  { 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 },
+  { 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 },
+ },
+ {
+  { -15371964,-12862754,32573250,4720197,-26436522,5875511,-19188627,-15224819,-9818940,-12085777 },
+  { -8549212,109983,15149363,2178705,22900618,4543417,3044240,-15689887,1762328,14866737 },
+  { -18199695,-15951423,-10473290,1707278,-17185920,3916101,-28236412,3959421,27914454,4383652 },
+ },
+ {
+  { 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 },
+  { -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 },
+  { 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 },
+ },
+ {
+  { 14499471,-2729599,-33191113,-4254652,28494862,14271267,30290735,10876454,-33154098,2381726 },
+  { -7195431,-2655363,-14730155,462251,-27724326,3941372,-6236617,3696005,-32300832,15351955 },
+  { 27431194,8222322,16448760,-3907995,-18707002,11938355,-32961401,-2970515,29551813,10109425 },
+ },
+},
+{
+ {
+  { -13657040,-13155431,-31283750,11777098,21447386,6519384,-2378284,-1627556,10092783,-4764171 },
+  { 27939166,14210322,4677035,16277044,-22964462,-12398139,-32508754,12005538,-17810127,12803510 },
+  { 17228999,-15661624,-1233527,300140,-1224870,-11714777,30364213,-9038194,18016357,4397660 },
+ },
+ {
+  { -10958843,-7690207,4776341,-14954238,27850028,-15602212,-26619106,14544525,-17477504,982639 },
+  { 29253598,15796703,-2863982,-9908884,10057023,3163536,7332899,-4120128,-21047696,9934963 },
+  { 5793303,16271923,-24131614,-10116404,29188560,1206517,-14747930,4559895,-30123922,-10897950 },
+ },
+ {
+  { -27643952,-11493006,16282657,-11036493,28414021,-15012264,24191034,4541697,-13338309,5500568 },
+  { 12650548,-1497113,9052871,11355358,-17680037,-8400164,-17430592,12264343,10874051,13524335 },
+  { 25556948,-3045990,714651,2510400,23394682,-10415330,33119038,5080568,-22528059,5376628 },
+ },
+ {
+  { -26088264,-4011052,-17013699,-3537628,-6726793,1920897,-22321305,-9447443,4535768,1569007 },
+  { -2255422,14606630,-21692440,-8039818,28430649,8775819,-30494562,3044290,31848280,12543772 },
+  { -22028579,2943893,-31857513,6777306,13784462,-4292203,-27377195,-2062731,7718482,14474653 },
+ },
+ {
+  { 2385315,2454213,-22631320,46603,-4437935,-15680415,656965,-7236665,24316168,-5253567 },
+  { 13741529,10911568,-33233417,-8603737,-20177830,-1033297,33040651,-13424532,-20729456,8321686 },
+  { 21060490,-2212744,15712757,-4336099,1639040,10656336,23845965,-11874838,-9984458,608372 },
+ },
+ {
+  { -13672732,-15087586,-10889693,-7557059,-6036909,11305547,1123968,-6780577,27229399,23887 },
+  { -23244140,-294205,-11744728,14712571,-29465699,-2029617,12797024,-6440308,-1633405,16678954 },
+  { -29500620,4770662,-16054387,14001338,7830047,9564805,-1508144,-4795045,-17169265,4904953 },
+ },
+ {
+  { 24059557,14617003,19037157,-15039908,19766093,-14906429,5169211,16191880,2128236,-4326833 },
+  { -16981152,4124966,-8540610,-10653797,30336522,-14105247,-29806336,916033,-6882542,-2986532 },
+  { -22630907,12419372,-7134229,-7473371,-16478904,16739175,285431,2763829,15736322,4143876 },
+ },
+ {
+  { 2379352,11839345,-4110402,-5988665,11274298,794957,212801,-14594663,23527084,-16458268 },
+  { 33431127,-11130478,-17838966,-15626900,8909499,8376530,-32625340,4087881,-15188911,-14416214 },
+  { 1767683,7197987,-13205226,-2022635,-13091350,448826,5799055,4357868,-4774191,-16323038 },
+ },
+},
+{
+ {
+  { 6721966,13833823,-23523388,-1551314,26354293,-11863321,23365147,-3949732,7390890,2759800 },
+  { 4409041,2052381,23373853,10530217,7676779,-12885954,21302353,-4264057,1244380,-12919645 },
+  { -4421239,7169619,4982368,-2957590,30256825,-2777540,14086413,9208236,15886429,16489664 },
+ },
+ {
+  { 1996075,10375649,14346367,13311202,-6874135,-16438411,-13693198,398369,-30606455,-712933 },
+  { -25307465,9795880,-2777414,14878809,-33531835,14780363,13348553,12076947,-30836462,5113182 },
+  { -17770784,11797796,31950843,13929123,-25888302,12288344,-30341101,-7336386,13847711,5387222 },
+ },
+ {
+  { -18582163,-3416217,17824843,-2340966,22744343,-10442611,8763061,3617786,-19600662,10370991 },
+  { 20246567,-14369378,22358229,-543712,18507283,-10413996,14554437,-8746092,32232924,16763880 },
+  { 9648505,10094563,26416693,14745928,-30374318,-6472621,11094161,15689506,3140038,-16510092 },
+ },
+ {
+  { -16160072,5472695,31895588,4744994,8823515,10365685,-27224800,9448613,-28774454,366295 },
+  { 19153450,11523972,-11096490,-6503142,-24647631,5420647,28344573,8041113,719605,11671788 },
+  { 8678025,2694440,-6808014,2517372,4964326,11152271,-15432916,-15266516,27000813,-10195553 },
+ },
+ {
+  { -15157904,7134312,8639287,-2814877,-7235688,10421742,564065,5336097,6750977,-14521026 },
+  { 11836410,-3979488,26297894,16080799,23455045,15735944,1695823,-8819122,8169720,16220347 },
+  { -18115838,8653647,17578566,-6092619,-8025777,-16012763,-11144307,-2627664,-5990708,-14166033 },
+ },
+ {
+  { -23308498,-10968312,15213228,-10081214,-30853605,-11050004,27884329,2847284,2655861,1738395 },
+  { -27537433,-14253021,-25336301,-8002780,-9370762,8129821,21651608,-3239336,-19087449,-11005278 },
+  { 1533110,3437855,23735889,459276,29970501,11335377,26030092,5821408,10478196,8544890 },
+ },
+ {
+  { 32173121,-16129311,24896207,3921497,22579056,-3410854,19270449,12217473,17789017,-3395995 },
+  { -30552961,-2228401,-15578829,-10147201,13243889,517024,15479401,-3853233,30460520,1052596 },
+  { -11614875,13323618,32618793,8175907,-15230173,12596687,27491595,-4612359,3179268,-9478891 },
+ },
+ {
+  { 31947069,-14366651,-4640583,-15339921,-15125977,-6039709,-14756777,-16411740,19072640,-9511060 },
+  { 11685058,11822410,3158003,-13952594,33402194,-4165066,5977896,-5215017,473099,5040608 },
+  { -20290863,8198642,-27410132,11602123,1290375,-2799760,28326862,1721092,-19558642,-3131606 },
+ },
+},
+{
+ {
+  { 7881532,10687937,7578723,7738378,-18951012,-2553952,21820786,8076149,-27868496,11538389 },
+  { -19935666,3899861,18283497,-6801568,-15728660,-11249211,8754525,7446702,-5676054,5797016 },
+  { -11295600,-3793569,-15782110,-7964573,12708869,-8456199,2014099,-9050574,-2369172,-5877341 },
+ },
+ {
+  { -22472376,-11568741,-27682020,1146375,18956691,16640559,1192730,-3714199,15123619,10811505 },
+  { 14352098,-3419715,-18942044,10822655,32750596,4699007,-70363,15776356,-28886779,-11974553 },
+  { -28241164,-8072475,-4978962,-5315317,29416931,1847569,-20654173,-16484855,4714547,-9600655 },
+ },
+ {
+  { 15200332,8368572,19679101,15970074,-31872674,1959451,24611599,-4543832,-11745876,12340220 },
+  { 12876937,-10480056,33134381,6590940,-6307776,14872440,9613953,8241152,15370987,9608631 },
+  { -4143277,-12014408,8446281,-391603,4407738,13629032,-7724868,15866074,-28210621,-8814099 },
+ },
+ {
+  { 26660628,-15677655,8393734,358047,-7401291,992988,-23904233,858697,20571223,8420556 },
+  { 14620715,13067227,-15447274,8264467,14106269,15080814,33531827,12516406,-21574435,-12476749 },
+  { 236881,10476226,57258,-14677024,6472998,2466984,17258519,7256740,8791136,15069930 },
+ },
+ {
+  { 1276410,-9371918,22949635,-16322807,-23493039,-5702186,14711875,4874229,-30663140,-2331391 },
+  { 5855666,4990204,-13711848,7294284,-7804282,1924647,-1423175,-7912378,-33069337,9234253 },
+  { 20590503,-9018988,31529744,-7352666,-2706834,10650548,31559055,-11609587,18979186,13396066 },
+ },
+ {
+  { 24474287,4968103,22267082,4407354,24063882,-8325180,-18816887,13594782,33514650,7021958 },
+  { -11566906,-6565505,-21365085,15928892,-26158305,4315421,-25948728,-3916677,-21480480,12868082 },
+  { -28635013,13504661,19988037,-2132761,21078225,6443208,-21446107,2244500,-12455797,-8089383 },
+ },
+ {
+  { -30595528,13793479,-5852820,319136,-25723172,-6263899,33086546,8957937,-15233648,5540521 },
+  { -11630176,-11503902,-8119500,-7643073,2620056,1022908,-23710744,-1568984,-16128528,-14962807 },
+  { 23152971,775386,27395463,14006635,-9701118,4649512,1689819,892185,-11513277,-15205948 },
+ },
+ {
+  { 9770129,9586738,26496094,4324120,1556511,-3550024,27453819,4763127,-19179614,5867134 },
+  { -32765025,1927590,31726409,-4753295,23962434,-16019500,27846559,5931263,-29749703,-16108455 },
+  { 27461885,-2977536,22380810,1815854,-23033753,-3031938,7283490,-15148073,-19526700,7734629 },
+ },
+},
+{
+ {
+  { -8010264,-9590817,-11120403,6196038,29344158,-13430885,7585295,-3176626,18549497,15302069 },
+  { -32658337,-6171222,-7672793,-11051681,6258878,13504381,10458790,-6418461,-8872242,8424746 },
+  { 24687205,8613276,-30667046,-3233545,1863892,-1830544,19206234,7134917,-11284482,-828919 },
+ },
+ {
+  { 11334899,-9218022,8025293,12707519,17523892,-10476071,10243738,-14685461,-5066034,16498837 },
+  { 8911542,6887158,-9584260,-6958590,11145641,-9543680,17303925,-14124238,6536641,10543906 },
+  { -28946384,15479763,-17466835,568876,-1497683,11223454,-2669190,-16625574,-27235709,8876771 },
+ },
+ {
+  { -25742899,-12566864,-15649966,-846607,-33026686,-796288,-33481822,15824474,-604426,-9039817 },
+  { 10330056,70051,7957388,-9002667,9764902,15609756,27698697,-4890037,1657394,3084098 },
+  { 10477963,-7470260,12119566,-13250805,29016247,-5365589,31280319,14396151,-30233575,15272409 },
+ },
+ {
+  { -12288309,3169463,28813183,16658753,25116432,-5630466,-25173957,-12636138,-25014757,1950504 },
+  { -26180358,9489187,11053416,-14746161,-31053720,5825630,-8384306,-8767532,15341279,8373727 },
+  { 28685821,7759505,-14378516,-12002860,-31971820,4079242,298136,-10232602,-2878207,15190420 },
+ },
+ {
+  { -32932876,13806336,-14337485,-15794431,-24004620,10940928,8669718,2742393,-26033313,-6875003 },
+  { -1580388,-11729417,-25979658,-11445023,-17411874,-10912854,9291594,-16247779,-12154742,6048605 },
+  { -30305315,14843444,1539301,11864366,20201677,1900163,13934231,5128323,11213262,9168384 },
+ },
+ {
+  { -26280513,11007847,19408960,-940758,-18592965,-4328580,-5088060,-11105150,20470157,-16398701 },
+  { -23136053,9282192,14855179,-15390078,-7362815,-14408560,-22783952,14461608,14042978,5230683 },
+  { 29969567,-2741594,-16711867,-8552442,9175486,-2468974,21556951,3506042,-5933891,-12449708 },
+ },
+ {
+  { -3144746,8744661,19704003,4581278,-20430686,6830683,-21284170,8971513,-28539189,15326563 },
+  { -19464629,10110288,-17262528,-3503892,-23500387,1355669,-15523050,15300988,-20514118,9168260 },
+  { -5353335,4488613,-23803248,16314347,7780487,-15638939,-28948358,9601605,33087103,-9011387 },
+ },
+ {
+  { -19443170,-15512900,-20797467,-12445323,-29824447,10229461,-27444329,-15000531,-5996870,15664672 },
+  { 23294591,-16632613,-22650781,-8470978,27844204,11461195,13099750,-2460356,18151676,13417686 },
+  { -24722913,-4176517,-31150679,5988919,-26858785,6685065,1661597,-12551441,15271676,-15452665 },
+ },
+},
+{
+ {
+  { 11433042,-13228665,8239631,-5279517,-1985436,-725718,-18698764,2167544,-6921301,-13440182 },
+  { -31436171,15575146,30436815,12192228,-22463353,9395379,-9917708,-8638997,12215110,12028277 },
+  { 14098400,6555944,23007258,5757252,-15427832,-12950502,30123440,4617780,-16900089,-655628 },
+ },
+ {
+  { -4026201,-15240835,11893168,13718664,-14809462,1847385,-15819999,10154009,23973261,-12684474 },
+  { -26531820,-3695990,-1908898,2534301,-31870557,-16550355,18341390,-11419951,32013174,-10103539 },
+  { -25479301,10876443,-11771086,-14625140,-12369567,1838104,21911214,6354752,4425632,-837822 },
+ },
+ {
+  { -10433389,-14612966,22229858,-3091047,-13191166,776729,-17415375,-12020462,4725005,14044970 },
+  { 19268650,-7304421,1555349,8692754,-21474059,-9910664,6347390,-1411784,-19522291,-16109756 },
+  { -24864089,12986008,-10898878,-5558584,-11312371,-148526,19541418,8180106,9282262,10282508 },
+ },
+ {
+  { -26205082,4428547,-8661196,-13194263,4098402,-14165257,15522535,8372215,5542595,-10702683 },
+  { -10562541,14895633,26814552,-16673850,-17480754,-2489360,-2781891,6993761,-18093885,10114655 },
+  { -20107055,-929418,31422704,10427861,-7110749,6150669,-29091755,-11529146,25953725,-106158 },
+ },
+ {
+  { -4234397,-8039292,-9119125,3046000,2101609,-12607294,19390020,6094296,-3315279,12831125 },
+  { -15998678,7578152,5310217,14408357,-33548620,-224739,31575954,6326196,7381791,-2421839 },
+  { -20902779,3296811,24736065,-16328389,18374254,7318640,6295303,8082724,-15362489,12339664 },
+ },
+ {
+  { 27724736,2291157,6088201,-14184798,1792727,5857634,13848414,15768922,25091167,14856294 },
+  { -18866652,8331043,24373479,8541013,-701998,-9269457,12927300,-12695493,-22182473,-9012899 },
+  { -11423429,-5421590,11632845,3405020,30536730,-11674039,-27260765,13866390,30146206,9142070 },
+ },
+ {
+  { 3924129,-15307516,-13817122,-10054960,12291820,-668366,-27702774,9326384,-8237858,4171294 },
+  { -15921940,16037937,6713787,16606682,-21612135,2790944,26396185,3731949,345228,-5462949 },
+  { -21327538,13448259,25284571,1143661,20614966,-8849387,2031539,-12391231,-16253183,-13582083 },
+ },
+ {
+  { 31016211,-16722429,26371392,-14451233,-5027349,14854137,17477601,3842657,28012650,-16405420 },
+  { -5075835,9368966,-8562079,-4600902,-15249953,6970560,-9189873,16292057,-8867157,3507940 },
+  { 29439664,3537914,23333589,6997794,-17555561,-11018068,-15209202,-15051267,-9164929,6580396 },
+ },
+},
+{
+ {
+  { -12185861,-7679788,16438269,10826160,-8696817,-6235611,17860444,-9273846,-2095802,9304567 },
+  { 20714564,-4336911,29088195,7406487,11426967,-5095705,14792667,-14608617,5289421,-477127 },
+  { -16665533,-10650790,-6160345,-13305760,9192020,-1802462,17271490,12349094,26939669,-3752294 },
+ },
+ {
+  { -12889898,9373458,31595848,16374215,21471720,13221525,-27283495,-12348559,-3698806,117887 },
+  { 22263325,-6560050,3984570,-11174646,-15114008,-566785,28311253,5358056,-23319780,541964 },
+  { 16259219,3261970,2309254,-15534474,-16885711,-4581916,24134070,-16705829,-13337066,-13552195 },
+ },
+ {
+  { 9378160,-13140186,-22845982,-12745264,28198281,-7244098,-2399684,-717351,690426,14876244 },
+  { 24977353,-314384,-8223969,-13465086,28432343,-1176353,-13068804,-12297348,-22380984,6618999 },
+  { -1538174,11685646,12944378,13682314,-24389511,-14413193,8044829,-13817328,32239829,-5652762 },
+ },
+ {
+  { -18603066,4762990,-926250,8885304,-28412480,-3187315,9781647,-10350059,32779359,5095274 },
+  { -33008130,-5214506,-32264887,-3685216,9460461,-9327423,-24601656,14506724,21639561,-2630236 },
+  { -16400943,-13112215,25239338,15531969,3987758,-4499318,-1289502,-6863535,17874574,558605 },
+ },
+ {
+  { -13600129,10240081,9171883,16131053,-20869254,9599700,33499487,5080151,2085892,5119761 },
+  { -22205145,-2519528,-16381601,414691,-25019550,2170430,30634760,-8363614,-31999993,-5759884 },
+  { -6845704,15791202,8550074,-1312654,29928809,-12092256,27534430,-7192145,-22351378,12961482 },
+ },
+ {
+  { -24492060,-9570771,10368194,11582341,-23397293,-2245287,16533930,8206996,-30194652,-5159638 },
+  { -11121496,-3382234,2307366,6362031,-135455,8868177,-16835630,7031275,7589640,8945490 },
+  { -32152748,8917967,6661220,-11677616,-1192060,-15793393,7251489,-11182180,24099109,-14456170 },
+ },
+ {
+  { 5019558,-7907470,4244127,-14714356,-26933272,6453165,-19118182,-13289025,-6231896,-10280736 },
+  { 10853594,10721687,26480089,5861829,-22995819,1972175,-1866647,-10557898,-3363451,-6441124 },
+  { -17002408,5906790,221599,-6563147,7828208,-13248918,24362661,-2008168,-13866408,7421392 },
+ },
+ {
+  { 8139927,-6546497,32257646,-5890546,30375719,1886181,-21175108,15441252,28826358,-4123029 },
+  { 6267086,9695052,7709135,-16603597,-32869068,-1886135,14795160,-7840124,13746021,-1742048 },
+  { 28584902,7787108,-6732942,-15050729,22846041,-7571236,-3181936,-363524,4771362,-8419958 },
+ },
+},
+{
+ {
+  { 24949256,6376279,-27466481,-8174608,-18646154,-9930606,33543569,-12141695,3569627,11342593 },
+  { 26514989,4740088,27912651,3697550,19331575,-11472339,6809886,4608608,7325975,-14801071 },
+  { -11618399,-14554430,-24321212,7655128,-1369274,5214312,-27400540,10258390,-17646694,-8186692 },
+ },
+ {
+  { 11431204,15823007,26570245,14329124,18029990,4796082,-31446179,15580664,9280358,-3973687 },
+  { -160783,-10326257,-22855316,-4304997,-20861367,-13621002,-32810901,-11181622,-15545091,4387441 },
+  { -20799378,12194512,3937617,-5805892,-27154820,9340370,-24513992,8548137,20617071,-7482001 },
+ },
+ {
+  { -938825,-3930586,-8714311,16124718,24603125,-6225393,-13775352,-11875822,24345683,10325460 },
+  { -19855277,-1568885,-22202708,8714034,14007766,6928528,16318175,-1010689,4766743,3552007 },
+  { -21751364,-16730916,1351763,-803421,-4009670,3950935,3217514,14481909,10988822,-3994762 },
+ },
+ {
+  { 15564307,-14311570,3101243,5684148,30446780,-8051356,12677127,-6505343,-8295852,13296005 },
+  { -9442290,6624296,-30298964,-11913677,-4670981,-2057379,31521204,9614054,-30000824,12074674 },
+  { 4771191,-135239,14290749,-13089852,27992298,14998318,-1413936,-1556716,29832613,-16391035 },
+ },
+ {
+  { 7064884,-7541174,-19161962,-5067537,-18891269,-2912736,25825242,5293297,-27122660,13101590 },
+  { -2298563,2439670,-7466610,1719965,-27267541,-16328445,32512469,-5317593,-30356070,-4190957 },
+  { -30006540,10162316,-33180176,3981723,-16482138,-13070044,14413974,9515896,19568978,9628812 },
+ },
+ {
+  { 33053803,199357,15894591,1583059,27380243,-4580435,-17838894,-6106839,-6291786,3437740 },
+  { -18978877,3884493,19469877,12726490,15913552,13614290,-22961733,70104,7463304,4176122 },
+  { -27124001,10659917,11482427,-16070381,12771467,-6635117,-32719404,-5322751,24216882,5944158 },
+ },
+ {
+  { 8894125,7450974,-2664149,-9765752,-28080517,-12389115,19345746,14680796,11632993,5847885 },
+  { 26942781,-2315317,9129564,-4906607,26024105,11769399,-11518837,6367194,-9727230,4782140 },
+  { 19916461,-4828410,-22910704,-11414391,25606324,-5972441,33253853,8220911,6358847,-1873857 },
+ },
+ {
+  { 801428,-2081702,16569428,11065167,29875704,96627,7908388,-4480480,-13538503,1387155 },
+  { 19646058,5720633,-11416706,12814209,11607948,12749789,14147075,15156355,-21866831,11835260 },
+  { 19299512,1155910,28703737,14890794,2925026,7269399,26121523,15467869,-26560550,5052483 },
+ },
+},
+{
+ {
+  { -3017432,10058206,1980837,3964243,22160966,12322533,-6431123,-12618185,12228557,-7003677 },
+  { 32944382,14922211,-22844894,5188528,21913450,-8719943,4001465,13238564,-6114803,8653815 },
+  { 22865569,-4652735,27603668,-12545395,14348958,8234005,24808405,5719875,28483275,2841751 },
+ },
+ {
+  { -16420968,-1113305,-327719,-12107856,21886282,-15552774,-1887966,-315658,19932058,-12739203 },
+  { -11656086,10087521,-8864888,-5536143,-19278573,-3055912,3999228,13239134,-4777469,-13910208 },
+  { 1382174,-11694719,17266790,9194690,-13324356,9720081,20403944,11284705,-14013818,3093230 },
+ },
+ {
+  { 16650921,-11037932,-1064178,1570629,-8329746,7352753,-302424,16271225,-24049421,-6691850 },
+  { -21911077,-5927941,-4611316,-5560156,-31744103,-10785293,24123614,15193618,-21652117,-16739389 },
+  { -9935934,-4289447,-25279823,4372842,2087473,10399484,31870908,14690798,17361620,11864968 },
+ },
+ {
+  { -11307610,6210372,13206574,5806320,-29017692,-13967200,-12331205,-7486601,-25578460,-16240689 },
+  { 14668462,-12270235,26039039,15305210,25515617,4542480,10453892,6577524,9145645,-6443880 },
+  { 5974874,3053895,-9433049,-10385191,-31865124,3225009,-7972642,3936128,-5652273,-3050304 },
+ },
+ {
+  { 30625386,-4729400,-25555961,-12792866,-20484575,7695099,17097188,-16303496,-27999779,1803632 },
+  { -3553091,9865099,-5228566,4272701,-5673832,-16689700,14911344,12196514,-21405489,7047412 },
+  { 20093277,9920966,-11138194,-5343857,13161587,12044805,-32856851,4124601,-32343828,-10257566 },
+ },
+ {
+  { -20788824,14084654,-13531713,7842147,19119038,-13822605,4752377,-8714640,-21679658,2288038 },
+  { -26819236,-3283715,29965059,3039786,-14473765,2540457,29457502,14625692,-24819617,12570232 },
+  { -1063558,-11551823,16920318,12494842,1278292,-5869109,-21159943,-3498680,-11974704,4724943 },
+ },
+ {
+  { 17960970,-11775534,-4140968,-9702530,-8876562,-1410617,-12907383,-8659932,-29576300,1903856 },
+  { 23134274,-14279132,-10681997,-1611936,20684485,15770816,-12989750,3190296,26955097,14109738 },
+  { 15308788,5320727,-30113809,-14318877,22902008,7767164,29425325,-11277562,31960942,11934971 },
+ },
+ {
+  { -27395711,8435796,4109644,12222639,-24627868,14818669,20638173,4875028,10491392,1379718 },
+  { -13159415,9197841,3875503,-8936108,-1383712,-5879801,33518459,16176658,21432314,12180697 },
+  { -11787308,11500838,13787581,-13832590,-22430679,10140205,1465425,12689540,-10301319,-13872883 },
+ },
+},
+{
+ {
+  { 5414091,-15386041,-21007664,9643570,12834970,1186149,-2622916,-1342231,26128231,6032912 },
+  { -26337395,-13766162,32496025,-13653919,17847801,-12669156,3604025,8316894,-25875034,-10437358 },
+  { 3296484,6223048,24680646,-12246460,-23052020,5903205,-8862297,-4639164,12376617,3188849 },
+ },
+ {
+  { 29190488,-14659046,27549113,-1183516,3520066,-10697301,32049515,-7309113,-16109234,-9852307 },
+  { -14744486,-9309156,735818,-598978,-20407687,-5057904,25246078,-15795669,18640741,-960977 },
+  { -6928835,-16430795,10361374,5642961,4910474,12345252,-31638386,-494430,10530747,1053335 },
+ },
+ {
+  { -29265967,-14186805,-13538216,-12117373,-19457059,-10655384,-31462369,-2948985,24018831,15026644 },
+  { -22592535,-3145277,-2289276,5953843,-13440189,9425631,25310643,13003497,-2314791,-15145616 },
+  { -27419985,-603321,-8043984,-1669117,-26092265,13987819,-27297622,187899,-23166419,-2531735 },
+ },
+ {
+  { -21744398,-13810475,1844840,5021428,-10434399,-15911473,9716667,16266922,-5070217,726099 },
+  { 29370922,-6053998,7334071,-15342259,9385287,2247707,-13661962,-4839461,30007388,-15823341 },
+  { -936379,16086691,23751945,-543318,-1167538,-5189036,9137109,730663,9835848,4555336 },
+ },
+ {
+  { -23376435,1410446,-22253753,-12899614,30867635,15826977,17693930,544696,-11985298,12422646 },
+  { 31117226,-12215734,-13502838,6561947,-9876867,-12757670,-5118685,-4096706,29120153,13924425 },
+  { -17400879,-14233209,19675799,-2734756,-11006962,-5858820,-9383939,-11317700,7240931,-237388 },
+ },
+ {
+  { -31361739,-11346780,-15007447,-5856218,-22453340,-12152771,1222336,4389483,3293637,-15551743 },
+  { -16684801,-14444245,11038544,11054958,-13801175,-3338533,-24319580,7733547,12796905,-6335822 },
+  { -8759414,-10817836,-25418864,10783769,-30615557,-9746811,-28253339,3647836,3222231,-11160462 },
+ },
+ {
+  { 18606113,1693100,-25448386,-15170272,4112353,10045021,23603893,-2048234,-7550776,2484985 },
+  { 9255317,-3131197,-12156162,-1004256,13098013,-9214866,16377220,-2102812,-19802075,-3034702 },
+  { -22729289,7496160,-5742199,11329249,19991973,-3347502,-31718148,9936966,-30097688,-10618797 },
+ },
+ {
+  { 21878590,-5001297,4338336,13643897,-3036865,13160960,19708896,5415497,-7360503,-4109293 },
+  { 27736861,10103576,12500508,8502413,-3413016,-9633558,10436918,-1550276,-23659143,-8132100 },
+  { 19492550,-12104365,-29681976,-852630,-3208171,12403437,30066266,8367329,13243957,8709688 },
+ },
+},
+{
+ {
+  { 12015105,2801261,28198131,10151021,24818120,-4743133,-11194191,-5645734,5150968,7274186 },
+  { 2831366,-12492146,1478975,6122054,23825128,-12733586,31097299,6083058,31021603,-9793610 },
+  { -2529932,-2229646,445613,10720828,-13849527,-11505937,-23507731,16354465,15067285,-14147707 },
+ },
+ {
+  { 7840942,14037873,-33364863,15934016,-728213,-3642706,21403988,1057586,-19379462,-12403220 },
+  { 915865,-16469274,15608285,-8789130,-24357026,6060030,-17371319,8410997,-7220461,16527025 },
+  { 32922597,-556987,20336074,-16184568,10903705,-5384487,16957574,52992,23834301,6588044 },
+ },
+ {
+  { 32752030,11232950,3381995,-8714866,22652988,-10744103,17159699,16689107,-20314580,-1305992 },
+  { -4689649,9166776,-25710296,-10847306,11576752,12733943,7924251,-2752281,1976123,-7249027 },
+  { 21251222,16309901,-2983015,-6783122,30810597,12967303,156041,-3371252,12331345,-8237197 },
+ },
+ {
+  { 8651614,-4477032,-16085636,-4996994,13002507,2950805,29054427,-5106970,10008136,-4667901 },
+  { 31486080,15114593,-14261250,12951354,14369431,-7387845,16347321,-13662089,8684155,-10532952 },
+  { 19443825,11385320,24468943,-9659068,-23919258,2187569,-26263207,-6086921,31316348,14219878 },
+ },
+ {
+  { -28594490,1193785,32245219,11392485,31092169,15722801,27146014,6992409,29126555,9207390 },
+  { 32382935,1110093,18477781,11028262,-27411763,-7548111,-4980517,10843782,-7957600,-14435730 },
+  { 2814918,7836403,27519878,-7868156,-20894015,-11553689,-21494559,8550130,28346258,1994730 },
+ },
+ {
+  { -19578299,8085545,-14000519,-3948622,2785838,-16231307,-19516951,7174894,22628102,8115180 },
+  { -30405132,955511,-11133838,-15078069,-32447087,-13278079,-25651578,3317160,-9943017,930272 },
+  { -15303681,-6833769,28856490,1357446,23421993,1057177,24091212,-1388970,-22765376,-10650715 },
+ },
+ {
+  { -22751231,-5303997,-12907607,-12768866,-15811511,-7797053,-14839018,-16554220,-1867018,8398970 },
+  { -31969310,2106403,-4736360,1362501,12813763,16200670,22981545,-6291273,18009408,-15772772 },
+  { -17220923,-9545221,-27784654,14166835,29815394,7444469,29551787,-3727419,19288549,1325865 },
+ },
+ {
+  { 15100157,-15835752,-23923978,-1005098,-26450192,15509408,12376730,-3479146,33166107,-8042750 },
+  { 20909231,13023121,-9209752,16251778,-5778415,-8094914,12412151,10018715,2213263,-13878373 },
+  { 32529814,-11074689,30361439,-16689753,-9135940,1513226,22922121,6382134,-5766928,8371348 },
+ },
+},
+{
+ {
+  { 9923462,11271500,12616794,3544722,-29998368,-1721626,12891687,-8193132,-26442943,10486144 },
+  { -22597207,-7012665,8587003,-8257861,4084309,-12970062,361726,2610596,-23921530,-11455195 },
+  { 5408411,-1136691,-4969122,10561668,24145918,14240566,31319731,-4235541,19985175,-3436086 },
+ },
+ {
+  { -13994457,16616821,14549246,3341099,32155958,13648976,-17577068,8849297,65030,8370684 },
+  { -8320926,-12049626,31204563,5839400,-20627288,-1057277,-19442942,6922164,12743482,-9800518 },
+  { -2361371,12678785,28815050,4759974,-23893047,4884717,23783145,11038569,18800704,255233 },
+ },
+ {
+  { -5269658,-1773886,13957886,7990715,23132995,728773,13393847,9066957,19258688,-14753793 },
+  { -2936654,-10827535,-10432089,14516793,-3640786,4372541,-31934921,2209390,-1524053,2055794 },
+  { 580882,16705327,5468415,-2683018,-30926419,-14696000,-7203346,-8994389,-30021019,7394435 },
+ },
+ {
+  { 23838809,1822728,-15738443,15242727,8318092,-3733104,-21672180,-3492205,-4821741,14799921 },
+  { 13345610,9759151,3371034,-16137791,16353039,8577942,31129804,13496856,-9056018,7402518 },
+  { 2286874,-4435931,-20042458,-2008336,-13696227,5038122,11006906,-15760352,8205061,1607563 },
+ },
+ {
+  { 14414086,-8002132,3331830,-3208217,22249151,-5594188,18364661,-2906958,30019587,-9029278 },
+  { -27688051,1585953,-10775053,931069,-29120221,-11002319,-14410829,12029093,9944378,8024 },
+  { 4368715,-3709630,29874200,-15022983,-20230386,-11410704,-16114594,-999085,-8142388,5640030 },
+ },
+ {
+  { 10299610,13746483,11661824,16234854,7630238,5998374,9809887,-16694564,15219798,-14327783 },
+  { 27425505,-5719081,3055006,10660664,23458024,595578,-15398605,-1173195,-18342183,9742717 },
+  { 6744077,2427284,26042789,2720740,-847906,1118974,32324614,7406442,12420155,1994844 },
+ },
+ {
+  { 14012521,-5024720,-18384453,-9578469,-26485342,-3936439,-13033478,-10909803,24319929,-6446333 },
+  { 16412690,-4507367,10772641,15929391,-17068788,-4658621,10555945,-10484049,-30102368,-4739048 },
+  { 22397382,-7767684,-9293161,-12792868,17166287,-9755136,-27333065,6199366,21880021,-12250760 },
+ },
+ {
+  { -4283307,5368523,-31117018,8163389,-30323063,3209128,16557151,8890729,8840445,4957760 },
+  { -15447727,709327,-6919446,-10870178,-29777922,6522332,-21720181,12130072,-14796503,5005757 },
+  { -2114751,-14308128,23019042,15765735,-25269683,6002752,10183197,-13239326,-16395286,-2176112 },
+ },
+},
+{
+ {
+  { -19025756,1632005,13466291,-7995100,-23640451,16573537,-32013908,-3057104,22208662,2000468 },
+  { 3065073,-1412761,-25598674,-361432,-17683065,-5703415,-8164212,11248527,-3691214,-7414184 },
+  { 10379208,-6045554,8877319,1473647,-29291284,-12507580,16690915,2553332,-3132688,16400289 },
+ },
+ {
+  { 15716668,1254266,-18472690,7446274,-8448918,6344164,-22097271,-7285580,26894937,9132066 },
+  { 24158887,12938817,11085297,-8177598,-28063478,-4457083,-30576463,64452,-6817084,-2692882 },
+  { 13488534,7794716,22236231,5989356,25426474,-12578208,2350710,-3418511,-4688006,2364226 },
+ },
+ {
+  { 16335052,9132434,25640582,6678888,1725628,8517937,-11807024,-11697457,15445875,-7798101 },
+  { 29004207,-7867081,28661402,-640412,-12794003,-7943086,31863255,-4135540,-278050,-15759279 },
+  { -6122061,-14866665,-28614905,14569919,-10857999,-3591829,10343412,-6976290,-29828287,-10815811 },
+ },
+ {
+  { 27081650,3463984,14099042,-4517604,1616303,-6205604,29542636,15372179,17293797,960709 },
+  { 20263915,11434237,-5765435,11236810,13505955,-10857102,-16111345,6493122,-19384511,7639714 },
+  { -2830798,-14839232,25403038,-8215196,-8317012,-16173699,18006287,-16043750,29994677,-15808121 },
+ },
+ {
+  { 9769828,5202651,-24157398,-13631392,-28051003,-11561624,-24613141,-13860782,-31184575,709464 },
+  { 12286395,13076066,-21775189,-1176622,-25003198,4057652,-32018128,-8890874,16102007,13205847 },
+  { 13733362,5599946,10557076,3195751,-5557991,8536970,-25540170,8525972,10151379,10394400 },
+ },
+ {
+  { 4024660,-16137551,22436262,12276534,-9099015,-2686099,19698229,11743039,-33302334,8934414 },
+  { -15879800,-4525240,-8580747,-2934061,14634845,-698278,-9449077,3137094,-11536886,11721158 },
+  { 17555939,-5013938,8268606,2331751,-22738815,9761013,9319229,8835153,-9205489,-1280045 },
+ },
+ {
+  { -461409,-7830014,20614118,16688288,-7514766,-4807119,22300304,505429,6108462,-6183415 },
+  { -5070281,12367917,-30663534,3234473,32617080,-8422642,29880583,-13483331,-26898490,-7867459 },
+  { -31975283,5726539,26934134,10237677,-3173717,-605053,24199304,3795095,7592688,-14992079 },
+ },
+ {
+  { 21594432,-14964228,17466408,-4077222,32537084,2739898,6407723,12018833,-28256052,4298412 },
+  { -20650503,-11961496,-27236275,570498,3767144,-1717540,13891942,-1569194,13717174,10805743 },
+  { -14676630,-15644296,15287174,11927123,24177847,-8175568,-796431,14860609,-26938930,-5863836 },
+ },
+},
+{
+ {
+  { 12962541,5311799,-10060768,11658280,18855286,-7954201,13286263,-12808704,-4381056,9882022 },
+  { 18512079,11319350,-20123124,15090309,18818594,5271736,-22727904,3666879,-23967430,-3299429 },
+  { -6789020,-3146043,16192429,13241070,15898607,-14206114,-10084880,-6661110,-2403099,5276065 },
+ },
+ {
+  { 30169808,-5317648,26306206,-11750859,27814964,7069267,7152851,3684982,1449224,13082861 },
+  { 10342826,3098505,2119311,193222,25702612,12233820,23697382,15056736,-21016438,-8202000 },
+  { -33150110,3261608,22745853,7948688,19370557,-15177665,-26171976,6482814,-10300080,-11060101 },
+ },
+ {
+  { 32869458,-5408545,25609743,15678670,-10687769,-15471071,26112421,2521008,-22664288,6904815 },
+  { 29506923,4457497,3377935,-9796444,-30510046,12935080,1561737,3841096,-29003639,-6657642 },
+  { 10340844,-6630377,-18656632,-2278430,12621151,-13339055,30878497,-11824370,-25584551,5181966 },
+ },
+ {
+  { 25940115,-12658025,17324188,-10307374,-8671468,15029094,24396252,-16450922,-2322852,-12388574 },
+  { -21765684,9916823,-1300409,4079498,-1028346,11909559,1782390,12641087,20603771,-6561742 },
+  { -18882287,-11673380,24849422,11501709,13161720,-4768874,1925523,11914390,4662781,7820689 },
+ },
+ {
+  { 12241050,-425982,8132691,9393934,32846760,-1599620,29749456,12172924,16136752,15264020 },
+  { -10349955,-14680563,-8211979,2330220,-17662549,-14545780,10658213,6671822,19012087,3772772 },
+  { 3753511,-3421066,10617074,2028709,14841030,-6721664,28718732,-15762884,20527771,12988982 },
+ },
+ {
+  { -14822485,-5797269,-3707987,12689773,-898983,-10914866,-24183046,-10564943,3299665,-12424953 },
+  { -16777703,-15253301,-9642417,4978983,3308785,8755439,6943197,6461331,-25583147,8991218 },
+  { -17226263,1816362,-1673288,-6086439,31783888,-8175991,-32948145,7417950,-30242287,1507265 },
+ },
+ {
+  { 29692663,6829891,-10498800,4334896,20945975,-11906496,-28887608,8209391,14606362,-10647073 },
+  { -3481570,8707081,32188102,5672294,22096700,1711240,-33020695,9761487,4170404,-2085325 },
+  { -11587470,14855945,-4127778,-1531857,-26649089,15084046,22186522,16002000,-14276837,-8400798 },
+ },
+ {
+  { -4811456,13761029,-31703877,-2483919,-3312471,7869047,-7113572,-9620092,13240845,10965870 },
+  { -7742563,-8256762,-14768334,-13656260,-23232383,12387166,4498947,14147411,29514390,4302863 },
+  { -13413405,-12407859,20757302,-13801832,14785143,8976368,-5061276,-2144373,17846988,-13971927 },
+ },
+},
+{
+ {
+  { -2244452,-754728,-4597030,-1066309,-6247172,1455299,-21647728,-9214789,-5222701,12650267 },
+  { -9906797,-16070310,21134160,12198166,-27064575,708126,387813,13770293,-19134326,10958663 },
+  { 22470984,12369526,23446014,-5441109,-21520802,-9698723,-11772496,-11574455,-25083830,4271862 },
+ },
+ {
+  { -25169565,-10053642,-19909332,15361595,-5984358,2159192,75375,-4278529,-32526221,8469673 },
+  { 15854970,4148314,-8893890,7259002,11666551,13824734,-30531198,2697372,24154791,-9460943 },
+  { 15446137,-15806644,29759747,14019369,30811221,-9610191,-31582008,12840104,24913809,9815020 },
+ },
+ {
+  { -4709286,-5614269,-31841498,-12288893,-14443537,10799414,-9103676,13438769,18735128,9466238 },
+  { 11933045,9281483,5081055,-5183824,-2628162,-4905629,-7727821,-10896103,-22728655,16199064 },
+  { 14576810,379472,-26786533,-8317236,-29426508,-10812974,-102766,1876699,30801119,2164795 },
+ },
+ {
+  { 15995086,3199873,13672555,13712240,-19378835,-4647646,-13081610,-15496269,-13492807,1268052 },
+  { -10290614,-3659039,-3286592,10948818,23037027,3794475,-3470338,-12600221,-17055369,3565904 },
+  { 29210088,-9419337,-5919792,-4952785,10834811,-13327726,-16512102,-10820713,-27162222,-14030531 },
+ },
+ {
+  { -13161890,15508588,16663704,-8156150,-28349942,9019123,-29183421,-3769423,2244111,-14001979 },
+  { -5152875,-3800936,-9306475,-6071583,16243069,14684434,-25673088,-16180800,13491506,4641841 },
+  { 10813417,643330,-19188515,-728916,30292062,-16600078,27548447,-7721242,14476989,-12767431 },
+ },
+ {
+  { 10292079,9984945,6481436,8279905,-7251514,7032743,27282937,-1644259,-27912810,12651324 },
+  { -31185513,-813383,22271204,11835308,10201545,15351028,17099662,3988035,21721536,-3148940 },
+  { 10202177,-6545839,-31373232,-9574638,-32150642,-8119683,-12906320,3852694,13216206,14842320 },
+ },
+ {
+  { -15815640,-10601066,-6538952,-7258995,-6984659,-6581778,-31500847,13765824,-27434397,9900184 },
+  { 14465505,-13833331,-32133984,-14738873,-27443187,12990492,33046193,15796406,-7051866,-8040114 },
+  { 30924417,-8279620,6359016,-12816335,16508377,9071735,-25488601,15413635,9524356,-7018878 },
+ },
+ {
+  { 12274201,-13175547,32627641,-1785326,6736625,13267305,5237659,-5109483,15663516,4035784 },
+  { -2951309,8903985,17349946,601635,-16432815,-4612556,-13732739,-15889334,-22258478,4659091 },
+  { -16916263,-4952973,-30393711,-15158821,20774812,15897498,5736189,15026997,-2178256,-13455585 },
+ },
+},
+{
+ {
+  { -8858980,-2219056,28571666,-10155518,-474467,-10105698,-3801496,278095,23440562,-290208 },
+  { 10226241,-5928702,15139956,120818,-14867693,5218603,32937275,11551483,-16571960,-7442864 },
+  { 17932739,-12437276,-24039557,10749060,11316803,7535897,22503767,5561594,-3646624,3898661 },
+ },
+ {
+  { 7749907,-969567,-16339731,-16464,-25018111,15122143,-1573531,7152530,21831162,1245233 },
+  { 26958459,-14658026,4314586,8346991,-5677764,11960072,-32589295,-620035,-30402091,-16716212 },
+  { -12165896,9166947,33491384,13673479,29787085,13096535,6280834,14587357,-22338025,13987525 },
+ },
+ {
+  { -24349909,7778775,21116000,15572597,-4833266,-5357778,-4300898,-5124639,-7469781,-2858068 },
+  { 9681908,-6737123,-31951644,13591838,-6883821,386950,31622781,6439245,-14581012,4091397 },
+  { -8426427,1470727,-28109679,-1596990,3978627,-5123623,-19622683,12092163,29077877,-14741988 },
+ },
+ {
+  { 5269168,-6859726,-13230211,-8020715,25932563,1763552,-5606110,-5505881,-20017847,2357889 },
+  { 32264008,-15407652,-5387735,-1160093,-2091322,-3946900,23104804,-12869908,5727338,189038 },
+  { 14609123,-8954470,-6000566,-16622781,-14577387,-7743898,-26745169,10942115,-25888931,-14884697 },
+ },
+ {
+  { 20513500,5557931,-15604613,7829531,26413943,-2019404,-21378968,7471781,13913677,-5137875 },
+  { -25574376,11967826,29233242,12948236,-6754465,4713227,-8940970,14059180,12878652,8511905 },
+  { -25656801,3393631,-2955415,-7075526,-2250709,9366908,-30223418,6812974,5568676,-3127656 },
+ },
+ {
+  { 11630004,12144454,2116339,13606037,27378885,15676917,-17408753,-13504373,-14395196,8070818 },
+  { 27117696,-10007378,-31282771,-5570088,1127282,12772488,-29845906,10483306,-11552749,-1028714 },
+  { 10637467,-5688064,5674781,1072708,-26343588,-6982302,-1683975,9177853,-27493162,15431203 },
+ },
+ {
+  { 20525145,10892566,-12742472,12779443,-29493034,16150075,-28240519,14943142,-15056790,-7935931 },
+  { -30024462,5626926,-551567,-9981087,753598,11981191,25244767,-3239766,-3356550,9594024 },
+  { -23752644,2636870,-5163910,-10103818,585134,7877383,11345683,-6492290,13352335,-10977084 },
+ },
+ {
+  { -1931799,-5407458,3304649,-12884869,17015806,-4877091,-29783850,-7752482,-13215537,-319204 },
+  { 20239939,6607058,6203985,3483793,-18386976,-779229,-20723742,15077870,-22750759,14523817 },
+  { 27406042,-6041657,27423596,-4497394,4996214,10002360,-28842031,-4545494,-30172742,-4805667 },
+ },
+},
+{
+ {
+  { 11374242,12660715,17861383,-12540833,10935568,1099227,-13886076,-9091740,-27727044,11358504 },
+  { -12730809,10311867,1510375,10778093,-2119455,-9145702,32676003,11149336,-26123651,4985768 },
+  { -19096303,341147,-6197485,-239033,15756973,-8796662,-983043,13794114,-19414307,-15621255 },
+ },
+ {
+  { 6490081,11940286,25495923,-7726360,8668373,-8751316,3367603,6970005,-1691065,-9004790 },
+  { 1656497,13457317,15370807,6364910,13605745,8362338,-19174622,-5475723,-16796596,-5031438 },
+  { -22273315,-13524424,-64685,-4334223,-18605636,-10921968,-20571065,-7007978,-99853,-10237333 },
+ },
+ {
+  { 17747465,10039260,19368299,-4050591,-20630635,-16041286,31992683,-15857976,-29260363,-5511971 },
+  { 31932027,-4986141,-19612382,16366580,22023614,88450,11371999,-3744247,4882242,-10626905 },
+  { 29796507,37186,19818052,10115756,-11829032,3352736,18551198,3272828,-5190932,-4162409 },
+ },
+ {
+  { 12501286,4044383,-8612957,-13392385,-32430052,5136599,-19230378,-3529697,330070,-3659409 },
+  { 6384877,2899513,17807477,7663917,-2358888,12363165,25366522,-8573892,-271295,12071499 },
+  { -8365515,-4042521,25133448,-4517355,-6211027,2265927,-32769618,1936675,-5159697,3829363 },
+ },
+ {
+  { 28425966,-5835433,-577090,-4697198,-14217555,6870930,7921550,-6567787,26333140,14267664 },
+  { -11067219,11871231,27385719,-10559544,-4585914,-11189312,10004786,-8709488,-21761224,8930324 },
+  { -21197785,-16396035,25654216,-1725397,12282012,11008919,1541940,4757911,-26491501,-16408940 },
+ },
+ {
+  { 13537262,-7759490,-20604840,10961927,-5922820,-13218065,-13156584,6217254,-15943699,13814990 },
+  { -17422573,15157790,18705543,29619,24409717,-260476,27361681,9257833,-1956526,-1776914 },
+  { -25045300,-10191966,15366585,15166509,-13105086,8423556,-29171540,12361135,-18685978,4578290 },
+ },
+ {
+  { 24579768,3711570,1342322,-11180126,-27005135,14124956,-22544529,14074919,21964432,8235257 },
+  { -6528613,-2411497,9442966,-5925588,12025640,-1487420,-2981514,-1669206,13006806,2355433 },
+  { -16304899,-13605259,-6632427,-5142349,16974359,-10911083,27202044,1719366,1141648,-12796236 },
+ },
+ {
+  { -12863944,-13219986,-8318266,-11018091,-6810145,-4843894,13475066,-3133972,32674895,13715045 },
+  { 11423335,-5468059,32344216,8962751,24989809,9241752,-13265253,16086212,-28740881,-15642093 },
+  { -1409668,12530728,-6368726,10847387,19531186,-14132160,-11709148,7791794,-27245943,4383347 },
+ },
+},
+{
+ {
+  { -28970898,5271447,-1266009,-9736989,-12455236,16732599,-4862407,-4906449,27193557,6245191 },
+  { -15193956,5362278,-1783893,2695834,4960227,12840725,23061898,3260492,22510453,8577507 },
+  { -12632451,11257346,-32692994,13548177,-721004,10879011,31168030,13952092,-29571492,-3635906 },
+ },
+ {
+  { 3877321,-9572739,32416692,5405324,-11004407,-13656635,3759769,11935320,5611860,8164018 },
+  { -16275802,14667797,15906460,12155291,-22111149,-9039718,32003002,-8832289,5773085,-8422109 },
+  { -23788118,-8254300,1950875,8937633,18686727,16459170,-905725,12376320,31632953,190926 },
+ },
+ {
+  { -24593607,-16138885,-8423991,13378746,14162407,6901328,-8288749,4508564,-25341555,-3627528 },
+  { 8884438,-5884009,6023974,10104341,-6881569,-4941533,18722941,-14786005,-1672488,827625 },
+  { -32720583,-16289296,-32503547,7101210,13354605,2659080,-1800575,-14108036,-24878478,1541286 },
+ },
+ {
+  { 2901347,-1117687,3880376,-10059388,-17620940,-3612781,-21802117,-3567481,20456845,-1885033 },
+  { 27019610,12299467,-13658288,-1603234,-12861660,-4861471,-19540150,-5016058,29439641,15138866 },
+  { 21536104,-6626420,-32447818,-10690208,-22408077,5175814,-5420040,-16361163,7779328,109896 },
+ },
+ {
+  { 30279744,14648750,-8044871,6425558,13639621,-743509,28698390,12180118,23177719,-554075 },
+  { 26572847,3405927,-31701700,12890905,-19265668,5335866,-6493768,2378492,4439158,-13279347 },
+  { -22716706,3489070,-9225266,-332753,18875722,-1140095,14819434,-12731527,-17717757,-5461437 },
+ },
+ {
+  { -5056483,16566551,15953661,3767752,-10436499,15627060,-820954,2177225,8550082,-15114165 },
+  { -18473302,16596775,-381660,15663611,22860960,15585581,-27844109,-3582739,-23260460,-8428588 },
+  { -32480551,15707275,-8205912,-5652081,29464558,2713815,-22725137,15860482,-21902570,1494193 },
+ },
+ {
+  { -19562091,-14087393,-25583872,-9299552,13127842,759709,21923482,16529112,8742704,12967017 },
+  { -28464899,1553205,32536856,-10473729,-24691605,-406174,-8914625,-2933896,-29903758,15553883 },
+  { 21877909,3230008,9881174,10539357,-4797115,2841332,11543572,14513274,19375923,-12647961 },
+ },
+ {
+  { 8832269,-14495485,13253511,5137575,5037871,4078777,24880818,-6222716,2862653,9455043 },
+  { 29306751,5123106,20245049,-14149889,9592566,8447059,-2077124,-2990080,15511449,4789663 },
+  { -20679756,7004547,8824831,-9434977,-4045704,-3750736,-5754762,108893,23513200,16652362 },
+ },
+},
+{
+ {
+  { -33256173,4144782,-4476029,-6579123,10770039,-7155542,-6650416,-12936300,-18319198,10212860 },
+  { 2756081,8598110,7383731,-6859892,22312759,-1105012,21179801,2600940,-9988298,-12506466 },
+  { -24645692,13317462,-30449259,-15653928,21365574,-10869657,11344424,864440,-2499677,-16710063 },
+ },
+ {
+  { -26432803,6148329,-17184412,-14474154,18782929,-275997,-22561534,211300,2719757,4940997 },
+  { -1323882,3911313,-6948744,14759765,-30027150,7851207,21690126,8518463,26699843,5276295 },
+  { -13149873,-6429067,9396249,365013,24703301,-10488939,1321586,149635,-15452774,7159369 },
+ },
+ {
+  { 9987780,-3404759,17507962,9505530,9731535,-2165514,22356009,8312176,22477218,-8403385 },
+  { 18155857,-16504990,19744716,9006923,15154154,-10538976,24256460,-4864995,-22548173,9334109 },
+  { 2986088,-4911893,10776628,-3473844,10620590,-7083203,-21413845,14253545,-22587149,536906 },
+ },
+ {
+  { 4377756,8115836,24567078,15495314,11625074,13064599,7390551,10589625,10838060,-15420424 },
+  { -19342404,867880,9277171,-3218459,-14431572,-1986443,19295826,-15796950,6378260,699185 },
+  { 7895026,4057113,-7081772,-13077756,-17886831,-323126,-716039,15693155,-5045064,-13373962 },
+ },
+ {
+  { -7737563,-5869402,-14566319,-7406919,11385654,13201616,31730678,-10962840,-3918636,-9669325 },
+  { 10188286,-15770834,-7336361,13427543,22223443,14896287,30743455,7116568,-21786507,5427593 },
+  { 696102,13206899,27047647,-10632082,15285305,-9853179,10798490,-4578720,19236243,12477404 },
+ },
+ {
+  { -11229439,11243796,-17054270,-8040865,-788228,-8167967,-3897669,11180504,-23169516,7733644 },
+  { 17800790,-14036179,-27000429,-11766671,23887827,3149671,23466177,-10538171,10322027,15313801 },
+  { 26246234,11968874,32263343,-5468728,6830755,-13323031,-15794704,-101982,-24449242,10890804 },
+ },
+ {
+  { -31365647,10271363,-12660625,-6267268,16690207,-13062544,-14982212,16484931,25180797,-5334884 },
+  { -586574,10376444,-32586414,-11286356,19801893,10997610,2276632,9482883,316878,13820577 },
+  { -9882808,-4510367,-2115506,16457136,-11100081,11674996,30756178,-7515054,30696930,-3712849 },
+ },
+ {
+  { 32988917,-9603412,12499366,7910787,-10617257,-11931514,-7342816,-9985397,-32349517,7392473 },
+  { -8855661,15927861,9866406,-3649411,-2396914,-16655781,-30409476,-9134995,25112947,-2926644 },
+  { -2504044,-436966,25621774,-5678772,15085042,-5479877,-24884878,-13526194,5537438,-13914319 },
+ },
+},
+{
+ {
+  { -11225584,2320285,-9584280,10149187,-33444663,5808648,-14876251,-1729667,31234590,6090599 },
+  { -9633316,116426,26083934,2897444,-6364437,-2688086,609721,15878753,-6970405,-9034768 },
+  { -27757857,247744,-15194774,-9002551,23288161,-10011936,-23869595,6503646,20650474,1804084 },
+ },
+ {
+  { -27589786,15456424,8972517,8469608,15640622,4439847,3121995,-10329713,27842616,-202328 },
+  { -15306973,2839644,22530074,10026331,4602058,5048462,28248656,5031932,-11375082,12714369 },
+  { 20807691,-7270825,29286141,11421711,-27876523,-13868230,-21227475,1035546,-19733229,12796920 },
+ },
+ {
+  { 12076899,-14301286,-8785001,-11848922,-25012791,16400684,-17591495,-12899438,3480665,-15182815 },
+  { -32361549,5457597,28548107,7833186,7303070,-11953545,-24363064,-15921875,-33374054,2771025 },
+  { -21389266,421932,26597266,6860826,22486084,-6737172,-17137485,-4210226,-24552282,15673397 },
+ },
+ {
+  { -20184622,2338216,19788685,-9620956,-4001265,-8740893,-20271184,4733254,3727144,-12934448 },
+  { 6120119,814863,-11794402,-622716,6812205,-15747771,2019594,7975683,31123697,-10958981 },
+  { 30069250,-11435332,30434654,2958439,18399564,-976289,12296869,9204260,-16432438,9648165 },
+ },
+ {
+  { 32705432,-1550977,30705658,7451065,-11805606,9631813,3305266,5248604,-26008332,-11377501 },
+  { 17219865,2375039,-31570947,-5575615,-19459679,9219903,294711,15298639,2662509,-16297073 },
+  { -1172927,-7558695,-4366770,-4287744,-21346413,-8434326,32087529,-1222777,32247248,-14389861 },
+ },
+ {
+  { 14312628,1221556,17395390,-8700143,-4945741,-8684635,-28197744,-9637817,-16027623,-13378845 },
+  { -1428825,-9678990,-9235681,6549687,-7383069,-468664,23046502,9803137,17597934,2346211 },
+  { 18510800,15337574,26171504,981392,-22241552,7827556,-23491134,-11323352,3059833,-11782870 },
+ },
+ {
+  { 10141598,6082907,17829293,-1947643,9830092,13613136,-25556636,-5544586,-33502212,3592096 },
+  { 33114168,-15889352,-26525686,-13343397,33076705,8716171,1151462,1521897,-982665,-6837803 },
+  { -32939165,-4255815,23947181,-324178,-33072974,-12305637,-16637686,3891704,26353178,693168 },
+ },
+ {
+  { 30374239,1595580,-16884039,13186931,4600344,406904,9585294,-400668,31375464,14369965 },
+  { -14370654,-7772529,1510301,6434173,-18784789,-6262728,32732230,-13108839,17901441,16011505 },
+  { 18171223,-11934626,-12500402,15197122,-11038147,-15230035,-19172240,-16046376,8764035,12309598 },
+ },
+},
+{
+ {
+  { 5975908,-5243188,-19459362,-9681747,-11541277,14015782,-23665757,1228319,17544096,-10593782 },
+  { 5811932,-1715293,3442887,-2269310,-18367348,-8359541,-18044043,-15410127,-5565381,12348900 },
+  { -31399660,11407555,25755363,6891399,-3256938,14872274,-24849353,8141295,-10632534,-585479 },
+ },
+ {
+  { -12675304,694026,-5076145,13300344,14015258,-14451394,-9698672,-11329050,30944593,1130208 },
+  { 8247766,-6710942,-26562381,-7709309,-14401939,-14648910,4652152,2488540,23550156,-271232 },
+  { 17294316,-3788438,7026748,15626851,22990044,113481,2267737,-5908146,-408818,-137719 },
+ },
+ {
+  { 16091085,-16253926,18599252,7340678,2137637,-1221657,-3364161,14550936,3260525,-7166271 },
+  { -4910104,-13332887,18550887,10864893,-16459325,-7291596,-23028869,-13204905,-12748722,2701326 },
+  { -8574695,16099415,4629974,-16340524,-20786213,-6005432,-10018363,9276971,11329923,1862132 },
+ },
+ {
+  { 14763076,-15903608,-30918270,3689867,3511892,10313526,-21951088,12219231,-9037963,-940300 },
+  { 8894987,-3446094,6150753,3013931,301220,15693451,-31981216,-2909717,-15438168,11595570 },
+  { 15214962,3537601,-26238722,-14058872,4418657,-15230761,13947276,10730794,-13489462,-4363670 },
+ },
+ {
+  { -2538306,7682793,32759013,263109,-29984731,-7955452,-22332124,-10188635,977108,699994 },
+  { -12466472,4195084,-9211532,550904,-15565337,12917920,19118110,-439841,-30534533,-14337913 },
+  { 31788461,-14507657,4799989,7372237,8808585,-14747943,9408237,-10051775,12493932,-5409317 },
+ },
+ {
+  { -25680606,5260744,-19235809,-6284470,-3695942,16566087,27218280,2607121,29375955,6024730 },
+  { 842132,-2794693,-4763381,-8722815,26332018,-12405641,11831880,6985184,-9940361,2854096 },
+  { -4847262,-7969331,2516242,-5847713,9695691,-7221186,16512645,960770,12121869,16648078 },
+ },
+ {
+  { -15218652,14667096,-13336229,2013717,30598287,-464137,-31504922,-7882064,20237806,2838411 },
+  { -19288047,4453152,15298546,-16178388,22115043,-15972604,12544294,-13470457,1068881,-12499905 },
+  { -9558883,-16518835,33238498,13506958,30505848,-1114596,-8486907,-2630053,12521378,4845654 },
+ },
+ {
+  { -28198521,10744108,-2958380,10199664,7759311,-13088600,3409348,-873400,-6482306,-12885870 },
+  { -23561822,6230156,-20382013,10655314,-24040585,-11621172,10477734,-1240216,-3113227,13974498 },
+  { 12966261,15550616,-32038948,-1615346,21025980,-629444,5642325,7188737,18895762,12629579 },
+ },
+},
+{
+ {
+  { 14741879,-14946887,22177208,-11721237,1279741,8058600,11758140,789443,32195181,3895677 },
+  { 10758205,15755439,-4509950,9243698,-4879422,6879879,-2204575,-3566119,-8982069,4429647 },
+  { -2453894,15725973,-20436342,-10410672,-5803908,-11040220,-7135870,-11642895,18047436,-15281743 },
+ },
+ {
+  { -25173001,-11307165,29759956,11776784,-22262383,-15820455,10993114,-12850837,-17620701,-9408468 },
+  { 21987233,700364,-24505048,14972008,-7774265,-5718395,32155026,2581431,-29958985,8773375 },
+  { -25568350,454463,-13211935,16126715,25240068,8594567,20656846,12017935,-7874389,-13920155 },
+ },
+ {
+  { 6028182,6263078,-31011806,-11301710,-818919,2461772,-31841174,-5468042,-1721788,-2776725 },
+  { -12278994,16624277,987579,-5922598,32908203,1248608,7719845,-4166698,28408820,6816612 },
+  { -10358094,-8237829,19549651,-12169222,22082623,16147817,20613181,13982702,-10339570,5067943 },
+ },
+ {
+  { -30505967,-3821767,12074681,13582412,-19877972,2443951,-19719286,12746132,5331210,-10105944 },
+  { 30528811,3601899,-1957090,4619785,-27361822,-15436388,24180793,-12570394,27679908,-1648928 },
+  { 9402404,-13957065,32834043,10838634,-26580150,-13237195,26653274,-8685565,22611444,-12715406 },
+ },
+ {
+  { 22190590,1118029,22736441,15130463,-30460692,-5991321,19189625,-4648942,4854859,6622139 },
+  { -8310738,-2953450,-8262579,-3388049,-10401731,-271929,13424426,-3567227,26404409,13001963 },
+  { -31241838,-15415700,-2994250,8939346,11562230,-12840670,-26064365,-11621720,-15405155,11020693 },
+ },
+ {
+  { 1866042,-7949489,-7898649,-10301010,12483315,13477547,3175636,-12424163,28761762,1406734 },
+  { -448555,-1777666,13018551,3194501,-9580420,-11161737,24760585,-4347088,25577411,-13378680 },
+  { -24290378,4759345,-690653,-1852816,2066747,10693769,-29595790,9884936,-9368926,4745410 },
+ },
+ {
+  { -9141284,6049714,-19531061,-4341411,-31260798,9944276,-15462008,-11311852,10931924,-11931931 },
+  { -16561513,14112680,-8012645,4817318,-8040464,-11414606,-22853429,10856641,-20470770,13434654 },
+  { 22759489,-10073434,-16766264,-1871422,13637442,-10168091,1765144,-12654326,28445307,-5364710 },
+ },
+ {
+  { 29875063,12493613,2795536,-3786330,1710620,15181182,-10195717,-8788675,9074234,1167180 },
+  { -26205683,11014233,-9842651,-2635485,-26908120,7532294,-18716888,-9535498,3843903,9367684 },
+  { -10969595,-6403711,9591134,9582310,11349256,108879,16235123,8601684,-139197,4242895 },
+ },
+},
+{
+ {
+  { 22092954,-13191123,-2042793,-11968512,32186753,-11517388,-6574341,2470660,-27417366,16625501 },
+  { -11057722,3042016,13770083,-9257922,584236,-544855,-7770857,2602725,-27351616,14247413 },
+  { 6314175,-10264892,-32772502,15957557,-10157730,168750,-8618807,14290061,27108877,-1180880 },
+ },
+ {
+  { -8586597,-7170966,13241782,10960156,-32991015,-13794596,33547976,-11058889,-27148451,981874 },
+  { 22833440,9293594,-32649448,-13618667,-9136966,14756819,-22928859,-13970780,-10479804,-16197962 },
+  { -7768587,3326786,-28111797,10783824,19178761,14905060,22680049,13906969,-15933690,3797899 },
+ },
+ {
+  { 21721356,-4212746,-12206123,9310182,-3882239,-13653110,23740224,-2709232,20491983,-8042152 },
+  { 9209270,-15135055,-13256557,-6167798,-731016,15289673,25947805,15286587,30997318,-6703063 },
+  { 7392032,16618386,23946583,-8039892,-13265164,-1533858,-14197445,-2321576,17649998,-250080 },
+ },
+ {
+  { -9301088,-14193827,30609526,-3049543,-25175069,-1283752,-15241566,-9525724,-2233253,7662146 },
+  { -17558673,1763594,-33114336,15908610,-30040870,-12174295,7335080,-8472199,-3174674,3440183 },
+  { -19889700,-5977008,-24111293,-9688870,10799743,-16571957,40450,-4431835,4862400,1133 },
+ },
+ {
+  { -32856209,-7873957,-5422389,14860950,-16319031,7956142,7258061,311861,-30594991,-7379421 },
+  { -3773428,-1565936,28985340,7499440,24445838,9325937,29727763,16527196,18278453,15405622 },
+  { -4381906,8508652,-19898366,-3674424,-5984453,15149970,-13313598,843523,-21875062,13626197 },
+ },
+ {
+  { 2281448,-13487055,-10915418,-2609910,1879358,16164207,-10783882,3953792,13340839,15928663 },
+  { 31727126,-7179855,-18437503,-8283652,2875793,-16390330,-25269894,-7014826,-23452306,5964753 },
+  { 4100420,-5959452,-17179337,6017714,-18705837,12227141,-26684835,11344144,2538215,-7570755 },
+ },
+ {
+  { -9433605,6123113,11159803,-2156608,30016280,14966241,-20474983,1485421,-629256,-15958862 },
+  { -26804558,4260919,11851389,9658551,-32017107,16367492,-20205425,-13191288,11659922,-11115118 },
+  { 26180396,10015009,-30844224,-8581293,5418197,9480663,2231568,-10170080,33100372,-1306171 },
+ },
+ {
+  { 15121113,-5201871,-10389905,15427821,-27509937,-15992507,21670947,4486675,-5931810,-14466380 },
+  { 16166486,-9483733,-11104130,6023908,-31926798,-1364923,2340060,-16254968,-10735770,-10039824 },
+  { 28042865,-3557089,-12126526,12259706,-3717498,-6945899,6766453,-8689599,18036436,5803270 },
+ },
+},
+{
+ {
+  { -817581,6763912,11803561,1585585,10958447,-2671165,23855391,4598332,-6159431,-14117438 },
+  { -31031306,-14256194,17332029,-2383520,31312682,-5967183,696309,50292,-20095739,11763584 },
+  { -594563,-2514283,-32234153,12643980,12650761,14811489,665117,-12613632,-19773211,-10713562 },
+ },
+ {
+  { 30464590,-11262872,-4127476,-12734478,19835327,-7105613,-24396175,2075773,-17020157,992471 },
+  { 18357185,-6994433,7766382,16342475,-29324918,411174,14578841,8080033,-11574335,-10601610 },
+  { 19598397,10334610,12555054,2555664,18821899,-10339780,21873263,16014234,26224780,16452269 },
+ },
+ {
+  { -30223925,5145196,5944548,16385966,3976735,2009897,-11377804,-7618186,-20533829,3698650 },
+  { 14187449,3448569,-10636236,-10810935,-22663880,-3433596,7268410,-10890444,27394301,12015369 },
+  { 19695761,16087646,28032085,12999827,6817792,11427614,20244189,-1312777,-13259127,-3402461 },
+ },
+ {
+  { 30860103,12735208,-1888245,-4699734,-16974906,2256940,-8166013,12298312,-8550524,-10393462 },
+  { -5719826,-11245325,-1910649,15569035,26642876,-7587760,-5789354,-15118654,-4976164,12651793 },
+  { -2848395,9953421,11531313,-5282879,26895123,-12697089,-13118820,-16517902,9768698,-2533218 },
+ },
+ {
+  { -24719459,1894651,-287698,-4704085,15348719,-8156530,32767513,12765450,4940095,10678226 },
+  { 18860224,15980149,-18987240,-1562570,-26233012,-11071856,-7843882,13944024,-24372348,16582019 },
+  { -15504260,4970268,-29893044,4175593,-20993212,-2199756,-11704054,15444560,-11003761,7989037 },
+ },
+ {
+  { 31490452,5568061,-2412803,2182383,-32336847,4531686,-32078269,6200206,-19686113,-14800171 },
+  { -17308668,-15879940,-31522777,-2831,-32887382,16375549,8680158,-16371713,28550068,-6857132 },
+  { -28126887,-5688091,16837845,-1820458,-6850681,12700016,-30039981,4364038,1155602,5988841 },
+ },
+ {
+  { 21890435,-13272907,-12624011,12154349,-7831873,15300496,23148983,-4470481,24618407,8283181 },
+  { -33136107,-10512751,9975416,6841041,-31559793,16356536,3070187,-7025928,1466169,10740210 },
+  { -1509399,-15488185,-13503385,-10655916,32799044,909394,-13938903,-5779719,-32164649,-15327040 },
+ },
+ {
+  { 3960823,-14267803,-28026090,-15918051,-19404858,13146868,15567327,951507,-3260321,-573935 },
+  { 24740841,5052253,-30094131,8961361,25877428,6165135,-24368180,14397372,-7380369,-6144105 },
+  { -28888365,3510803,-28103278,-1158478,-11238128,-10631454,-15441463,-14453128,-1625486,-6494814 },
+ },
+},
+{
+ {
+  { 793299,-9230478,8836302,-6235707,-27360908,-2369593,33152843,-4885251,-9906200,-621852 },
+  { 5666233,525582,20782575,-8038419,-24538499,14657740,16099374,1468826,-6171428,-15186581 },
+  { -4859255,-3779343,-2917758,-6748019,7778750,11688288,-30404353,-9871238,-1558923,-9863646 },
+ },
+ {
+  { 10896332,-7719704,824275,472601,-19460308,3009587,25248958,14783338,-30581476,-15757844 },
+  { 10566929,12612572,-31944212,11118703,-12633376,12362879,21752402,8822496,24003793,14264025 },
+  { 27713862,-7355973,-11008240,9227530,27050101,2504721,23886875,-13117525,13958495,-5732453 },
+ },
+ {
+  { -23481610,4867226,-27247128,3900521,29838369,-8212291,-31889399,-10041781,7340521,-15410068 },
+  { 4646514,-8011124,-22766023,-11532654,23184553,8566613,31366726,-1381061,-15066784,-10375192 },
+  { -17270517,12723032,-16993061,14878794,21619651,-6197576,27584817,3093888,-8843694,3849921 },
+ },
+ {
+  { -9064912,2103172,25561640,-15125738,-5239824,9582958,32477045,-9017955,5002294,-15550259 },
+  { -12057553,-11177906,21115585,-13365155,8808712,-12030708,16489530,13378448,-25845716,12741426 },
+  { -5946367,10645103,-30911586,15390284,-3286982,-7118677,24306472,15852464,28834118,-7646072 },
+ },
+ {
+  { -17335748,-9107057,-24531279,9434953,-8472084,-583362,-13090771,455841,20461858,5491305 },
+  { 13669248,-16095482,-12481974,-10203039,-14569770,-11893198,-24995986,11293807,-28588204,-9421832 },
+  { 28497928,6272777,-33022994,14470570,8906179,-1225630,18504674,-14165166,29867745,-8795943 },
+ },
+ {
+  { -16207023,13517196,-27799630,-13697798,24009064,-6373891,-6367600,-13175392,22853429,-4012011 },
+  { 24191378,16712145,-13931797,15217831,14542237,1646131,18603514,-11037887,12876623,-2112447 },
+  { 17902668,4518229,-411702,-2829247,26878217,5258055,-12860753,608397,16031844,3723494 },
+ },
+ {
+  { -28632773,12763728,-20446446,7577504,33001348,-13017745,17558842,-7872890,23896954,-4314245 },
+  { -20005381,-12011952,31520464,605201,2543521,5991821,-2945064,7229064,-9919646,-8826859 },
+  { 28816045,298879,-28165016,-15920938,19000928,-1665890,-12680833,-2949325,-18051778,-2082915 },
+ },
+ {
+  { 16000882,-344896,3493092,-11447198,-29504595,-13159789,12577740,16041268,-19715240,7847707 },
+  { 10151868,10572098,27312476,7922682,14825339,4723128,-32855931,-6519018,-10020567,3852848 },
+  { -11430470,15697596,-21121557,-4420647,5386314,15063598,16514493,-15932110,29330899,-15076224 },
+ },
+},
+{
+ {
+  { -25499735,-4378794,-15222908,-6901211,16615731,2051784,3303702,15490,-27548796,12314391 },
+  { 15683520,-6003043,18109120,-9980648,15337968,-5997823,-16717435,15921866,16103996,-3731215 },
+  { -23169824,-10781249,13588192,-1628807,-3798557,-1074929,-19273607,5402699,-29815713,-9841101 },
+ },
+ {
+  { 23190676,2384583,-32714340,3462154,-29903655,-1529132,-11266856,8911517,-25205859,2739713 },
+  { 21374101,-3554250,-33524649,9874411,15377179,11831242,-33529904,6134907,4931255,11987849 },
+  { -7732,-2978858,-16223486,7277597,105524,-322051,-31480539,13861388,-30076310,10117930 },
+ },
+ {
+  { -29501170,-10744872,-26163768,13051539,-25625564,5089643,-6325503,6704079,12890019,15728940 },
+  { -21972360,-11771379,-951059,-4418840,14704840,2695116,903376,-10428139,12885167,8311031 },
+  { -17516482,5352194,10384213,-13811658,7506451,13453191,26423267,4384730,1888765,-5435404 },
+ },
+ {
+  { -25817338,-3107312,-13494599,-3182506,30896459,-13921729,-32251644,-12707869,-19464434,-3340243 },
+  { -23607977,-2665774,-526091,4651136,5765089,4618330,6092245,14845197,17151279,-9854116 },
+  { -24830458,-12733720,-15165978,10367250,-29530908,-265356,22825805,-7087279,-16866484,16176525 },
+ },
+ {
+  { -23583256,6564961,20063689,3798228,-4740178,7359225,2006182,-10363426,-28746253,-10197509 },
+  { -10626600,-4486402,-13320562,-5125317,3432136,-6393229,23632037,-1940610,32808310,1099883 },
+  { 15030977,5768825,-27451236,-2887299,-6427378,-15361371,-15277896,-6809350,2051441,-15225865 },
+ },
+ {
+  { -3362323,-7239372,7517890,9824992,23555850,295369,5148398,-14154188,-22686354,16633660 },
+  { 4577086,-16752288,13249841,-15304328,19958763,-14537274,18559670,-10759549,8402478,-9864273 },
+  { -28406330,-1051581,-26790155,-907698,-17212414,-11030789,9453451,-14980072,17983010,9967138 },
+ },
+ {
+  { -25762494,6524722,26585488,9969270,24709298,1220360,-1677990,7806337,17507396,3651560 },
+  { -10420457,-4118111,14584639,15971087,-15768321,8861010,26556809,-5574557,-18553322,-11357135 },
+  { 2839101,14284142,4029895,3472686,14402957,12689363,-26642121,8459447,-5605463,-7621941 },
+ },
+ {
+  { -4839289,-3535444,9744961,2871048,25113978,3187018,-25110813,-849066,17258084,-7977739 },
+  { 18164541,-10595176,-17154882,-1542417,19237078,-9745295,23357533,-15217008,26908270,12150756 },
+  { -30264870,-7647865,5112249,-7036672,-1499807,-6974257,43168,-5537701,-32302074,16215819 },
+ },
+},
+{
+ {
+  { -6898905,9824394,-12304779,-4401089,-31397141,-6276835,32574489,12532905,-7503072,-8675347 },
+  { -27343522,-16515468,-27151524,-10722951,946346,16291093,254968,7168080,21676107,-1943028 },
+  { 21260961,-8424752,-16831886,-11920822,-23677961,3968121,-3651949,-6215466,-3556191,-7913075 },
+ },
+ {
+  { 16544754,13250366,-16804428,15546242,-4583003,12757258,-2462308,-8680336,-18907032,-9662799 },
+  { -2415239,-15577728,18312303,4964443,-15272530,-12653564,26820651,16690659,25459437,-4564609 },
+  { -25144690,11425020,28423002,-11020557,-6144921,-15826224,9142795,-2391602,-6432418,-1644817 },
+ },
+ {
+  { -23104652,6253476,16964147,-3768872,-25113972,-12296437,-27457225,-16344658,6335692,7249989 },
+  { -30333227,13979675,7503222,-12368314,-11956721,-4621693,-30272269,2682242,25993170,-12478523 },
+  { 4364628,5930691,32304656,-10044554,-8054781,15091131,22857016,-10598955,31820368,15075278 },
+ },
+ {
+  { 31879134,-8918693,17258761,90626,-8041836,-4917709,24162788,-9650886,-17970238,12833045 },
+  { 19073683,14851414,-24403169,-11860168,7625278,11091125,-19619190,2074449,-9413939,14905377 },
+  { 24483667,-11935567,-2518866,-11547418,-1553130,15355506,-25282080,9253129,27628530,-7555480 },
+ },
+ {
+  { 17597607,8340603,19355617,552187,26198470,-3176583,4593324,-9157582,-14110875,15297016 },
+  { 510886,14337390,-31785257,16638632,6328095,2713355,-20217417,-11864220,8683221,2921426 },
+  { 18606791,11874196,27155355,-5281482,-24031742,6265446,-25178240,-1278924,4674690,13890525 },
+ },
+ {
+  { 13609624,13069022,-27372361,-13055908,24360586,9592974,14977157,9835105,4389687,288396 },
+  { 9922506,-519394,13613107,5883594,-18758345,-434263,-12304062,8317628,23388070,16052080 },
+  { 12720016,11937594,-31970060,-5028689,26900120,8561328,-20155687,-11632979,-14754271,-10812892 },
+ },
+ {
+  { 15961858,14150409,26716931,-665832,-22794328,13603569,11829573,7467844,-28822128,929275 },
+  { 11038231,-11582396,-27310482,-7316562,-10498527,-16307831,-23479533,-9371869,-21393143,2465074 },
+  { 20017163,-4323226,27915242,1529148,12396362,15675764,13817261,-9658066,2463391,-4622140 },
+ },
+ {
+  { -16358878,-12663911,-12065183,4996454,-1256422,1073572,9583558,12851107,4003896,12673717 },
+  { -1731589,-15155870,-3262930,16143082,19294135,13385325,14741514,-9103726,7903886,2348101 },
+  { 24536016,-16515207,12715592,-3862155,1511293,10047386,-3842346,-7129159,-28377538,10048127 },
+ },
+},
+{
+ {
+  { -12622226,-6204820,30718825,2591312,-10617028,12192840,18873298,-7297090,-32297756,15221632 },
+  { -26478122,-11103864,11546244,-1852483,9180880,7656409,-21343950,2095755,29769758,6593415 },
+  { -31994208,-2907461,4176912,3264766,12538965,-868111,26312345,-6118678,30958054,8292160 },
+ },
+ {
+  { 31429822,-13959116,29173532,15632448,12174511,-2760094,32808831,3977186,26143136,-3148876 },
+  { 22648901,1402143,-22799984,13746059,7936347,365344,-8668633,-1674433,-3758243,-2304625 },
+  { -15491917,8012313,-2514730,-12702462,-23965846,-10254029,-1612713,-1535569,-16664475,8194478 },
+ },
+ {
+  { 27338066,-7507420,-7414224,10140405,-19026427,-6589889,27277191,8855376,28572286,3005164 },
+  { 26287124,4821776,25476601,-4145903,-3764513,-15788984,-18008582,1182479,-26094821,-13079595 },
+  { -7171154,3178080,23970071,6201893,-17195577,-4489192,-21876275,-13982627,32208683,-1198248 },
+ },
+ {
+  { -16657702,2817643,-10286362,14811298,6024667,13349505,-27315504,-10497842,-27672585,-11539858 },
+  { 15941029,-9405932,-21367050,8062055,31876073,-238629,-15278393,-1444429,15397331,-4130193 },
+  { 8934485,-13485467,-23286397,-13423241,-32446090,14047986,31170398,-1441021,-27505566,15087184 },
+ },
+ {
+  { -18357243,-2156491,24524913,-16677868,15520427,-6360776,-15502406,11461896,16788528,-5868942 },
+  { -1947386,16013773,21750665,3714552,-17401782,-16055433,-3770287,-10323320,31322514,-11615635 },
+  { 21426655,-5650218,-13648287,-5347537,-28812189,-4920970,-18275391,-14621414,13040862,-12112948 },
+ },
+ {
+  { 11293895,12478086,-27136401,15083750,-29307421,14748872,14555558,-13417103,1613711,4896935 },
+  { -25894883,15323294,-8489791,-8057900,25967126,-13425460,2825960,-4897045,-23971776,-11267415 },
+  { -15924766,-5229880,-17443532,6410664,3622847,10243618,20615400,12405433,-23753030,-8436416 },
+ },
+ {
+  { -7091295,12556208,-20191352,9025187,-17072479,4333801,4378436,2432030,23097949,-566018 },
+  { 4565804,-16025654,20084412,-7842817,1724999,189254,24767264,10103221,-18512313,2424778 },
+  { 366633,-11976806,8173090,-6890119,30788634,5745705,-7168678,1344109,-3642553,12412659 },
+ },
+ {
+  { -24001791,7690286,14929416,-168257,-32210835,-13412986,24162697,-15326504,-3141501,11179385 },
+  { 18289522,-14724954,8056945,16430056,-21729724,7842514,-6001441,-1486897,-18684645,-11443503 },
+  { 476239,6601091,-6152790,-9723375,17503545,-4863900,27672959,13403813,11052904,5219329 },
+ },
+},
+{
+ {
+  { 20678546,-8375738,-32671898,8849123,-5009758,14574752,31186971,-3973730,9014762,-8579056 },
+  { -13644050,-10350239,-15962508,5075808,-1514661,-11534600,-33102500,9160280,8473550,-3256838 },
+  { 24900749,14435722,17209120,-15292541,-22592275,9878983,-7689309,-16335821,-24568481,11788948 },
+ },
+ {
+  { -3118155,-11395194,-13802089,14797441,9652448,-6845904,-20037437,10410733,-24568470,-1458691 },
+  { -15659161,16736706,-22467150,10215878,-9097177,7563911,11871841,-12505194,-18513325,8464118 },
+  { -23400612,8348507,-14585951,-861714,-3950205,-6373419,14325289,8628612,33313881,-8370517 },
+ },
+ {
+  { -20186973,-4967935,22367356,5271547,-1097117,-4788838,-24805667,-10236854,-8940735,-5818269 },
+  { -6948785,-1795212,-32625683,-16021179,32635414,-7374245,15989197,-12838188,28358192,-4253904 },
+  { -23561781,-2799059,-32351682,-1661963,-9147719,10429267,-16637684,4072016,-5351664,5596589 },
+ },
+ {
+  { -28236598,-3390048,12312896,6213178,3117142,16078565,29266239,2557221,1768301,15373193 },
+  { -7243358,-3246960,-4593467,-7553353,-127927,-912245,-1090902,-4504991,-24660491,3442910 },
+  { -30210571,5124043,14181784,8197961,18964734,-11939093,22597931,7176455,-18585478,13365930 },
+ },
+ {
+  { -7877390,-1499958,8324673,4690079,6261860,890446,24538107,-8570186,-9689599,-3031667 },
+  { 25008904,-10771599,-4305031,-9638010,16265036,15721635,683793,-11823784,15723479,-15163481 },
+  { -9660625,12374379,-27006999,-7026148,-7724114,-12314514,11879682,5400171,519526,-1235876 },
+ },
+ {
+  { 22258397,-16332233,-7869817,14613016,-22520255,-2950923,-20353881,7315967,16648397,7605640 },
+  { -8081308,-8464597,-8223311,9719710,19259459,-15348212,23994942,-5281555,-9468848,4763278 },
+  { -21699244,9220969,-15730624,1084137,-25476107,-2852390,31088447,-7764523,-11356529,728112 },
+ },
+ {
+  { 26047220,-11751471,-6900323,-16521798,24092068,9158119,-4273545,-12555558,-29365436,-5498272 },
+  { 17510331,-322857,5854289,8403524,17133918,-3112612,-28111007,12327945,10750447,10014012 },
+  { -10312768,3936952,9156313,-8897683,16498692,-994647,-27481051,-666732,3424691,7540221 },
+ },
+ {
+  { 30322361,-6964110,11361005,-4143317,7433304,4989748,-7071422,-16317219,-9244265,15258046 },
+  { 13054562,-2779497,19155474,469045,-12482797,4566042,5631406,2711395,1062915,-5136345 },
+  { -19240248,-11254599,-29509029,-7499965,-5835763,13005411,-6066489,12194497,32960380,1459310 },
+ },
+},
+{
+ {
+  { 19852034,7027924,23669353,10020366,8586503,-6657907,394197,-6101885,18638003,-11174937 },
+  { 31395534,15098109,26581030,8030562,-16527914,-5007134,9012486,-7584354,-6643087,-5442636 },
+  { -9192165,-2347377,-1997099,4529534,25766844,607986,-13222,9677543,-32294889,-6456008 },
+ },
+ {
+  { -2444496,-149937,29348902,8186665,1873760,12489863,-30934579,-7839692,-7852844,-8138429 },
+  { -15236356,-15433509,7766470,746860,26346930,-10221762,-27333451,10754588,-9431476,5203576 },
+  { 31834314,14135496,-770007,5159118,20917671,-16768096,-7467973,-7337524,31809243,7347066 },
+ },
+ {
+  { -9606723,-11874240,20414459,13033986,13716524,-11691881,19797970,-12211255,15192876,-2087490 },
+  { -12663563,-2181719,1168162,-3804809,26747877,-14138091,10609330,12694420,33473243,-13382104 },
+  { 33184999,11180355,15832085,-11385430,-1633671,225884,15089336,-11023903,-6135662,14480053 },
+ },
+ {
+  { 31308717,-5619998,31030840,-1897099,15674547,-6582883,5496208,13685227,27595050,8737275 },
+  { -20318852,-15150239,10933843,-16178022,8335352,-7546022,-31008351,-12610604,26498114,66511 },
+  { 22644454,-8761729,-16671776,4884562,-3105614,-13559366,30540766,-4286747,-13327787,-7515095 },
+ },
+ {
+  { -28017847,9834845,18617207,-2681312,-3401956,-13307506,8205540,13585437,-17127465,15115439 },
+  { 23711543,-672915,31206561,-8362711,6164647,-9709987,-33535882,-1426096,8236921,16492939 },
+  { -23910559,-13515526,-26299483,-4503841,25005590,-7687270,19574902,10071562,6708380,-6222424 },
+ },
+ {
+  { 2101391,-4930054,19702731,2367575,-15427167,1047675,5301017,9328700,29955601,-11678310 },
+  { 3096359,9271816,-21620864,-15521844,-14847996,-7592937,-25892142,-12635595,-9917575,6216608 },
+  { -32615849,338663,-25195611,2510422,-29213566,-13820213,24822830,-6146567,-26767480,7525079 },
+ },
+ {
+  { -23066649,-13985623,16133487,-7896178,-3389565,778788,-910336,-2782495,-19386633,11994101 },
+  { 21691500,-13624626,-641331,-14367021,3285881,-3483596,-25064666,9718258,-7477437,13381418 },
+  { 18445390,-4202236,14979846,11622458,-1727110,-3582980,23111648,-6375247,28535282,15779576 },
+ },
+ {
+  { 30098053,3089662,-9234387,16662135,-21306940,11308411,-14068454,12021730,9955285,-16303356 },
+  { 9734894,-14576830,-7473633,-9138735,2060392,11313496,-18426029,9924399,20194861,13380996 },
+  { -26378102,-7965207,-22167821,15789297,-18055342,-6168792,-1984914,15707771,26342023,10146099 },
+ },
+},
+{
+ {
+  { -26016874,-219943,21339191,-41388,19745256,-2878700,-29637280,2227040,21612326,-545728 },
+  { -13077387,1184228,23562814,-5970442,-20351244,-6348714,25764461,12243797,-20856566,11649658 },
+  { -10031494,11262626,27384172,2271902,26947504,-15997771,39944,6114064,33514190,2333242 },
+ },
+ {
+  { -21433588,-12421821,8119782,7219913,-21830522,-9016134,-6679750,-12670638,24350578,-13450001 },
+  { -4116307,-11271533,-23886186,4843615,-30088339,690623,-31536088,-10406836,8317860,12352766 },
+  { 18200138,-14475911,-33087759,-2696619,-23702521,-9102511,-23552096,-2287550,20712163,6719373 },
+ },
+ {
+  { 26656208,6075253,-7858556,1886072,-28344043,4262326,11117530,-3763210,26224235,-3297458 },
+  { -17168938,-14854097,-3395676,-16369877,-19954045,14050420,21728352,9493610,18620611,-16428628 },
+  { -13323321,13325349,11432106,5964811,18609221,6062965,-5269471,-9725556,-30701573,-16479657 },
+ },
+ {
+  { -23860538,-11233159,26961357,1640861,-32413112,-16737940,12248509,-5240639,13735342,1934062 },
+  { 25089769,6742589,17081145,-13406266,21909293,-16067981,-15136294,-3765346,-21277997,5473616 },
+  { 31883677,-7961101,1083432,-11572403,22828471,13290673,-7125085,12469656,29111212,-5451014 },
+ },
+ {
+  { 24244947,-15050407,-26262976,2791540,-14997599,16666678,24367466,6388839,-10295587,452383 },
+  { -25640782,-3417841,5217916,16224624,19987036,-4082269,-24236251,-5915248,15766062,8407814 },
+  { -20406999,13990231,15495425,16395525,5377168,15166495,-8917023,-4388953,-8067909,2276718 },
+ },
+ {
+  { 30157918,12924066,-17712050,9245753,19895028,3368142,-23827587,5096219,22740376,-7303417 },
+  { 2041139,-14256350,7783687,13876377,-25946985,-13352459,24051124,13742383,-15637599,13295222 },
+  { 33338237,-8505733,12532113,7977527,9106186,-1715251,-17720195,-4612972,-4451357,-14669444 },
+ },
+ {
+  { -20045281,5454097,-14346548,6447146,28862071,1883651,-2469266,-4141880,7770569,9620597 },
+  { 23208068,7979712,33071466,8149229,1758231,-10834995,30945528,-1694323,-33502340,-14767970 },
+  { 1439958,-16270480,-1079989,-793782,4625402,10647766,-5043801,1220118,30494170,-11440799 },
+ },
+ {
+  { -5037580,-13028295,-2970559,-3061767,15640974,-6701666,-26739026,926050,-1684339,-13333647 },
+  { 13908495,-3549272,30919928,-6273825,-21521863,7989039,9021034,9078865,3353509,4033511 },
+  { -29663431,-15113610,32259991,-344482,24295849,-12912123,23161163,8839127,27485041,7356032 },
+ },
+},
+{
+ {
+  { 9661027,705443,11980065,-5370154,-1628543,14661173,-6346142,2625015,28431036,-16771834 },
+  { -23839233,-8311415,-25945511,7480958,-17681669,-8354183,-22545972,14150565,15970762,4099461 },
+  { 29262576,16756590,26350592,-8793563,8529671,-11208050,13617293,-9937143,11465739,8317062 },
+ },
+ {
+  { -25493081,-6962928,32500200,-9419051,-23038724,-2302222,14898637,3848455,20969334,-5157516 },
+  { -20384450,-14347713,-18336405,13884722,-33039454,2842114,-21610826,-3649888,11177095,14989547 },
+  { -24496721,-11716016,16959896,2278463,12066309,10137771,13515641,2581286,-28487508,9930240 },
+ },
+ {
+  { -17751622,-2097826,16544300,-13009300,-15914807,-14949081,18345767,-13403753,16291481,-5314038 },
+  { -33229194,2553288,32678213,9875984,8534129,6889387,-9676774,6957617,4368891,9788741 },
+  { 16660756,7281060,-10830758,12911820,20108584,-8101676,-21722536,-8613148,16250552,-11111103 },
+ },
+ {
+  { -19765507,2390526,-16551031,14161980,1905286,6414907,4689584,10604807,-30190403,4782747 },
+  { -1354539,14736941,-7367442,-13292886,7710542,-14155590,-9981571,4383045,22546403,437323 },
+  { 31665577,-12180464,-16186830,1491339,-18368625,3294682,27343084,2786261,-30633590,-14097016 },
+ },
+ {
+  { -14467279,-683715,-33374107,7448552,19294360,14334329,-19690631,2355319,-19284671,-6114373 },
+  { 15121312,-15796162,6377020,-6031361,-10798111,-12957845,18952177,15496498,-29380133,11754228 },
+  { -2637277,-13483075,8488727,-14303896,12728761,-1622493,7141596,11724556,22761615,-10134141 },
+ },
+ {
+  { 16918416,11729663,-18083579,3022987,-31015732,-13339659,-28741185,-12227393,32851222,11717399 },
+  { 11166634,7338049,-6722523,4531520,-29468672,-7302055,31474879,3483633,-1193175,-4030831 },
+  { -185635,9921305,31456609,-13536438,-12013818,13348923,33142652,6546660,-19985279,-3948376 },
+ },
+ {
+  { -32460596,11266712,-11197107,-7899103,31703694,3855903,-8537131,-12833048,-30772034,-15486313 },
+  { -18006477,12709068,3991746,-6479188,-21491523,-10550425,-31135347,-16049879,10928917,3011958 },
+  { -6957757,-15594337,31696059,334240,29576716,14796075,-30831056,-12805180,18008031,10258577 },
+ },
+ {
+  { -22448644,15655569,7018479,-4410003,-30314266,-1201591,-1853465,1367120,25127874,6671743 },
+  { 29701166,-14373934,-10878120,9279288,-17568,13127210,21382910,11042292,25838796,4642684 },
+  { -20430234,14955537,-24126347,8124619,-5369288,-5990470,30468147,-13900640,18423289,4177476 },
+ },
+},
+} ;
+
+
+static void ge_select(ge_precomp *t,int pos,signed char b)
+{
+  ge_precomp minust;
+  unsigned char bnegative = negative(b);
+  unsigned char babs = b - (((-bnegative) & b) << 1);
+
+  ge_precomp_0(t);
+  cmov(t,&base[pos][0],equal(babs,1));
+  cmov(t,&base[pos][1],equal(babs,2));
+  cmov(t,&base[pos][2],equal(babs,3));
+  cmov(t,&base[pos][3],equal(babs,4));
+  cmov(t,&base[pos][4],equal(babs,5));
+  cmov(t,&base[pos][5],equal(babs,6));
+  cmov(t,&base[pos][6],equal(babs,7));
+  cmov(t,&base[pos][7],equal(babs,8));
+  fe_copy(minust.yplusx,t->yminusx);
+  fe_copy(minust.yminusx,t->yplusx);
+  fe_neg(minust.xy2d,t->xy2d);
+  cmov(t,&minust,bnegative);
+}
+
+
+/*
+h = a * B
+where a = a[0]+256*a[1]+...+256^31 a[31]
+B is the Ed25519 base point (x,4/5) with x positive.
+
+Preconditions:
+  a[31] <= 127
+*/
+void ge_scalarmult_base(ge_p3 *h,const unsigned char *a)
+{
+  signed char e[64];
+  signed char carry;
+  ge_p1p1 r;
+  ge_p2 s;
+  ge_precomp t;
+  int i;
+
+  for (i = 0;i < 32;++i) {
+    e[2 * i + 0] = (a[i] >> 0) & 15;
+    e[2 * i + 1] = (a[i] >> 4) & 15;
+  }
+  /* each e[i] is between 0 and 15 */
+  /* e[63] is between 0 and 7 */
+
+  carry = 0;
+  for (i = 0;i < 63;++i) {
+    e[i] += carry;
+    carry = e[i] + 8;
+    carry >>= 4;
+    e[i] -= carry << 4;
+  }
+  e[63] += carry;
+  /* each e[i] is between -8 and 8 */
+
+  ge_p3_0(h);
+  for (i = 1;i < 64;i += 2) {
+    ge_select(&t,i / 2,e[i]);
+    ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r);
+  }
+
+  ge_p3_dbl(&r,h);  ge_p1p1_to_p2(&s,&r);
+  ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r);
+  ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r);
+  ge_p2_dbl(&r,&s); ge_p1p1_to_p3(h,&r);
+
+  for (i = 0;i < 64;i += 2) {
+    ge_select(&t,i / 2,e[i]);
+    ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r);
+  }
+}
+
+
+/* ge double scalar mult */
+static void slide(signed char *r,const unsigned char *a)
+{
+  int i;
+  int b;
+  int k;
+
+  for (i = 0;i < 256;++i)
+    r[i] = 1 & (a[i >> 3] >> (i & 7));
+
+  for (i = 0;i < 256;++i)
+    if (r[i]) {
+      for (b = 1;b <= 6 && i + b < 256;++b) {
+        if (r[i + b]) {
+          if (r[i] + (r[i + b] << b) <= 15) {
+            r[i] += r[i + b] << b; r[i + b] = 0;
+          } else if (r[i] - (r[i + b] << b) >= -15) {
+            r[i] -= r[i + b] << b;
+            for (k = i + b;k < 256;++k) {
+              if (!r[k]) {
+                r[k] = 1;
+                break;
+              }
+              r[k] = 0;
+            }
+          } else
+            break;
+        }
+      }
+    }
+}
+
+
+static ge_precomp Bi[8] = {
+ {
+  { 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 },
+  { -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 },
+  { -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 },
+ },
+ {
+  { 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 },
+  { 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 },
+  { 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 },
+ },
+ {
+  { 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 },
+  { 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 },
+  { 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 },
+ },
+ {
+  { 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 },
+  { -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 },
+  { 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 },
+ },
+ {
+  { -22518993,-6692182,14201702,-8745502,-23510406,8844726,18474211,-1361450,-13062696,13821877 },
+  { -6455177,-7839871,3374702,-4740862,-27098617,-10571707,31655028,-7212327,18853322,-14220951 },
+  { 4566830,-12963868,-28974889,-12240689,-7602672,-2830569,-8514358,-10431137,2207753,-3209784 },
+ },
+ {
+  { -25154831,-4185821,29681144,7868801,-6854661,-9423865,-12437364,-663000,-31111463,-16132436 },
+  { 25576264,-2703214,7349804,-11814844,16472782,9300885,3844789,15725684,171356,6466918 },
+  { 23103977,13316479,9739013,-16149481,817875,-15038942,8965339,-14088058,-30714912,16193877 },
+ },
+ {
+  { -33521811,3180713,-2394130,14003687,-16903474,-16270840,17238398,4729455,-18074513,9256800 },
+  { -25182317,-4174131,32336398,5036987,-21236817,11360617,22616405,9761698,-19827198,630305 },
+  { -13720693,2639453,-24237460,-7406481,9494427,-5774029,-6554551,-15960994,-2449256,-14291300 },
+ },
+ {
+  { -3151181,-5046075,9282714,6866145,-31907062,-863023,-18940575,15033784,25105118,-7894876 },
+  { -24326370,15950226,-31801215,-14592823,-11662737,-5090925,1573892,-2625887,2198790,-15804619 },
+  { -3099351,10324967,-2241613,7453183,-5446979,-2735503,-13812022,-16236442,-32461234,-12290683 },
+ },
+} ;
+
+
+/*
+r = a * A + b * B
+where a = a[0]+256*a[1]+...+256^31 a[31].
+and b = b[0]+256*b[1]+...+256^31 b[31].
+B is the Ed25519 base point (x,4/5) with x positive.
+*/
+int ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, 
+                                 const ge_p3 *A, const unsigned char *b)
+{
+  signed char aslide[256];
+  signed char bslide[256];
+  ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
+  ge_p1p1 t;
+  ge_p3 u;
+  ge_p3 A2;
+  int i;
+
+  slide(aslide,a);
+  slide(bslide,b);
+
+  ge_p3_to_cached(&Ai[0],A);
+  ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
+  ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u);
+  ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u);
+  ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u);
+  ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u);
+  ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u);
+  ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u);
+  ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u);
+
+  ge_p2_0(r);
+
+  for (i = 255;i >= 0;--i) {
+    if (aslide[i] || bslide[i]) break;
+  }
+
+  for (;i >= 0;--i) {
+    ge_p2_dbl(&t,r);
+
+    if (aslide[i] > 0) {
+      ge_p1p1_to_p3(&u,&t);
+      ge_add(&t,&u,&Ai[aslide[i]/2]);
+    } else if (aslide[i] < 0) {
+      ge_p1p1_to_p3(&u,&t);
+      ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
+    }
+
+    if (bslide[i] > 0) {
+      ge_p1p1_to_p3(&u,&t);
+      ge_madd(&t,&u,&Bi[bslide[i]/2]);
+    } else if (bslide[i] < 0) {
+      ge_p1p1_to_p3(&u,&t);
+      ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
+    }
+
+    ge_p1p1_to_p2(r,&t);
+  }
+
+  return 0;
+}
+
+
+static const fe d = {
+-10913610,13857413,-15372611,6949391,114729,
+-8787816,-6275908,-3247719,-18696448,-12055116
+} ;
+
+
+static const fe sqrtm1 = {
+-32595792,-7943725,9377950,3500415,12389472,
+-272473,-25146209,-2005654,326686,11406482
+} ;
+
+
+int ge_frombytes_negate_vartime(ge_p3 *h,const unsigned char *s)
+{
+  fe u;
+  fe v;
+  fe v3;
+  fe vxx;
+  fe check;
+
+  fe_frombytes(h->Y,s);
+  fe_1(h->Z);
+  fe_sq(u,h->Y);
+  fe_mul(v,u,d);
+  fe_sub(u,u,h->Z);       /* u = y^2-1 */
+  fe_add(v,v,h->Z);       /* v = dy^2+1 */
+
+
+  fe_sq(v3,v);
+  fe_mul(v3,v3,v);        /* v3 = v^3 */
+  fe_sq(h->X,v3);
+  fe_mul(h->X,h->X,v);
+  fe_mul(h->X,h->X,u);    /* x = uv^7 */
+
+  fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
+  fe_mul(h->X,h->X,v3);
+  fe_mul(h->X,h->X,u);    /* x = uv^3(uv^7)^((q-5)/8) */
+
+  fe_sq(vxx,h->X);
+  fe_mul(vxx,vxx,v);
+  fe_sub(check,vxx,u);    /* vx^2-u */
+  if (fe_isnonzero(check)) {
+    fe_add(check,vxx,u);  /* vx^2+u */
+    if (fe_isnonzero(check)) return -1;
+    fe_mul(h->X,h->X,sqrtm1);
+  }
+
+  if (fe_isnegative(h->X) == (s[31] >> 7))
+    fe_neg(h->X,h->X);
+
+  fe_mul(h->T,h->X,h->Y);
+  return 0;
+}
+
+
+/* ge madd */
+/*
+r = p + q
+*/
+
+void ge_madd(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q)
+{
+	fe t0;
+	fe_add(r->X,p->Y,p->X);
+	fe_sub(r->Y,p->Y,p->X);
+	fe_mul(r->Z,r->X,q->yplusx);
+	fe_mul(r->Y,r->Y,q->yminusx);
+	fe_mul(r->T,q->xy2d,p->T);
+	fe_add(t0,p->Z,p->Z);
+	fe_sub(r->X,r->Z,r->Y);
+	fe_add(r->Y,r->Z,r->Y);
+	fe_add(r->Z,t0,r->T);
+	fe_sub(r->T,t0,r->T);
+}
+
+
+/* ge msub */
+
+/*
+r = p - q
+*/
+
+void ge_msub(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q)
+{
+	fe t0;
+	fe_add(r->X,p->Y,p->X);
+	fe_sub(r->Y,p->Y,p->X);
+	fe_mul(r->Z,r->X,q->yminusx);
+	fe_mul(r->Y,r->Y,q->yplusx);
+	fe_mul(r->T,q->xy2d,p->T);
+	fe_add(t0,p->Z,p->Z);
+	fe_sub(r->X,r->Z,r->Y);
+	fe_add(r->Y,r->Z,r->Y);
+	fe_sub(r->Z,t0,r->T);
+	fe_add(r->T,t0,r->T);
+}
+
+
+/* ge p1p1 to p2 */
+/*
+r = p
+*/
+
+extern void ge_p1p1_to_p2(ge_p2 *r,const ge_p1p1 *p)
+{
+  fe_mul(r->X,p->X,p->T);
+  fe_mul(r->Y,p->Y,p->Z);
+  fe_mul(r->Z,p->Z,p->T);
+}
+
+
+/* ge p1p1 to p3 */
+
+/*
+r = p
+*/
+
+extern void ge_p1p1_to_p3(ge_p3 *r,const ge_p1p1 *p)
+{
+  fe_mul(r->X,p->X,p->T);
+  fe_mul(r->Y,p->Y,p->Z);
+  fe_mul(r->Z,p->Z,p->T);
+  fe_mul(r->T,p->X,p->Y);
+}
+
+
+/* ge p2 0 */
+
+void ge_p2_0(ge_p2 *h)
+{
+  fe_0(h->X);
+  fe_1(h->Y);
+  fe_1(h->Z);
+}
+
+
+/* ge p2 dbl */
+
+/*
+r = 2 * p
+*/
+
+void ge_p2_dbl(ge_p1p1 *r,const ge_p2 *p)
+{
+	fe t0;
+	fe_sq(r->X,p->X);
+	fe_sq(r->Z,p->Y);
+	fe_sq2(r->T,p->Z);
+	fe_add(r->Y,p->X,p->Y);
+	fe_sq(t0,r->Y);
+	fe_add(r->Y,r->Z,r->X);
+	fe_sub(r->Z,r->Z,r->X);
+	fe_sub(r->X,t0,r->Y);
+	fe_sub(r->T,r->T,r->Z);
+}
+
+
+/* ge p3 0 */
+
+void ge_p3_0(ge_p3 *h)
+{
+  fe_0(h->X);
+  fe_1(h->Y);
+  fe_1(h->Z);
+  fe_0(h->T);
+}
+
+
+/* ge p3 dble */
+
+/*
+r = 2 * p
+*/
+
+void ge_p3_dbl(ge_p1p1 *r,const ge_p3 *p)
+{
+  ge_p2 q;
+  ge_p3_to_p2(&q,p);
+  ge_p2_dbl(r,&q);
+}
+
+
+/* ge p3 to cached */
+
+/*
+r = p
+*/
+
+static const fe d2 = {
+-21827239,-5839606,-30745221,13898782,229458,
+15978800,-12551817,-6495438,29715968,9444199
+} ;
+
+
+extern void ge_p3_to_cached(ge_cached *r,const ge_p3 *p)
+{
+  fe_add(r->YplusX,p->Y,p->X);
+  fe_sub(r->YminusX,p->Y,p->X);
+  fe_copy(r->Z,p->Z);
+  fe_mul(r->T2d,p->T,d2);
+}
+
+
+/* ge p3 to p2 */
+/*
+r = p
+*/
+
+extern void ge_p3_to_p2(ge_p2 *r,const ge_p3 *p)
+{
+  fe_copy(r->X,p->X);
+  fe_copy(r->Y,p->Y);
+  fe_copy(r->Z,p->Z);
+}
+
+
+/* ge p3 tobytes */
+void ge_p3_tobytes(unsigned char *s,const ge_p3 *h)
+{
+  fe recip;
+  fe x;
+  fe y;
+
+  fe_invert(recip,h->Z);
+  fe_mul(x,h->X,recip);
+  fe_mul(y,h->Y,recip);
+  fe_tobytes(s,y);
+  s[31] ^= fe_isnegative(x) << 7;
+}
+
+
+/* ge_precomp_0 */
+void ge_precomp_0(ge_precomp *h)
+{
+  fe_1(h->yplusx);
+  fe_1(h->yminusx);
+  fe_0(h->xy2d);
+}
+
+
+/* ge_sub */
+/*
+r = p - q
+*/
+
+void ge_sub(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q)
+{
+	fe t0;
+	fe_add(r->X,p->Y,p->X);
+	fe_sub(r->Y,p->Y,p->X);
+	fe_mul(r->Z,r->X,q->YminusX);
+	fe_mul(r->Y,r->Y,q->YplusX);
+	fe_mul(r->T,q->T2d,p->T);
+	fe_mul(r->X,p->Z,q->Z);
+	fe_add(t0,r->X,r->X);
+	fe_sub(r->X,r->Z,r->Y);
+	fe_add(r->Y,r->Z,r->Y);
+	fe_sub(r->Z,t0,r->T);
+	fe_add(r->T,t0,r->T);
+}
+
+
+/* ge tobytes */
+void ge_tobytes(unsigned char *s,const ge_p2 *h)
+{
+  fe recip;
+  fe x;
+  fe y;
+
+  fe_invert(recip,h->Z);
+  fe_mul(x,h->X,recip);
+  fe_mul(y,h->Y,recip);
+  fe_tobytes(s,y);
+  s[31] ^= fe_isnegative(x) << 7;
+}
+#endif /* HAVE_ED25519 */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/hash.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,77 @@
+/* hash.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#if !defined(WOLFSSL_TI_HASH)
+
+#include <wolfssl/wolfcrypt/hash.h>
+
+#if !defined(NO_MD5)
+void wc_Md5GetHash(Md5* md5, byte* hash)
+{
+    Md5 save = *md5 ;
+    wc_Md5Final(md5, hash) ;
+    *md5 = save ;
+}
+
+WOLFSSL_API void wc_Md5RestorePos(Md5* m1, Md5* m2) {
+    *m1 = *m2 ;
+}
+#endif
+
+#if !defined(NO_SHA)
+int wc_ShaGetHash(Sha* sha, byte* hash)
+{
+    int ret ;
+    Sha save = *sha ;
+    ret = wc_ShaFinal(sha, hash) ;
+    *sha = save ;
+    return ret ;
+}
+
+WOLFSSL_API void wc_ShaRestorePos(Sha* s1, Sha* s2) {
+    *s1 = *s2 ;
+}
+#endif
+
+#if !defined(NO_SHA256)
+int wc_Sha256GetHash(Sha256* sha256, byte* hash)
+{
+    int ret ;
+    Sha256 save = *sha256 ;
+    ret = wc_Sha256Final(sha256, hash) ;
+    *sha256 = save ;
+    return ret ;
+}
+
+WOLFSSL_API void wc_Sha256RestorePos(Sha256* s1, Sha256* s2) {
+    *s1 = *s2 ;
+}
+#endif
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/hc128.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,400 @@
+/* hc128.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_HC128
+
+#include <wolfssl/wolfcrypt/hc128.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/logging.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/hc128.h>
+		#include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+
+#ifdef BIG_ENDIAN_ORDER
+    #define LITTLE32(x) ByteReverseWord32(x)
+#else
+    #define LITTLE32(x) (x)
+#endif
+
+
+/*h1 function*/
+#define h1(ctx, x, y) {                         \
+     byte a,c;                                  \
+     a = (byte) (x);                            \
+     c = (byte) ((x) >> 16);                    \
+     y = (ctx->T[512+a])+(ctx->T[512+256+c]);   \
+}
+
+/*h2 function*/
+#define h2(ctx, x, y) {                         \
+     byte a,c;                                  \
+     a = (byte) (x);                            \
+     c = (byte) ((x) >> 16);                    \
+     y = (ctx->T[a])+(ctx->T[256+c]);           \
+}
+
+/*one step of HC-128, update P and generate 32 bits keystream*/
+#define step_P(ctx,u,v,a,b,c,d,n){              \
+     word32 tem0,tem1,tem2,tem3;                \
+     h1((ctx),(ctx->X[(d)]),tem3);              \
+     tem0 = rotrFixed((ctx->T[(v)]),23);        \
+     tem1 = rotrFixed((ctx->X[(c)]),10);        \
+     tem2 = rotrFixed((ctx->X[(b)]),8);         \
+     (ctx->T[(u)]) += tem2+(tem0 ^ tem1);       \
+     (ctx->X[(a)]) = (ctx->T[(u)]);             \
+     (n) = tem3 ^ (ctx->T[(u)]) ;               \
+}       
+
+/*one step of HC-128, update Q and generate 32 bits keystream*/
+#define step_Q(ctx,u,v,a,b,c,d,n){              \
+     word32 tem0,tem1,tem2,tem3;                \
+     h2((ctx),(ctx->Y[(d)]),tem3);              \
+     tem0 = rotrFixed((ctx->T[(v)]),(32-23));   \
+     tem1 = rotrFixed((ctx->Y[(c)]),(32-10));   \
+     tem2 = rotrFixed((ctx->Y[(b)]),(32-8));    \
+     (ctx->T[(u)]) += tem2 + (tem0 ^ tem1);     \
+     (ctx->Y[(a)]) = (ctx->T[(u)]);             \
+     (n) = tem3 ^ (ctx->T[(u)]) ;               \
+}   
+
+/*16 steps of HC-128, generate 512 bits keystream*/
+static void generate_keystream(HC128* ctx, word32* keystream)  
+{
+   word32 cc,dd;
+   cc = ctx->counter1024 & 0x1ff;
+   dd = (cc+16)&0x1ff;
+
+   if (ctx->counter1024 < 512)	
+   {   		
+      ctx->counter1024 = (ctx->counter1024 + 16) & 0x3ff;
+      step_P(ctx, cc+0, cc+1, 0, 6, 13,4, keystream[0]);
+      step_P(ctx, cc+1, cc+2, 1, 7, 14,5, keystream[1]);
+      step_P(ctx, cc+2, cc+3, 2, 8, 15,6, keystream[2]);
+      step_P(ctx, cc+3, cc+4, 3, 9, 0, 7, keystream[3]);
+      step_P(ctx, cc+4, cc+5, 4, 10,1, 8, keystream[4]);
+      step_P(ctx, cc+5, cc+6, 5, 11,2, 9, keystream[5]);
+      step_P(ctx, cc+6, cc+7, 6, 12,3, 10,keystream[6]);
+      step_P(ctx, cc+7, cc+8, 7, 13,4, 11,keystream[7]);
+      step_P(ctx, cc+8, cc+9, 8, 14,5, 12,keystream[8]);
+      step_P(ctx, cc+9, cc+10,9, 15,6, 13,keystream[9]);
+      step_P(ctx, cc+10,cc+11,10,0, 7, 14,keystream[10]);
+      step_P(ctx, cc+11,cc+12,11,1, 8, 15,keystream[11]);
+      step_P(ctx, cc+12,cc+13,12,2, 9, 0, keystream[12]);
+      step_P(ctx, cc+13,cc+14,13,3, 10,1, keystream[13]);
+      step_P(ctx, cc+14,cc+15,14,4, 11,2, keystream[14]);
+      step_P(ctx, cc+15,dd+0, 15,5, 12,3, keystream[15]);
+   }
+   else				    
+   {
+	  ctx->counter1024 = (ctx->counter1024 + 16) & 0x3ff;
+      step_Q(ctx, 512+cc+0, 512+cc+1, 0, 6, 13,4, keystream[0]);
+      step_Q(ctx, 512+cc+1, 512+cc+2, 1, 7, 14,5, keystream[1]);
+      step_Q(ctx, 512+cc+2, 512+cc+3, 2, 8, 15,6, keystream[2]);
+      step_Q(ctx, 512+cc+3, 512+cc+4, 3, 9, 0, 7, keystream[3]);
+      step_Q(ctx, 512+cc+4, 512+cc+5, 4, 10,1, 8, keystream[4]);
+      step_Q(ctx, 512+cc+5, 512+cc+6, 5, 11,2, 9, keystream[5]);
+      step_Q(ctx, 512+cc+6, 512+cc+7, 6, 12,3, 10,keystream[6]);
+      step_Q(ctx, 512+cc+7, 512+cc+8, 7, 13,4, 11,keystream[7]);
+      step_Q(ctx, 512+cc+8, 512+cc+9, 8, 14,5, 12,keystream[8]);
+      step_Q(ctx, 512+cc+9, 512+cc+10,9, 15,6, 13,keystream[9]);
+      step_Q(ctx, 512+cc+10,512+cc+11,10,0, 7, 14,keystream[10]);
+      step_Q(ctx, 512+cc+11,512+cc+12,11,1, 8, 15,keystream[11]);
+      step_Q(ctx, 512+cc+12,512+cc+13,12,2, 9, 0, keystream[12]);
+      step_Q(ctx, 512+cc+13,512+cc+14,13,3, 10,1, keystream[13]);
+      step_Q(ctx, 512+cc+14,512+cc+15,14,4, 11,2, keystream[14]);
+      step_Q(ctx, 512+cc+15,512+dd+0, 15,5, 12,3, keystream[15]);
+   }
+}
+
+
+/* The following defines the initialization functions */
+#define f1(x)  (rotrFixed((x),7)  ^ rotrFixed((x),18) ^ ((x) >> 3))
+#define f2(x)  (rotrFixed((x),17) ^ rotrFixed((x),19) ^ ((x) >> 10))
+
+/*update table P*/
+#define update_P(ctx,u,v,a,b,c,d){                  \
+     word32 tem0,tem1,tem2,tem3;                    \
+     tem0 = rotrFixed((ctx->T[(v)]),23);            \
+     tem1 = rotrFixed((ctx->X[(c)]),10);            \
+     tem2 = rotrFixed((ctx->X[(b)]),8);             \
+     h1((ctx),(ctx->X[(d)]),tem3);                  \
+     (ctx->T[(u)]) = ((ctx->T[(u)]) + tem2+(tem0^tem1)) ^ tem3;     \
+     (ctx->X[(a)]) = (ctx->T[(u)]);                 \
+}  
+
+/*update table Q*/
+#define update_Q(ctx,u,v,a,b,c,d){                  \
+     word32 tem0,tem1,tem2,tem3;                    \
+     tem0 = rotrFixed((ctx->T[(v)]),(32-23));       \
+     tem1 = rotrFixed((ctx->Y[(c)]),(32-10));       \
+     tem2 = rotrFixed((ctx->Y[(b)]),(32-8));        \
+     h2((ctx),(ctx->Y[(d)]),tem3);                  \
+     (ctx->T[(u)]) = ((ctx->T[(u)]) + tem2+(tem0^tem1)) ^ tem3;     \
+     (ctx->Y[(a)]) = (ctx->T[(u)]);                 \
+}     
+
+/*16 steps of HC-128, without generating keystream, */
+/*but use the outputs to update P and Q*/
+static void setup_update(HC128* ctx)  /*each time 16 steps*/
+{
+   word32 cc,dd;
+   cc = ctx->counter1024 & 0x1ff;
+   dd = (cc+16)&0x1ff;
+
+   if (ctx->counter1024 < 512)	
+   {   		
+      ctx->counter1024 = (ctx->counter1024 + 16) & 0x3ff;
+      update_P(ctx, cc+0, cc+1, 0, 6, 13, 4);
+      update_P(ctx, cc+1, cc+2, 1, 7, 14, 5);
+      update_P(ctx, cc+2, cc+3, 2, 8, 15, 6);
+      update_P(ctx, cc+3, cc+4, 3, 9, 0,  7);
+      update_P(ctx, cc+4, cc+5, 4, 10,1,  8);
+      update_P(ctx, cc+5, cc+6, 5, 11,2,  9);
+      update_P(ctx, cc+6, cc+7, 6, 12,3,  10);
+      update_P(ctx, cc+7, cc+8, 7, 13,4,  11);
+      update_P(ctx, cc+8, cc+9, 8, 14,5,  12);
+      update_P(ctx, cc+9, cc+10,9, 15,6,  13);
+      update_P(ctx, cc+10,cc+11,10,0, 7,  14);
+      update_P(ctx, cc+11,cc+12,11,1, 8,  15);
+      update_P(ctx, cc+12,cc+13,12,2, 9,  0);
+      update_P(ctx, cc+13,cc+14,13,3, 10, 1);
+      update_P(ctx, cc+14,cc+15,14,4, 11, 2);
+      update_P(ctx, cc+15,dd+0, 15,5, 12, 3);   
+   }
+   else				    
+   {
+      ctx->counter1024 = (ctx->counter1024 + 16) & 0x3ff;
+      update_Q(ctx, 512+cc+0, 512+cc+1, 0, 6, 13, 4);
+      update_Q(ctx, 512+cc+1, 512+cc+2, 1, 7, 14, 5);
+      update_Q(ctx, 512+cc+2, 512+cc+3, 2, 8, 15, 6);
+      update_Q(ctx, 512+cc+3, 512+cc+4, 3, 9, 0,  7);
+      update_Q(ctx, 512+cc+4, 512+cc+5, 4, 10,1,  8);
+      update_Q(ctx, 512+cc+5, 512+cc+6, 5, 11,2,  9);
+      update_Q(ctx, 512+cc+6, 512+cc+7, 6, 12,3,  10);
+      update_Q(ctx, 512+cc+7, 512+cc+8, 7, 13,4,  11);
+      update_Q(ctx, 512+cc+8, 512+cc+9, 8, 14,5,  12);
+      update_Q(ctx, 512+cc+9, 512+cc+10,9, 15,6,  13);
+      update_Q(ctx, 512+cc+10,512+cc+11,10,0, 7,  14);
+      update_Q(ctx, 512+cc+11,512+cc+12,11,1, 8,  15);
+      update_Q(ctx, 512+cc+12,512+cc+13,12,2, 9,  0);
+      update_Q(ctx, 512+cc+13,512+cc+14,13,3, 10, 1);
+      update_Q(ctx, 512+cc+14,512+cc+15,14,4, 11, 2);
+      update_Q(ctx, 512+cc+15,512+dd+0, 15,5, 12, 3); 
+   }       
+}
+
+
+/* for the 128-bit key:  key[0]...key[15]
+*  key[0] is the least significant byte of ctx->key[0] (K_0);
+*  key[3] is the most significant byte of ctx->key[0]  (K_0);
+*  ...
+*  key[12] is the least significant byte of ctx->key[3] (K_3)
+*  key[15] is the most significant byte of ctx->key[3]  (K_3)
+*
+*  for the 128-bit iv:  iv[0]...iv[15]
+*  iv[0] is the least significant byte of ctx->iv[0] (IV_0);
+*  iv[3] is the most significant byte of ctx->iv[0]  (IV_0);
+*  ...
+*  iv[12] is the least significant byte of ctx->iv[3] (IV_3)
+*  iv[15] is the most significant byte of ctx->iv[3]  (IV_3)
+*/
+
+
+
+static void Hc128_SetIV(HC128* ctx, const byte* inIv)
+{ 
+    word32 i;
+    word32 iv[4];
+
+    if (inIv)
+        XMEMCPY(iv, inIv, sizeof(iv));
+    else
+        XMEMSET(iv,    0, sizeof(iv));
+    
+	for (i = 0; i < (128 >> 5); i++)
+        ctx->iv[i] = LITTLE32(iv[i]);
+	
+    for (; i < 8; i++) ctx->iv[i] = ctx->iv[i-4];
+  
+    /* expand the key and IV into the table T */ 
+    /* (expand the key and IV into the table P and Q) */ 
+	
+	for (i = 0; i < 8;  i++)   ctx->T[i] = ctx->key[i];
+	for (i = 8; i < 16; i++)   ctx->T[i] = ctx->iv[i-8];
+
+    for (i = 16; i < (256+16); i++) 
+		ctx->T[i] = f2(ctx->T[i-2]) + ctx->T[i-7] + f1(ctx->T[i-15]) +
+                                                       ctx->T[i-16]+i;
+    
+	for (i = 0; i < 16;  i++)  ctx->T[i] = ctx->T[256+i];
+
+	for (i = 16; i < 1024; i++) 
+		ctx->T[i] = f2(ctx->T[i-2]) + ctx->T[i-7] + f1(ctx->T[i-15]) +
+                                                       ctx->T[i-16]+256+i;
+    
+    /* initialize counter1024, X and Y */
+	ctx->counter1024 = 0;
+	for (i = 0; i < 16; i++) ctx->X[i] = ctx->T[512-16+i];
+    for (i = 0; i < 16; i++) ctx->Y[i] = ctx->T[512+512-16+i];
+    
+    /* run the cipher 1024 steps before generating the output */
+	for (i = 0; i < 64; i++)  setup_update(ctx);  
+}
+
+
+static INLINE int DoKey(HC128* ctx, const byte* key, const byte* iv)
+{ 
+  word32 i;  
+
+  /* Key size in bits 128 */ 
+  for (i = 0; i < (128 >> 5); i++)
+      ctx->key[i] = LITTLE32(((word32*)key)[i]);
+ 
+  for ( ; i < 8 ; i++) ctx->key[i] = ctx->key[i-4];
+
+  Hc128_SetIV(ctx, iv);
+
+  return 0;
+}
+
+
+/* Key setup */
+int wc_Hc128_SetKey(HC128* ctx, const byte* key, const byte* iv)
+{
+#ifdef XSTREAM_ALIGN
+    if ((wolfssl_word)key % 4) {
+        int alignKey[4];
+
+        /* iv gets aligned in SetIV */
+        WOLFSSL_MSG("Hc128SetKey unaligned key");
+
+        XMEMCPY(alignKey, key, sizeof(alignKey));
+
+        return DoKey(ctx, (const byte*)alignKey, iv);
+    }
+#endif /* XSTREAM_ALIGN */
+
+    return DoKey(ctx, key, iv);
+}
+
+
+
+/* The following defines the encryption of data stream */
+static INLINE int DoProcess(HC128* ctx, byte* output, const byte* input,
+                            word32 msglen)
+{
+  word32 i, keystream[16];
+
+  for ( ; msglen >= 64; msglen -= 64, input += 64, output += 64)
+  {
+	  generate_keystream(ctx, keystream);
+
+      /* unroll loop */
+	  ((word32*)output)[0]  = ((word32*)input)[0]  ^ LITTLE32(keystream[0]);
+	  ((word32*)output)[1]  = ((word32*)input)[1]  ^ LITTLE32(keystream[1]);
+	  ((word32*)output)[2]  = ((word32*)input)[2]  ^ LITTLE32(keystream[2]);
+	  ((word32*)output)[3]  = ((word32*)input)[3]  ^ LITTLE32(keystream[3]);
+	  ((word32*)output)[4]  = ((word32*)input)[4]  ^ LITTLE32(keystream[4]);
+	  ((word32*)output)[5]  = ((word32*)input)[5]  ^ LITTLE32(keystream[5]);
+	  ((word32*)output)[6]  = ((word32*)input)[6]  ^ LITTLE32(keystream[6]);
+	  ((word32*)output)[7]  = ((word32*)input)[7]  ^ LITTLE32(keystream[7]);
+	  ((word32*)output)[8]  = ((word32*)input)[8]  ^ LITTLE32(keystream[8]);
+	  ((word32*)output)[9]  = ((word32*)input)[9]  ^ LITTLE32(keystream[9]);
+	  ((word32*)output)[10] = ((word32*)input)[10] ^ LITTLE32(keystream[10]);
+	  ((word32*)output)[11] = ((word32*)input)[11] ^ LITTLE32(keystream[11]);
+	  ((word32*)output)[12] = ((word32*)input)[12] ^ LITTLE32(keystream[12]);
+	  ((word32*)output)[13] = ((word32*)input)[13] ^ LITTLE32(keystream[13]);
+	  ((word32*)output)[14] = ((word32*)input)[14] ^ LITTLE32(keystream[14]);
+	  ((word32*)output)[15] = ((word32*)input)[15] ^ LITTLE32(keystream[15]);
+  }
+
+  if (msglen > 0)
+  {
+      XMEMSET(keystream, 0, sizeof(keystream)); /* hush the static analysis */
+      generate_keystream(ctx, keystream);
+
+#ifdef BIG_ENDIAN_ORDER
+      {
+          word32 wordsLeft = msglen / sizeof(word32);
+          if (msglen % sizeof(word32)) wordsLeft++;
+          
+          ByteReverseWords(keystream, keystream, wordsLeft * sizeof(word32));
+      }
+#endif
+
+      for (i = 0; i < msglen; i++)
+	      output[i] = input[i] ^ ((byte*)keystream)[i];
+  }
+
+  return 0;
+}
+
+
+/* Encrypt/decrypt a message of any size */
+int wc_Hc128_Process(HC128* ctx, byte* output, const byte* input, word32 msglen)
+{
+#ifdef XSTREAM_ALIGN
+    if ((wolfssl_word)input % 4 || (wolfssl_word)output % 4) {
+        #ifndef NO_WOLFSSL_ALLOC_ALIGN
+            byte* tmp;
+            WOLFSSL_MSG("Hc128Process unaligned");
+
+            tmp = (byte*)XMALLOC(msglen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            if (tmp == NULL) return MEMORY_E;
+
+            XMEMCPY(tmp, input, msglen);
+            DoProcess(ctx, tmp, tmp, msglen);
+            XMEMCPY(output, tmp, msglen);
+
+            XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+            return 0;
+        #else
+            return BAD_ALIGN_E;
+        #endif
+    }
+#endif /* XSTREAM_ALIGN */
+
+    return DoProcess(ctx, output, input, msglen);
+}
+
+
+#else  /* HAVE_HC128 */
+
+
+#ifdef _MSC_VER
+    /* 4206 warning for blank file */
+    #pragma warning(disable: 4206)
+#endif
+
+
+#endif /* HAVE_HC128 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/hmac.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,880 @@
+/* hmac.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifndef NO_HMAC
+
+#include <wolfssl/wolfcrypt/hmac.h>
+
+#ifdef HAVE_FIPS
+/* does init */
+int wc_HmacSetKey(Hmac* hmac, int type, const byte* key, word32 keySz)
+{
+    return HmacSetKey_fips(hmac, type, key, keySz);
+}
+
+
+int wc_HmacUpdate(Hmac* hmac, const byte* in, word32 sz)
+{
+    return HmacUpdate_fips(hmac, in, sz);
+}
+
+
+int wc_HmacFinal(Hmac* hmac, byte* out)
+{
+    return HmacFinal_fips(hmac, out);
+}
+
+
+#ifdef HAVE_CAVIUM
+    int  wc_HmacInitCavium(Hmac* hmac, int i)
+    {
+        return HmacInitCavium(hmac, i);
+    }
+
+
+    void wc_HmacFreeCavium(Hmac* hmac)
+    {
+        HmacFreeCavium(hmac);
+    }
+#endif
+
+int wolfSSL_GetHmacMaxSize(void)
+{
+    return CyaSSL_GetHmacMaxSize();
+}
+
+#ifdef HAVE_HKDF
+
+int wc_HKDF(int type, const byte* inKey, word32 inKeySz,
+                    const byte* salt, word32 saltSz,
+                    const byte* info, word32 infoSz,
+                    byte* out, word32 outSz)
+{
+    return HKDF(type, inKey, inKeySz, salt, saltSz, info, infoSz, out, outSz);
+}
+
+
+#endif /* HAVE_HKDF */
+#else /* else build without fips */
+#ifdef WOLFSSL_PIC32MZ_HASH
+
+#define wc_InitMd5   wc_InitMd5_sw
+#define wc_Md5Update wc_Md5Update_sw
+#define wc_Md5Final  wc_Md5Final_sw
+
+#define wc_InitSha   wc_InitSha_sw
+#define wc_ShaUpdate wc_ShaUpdate_sw
+#define wc_ShaFinal  wc_ShaFinal_sw
+
+#define wc_InitSha256   wc_InitSha256_sw
+#define wc_Sha256Update wc_Sha256Update_sw
+#define wc_Sha256Final  wc_Sha256Final_sw
+
+#endif
+
+#ifdef HAVE_FIPS
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+#endif
+
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+
+#ifdef HAVE_CAVIUM
+    static void HmacCaviumFinal(Hmac* hmac, byte* hash);
+    static void HmacCaviumUpdate(Hmac* hmac, const byte* msg, word32 length);
+    static void HmacCaviumSetKey(Hmac* hmac, int type, const byte* key,
+                                 word32 length);
+#endif
+
+static int InitHmac(Hmac* hmac, int type)
+{
+    int ret = 0;
+
+    hmac->innerHashKeyed = 0;
+    hmac->macType = (byte)type;
+
+    if (!(type == MD5 || type == SHA    || type == SHA256 || type == SHA384
+                      || type == SHA512 || type == BLAKE2B_ID))
+        return BAD_FUNC_ARG;
+
+    switch (type) {
+        #ifndef NO_MD5
+        case MD5:
+            wc_InitMd5(&hmac->hash.md5);
+        break;
+        #endif
+
+        #ifndef NO_SHA
+        case SHA:
+            ret = wc_InitSha(&hmac->hash.sha);
+        break;
+        #endif
+        
+        #ifndef NO_SHA256
+        case SHA256:
+            ret = wc_InitSha256(&hmac->hash.sha256);
+        break;
+        #endif
+        
+        #ifdef WOLFSSL_SHA384
+        case SHA384:
+            ret = wc_InitSha384(&hmac->hash.sha384);
+        break;
+        #endif
+        
+        #ifdef WOLFSSL_SHA512
+        case SHA512:
+            ret = wc_InitSha512(&hmac->hash.sha512);
+        break;
+        #endif
+        
+        #ifdef HAVE_BLAKE2 
+        case BLAKE2B_ID:
+            ret = wc_InitBlake2b(&hmac->hash.blake2b, BLAKE2B_256);
+        break;
+        #endif
+        
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    return ret;
+}
+
+
+int wc_HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length)
+{
+    byte*  ip = (byte*) hmac->ipad;
+    byte*  op = (byte*) hmac->opad;
+    word32 i, hmac_block_size = 0;
+    int    ret;
+
+#ifdef HAVE_CAVIUM
+    if (hmac->magic == WOLFSSL_HMAC_CAVIUM_MAGIC)
+        return HmacCaviumSetKey(hmac, type, key, length);
+#endif
+
+    ret = InitHmac(hmac, type);
+    if (ret != 0)
+        return ret;
+
+#ifdef HAVE_FIPS
+    if (length < HMAC_FIPS_MIN_KEY)
+        return HMAC_MIN_KEYLEN_E;
+#endif
+
+    switch (hmac->macType) {
+        #ifndef NO_MD5
+        case MD5:
+        {
+            hmac_block_size = MD5_BLOCK_SIZE;
+            if (length <= MD5_BLOCK_SIZE) {
+                XMEMCPY(ip, key, length);
+            }
+            else {
+                wc_Md5Update(&hmac->hash.md5, key, length);
+                wc_Md5Final(&hmac->hash.md5, ip);
+                length = MD5_DIGEST_SIZE;
+            }
+        }
+        break;
+        #endif
+
+        #ifndef NO_SHA
+        case SHA:
+        {
+            hmac_block_size = SHA_BLOCK_SIZE;
+            if (length <= SHA_BLOCK_SIZE) {
+                XMEMCPY(ip, key, length);
+            }
+            else {
+                wc_ShaUpdate(&hmac->hash.sha, key, length);
+                wc_ShaFinal(&hmac->hash.sha, ip);
+                length = SHA_DIGEST_SIZE;
+            }
+        }
+        break;
+        #endif
+
+        #ifndef NO_SHA256
+        case SHA256:
+        {
+    		hmac_block_size = SHA256_BLOCK_SIZE;
+            if (length <= SHA256_BLOCK_SIZE) {
+                XMEMCPY(ip, key, length);
+            }
+            else {
+                ret = wc_Sha256Update(&hmac->hash.sha256, key, length);
+                if (ret != 0)
+                    return ret;
+
+                ret = wc_Sha256Final(&hmac->hash.sha256, ip);
+                if (ret != 0)
+                    return ret;
+
+                length = SHA256_DIGEST_SIZE;
+            }
+        }
+        break;
+        #endif
+
+        #ifdef WOLFSSL_SHA384
+        case SHA384:
+        {
+            hmac_block_size = SHA384_BLOCK_SIZE;
+            if (length <= SHA384_BLOCK_SIZE) {
+                XMEMCPY(ip, key, length);
+            }
+            else {
+                ret = wc_Sha384Update(&hmac->hash.sha384, key, length);
+                if (ret != 0)
+                    return ret;
+
+                ret = wc_Sha384Final(&hmac->hash.sha384, ip);
+                if (ret != 0)
+                    return ret;
+
+                length = SHA384_DIGEST_SIZE;
+            }
+        }
+        break;
+        #endif
+
+        #ifdef WOLFSSL_SHA512
+        case SHA512:
+        {
+            hmac_block_size = SHA512_BLOCK_SIZE;
+            if (length <= SHA512_BLOCK_SIZE) {
+                XMEMCPY(ip, key, length);
+            }
+            else {
+                ret = wc_Sha512Update(&hmac->hash.sha512, key, length);
+                if (ret != 0)
+                    return ret;
+
+                ret = wc_Sha512Final(&hmac->hash.sha512, ip);
+                if (ret != 0)
+                    return ret;
+
+                length = SHA512_DIGEST_SIZE;
+            }
+        }
+        break;
+        #endif
+
+        #ifdef HAVE_BLAKE2 
+        case BLAKE2B_ID:
+        {
+            hmac_block_size = BLAKE2B_BLOCKBYTES;
+            if (length <= BLAKE2B_BLOCKBYTES) {
+                XMEMCPY(ip, key, length);
+            }
+            else {
+                ret = wc_Blake2bUpdate(&hmac->hash.blake2b, key, length);
+                if (ret != 0)
+                    return ret;
+
+                ret = wc_Blake2bFinal(&hmac->hash.blake2b, ip, BLAKE2B_256);
+                if (ret != 0)
+                    return ret;
+
+                length = BLAKE2B_256;
+            }
+        }
+        break;
+        #endif
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+    if (length < hmac_block_size)
+        XMEMSET(ip + length, 0, hmac_block_size - length);
+
+    for(i = 0; i < hmac_block_size; i++) {
+        op[i] = ip[i] ^ OPAD;
+        ip[i] ^= IPAD;
+    }
+    return 0;
+}
+
+
+static int HmacKeyInnerHash(Hmac* hmac)
+{
+    int ret = 0;
+
+    switch (hmac->macType) {
+        #ifndef NO_MD5
+        case MD5:
+            wc_Md5Update(&hmac->hash.md5, (byte*) hmac->ipad, MD5_BLOCK_SIZE);
+        break;
+        #endif
+
+        #ifndef NO_SHA
+        case SHA:
+            wc_ShaUpdate(&hmac->hash.sha, (byte*) hmac->ipad, SHA_BLOCK_SIZE);
+        break;
+        #endif
+
+        #ifndef NO_SHA256
+        case SHA256:
+            ret = wc_Sha256Update(&hmac->hash.sha256,
+                                         (byte*) hmac->ipad, SHA256_BLOCK_SIZE);
+            if (ret != 0)
+                return ret;
+        break;
+        #endif
+
+        #ifdef WOLFSSL_SHA384
+        case SHA384:
+            ret = wc_Sha384Update(&hmac->hash.sha384,
+                                         (byte*) hmac->ipad, SHA384_BLOCK_SIZE);
+            if (ret != 0)
+                return ret;
+        break;
+        #endif
+
+        #ifdef WOLFSSL_SHA512
+        case SHA512:
+            ret = wc_Sha512Update(&hmac->hash.sha512,
+                                         (byte*) hmac->ipad, SHA512_BLOCK_SIZE);
+            if (ret != 0)
+                return ret;
+        break;
+        #endif
+
+        #ifdef HAVE_BLAKE2 
+        case BLAKE2B_ID:
+            ret = wc_Blake2bUpdate(&hmac->hash.blake2b,
+                                         (byte*) hmac->ipad,BLAKE2B_BLOCKBYTES);
+            if (ret != 0)
+                return ret;
+        break;
+        #endif
+
+        default:
+        break;
+    }
+
+    hmac->innerHashKeyed = 1;
+
+    return ret;
+}
+
+
+int wc_HmacUpdate(Hmac* hmac, const byte* msg, word32 length)
+{
+    int ret;
+
+#ifdef HAVE_CAVIUM
+    if (hmac->magic == WOLFSSL_HMAC_CAVIUM_MAGIC)
+        return HmacCaviumUpdate(hmac, msg, length);
+#endif
+
+    if (!hmac->innerHashKeyed) {
+        ret = HmacKeyInnerHash(hmac);
+        if (ret != 0)
+            return ret;
+    }
+
+    switch (hmac->macType) {
+        #ifndef NO_MD5
+        case MD5:
+            wc_Md5Update(&hmac->hash.md5, msg, length);
+        break;
+        #endif
+
+        #ifndef NO_SHA
+        case SHA:
+            wc_ShaUpdate(&hmac->hash.sha, msg, length);
+        break;
+        #endif
+
+        #ifndef NO_SHA256
+        case SHA256:
+            ret = wc_Sha256Update(&hmac->hash.sha256, msg, length);
+            if (ret != 0)
+                return ret;
+        break;
+        #endif
+
+        #ifdef WOLFSSL_SHA384
+        case SHA384:
+            ret = wc_Sha384Update(&hmac->hash.sha384, msg, length);
+            if (ret != 0)
+                return ret;
+        break;
+        #endif
+
+        #ifdef WOLFSSL_SHA512
+        case SHA512:
+            ret = wc_Sha512Update(&hmac->hash.sha512, msg, length);
+            if (ret != 0)
+                return ret;
+        break;
+        #endif
+
+        #ifdef HAVE_BLAKE2 
+        case BLAKE2B_ID:
+            ret = wc_Blake2bUpdate(&hmac->hash.blake2b, msg, length);
+            if (ret != 0)
+                return ret;
+        break;
+        #endif
+
+        default:
+        break;
+    }
+
+    return 0;
+}
+
+
+int wc_HmacFinal(Hmac* hmac, byte* hash)
+{
+    int ret;
+
+#ifdef HAVE_CAVIUM
+    if (hmac->magic == WOLFSSL_HMAC_CAVIUM_MAGIC)
+        return HmacCaviumFinal(hmac, hash);
+#endif
+
+    if (!hmac->innerHashKeyed) {
+        ret = HmacKeyInnerHash(hmac);
+        if (ret != 0)
+            return ret;
+    }
+
+    switch (hmac->macType) {
+        #ifndef NO_MD5
+        case MD5:
+        {
+            wc_Md5Final(&hmac->hash.md5, (byte*) hmac->innerHash);
+
+            wc_Md5Update(&hmac->hash.md5, (byte*) hmac->opad, MD5_BLOCK_SIZE);
+            wc_Md5Update(&hmac->hash.md5,
+                                     (byte*) hmac->innerHash, MD5_DIGEST_SIZE);
+
+            wc_Md5Final(&hmac->hash.md5, hash);
+        }
+        break;
+        #endif
+
+        #ifndef NO_SHA
+        case SHA:
+        {
+            wc_ShaFinal(&hmac->hash.sha, (byte*) hmac->innerHash);
+
+            wc_ShaUpdate(&hmac->hash.sha, (byte*) hmac->opad, SHA_BLOCK_SIZE);
+            wc_ShaUpdate(&hmac->hash.sha,
+                                     (byte*) hmac->innerHash, SHA_DIGEST_SIZE);
+
+            wc_ShaFinal(&hmac->hash.sha, hash);
+        }
+        break;
+        #endif
+
+        #ifndef NO_SHA256
+        case SHA256:
+        {
+            ret = wc_Sha256Final(&hmac->hash.sha256, (byte*) hmac->innerHash);
+            if (ret != 0)
+                return ret;
+
+            ret = wc_Sha256Update(&hmac->hash.sha256,
+                                (byte*) hmac->opad, SHA256_BLOCK_SIZE);
+            if (ret != 0)
+                return ret;
+
+            ret = wc_Sha256Update(&hmac->hash.sha256,
+                                (byte*) hmac->innerHash, SHA256_DIGEST_SIZE);
+            if (ret != 0)
+                return ret;
+
+            ret = wc_Sha256Final(&hmac->hash.sha256, hash);
+            if (ret != 0)
+                return ret;
+        }
+        break;
+        #endif
+
+        #ifdef WOLFSSL_SHA384
+        case SHA384:
+        {
+            ret = wc_Sha384Final(&hmac->hash.sha384, (byte*) hmac->innerHash);
+            if (ret != 0)
+                return ret;
+
+            ret = wc_Sha384Update(&hmac->hash.sha384,
+                                 (byte*) hmac->opad, SHA384_BLOCK_SIZE);
+            if (ret != 0)
+                return ret;
+
+            ret = wc_Sha384Update(&hmac->hash.sha384,
+                                 (byte*) hmac->innerHash, SHA384_DIGEST_SIZE);
+            if (ret != 0)
+                return ret;
+
+            ret = wc_Sha384Final(&hmac->hash.sha384, hash);
+            if (ret != 0)
+                return ret;
+        }
+        break;
+        #endif
+
+        #ifdef WOLFSSL_SHA512
+        case SHA512:
+        {
+            ret = wc_Sha512Final(&hmac->hash.sha512, (byte*) hmac->innerHash);
+            if (ret != 0)
+                return ret;
+
+            ret = wc_Sha512Update(&hmac->hash.sha512,
+                                 (byte*) hmac->opad, SHA512_BLOCK_SIZE);
+            if (ret != 0)
+                return ret;
+
+            ret = wc_Sha512Update(&hmac->hash.sha512,
+                                 (byte*) hmac->innerHash, SHA512_DIGEST_SIZE);
+            if (ret != 0)
+                return ret;
+
+            ret = wc_Sha512Final(&hmac->hash.sha512, hash);
+            if (ret != 0)
+                return ret;
+        }
+        break;
+        #endif
+
+        #ifdef HAVE_BLAKE2 
+        case BLAKE2B_ID:
+        {
+            ret = wc_Blake2bFinal(&hmac->hash.blake2b, (byte*) hmac->innerHash,
+                         BLAKE2B_256);
+            if (ret != 0)
+                return ret;
+
+            ret = wc_Blake2bUpdate(&hmac->hash.blake2b,
+                                 (byte*) hmac->opad, BLAKE2B_BLOCKBYTES);
+            if (ret != 0)
+                return ret;
+
+            ret = wc_Blake2bUpdate(&hmac->hash.blake2b,
+                                 (byte*) hmac->innerHash, BLAKE2B_256);
+            if (ret != 0)
+                return ret;
+
+            ret = wc_Blake2bFinal(&hmac->hash.blake2b, hash, BLAKE2B_256);
+            if (ret != 0)
+                return ret;
+        }
+        break;
+        #endif
+
+        default:
+        break;
+    }
+
+    hmac->innerHashKeyed = 0;
+
+    return 0;
+}
+
+
+#ifdef HAVE_CAVIUM
+
+/* Initiliaze Hmac for use with Nitrox device */
+int wc_HmacInitCavium(Hmac* hmac, int devId)
+{
+    if (hmac == NULL)
+        return -1;
+
+    if (CspAllocContext(CONTEXT_SSL, &hmac->contextHandle, devId) != 0)
+        return -1;
+
+    hmac->keyLen  = 0;
+    hmac->dataLen = 0;
+    hmac->type    = 0;
+    hmac->devId   = devId;
+    hmac->magic   = WOLFSSL_HMAC_CAVIUM_MAGIC;
+    hmac->data    = NULL;        /* buffered input data */
+   
+    hmac->innerHashKeyed = 0;
+
+    return 0;
+}
+
+
+/* Free Hmac from use with Nitrox device */
+void wc_HmacFreeCavium(Hmac* hmac)
+{
+    if (hmac == NULL)
+        return;
+
+    CspFreeContext(CONTEXT_SSL, hmac->contextHandle, hmac->devId);
+    hmac->magic = 0;
+    XFREE(hmac->data, NULL, DYNAMIC_TYPE_CAVIUM_TMP);
+    hmac->data = NULL;
+}
+
+
+static void HmacCaviumFinal(Hmac* hmac, byte* hash)
+{
+    word32 requestId;
+
+    if (CspHmac(CAVIUM_BLOCKING, hmac->type, NULL, hmac->keyLen,
+                (byte*)hmac->ipad, hmac->dataLen, hmac->data, hash, &requestId,
+                hmac->devId) != 0) {
+        WOLFSSL_MSG("Cavium Hmac failed");
+    } 
+    hmac->innerHashKeyed = 0;  /* tell update to start over if used again */
+}
+
+
+static void HmacCaviumUpdate(Hmac* hmac, const byte* msg, word32 length)
+{
+    word16 add = (word16)length;
+    word32 total;
+    byte*  tmp;
+
+    if (length > WOLFSSL_MAX_16BIT) {
+        WOLFSSL_MSG("Too big msg for cavium hmac");
+        return;
+    }
+
+    if (hmac->innerHashKeyed == 0) {  /* starting new */
+        hmac->dataLen        = 0;
+        hmac->innerHashKeyed = 1;
+    }
+
+    total = add + hmac->dataLen;
+    if (total > WOLFSSL_MAX_16BIT) {
+        WOLFSSL_MSG("Too big msg for cavium hmac");
+        return;
+    }
+
+    tmp = XMALLOC(hmac->dataLen + add, NULL,DYNAMIC_TYPE_CAVIUM_TMP);
+    if (tmp == NULL) {
+        WOLFSSL_MSG("Out of memory for cavium update");
+        return;
+    }
+    if (hmac->dataLen)
+        XMEMCPY(tmp, hmac->data,  hmac->dataLen);
+    XMEMCPY(tmp + hmac->dataLen, msg, add);
+        
+    hmac->dataLen += add;
+    XFREE(hmac->data, NULL, DYNAMIC_TYPE_CAVIUM_TMP);
+    hmac->data = tmp;
+}
+
+
+static void HmacCaviumSetKey(Hmac* hmac, int type, const byte* key,
+                             word32 length)
+{
+    hmac->macType = (byte)type;
+    if (type == MD5)
+        hmac->type = MD5_TYPE;
+    else if (type == SHA)
+        hmac->type = SHA1_TYPE;
+    else if (type == SHA256)
+        hmac->type = SHA256_TYPE;
+    else  {
+        WOLFSSL_MSG("unsupported cavium hmac type");
+    }
+
+    hmac->innerHashKeyed = 0;  /* should we key Startup flag */
+
+    hmac->keyLen = (word16)length;
+    /* store key in ipad */
+    XMEMCPY(hmac->ipad, key, length);
+}
+
+#endif /* HAVE_CAVIUM */
+
+int wolfSSL_GetHmacMaxSize(void)
+{
+    return MAX_DIGEST_SIZE;
+}
+
+#ifdef HAVE_HKDF
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* WOLFSSL_HAVE_MIN */
+
+
+static INLINE int GetHashSizeByType(int type)
+{
+    if (!(type == MD5 || type == SHA    || type == SHA256 || type == SHA384
+                      || type == SHA512 || type == BLAKE2B_ID))
+        return BAD_FUNC_ARG;
+
+    switch (type) {
+        #ifndef NO_MD5
+        case MD5:
+            return MD5_DIGEST_SIZE;
+        break;
+        #endif
+
+        #ifndef NO_SHA
+        case SHA:
+            return SHA_DIGEST_SIZE;
+        break;
+        #endif
+        
+        #ifndef NO_SHA256
+        case SHA256:
+            return SHA256_DIGEST_SIZE;
+        break;
+        #endif
+        
+        #ifdef WOLFSSL_SHA384
+        case SHA384:
+            return SHA384_DIGEST_SIZE;
+        break;
+        #endif
+        
+        #ifdef WOLFSSL_SHA512
+        case SHA512:
+            return SHA512_DIGEST_SIZE;
+        break;
+        #endif
+        
+        #ifdef HAVE_BLAKE2 
+        case BLAKE2B_ID:
+            return BLAKE2B_OUTBYTES;
+        break;
+        #endif
+        
+        default:
+            return BAD_FUNC_ARG;
+        break;
+    }
+}
+
+
+/* HMAC-KDF with hash type, optional salt and info, return 0 on success */
+int wc_HKDF(int type, const byte* inKey, word32 inKeySz,
+                   const byte* salt,  word32 saltSz,
+                   const byte* info,  word32 infoSz,
+                   byte* out,         word32 outSz)
+{
+    Hmac   myHmac;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* tmp;
+    byte* prk;
+#else
+    byte   tmp[MAX_DIGEST_SIZE]; /* localSalt helper and T */
+    byte   prk[MAX_DIGEST_SIZE];
+#endif
+    const  byte* localSalt;  /* either points to user input or tmp */
+    int    hashSz = GetHashSizeByType(type);
+    word32 outIdx = 0;
+    byte   n = 0x1;
+    int    ret;
+
+    if (hashSz < 0)
+        return BAD_FUNC_ARG;
+
+#ifdef WOLFSSL_SMALL_STACK
+    tmp = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (tmp == NULL)
+        return MEMORY_E;
+
+    prk = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (prk == NULL) {
+        XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    localSalt = salt;
+    if (localSalt == NULL) {
+        XMEMSET(tmp, 0, hashSz);
+        localSalt = tmp;
+        saltSz    = hashSz;
+    }
+    
+    do {
+    ret = wc_HmacSetKey(&myHmac, type, localSalt, saltSz);
+    if (ret != 0)
+        break;
+    ret = wc_HmacUpdate(&myHmac, inKey, inKeySz);
+    if (ret != 0)
+        break;
+    ret = wc_HmacFinal(&myHmac,  prk);
+    } while (0);
+
+    if (ret == 0) {
+        while (outIdx < outSz) {
+            int    tmpSz = (n == 1) ? 0 : hashSz;
+            word32 left = outSz - outIdx;
+
+            ret = wc_HmacSetKey(&myHmac, type, prk, hashSz);
+            if (ret != 0)
+                break;
+            ret = wc_HmacUpdate(&myHmac, tmp, tmpSz);
+            if (ret != 0)
+                break;
+            ret = wc_HmacUpdate(&myHmac, info, infoSz);
+            if (ret != 0)
+                break;
+            ret = wc_HmacUpdate(&myHmac, &n, 1);
+            if (ret != 0)
+                break;
+            ret = wc_HmacFinal(&myHmac, tmp);
+            if (ret != 0)
+                break;
+
+            left = min(left, (word32)hashSz);
+            XMEMCPY(out+outIdx, tmp, left);
+
+            outIdx += hashSz;
+            n++;
+        }
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(prk, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+#endif /* HAVE_HKDF */
+
+#endif /* HAVE_FIPS */
+#endif /* NO_HMAC */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/include.am	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,49 @@
+# vim:ft=automake
+# All paths should be given relative to the root
+
+EXTRA_DIST += wolfcrypt/src/misc.c
+EXTRA_DIST += wolfcrypt/src/asm.c
+EXTRA_DIST += wolfcrypt/src/aes_asm.asm
+
+EXTRA_DIST += \
+              wolfcrypt/src/ecc_fp.c \
+              wolfcrypt/src/fp_mont_small.i \
+              wolfcrypt/src/fp_mul_comba_12.i \
+              wolfcrypt/src/fp_mul_comba_17.i \
+              wolfcrypt/src/fp_mul_comba_20.i \
+              wolfcrypt/src/fp_mul_comba_24.i \
+              wolfcrypt/src/fp_mul_comba_28.i \
+              wolfcrypt/src/fp_mul_comba_32.i \
+              wolfcrypt/src/fp_mul_comba_3.i \
+              wolfcrypt/src/fp_mul_comba_48.i \
+              wolfcrypt/src/fp_mul_comba_4.i \
+              wolfcrypt/src/fp_mul_comba_64.i \
+              wolfcrypt/src/fp_mul_comba_6.i \
+              wolfcrypt/src/fp_mul_comba_7.i \
+              wolfcrypt/src/fp_mul_comba_8.i \
+              wolfcrypt/src/fp_mul_comba_9.i \
+              wolfcrypt/src/fp_mul_comba_small_set.i \
+              wolfcrypt/src/fp_sqr_comba_12.i \
+              wolfcrypt/src/fp_sqr_comba_17.i \
+              wolfcrypt/src/fp_sqr_comba_20.i \
+              wolfcrypt/src/fp_sqr_comba_24.i \
+              wolfcrypt/src/fp_sqr_comba_28.i \
+              wolfcrypt/src/fp_sqr_comba_32.i \
+              wolfcrypt/src/fp_sqr_comba_3.i \
+              wolfcrypt/src/fp_sqr_comba_48.i \
+              wolfcrypt/src/fp_sqr_comba_4.i \
+              wolfcrypt/src/fp_sqr_comba_64.i \
+              wolfcrypt/src/fp_sqr_comba_6.i \
+              wolfcrypt/src/fp_sqr_comba_7.i \
+              wolfcrypt/src/fp_sqr_comba_8.i \
+              wolfcrypt/src/fp_sqr_comba_9.i \
+              wolfcrypt/src/fp_sqr_comba_small_set.i
+
+EXTRA_DIST += wolfcrypt/src/port/ti/ti-aes.c \
+              wolfcrypt/src/port/ti/ti-des3.c \
+              wolfcrypt/src/port/ti/ti-hash.c \
+              wolfcrypt/src/port/ti/ti-ccm.c \
+              wolfcrypt/src/port/pic32/pic32mz-hash.c
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/integer.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,4523 @@
+/* integer.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+/*
+ * Based on public domain LibTomMath 0.38 by Tom St Denis, tomstdenis@iahu.ca,
+ * http://math.libtomcrypt.com
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+/* in case user set USE_FAST_MATH there */
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifndef NO_BIG_INT
+
+#ifndef USE_FAST_MATH
+
+#include <wolfssl/wolfcrypt/integer.h>
+
+#ifndef NO_WOLFSSL_SMALL_STACK
+    #ifndef WOLFSSL_SMALL_STACK
+        #define WOLFSSL_SMALL_STACK
+    #endif
+#endif
+
+static void bn_reverse (unsigned char *s, int len);
+
+/* math settings check */
+word32 CheckRunTimeSettings(void)
+{
+    return CTC_SETTINGS;
+}
+
+
+/* handle up to 6 inits */
+int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e,
+                  mp_int* f)
+{
+    int res = MP_OKAY;
+
+    if (a && ((res = mp_init(a)) != MP_OKAY))
+        return res;
+
+    if (b && ((res = mp_init(b)) != MP_OKAY)) {
+        mp_clear(a);
+        return res;
+    }
+
+    if (c && ((res = mp_init(c)) != MP_OKAY)) {
+        mp_clear(a); mp_clear(b);
+        return res;
+    }
+
+    if (d && ((res = mp_init(d)) != MP_OKAY)) {
+        mp_clear(a); mp_clear(b); mp_clear(c);
+        return res;
+    }
+
+    if (e && ((res = mp_init(e)) != MP_OKAY)) {
+        mp_clear(a); mp_clear(b); mp_clear(c); mp_clear(d);
+        return res;
+    }
+
+    if (f && ((res = mp_init(f)) != MP_OKAY)) {
+        mp_clear(a); mp_clear(b); mp_clear(c); mp_clear(d); mp_clear(e);
+        return res;
+    }
+
+    return res;
+}
+
+
+/* init a new mp_int */
+int mp_init (mp_int * a)
+{
+  int i;
+
+  /* allocate memory required and clear it */
+  a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC, 0,
+                                      DYNAMIC_TYPE_BIGINT);
+  if (a->dp == NULL) {
+    return MP_MEM;
+  }
+
+  /* set the digits to zero */
+  for (i = 0; i < MP_PREC; i++) {
+      a->dp[i] = 0;
+  }
+
+  /* set the used to zero, allocated digits to the default precision
+   * and sign to positive */
+  a->used  = 0;
+  a->alloc = MP_PREC;
+  a->sign  = MP_ZPOS;
+
+  return MP_OKAY;
+}
+
+
+/* clear one (frees)  */
+void
+mp_clear (mp_int * a)
+{
+  int i;
+
+  if (a == NULL)
+      return;
+
+  /* only do anything if a hasn't been freed previously */
+  if (a->dp != NULL) {
+    /* first zero the digits */
+    for (i = 0; i < a->used; i++) {
+        a->dp[i] = 0;
+    }
+
+    /* free ram */
+    XFREE(a->dp, 0, DYNAMIC_TYPE_BIGINT);
+
+    /* reset members to make debugging easier */
+    a->dp    = NULL;
+    a->alloc = a->used = 0;
+    a->sign  = MP_ZPOS;
+  }
+}
+
+
+/* get the size for an unsigned equivalent */
+int mp_unsigned_bin_size (mp_int * a)
+{
+  int     size = mp_count_bits (a);
+  return (size / 8 + ((size & 7) != 0 ? 1 : 0));
+}
+
+
+/* returns the number of bits in an int */
+int
+mp_count_bits (mp_int * a)
+{
+  int     r;
+  mp_digit q;
+
+  /* shortcut */
+  if (a->used == 0) {
+    return 0;
+  }
+
+  /* get number of digits and add that */
+  r = (a->used - 1) * DIGIT_BIT;
+
+  /* take the last digit and count the bits in it */
+  q = a->dp[a->used - 1];
+  while (q > ((mp_digit) 0)) {
+    ++r;
+    q >>= ((mp_digit) 1);
+  }
+  return r;
+}
+
+
+int mp_leading_bit (mp_int * a)
+{
+    int bit = 0;
+    mp_int t;
+
+    if (mp_init_copy(&t, a) != MP_OKAY)
+        return 0;
+
+    while (mp_iszero(&t) == 0) {
+#ifndef MP_8BIT
+        bit = (t.dp[0] & 0x80) != 0;
+#else
+        bit = (t.dp[0] | ((t.dp[1] & 0x01) << 7)) & 0x80 != 0;
+#endif
+        if (mp_div_2d (&t, 8, &t, NULL) != MP_OKAY)
+            break;
+    }
+    mp_clear(&t);
+    return bit;
+}
+
+
+/* store in unsigned [big endian] format */
+int mp_to_unsigned_bin (mp_int * a, unsigned char *b)
+{
+  int     x, res;
+  mp_int  t;
+
+  if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
+    return res;
+  }
+
+  x = 0;
+  while (mp_iszero (&t) == 0) {
+#ifndef MP_8BIT
+      b[x++] = (unsigned char) (t.dp[0] & 255);
+#else
+      b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
+#endif
+    if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) {
+      mp_clear (&t);
+      return res;
+    }
+  }
+  bn_reverse (b, x);
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+/* creates "a" then copies b into it */
+int mp_init_copy (mp_int * a, mp_int * b)
+{
+  int     res;
+
+  if ((res = mp_init (a)) != MP_OKAY) {
+    return res;
+  }
+  return mp_copy (b, a);
+}
+
+
+/* copy, b = a */
+int
+mp_copy (mp_int * a, mp_int * b)
+{
+  int     res, n;
+
+  /* if dst == src do nothing */
+  if (a == b) {
+    return MP_OKAY;
+  }
+
+  /* grow dest */
+  if (b->alloc < a->used) {
+     if ((res = mp_grow (b, a->used)) != MP_OKAY) {
+        return res;
+     }
+  }
+
+  /* zero b and copy the parameters over */
+  {
+    register mp_digit *tmpa, *tmpb;
+
+    /* pointer aliases */
+
+    /* source */
+    tmpa = a->dp;
+
+    /* destination */
+    tmpb = b->dp;
+
+    /* copy all the digits */
+    for (n = 0; n < a->used; n++) {
+      *tmpb++ = *tmpa++;
+    }
+
+    /* clear high digits */
+    for (; n < b->used; n++) {
+      *tmpb++ = 0;
+    }
+  }
+
+  /* copy used count and sign */
+  b->used = a->used;
+  b->sign = a->sign;
+  return MP_OKAY;
+}
+
+
+/* grow as required */
+int mp_grow (mp_int * a, int size)
+{
+  int     i;
+  mp_digit *tmp;
+
+  /* if the alloc size is smaller alloc more ram */
+  if (a->alloc < size) {
+    /* ensure there are always at least MP_PREC digits extra on top */
+    size += (MP_PREC * 2) - (size % MP_PREC);
+
+    /* reallocate the array a->dp
+     *
+     * We store the return in a temporary variable
+     * in case the operation failed we don't want
+     * to overwrite the dp member of a.
+     */
+    tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size, 0,
+                                       DYNAMIC_TYPE_BIGINT);
+    if (tmp == NULL) {
+      /* reallocation failed but "a" is still valid [can be freed] */
+      return MP_MEM;
+    }
+
+    /* reallocation succeeded so set a->dp */
+    a->dp = tmp;
+
+    /* zero excess digits */
+    i        = a->alloc;
+    a->alloc = size;
+    for (; i < a->alloc; i++) {
+      a->dp[i] = 0;
+    }
+  }
+  return MP_OKAY;
+}
+
+
+/* reverse an array, used for radix code */
+void
+bn_reverse (unsigned char *s, int len)
+{
+  int     ix, iy;
+  unsigned char t;
+
+  ix = 0;
+  iy = len - 1;
+  while (ix < iy) {
+    t     = s[ix];
+    s[ix] = s[iy];
+    s[iy] = t;
+    ++ix;
+    --iy;
+  }
+}
+
+
+/* shift right by a certain bit count (store quotient in c, optional
+   remainder in d) */
+int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
+{
+  int     D, res;
+  mp_int  t;
+
+
+  /* if the shift count is <= 0 then we do no work */
+  if (b <= 0) {
+    res = mp_copy (a, c);
+    if (d != NULL) {
+      mp_zero (d);
+    }
+    return res;
+  }
+
+  if ((res = mp_init (&t)) != MP_OKAY) {
+    return res;
+  }
+
+  /* get the remainder */
+  if (d != NULL) {
+    if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
+      mp_clear (&t);
+      return res;
+    }
+  }
+
+  /* copy */
+  if ((res = mp_copy (a, c)) != MP_OKAY) {
+    mp_clear (&t);
+    return res;
+  }
+
+  /* shift by as many digits in the bit count */
+  if (b >= (int)DIGIT_BIT) {
+    mp_rshd (c, b / DIGIT_BIT);
+  }
+
+  /* shift any bit count < DIGIT_BIT */
+  D = (b % DIGIT_BIT);
+  if (D != 0) {
+    mp_rshb(c, D);
+  }
+  mp_clamp (c);
+  if (d != NULL) {
+    mp_exch (&t, d);
+  }
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+/* set to zero */
+void mp_zero (mp_int * a)
+{
+  int       n;
+  mp_digit *tmp;
+
+  a->sign = MP_ZPOS;
+  a->used = 0;
+
+  tmp = a->dp;
+  for (n = 0; n < a->alloc; n++) {
+     *tmp++ = 0;
+  }
+}
+
+
+/* trim unused digits
+ *
+ * This is used to ensure that leading zero digits are
+ * trimed and the leading "used" digit will be non-zero
+ * Typically very fast.  Also fixes the sign if there
+ * are no more leading digits
+ */
+void
+mp_clamp (mp_int * a)
+{
+  /* decrease used while the most significant digit is
+   * zero.
+   */
+  while (a->used > 0 && a->dp[a->used - 1] == 0) {
+    --(a->used);
+  }
+
+  /* reset the sign flag if used == 0 */
+  if (a->used == 0) {
+    a->sign = MP_ZPOS;
+  }
+}
+
+
+/* swap the elements of two integers, for cases where you can't simply swap the
+ * mp_int pointers around
+ */
+void
+mp_exch (mp_int * a, mp_int * b)
+{
+  mp_int  t;
+
+  t  = *a;
+  *a = *b;
+  *b = t;
+}
+
+
+/* shift right a certain number of bits */
+void mp_rshb (mp_int *c, int x)
+{
+    register mp_digit *tmpc, mask, shift;
+    mp_digit r, rr;
+    mp_digit D = x;
+
+    /* mask */
+    mask = (((mp_digit)1) << D) - 1;
+
+    /* shift for lsb */
+    shift = DIGIT_BIT - D;
+
+    /* alias */
+    tmpc = c->dp + (c->used - 1);
+
+    /* carry */
+    r = 0;
+    for (x = c->used - 1; x >= 0; x--) {
+      /* get the lower  bits of this word in a temp */
+      rr = *tmpc & mask;
+
+      /* shift the current word and mix in the carry bits from previous word */
+      *tmpc = (*tmpc >> D) | (r << shift);
+      --tmpc;
+
+      /* set the carry to the carry bits of the current word found above */
+      r = rr;
+    }
+}
+
+
+/* shift right a certain amount of digits */
+void mp_rshd (mp_int * a, int b)
+{
+  int     x;
+
+  /* if b <= 0 then ignore it */
+  if (b <= 0) {
+    return;
+  }
+
+  /* if b > used then simply zero it and return */
+  if (a->used <= b) {
+    mp_zero (a);
+    return;
+  }
+
+  {
+    register mp_digit *bottom, *top;
+
+    /* shift the digits down */
+
+    /* bottom */
+    bottom = a->dp;
+
+    /* top [offset into digits] */
+    top = a->dp + b;
+
+    /* this is implemented as a sliding window where
+     * the window is b-digits long and digits from
+     * the top of the window are copied to the bottom
+     *
+     * e.g.
+
+     b-2 | b-1 | b0 | b1 | b2 | ... | bb |   ---->
+                 /\                   |      ---->
+                  \-------------------/      ---->
+     */
+    for (x = 0; x < (a->used - b); x++) {
+      *bottom++ = *top++;
+    }
+
+    /* zero the top digits */
+    for (; x < a->used; x++) {
+      *bottom++ = 0;
+    }
+  }
+
+  /* remove excess digits */
+  a->used -= b;
+}
+
+
+/* calc a value mod 2**b */
+int
+mp_mod_2d (mp_int * a, int b, mp_int * c)
+{
+  int     x, res;
+
+  /* if b is <= 0 then zero the int */
+  if (b <= 0) {
+    mp_zero (c);
+    return MP_OKAY;
+  }
+
+  /* if the modulus is larger than the value than return */
+  if (b >= (int) (a->used * DIGIT_BIT)) {
+    res = mp_copy (a, c);
+    return res;
+  }
+
+  /* copy */
+  if ((res = mp_copy (a, c)) != MP_OKAY) {
+    return res;
+  }
+
+  /* zero digits above the last digit of the modulus */
+  for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
+    c->dp[x] = 0;
+  }
+  /* clear the digit that is not completely outside/inside the modulus */
+  c->dp[b / DIGIT_BIT] &= (mp_digit) ((((mp_digit) 1) <<
+              (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+/* reads a unsigned char array, assumes the msb is stored first [big endian] */
+int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
+{
+  int     res;
+
+  /* make sure there are at least two digits */
+  if (a->alloc < 2) {
+     if ((res = mp_grow(a, 2)) != MP_OKAY) {
+        return res;
+     }
+  }
+
+  /* zero the int */
+  mp_zero (a);
+
+  /* read the bytes in */
+  while (c-- > 0) {
+    if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
+      return res;
+    }
+
+#ifndef MP_8BIT
+      a->dp[0] |= *b++;
+      a->used += 1;
+#else
+      a->dp[0] = (*b & MP_MASK);
+      a->dp[1] |= ((*b++ >> 7U) & 1);
+      a->used += 2;
+#endif
+  }
+  mp_clamp (a);
+  return MP_OKAY;
+}
+
+
+/* shift left by a certain bit count */
+int mp_mul_2d (mp_int * a, int b, mp_int * c)
+{
+  mp_digit d;
+  int      res;
+
+  /* copy */
+  if (a != c) {
+     if ((res = mp_copy (a, c)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
+     if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  /* shift by as many digits in the bit count */
+  if (b >= (int)DIGIT_BIT) {
+    if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* shift any bit count < DIGIT_BIT */
+  d = (mp_digit) (b % DIGIT_BIT);
+  if (d != 0) {
+    register mp_digit *tmpc, shift, mask, r, rr;
+    register int x;
+
+    /* bitmask for carries */
+    mask = (((mp_digit)1) << d) - 1;
+
+    /* shift for msbs */
+    shift = DIGIT_BIT - d;
+
+    /* alias */
+    tmpc = c->dp;
+
+    /* carry */
+    r    = 0;
+    for (x = 0; x < c->used; x++) {
+      /* get the higher bits of the current word */
+      rr = (*tmpc >> shift) & mask;
+
+      /* shift the current word and OR in the carry */
+      *tmpc = ((*tmpc << d) | r) & MP_MASK;
+      ++tmpc;
+
+      /* set the carry to the carry bits of the current word */
+      r = rr;
+    }
+
+    /* set final carry */
+    if (r != 0) {
+       c->dp[(c->used)++] = r;
+    }
+  }
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+/* shift left a certain amount of digits */
+int mp_lshd (mp_int * a, int b)
+{
+  int     x, res;
+
+  /* if its less than zero return */
+  if (b <= 0) {
+    return MP_OKAY;
+  }
+
+  /* grow to fit the new digits */
+  if (a->alloc < a->used + b) {
+     if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  {
+    register mp_digit *top, *bottom;
+
+    /* increment the used by the shift amount then copy upwards */
+    a->used += b;
+
+    /* top */
+    top = a->dp + a->used - 1;
+
+    /* base */
+    bottom = a->dp + a->used - 1 - b;
+
+    /* much like mp_rshd this is implemented using a sliding window
+     * except the window goes the otherway around.  Copying from
+     * the bottom to the top.  see bn_mp_rshd.c for more info.
+     */
+    for (x = a->used - 1; x >= b; x--) {
+      *top-- = *bottom--;
+    }
+
+    /* zero the lower digits */
+    top = a->dp;
+    for (x = 0; x < b; x++) {
+      *top++ = 0;
+    }
+  }
+  return MP_OKAY;
+}
+
+
+/* this is a shell function that calls either the normal or Montgomery
+ * exptmod functions.  Originally the call to the montgomery code was
+ * embedded in the normal function but that wasted alot of stack space
+ * for nothing (since 99% of the time the Montgomery code would be called)
+ */
+int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
+{
+  int dr;
+
+  /* modulus P must be positive */
+  if (P->sign == MP_NEG) {
+     return MP_VAL;
+  }
+
+  /* if exponent X is negative we have to recurse */
+  if (X->sign == MP_NEG) {
+#ifdef BN_MP_INVMOD_C
+     mp_int tmpG, tmpX;
+     int err;
+
+     /* first compute 1/G mod P */
+     if ((err = mp_init(&tmpG)) != MP_OKAY) {
+        return err;
+     }
+     if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
+        mp_clear(&tmpG);
+        return err;
+     }
+
+     /* now get |X| */
+     if ((err = mp_init(&tmpX)) != MP_OKAY) {
+        mp_clear(&tmpG);
+        return err;
+     }
+     if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
+        mp_clear(&tmpG);
+        mp_clear(&tmpX);
+        return err;
+     }
+
+     /* and now compute (1/G)**|X| instead of G**X [X < 0] */
+     err = mp_exptmod(&tmpG, &tmpX, P, Y);
+     mp_clear(&tmpG);
+     mp_clear(&tmpX);
+     return err;
+#else
+     /* no invmod */
+     return MP_VAL;
+#endif
+  }
+
+/* modified diminished radix reduction */
+#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && \
+  defined(BN_S_MP_EXPTMOD_C)
+  if (mp_reduce_is_2k_l(P) == MP_YES) {
+     return s_mp_exptmod(G, X, P, Y, 1);
+  }
+#endif
+
+#ifdef BN_MP_DR_IS_MODULUS_C
+  /* is it a DR modulus? */
+  dr = mp_dr_is_modulus(P);
+#else
+  /* default to no */
+  dr = 0;
+#endif
+
+#ifdef BN_MP_REDUCE_IS_2K_C
+  /* if not, is it a unrestricted DR modulus? */
+  if (dr == 0) {
+     dr = mp_reduce_is_2k(P) << 1;
+  }
+#endif
+
+  /* if the modulus is odd or dr != 0 use the montgomery method */
+#ifdef BN_MP_EXPTMOD_FAST_C
+  if (mp_isodd (P) == 1 || dr !=  0) {
+    return mp_exptmod_fast (G, X, P, Y, dr);
+  } else {
+#endif
+#ifdef BN_S_MP_EXPTMOD_C
+    /* otherwise use the generic Barrett reduction technique */
+    return s_mp_exptmod (G, X, P, Y, 0);
+#else
+    /* no exptmod for evens */
+    return MP_VAL;
+#endif
+#ifdef BN_MP_EXPTMOD_FAST_C
+  }
+#endif
+}
+
+
+/* b = |a|
+ *
+ * Simple function copies the input and fixes the sign to positive
+ */
+int
+mp_abs (mp_int * a, mp_int * b)
+{
+  int     res;
+
+  /* copy a to b */
+  if (a != b) {
+     if ((res = mp_copy (a, b)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  /* force the sign of b to positive */
+  b->sign = MP_ZPOS;
+
+  return MP_OKAY;
+}
+
+
+/* hac 14.61, pp608 */
+int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
+{
+  /* b cannot be negative */
+  if (b->sign == MP_NEG || mp_iszero(b) == 1) {
+    return MP_VAL;
+  }
+
+#ifdef BN_FAST_MP_INVMOD_C
+  /* if the modulus is odd we can use a faster routine instead */
+  if (mp_isodd (b) == 1) {
+    return fast_mp_invmod (a, b, c);
+  }
+#endif
+
+#ifdef BN_MP_INVMOD_SLOW_C
+  return mp_invmod_slow(a, b, c);
+#endif
+}
+
+
+/* computes the modular inverse via binary extended euclidean algorithm,
+ * that is c = 1/a mod b
+ *
+ * Based on slow invmod except this is optimized for the case where b is
+ * odd as per HAC Note 14.64 on pp. 610
+ */
+int fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c)
+{
+  mp_int  x, y, u, v, B, D;
+  int     res, neg, loop_check = 0;
+
+  /* 2. [modified] b must be odd   */
+  if (mp_iseven (b) == 1) {
+    return MP_VAL;
+  }
+
+  /* init all our temps */
+  if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D)) != MP_OKAY) {
+     return res;
+  }
+
+  /* x == modulus, y == value to invert */
+  if ((res = mp_copy (b, &x)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+
+  /* we need y = |a| */
+  if ((res = mp_mod (a, b, &y)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+
+  /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+  if ((res = mp_copy (&x, &u)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+  if ((res = mp_copy (&y, &v)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+  mp_set (&D, 1);
+
+top:
+  /* 4.  while u is even do */
+  while (mp_iseven (&u) == 1) {
+    /* 4.1 u = u/2 */
+    if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    /* 4.2 if B is odd then */
+    if (mp_isodd (&B) == 1) {
+      if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
+        goto LBL_ERR;
+      }
+    }
+    /* B = B/2 */
+    if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+
+  /* 5.  while v is even do */
+  while (mp_iseven (&v) == 1) {
+    /* 5.1 v = v/2 */
+    if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    /* 5.2 if D is odd then */
+    if (mp_isodd (&D) == 1) {
+      /* D = (D-x)/2 */
+      if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
+        goto LBL_ERR;
+      }
+    }
+    /* D = D/2 */
+    if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+
+  /* 6.  if u >= v then */
+  if (mp_cmp (&u, &v) != MP_LT) {
+    /* u = u - v, B = B - D */
+    if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  } else {
+    /* v - v - u, D = D - B */
+    if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+
+  /* if not zero goto step 4 */
+  if (mp_iszero (&u) == 0) {
+    if (++loop_check > 1024) {
+        res = MP_VAL;
+        goto LBL_ERR;
+    }
+    goto top;
+  }
+
+  /* now a = C, b = D, gcd == g*v */
+
+  /* if v != 1 then there is no inverse */
+  if (mp_cmp_d (&v, 1) != MP_EQ) {
+    res = MP_VAL;
+    goto LBL_ERR;
+  }
+
+  /* b is now the inverse */
+  neg = a->sign;
+  while (D.sign == MP_NEG) {
+    if ((res = mp_add (&D, b, &D)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+  mp_exch (&D, c);
+  c->sign = neg;
+  res = MP_OKAY;
+
+LBL_ERR:mp_clear(&x);
+        mp_clear(&y);
+        mp_clear(&u);
+        mp_clear(&v);
+        mp_clear(&B);
+        mp_clear(&D);
+  return res;
+}
+
+
+/* hac 14.61, pp608 */
+int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
+{
+  mp_int  x, y, u, v, A, B, C, D;
+  int     res;
+
+  /* b cannot be negative */
+  if (b->sign == MP_NEG || mp_iszero(b) == 1) {
+    return MP_VAL;
+  }
+
+  /* init temps */
+  if ((res = mp_init_multi(&x, &y, &u, &v,
+                           &A, &B)) != MP_OKAY) {
+     return res;
+  }
+
+  /* init rest of tmps temps */
+  if ((res = mp_init_multi(&C, &D, 0, 0, 0, 0)) != MP_OKAY) {
+     return res;
+  }
+
+  /* x = a, y = b */
+  if ((res = mp_mod(a, b, &x)) != MP_OKAY) {
+      goto LBL_ERR;
+  }
+  if ((res = mp_copy (b, &y)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+
+  /* 2. [modified] if x,y are both even then return an error! */
+  if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) {
+    res = MP_VAL;
+    goto LBL_ERR;
+  }
+
+  /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+  if ((res = mp_copy (&x, &u)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+  if ((res = mp_copy (&y, &v)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+  mp_set (&A, 1);
+  mp_set (&D, 1);
+
+top:
+  /* 4.  while u is even do */
+  while (mp_iseven (&u) == 1) {
+    /* 4.1 u = u/2 */
+    if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    /* 4.2 if A or B is odd then */
+    if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) {
+      /* A = (A+y)/2, B = (B-x)/2 */
+      if ((res = mp_add (&A, &y, &A)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+      if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+    }
+    /* A = A/2, B = B/2 */
+    if ((res = mp_div_2 (&A, &A)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+
+  /* 5.  while v is even do */
+  while (mp_iseven (&v) == 1) {
+    /* 5.1 v = v/2 */
+    if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    /* 5.2 if C or D is odd then */
+    if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) {
+      /* C = (C+y)/2, D = (D-x)/2 */
+      if ((res = mp_add (&C, &y, &C)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+      if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+    }
+    /* C = C/2, D = D/2 */
+    if ((res = mp_div_2 (&C, &C)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+
+  /* 6.  if u >= v then */
+  if (mp_cmp (&u, &v) != MP_LT) {
+    /* u = u - v, A = A - C, B = B - D */
+    if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  } else {
+    /* v - v - u, C = C - A, D = D - B */
+    if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+
+  /* if not zero goto step 4 */
+  if (mp_iszero (&u) == 0)
+    goto top;
+
+  /* now a = C, b = D, gcd == g*v */
+
+  /* if v != 1 then there is no inverse */
+  if (mp_cmp_d (&v, 1) != MP_EQ) {
+    res = MP_VAL;
+    goto LBL_ERR;
+  }
+
+  /* if its too low */
+  while (mp_cmp_d(&C, 0) == MP_LT) {
+      if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+  }
+
+  /* too big */
+  while (mp_cmp_mag(&C, b) != MP_LT) {
+      if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+  }
+
+  /* C is now the inverse */
+  mp_exch (&C, c);
+  res = MP_OKAY;
+LBL_ERR:mp_clear(&x);
+        mp_clear(&y);
+        mp_clear(&u);
+        mp_clear(&v);
+        mp_clear(&A);
+        mp_clear(&B);
+        mp_clear(&C);
+        mp_clear(&D);
+  return res;
+}
+
+
+/* compare maginitude of two ints (unsigned) */
+int mp_cmp_mag (mp_int * a, mp_int * b)
+{
+  int     n;
+  mp_digit *tmpa, *tmpb;
+
+  /* compare based on # of non-zero digits */
+  if (a->used > b->used) {
+    return MP_GT;
+  }
+
+  if (a->used < b->used) {
+    return MP_LT;
+  }
+
+  /* alias for a */
+  tmpa = a->dp + (a->used - 1);
+
+  /* alias for b */
+  tmpb = b->dp + (a->used - 1);
+
+  /* compare based on digits  */
+  for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
+    if (*tmpa > *tmpb) {
+      return MP_GT;
+    }
+
+    if (*tmpa < *tmpb) {
+      return MP_LT;
+    }
+  }
+  return MP_EQ;
+}
+
+
+/* compare two ints (signed)*/
+int
+mp_cmp (mp_int * a, mp_int * b)
+{
+  /* compare based on sign */
+  if (a->sign != b->sign) {
+     if (a->sign == MP_NEG) {
+        return MP_LT;
+     } else {
+        return MP_GT;
+     }
+  }
+
+  /* compare digits */
+  if (a->sign == MP_NEG) {
+     /* if negative compare opposite direction */
+     return mp_cmp_mag(b, a);
+  } else {
+     return mp_cmp_mag(a, b);
+  }
+}
+
+
+/* compare a digit */
+int mp_cmp_d(mp_int * a, mp_digit b)
+{
+  /* compare based on sign */
+  if (a->sign == MP_NEG) {
+    return MP_LT;
+  }
+
+  /* compare based on magnitude */
+  if (a->used > 1) {
+    return MP_GT;
+  }
+
+  /* compare the only digit of a to b */
+  if (a->dp[0] > b) {
+    return MP_GT;
+  } else if (a->dp[0] < b) {
+    return MP_LT;
+  } else {
+    return MP_EQ;
+  }
+}
+
+
+/* set to a digit */
+void mp_set (mp_int * a, mp_digit b)
+{
+  mp_zero (a);
+  a->dp[0] = b & MP_MASK;
+  a->used  = (a->dp[0] != 0) ? 1 : 0;
+}
+
+
+/* c = a mod b, 0 <= c < b */
+int
+mp_mod (mp_int * a, mp_int * b, mp_int * c)
+{
+  mp_int  t;
+  int     res;
+
+  if ((res = mp_init (&t)) != MP_OKAY) {
+    return res;
+  }
+
+  if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) {
+    mp_clear (&t);
+    return res;
+  }
+
+  if (t.sign != b->sign) {
+    res = mp_add (b, &t, c);
+  } else {
+    res = MP_OKAY;
+    mp_exch (&t, c);
+  }
+
+  mp_clear (&t);
+  return res;
+}
+
+
+/* slower bit-bang division... also smaller */
+int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+   mp_int ta, tb, tq, q;
+   int    res, n, n2;
+
+  /* is divisor zero ? */
+  if (mp_iszero (b) == 1) {
+    return MP_VAL;
+  }
+
+  /* if a < b then q=0, r = a */
+  if (mp_cmp_mag (a, b) == MP_LT) {
+    if (d != NULL) {
+      res = mp_copy (a, d);
+    } else {
+      res = MP_OKAY;
+    }
+    if (c != NULL) {
+      mp_zero (c);
+    }
+    return res;
+  }
+
+  /* init our temps */
+  if ((res = mp_init_multi(&ta, &tb, &tq, &q, 0, 0)) != MP_OKAY) {
+     return res;
+  }
+
+
+  mp_set(&tq, 1);
+  n = mp_count_bits(a) - mp_count_bits(b);
+  if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
+      ((res = mp_abs(b, &tb)) != MP_OKAY) ||
+      ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
+      ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
+      goto LBL_ERR;
+  }
+
+  while (n-- >= 0) {
+     if (mp_cmp(&tb, &ta) != MP_GT) {
+        if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
+            ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
+           goto LBL_ERR;
+        }
+     }
+     if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
+         ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
+           goto LBL_ERR;
+     }
+  }
+
+  /* now q == quotient and ta == remainder */
+  n  = a->sign;
+  n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
+  if (c != NULL) {
+     mp_exch(c, &q);
+     c->sign  = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
+  }
+  if (d != NULL) {
+     mp_exch(d, &ta);
+     d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
+  }
+LBL_ERR:
+   mp_clear(&ta);
+   mp_clear(&tb);
+   mp_clear(&tq);
+   mp_clear(&q);
+   return res;
+}
+
+
+/* b = a/2 */
+int mp_div_2(mp_int * a, mp_int * b)
+{
+  int     x, res, oldused;
+
+  /* copy */
+  if (b->alloc < a->used) {
+    if ((res = mp_grow (b, a->used)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  oldused = b->used;
+  b->used = a->used;
+  {
+    register mp_digit r, rr, *tmpa, *tmpb;
+
+    /* source alias */
+    tmpa = a->dp + b->used - 1;
+
+    /* dest alias */
+    tmpb = b->dp + b->used - 1;
+
+    /* carry */
+    r = 0;
+    for (x = b->used - 1; x >= 0; x--) {
+      /* get the carry for the next iteration */
+      rr = *tmpa & 1;
+
+      /* shift the current digit, add in carry and store */
+      *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
+
+      /* forward carry to next iteration */
+      r = rr;
+    }
+
+    /* zero excess digits */
+    tmpb = b->dp + b->used;
+    for (x = b->used; x < oldused; x++) {
+      *tmpb++ = 0;
+    }
+  }
+  b->sign = a->sign;
+  mp_clamp (b);
+  return MP_OKAY;
+}
+
+
+/* high level addition (handles signs) */
+int mp_add (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     sa, sb, res;
+
+  /* get sign of both inputs */
+  sa = a->sign;
+  sb = b->sign;
+
+  /* handle two cases, not four */
+  if (sa == sb) {
+    /* both positive or both negative */
+    /* add their magnitudes, copy the sign */
+    c->sign = sa;
+    res = s_mp_add (a, b, c);
+  } else {
+    /* one positive, the other negative */
+    /* subtract the one with the greater magnitude from */
+    /* the one of the lesser magnitude.  The result gets */
+    /* the sign of the one with the greater magnitude. */
+    if (mp_cmp_mag (a, b) == MP_LT) {
+      c->sign = sb;
+      res = s_mp_sub (b, a, c);
+    } else {
+      c->sign = sa;
+      res = s_mp_sub (a, b, c);
+    }
+  }
+  return res;
+}
+
+
+/* low level addition, based on HAC pp.594, Algorithm 14.7 */
+int
+s_mp_add (mp_int * a, mp_int * b, mp_int * c)
+{
+  mp_int *x;
+  int     olduse, res, min, max;
+
+  /* find sizes, we let |a| <= |b| which means we have to sort
+   * them.  "x" will point to the input with the most digits
+   */
+  if (a->used > b->used) {
+    min = b->used;
+    max = a->used;
+    x = a;
+  } else {
+    min = a->used;
+    max = b->used;
+    x = b;
+  }
+
+  /* init result */
+  if (c->alloc < max + 1) {
+    if ((res = mp_grow (c, max + 1)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* get old used digit count and set new one */
+  olduse = c->used;
+  c->used = max + 1;
+
+  {
+    register mp_digit u, *tmpa, *tmpb, *tmpc;
+    register int i;
+
+    /* alias for digit pointers */
+
+    /* first input */
+    tmpa = a->dp;
+
+    /* second input */
+    tmpb = b->dp;
+
+    /* destination */
+    tmpc = c->dp;
+
+    /* zero the carry */
+    u = 0;
+    for (i = 0; i < min; i++) {
+      /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
+      *tmpc = *tmpa++ + *tmpb++ + u;
+
+      /* U = carry bit of T[i] */
+      u = *tmpc >> ((mp_digit)DIGIT_BIT);
+
+      /* take away carry bit from T[i] */
+      *tmpc++ &= MP_MASK;
+    }
+
+    /* now copy higher words if any, that is in A+B
+     * if A or B has more digits add those in
+     */
+    if (min != max) {
+      for (; i < max; i++) {
+        /* T[i] = X[i] + U */
+        *tmpc = x->dp[i] + u;
+
+        /* U = carry bit of T[i] */
+        u = *tmpc >> ((mp_digit)DIGIT_BIT);
+
+        /* take away carry bit from T[i] */
+        *tmpc++ &= MP_MASK;
+      }
+    }
+
+    /* add carry */
+    *tmpc++ = u;
+
+    /* clear digits above oldused */
+    for (i = c->used; i < olduse; i++) {
+      *tmpc++ = 0;
+    }
+  }
+
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
+int
+s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     olduse, res, min, max;
+
+  /* find sizes */
+  min = b->used;
+  max = a->used;
+
+  /* init result */
+  if (c->alloc < max) {
+    if ((res = mp_grow (c, max)) != MP_OKAY) {
+      return res;
+    }
+  }
+  olduse = c->used;
+  c->used = max;
+
+  {
+    register mp_digit u, *tmpa, *tmpb, *tmpc;
+    register int i;
+
+    /* alias for digit pointers */
+    tmpa = a->dp;
+    tmpb = b->dp;
+    tmpc = c->dp;
+
+    /* set carry to zero */
+    u = 0;
+    for (i = 0; i < min; i++) {
+      /* T[i] = A[i] - B[i] - U */
+      *tmpc = *tmpa++ - *tmpb++ - u;
+
+      /* U = carry bit of T[i]
+       * Note this saves performing an AND operation since
+       * if a carry does occur it will propagate all the way to the
+       * MSB.  As a result a single shift is enough to get the carry
+       */
+      u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
+
+      /* Clear carry from T[i] */
+      *tmpc++ &= MP_MASK;
+    }
+
+    /* now copy higher words if any, e.g. if A has more digits than B  */
+    for (; i < max; i++) {
+      /* T[i] = A[i] - U */
+      *tmpc = *tmpa++ - u;
+
+      /* U = carry bit of T[i] */
+      u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
+
+      /* Clear carry from T[i] */
+      *tmpc++ &= MP_MASK;
+    }
+
+    /* clear digits above used (since we may not have grown result above) */
+    for (i = c->used; i < olduse; i++) {
+      *tmpc++ = 0;
+    }
+  }
+
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+/* high level subtraction (handles signs) */
+int
+mp_sub (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     sa, sb, res;
+
+  sa = a->sign;
+  sb = b->sign;
+
+  if (sa != sb) {
+    /* subtract a negative from a positive, OR */
+    /* subtract a positive from a negative. */
+    /* In either case, ADD their magnitudes, */
+    /* and use the sign of the first number. */
+    c->sign = sa;
+    res = s_mp_add (a, b, c);
+  } else {
+    /* subtract a positive from a positive, OR */
+    /* subtract a negative from a negative. */
+    /* First, take the difference between their */
+    /* magnitudes, then... */
+    if (mp_cmp_mag (a, b) != MP_LT) {
+      /* Copy the sign from the first */
+      c->sign = sa;
+      /* The first has a larger or equal magnitude */
+      res = s_mp_sub (a, b, c);
+    } else {
+      /* The result has the *opposite* sign from */
+      /* the first number. */
+      c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
+      /* The second has a larger magnitude */
+      res = s_mp_sub (b, a, c);
+    }
+  }
+  return res;
+}
+
+
+/* determines if reduce_2k_l can be used */
+int mp_reduce_is_2k_l(mp_int *a)
+{
+   int ix, iy;
+
+   if (a->used == 0) {
+      return MP_NO;
+   } else if (a->used == 1) {
+      return MP_YES;
+   } else if (a->used > 1) {
+      /* if more than half of the digits are -1 we're sold */
+      for (iy = ix = 0; ix < a->used; ix++) {
+          if (a->dp[ix] == MP_MASK) {
+              ++iy;
+          }
+      }
+      return (iy >= (a->used/2)) ? MP_YES : MP_NO;
+
+   }
+   return MP_NO;
+}
+
+
+/* determines if mp_reduce_2k can be used */
+int mp_reduce_is_2k(mp_int *a)
+{
+   int ix, iy, iw;
+   mp_digit iz;
+
+   if (a->used == 0) {
+      return MP_NO;
+   } else if (a->used == 1) {
+      return MP_YES;
+   } else if (a->used > 1) {
+      iy = mp_count_bits(a);
+      iz = 1;
+      iw = 1;
+
+      /* Test every bit from the second digit up, must be 1 */
+      for (ix = DIGIT_BIT; ix < iy; ix++) {
+          if ((a->dp[iw] & iz) == 0) {
+             return MP_NO;
+          }
+          iz <<= 1;
+          if (iz > (mp_digit)MP_MASK) {
+             ++iw;
+             iz = 1;
+          }
+      }
+   }
+   return MP_YES;
+}
+
+
+/* determines if a number is a valid DR modulus */
+int mp_dr_is_modulus(mp_int *a)
+{
+   int ix;
+
+   /* must be at least two digits */
+   if (a->used < 2) {
+      return 0;
+   }
+
+   /* must be of the form b**k - a [a <= b] so all
+    * but the first digit must be equal to -1 (mod b).
+    */
+   for (ix = 1; ix < a->used; ix++) {
+       if (a->dp[ix] != MP_MASK) {
+          return 0;
+       }
+   }
+   return 1;
+}
+
+
+/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
+ *
+ * Uses a left-to-right k-ary sliding window to compute the modular
+ * exponentiation.
+ * The value of k changes based on the size of the exponent.
+ *
+ * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
+ */
+
+#ifdef MP_LOW_MEM
+   #define TAB_SIZE 32
+#else
+   #define TAB_SIZE 256
+#endif
+
+int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y,
+                     int redmode)
+{
+  mp_int res;
+  mp_digit buf, mp;
+  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+#ifdef WOLFSSL_SMALL_STACK
+  mp_int* M = NULL;
+#else
+  mp_int M[TAB_SIZE];
+#endif
+  /* use a pointer to the reduction algorithm.  This allows us to use
+   * one of many reduction algorithms without modding the guts of
+   * the code with if statements everywhere.
+   */
+  int     (*redux)(mp_int*,mp_int*,mp_digit);
+
+#ifdef WOLFSSL_SMALL_STACK
+  M = (mp_int*) XMALLOC(sizeof(mp_int) * TAB_SIZE, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+  if (M == NULL)
+    return MP_MEM;
+#endif
+
+  /* find window size */
+  x = mp_count_bits (X);
+  if (x <= 7) {
+    winsize = 2;
+  } else if (x <= 36) {
+    winsize = 3;
+  } else if (x <= 140) {
+    winsize = 4;
+  } else if (x <= 450) {
+    winsize = 5;
+  } else if (x <= 1303) {
+    winsize = 6;
+  } else if (x <= 3529) {
+    winsize = 7;
+  } else {
+    winsize = 8;
+  }
+
+#ifdef MP_LOW_MEM
+  if (winsize > 5) {
+     winsize = 5;
+  }
+#endif
+
+  /* init M array */
+  /* init first cell */
+  if ((err = mp_init(&M[1])) != MP_OKAY) {
+#ifdef WOLFSSL_SMALL_STACK
+  XFREE(M, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+     return err;
+  }
+
+  /* now init the second half of the array */
+  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+    if ((err = mp_init(&M[x])) != MP_OKAY) {
+      for (y = 1<<(winsize-1); y < x; y++) {
+        mp_clear (&M[y]);
+      }
+      mp_clear(&M[1]);
+
+#ifdef WOLFSSL_SMALL_STACK
+      XFREE(M, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+      return err;
+    }
+  }
+
+  /* determine and setup reduction code */
+  if (redmode == 0) {
+#ifdef BN_MP_MONTGOMERY_SETUP_C
+     /* now setup montgomery  */
+     if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
+        goto LBL_M;
+     }
+#else
+     err = MP_VAL;
+     goto LBL_M;
+#endif
+
+     /* automatically pick the comba one if available (saves quite a few
+        calls/ifs) */
+#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
+     if (((P->used * 2 + 1) < MP_WARRAY) &&
+          P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+        redux = fast_mp_montgomery_reduce;
+     } else
+#endif
+     {
+#ifdef BN_MP_MONTGOMERY_REDUCE_C
+        /* use slower baseline Montgomery method */
+        redux = mp_montgomery_reduce;
+#else
+        err = MP_VAL;
+        goto LBL_M;
+#endif
+     }
+  } else if (redmode == 1) {
+#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
+     /* setup DR reduction for moduli of the form B**k - b */
+     mp_dr_setup(P, &mp);
+     redux = mp_dr_reduce;
+#else
+     err = MP_VAL;
+     goto LBL_M;
+#endif
+  } else {
+#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
+     /* setup DR reduction for moduli of the form 2**k - b */
+     if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
+        goto LBL_M;
+     }
+     redux = mp_reduce_2k;
+#else
+     err = MP_VAL;
+     goto LBL_M;
+#endif
+  }
+
+  /* setup result */
+  if ((err = mp_init (&res)) != MP_OKAY) {
+    goto LBL_M;
+  }
+
+  /* create M table
+   *
+
+   *
+   * The first half of the table is not computed though accept for M[0] and M[1]
+   */
+
+  if (redmode == 0) {
+#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+     /* now we need R mod m */
+     if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
+       goto LBL_RES;
+     }
+#else
+     err = MP_VAL;
+     goto LBL_RES;
+#endif
+
+     /* now set M[1] to G * R mod m */
+     if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
+       goto LBL_RES;
+     }
+  } else {
+     mp_set(&res, 1);
+     if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
+        goto LBL_RES;
+     }
+  }
+
+  /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times*/
+  if ((err = mp_copy (&M[1], &M[(mp_digit)(1 << (winsize - 1))])) != MP_OKAY) {
+    goto LBL_RES;
+  }
+
+  for (x = 0; x < (winsize - 1); x++) {
+    if ((err = mp_sqr (&M[(mp_digit)(1 << (winsize - 1))], &M[(mp_digit)(1 << (winsize - 1))])) != MP_OKAY) {
+      goto LBL_RES;
+    }
+    if ((err = redux (&M[(mp_digit)(1 << (winsize - 1))], P, mp)) != MP_OKAY) {
+      goto LBL_RES;
+    }
+  }
+
+  /* create upper table */
+  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+    if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
+      goto LBL_RES;
+    }
+    if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
+      goto LBL_RES;
+    }
+  }
+
+  /* set initial mode and bit cnt */
+  mode   = 0;
+  bitcnt = 1;
+  buf    = 0;
+  digidx = X->used - 1;
+  bitcpy = 0;
+  bitbuf = 0;
+
+  for (;;) {
+    /* grab next digit as required */
+    if (--bitcnt == 0) {
+      /* if digidx == -1 we are out of digits so break */
+      if (digidx == -1) {
+        break;
+      }
+      /* read next digit and reset bitcnt */
+      buf    = X->dp[digidx--];
+      bitcnt = (int)DIGIT_BIT;
+    }
+
+    /* grab the next msb from the exponent */
+    y     = (int)(buf >> (DIGIT_BIT - 1)) & 1;
+    buf <<= (mp_digit)1;
+
+    /* if the bit is zero and mode == 0 then we ignore it
+     * These represent the leading zero bits before the first 1 bit
+     * in the exponent.  Technically this opt is not required but it
+     * does lower the # of trivial squaring/reductions used
+     */
+    if (mode == 0 && y == 0) {
+      continue;
+    }
+
+    /* if the bit is zero and mode == 1 then we square */
+    if (mode == 1 && y == 0) {
+      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, mp)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      continue;
+    }
+
+    /* else we add it to the window */
+    bitbuf |= (y << (winsize - ++bitcpy));
+    mode    = 2;
+
+    if (bitcpy == winsize) {
+      /* ok window is filled so square as required and multiply  */
+      /* square first */
+      for (x = 0; x < winsize; x++) {
+        if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+        if ((err = redux (&res, P, mp)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+      }
+
+      /* then multiply */
+      if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, mp)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+
+      /* empty window and reset */
+      bitcpy = 0;
+      bitbuf = 0;
+      mode   = 1;
+    }
+  }
+
+  /* if bits remain then square/multiply */
+  if (mode == 2 && bitcpy > 0) {
+    /* square then multiply if the bit is set */
+    for (x = 0; x < bitcpy; x++) {
+      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, mp)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+
+      /* get next bit of the window */
+      bitbuf <<= 1;
+      if ((bitbuf & (1 << winsize)) != 0) {
+        /* then multiply */
+        if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+        if ((err = redux (&res, P, mp)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+      }
+    }
+  }
+
+  if (redmode == 0) {
+     /* fixup result if Montgomery reduction is used
+      * recall that any value in a Montgomery system is
+      * actually multiplied by R mod n.  So we have
+      * to reduce one more time to cancel out the factor
+      * of R.
+      */
+     if ((err = redux(&res, P, mp)) != MP_OKAY) {
+       goto LBL_RES;
+     }
+  }
+
+  /* swap res with Y */
+  mp_exch (&res, Y);
+  err = MP_OKAY;
+LBL_RES:mp_clear (&res);
+LBL_M:
+  mp_clear(&M[1]);
+  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+    mp_clear (&M[x]);
+  }
+
+#ifdef WOLFSSL_SMALL_STACK
+  XFREE(M, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+  return err;
+}
+
+
+/* setups the montgomery reduction stuff */
+int
+mp_montgomery_setup (mp_int * n, mp_digit * rho)
+{
+  mp_digit x, b;
+
+/* fast inversion mod 2**k
+ *
+ * Based on the fact that
+ *
+ * XA = 1 (mod 2**n)  =>  (X(2-XA)) A = 1 (mod 2**2n)
+ *                    =>  2*X*A - X*X*A*A = 1
+ *                    =>  2*(1) - (1)     = 1
+ */
+  b = n->dp[0];
+
+  if ((b & 1) == 0) {
+    return MP_VAL;
+  }
+
+  x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
+  x *= 2 - b * x;               /* here x*a==1 mod 2**8 */
+#if !defined(MP_8BIT)
+  x *= 2 - b * x;               /* here x*a==1 mod 2**16 */
+#endif
+#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
+  x *= 2 - b * x;               /* here x*a==1 mod 2**32 */
+#endif
+#ifdef MP_64BIT
+  x *= 2 - b * x;               /* here x*a==1 mod 2**64 */
+#endif
+
+  /* rho = -1/m mod b */
+  /* TAO, switched mp_word casts to mp_digit to shut up compiler */
+  *rho = (((mp_digit)1 << ((mp_digit) DIGIT_BIT)) - x) & MP_MASK;
+
+  return MP_OKAY;
+}
+
+
+/* computes xR**-1 == x (mod N) via Montgomery Reduction
+ *
+ * This is an optimized implementation of montgomery_reduce
+ * which uses the comba method to quickly calculate the columns of the
+ * reduction.
+ *
+ * Based on Algorithm 14.32 on pp.601 of HAC.
+*/
+int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+{
+  int     ix, res, olduse;
+#ifdef WOLFSSL_SMALL_STACK
+  mp_word* W;    /* uses dynamic memory and slower */
+#else
+  mp_word W[MP_WARRAY];
+#endif
+
+  /* get old used count */
+  olduse = x->used;
+
+  /* grow a as required */
+  if (x->alloc < n->used + 1) {
+    if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+#ifdef WOLFSSL_SMALL_STACK
+  W = (mp_word*)XMALLOC(sizeof(mp_word) * MP_WARRAY, 0, DYNAMIC_TYPE_BIGINT);
+  if (W == NULL)
+    return MP_MEM;
+#endif
+
+  /* first we have to get the digits of the input into
+   * an array of double precision words W[...]
+   */
+  {
+    register mp_word *_W;
+    register mp_digit *tmpx;
+
+    /* alias for the W[] array */
+    _W   = W;
+
+    /* alias for the digits of  x*/
+    tmpx = x->dp;
+
+    /* copy the digits of a into W[0..a->used-1] */
+    for (ix = 0; ix < x->used; ix++) {
+      *_W++ = *tmpx++;
+    }
+
+    /* zero the high words of W[a->used..m->used*2] */
+    for (; ix < n->used * 2 + 1; ix++) {
+      *_W++ = 0;
+    }
+  }
+
+  /* now we proceed to zero successive digits
+   * from the least significant upwards
+   */
+  for (ix = 0; ix < n->used; ix++) {
+    /* mu = ai * m' mod b
+     *
+     * We avoid a double precision multiplication (which isn't required)
+     * by casting the value down to a mp_digit.  Note this requires
+     * that W[ix-1] have  the carry cleared (see after the inner loop)
+     */
+    register mp_digit mu;
+    mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
+
+    /* a = a + mu * m * b**i
+     *
+     * This is computed in place and on the fly.  The multiplication
+     * by b**i is handled by offseting which columns the results
+     * are added to.
+     *
+     * Note the comba method normally doesn't handle carries in the
+     * inner loop In this case we fix the carry from the previous
+     * column since the Montgomery reduction requires digits of the
+     * result (so far) [see above] to work.  This is
+     * handled by fixing up one carry after the inner loop.  The
+     * carry fixups are done in order so after these loops the
+     * first m->used words of W[] have the carries fixed
+     */
+    {
+      register int iy;
+      register mp_digit *tmpn;
+      register mp_word *_W;
+
+      /* alias for the digits of the modulus */
+      tmpn = n->dp;
+
+      /* Alias for the columns set by an offset of ix */
+      _W = W + ix;
+
+      /* inner loop */
+      for (iy = 0; iy < n->used; iy++) {
+          *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
+      }
+    }
+
+    /* now fix carry for next digit, W[ix+1] */
+    W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
+  }
+
+  /* now we have to propagate the carries and
+   * shift the words downward [all those least
+   * significant digits we zeroed].
+   */
+  {
+    register mp_digit *tmpx;
+    register mp_word *_W, *_W1;
+
+    /* nox fix rest of carries */
+
+    /* alias for current word */
+    _W1 = W + ix;
+
+    /* alias for next word, where the carry goes */
+    _W = W + ++ix;
+
+    for (; ix <= n->used * 2 + 1; ix++) {
+      *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
+    }
+
+    /* copy out, A = A/b**n
+     *
+     * The result is A/b**n but instead of converting from an
+     * array of mp_word to mp_digit than calling mp_rshd
+     * we just copy them in the right order
+     */
+
+    /* alias for destination word */
+    tmpx = x->dp;
+
+    /* alias for shifted double precision result */
+    _W = W + n->used;
+
+    for (ix = 0; ix < n->used + 1; ix++) {
+      *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
+    }
+
+    /* zero oldused digits, if the input a was larger than
+     * m->used+1 we'll have to clear the digits
+     */
+    for (; ix < olduse; ix++) {
+      *tmpx++ = 0;
+    }
+  }
+
+  /* set the max used and clamp */
+  x->used = n->used + 1;
+  mp_clamp (x);
+
+#ifdef WOLFSSL_SMALL_STACK
+  XFREE(W, 0, DYNAMIC_TYPE_BIGINT);
+#endif
+
+  /* if A >= m then A = A - m */
+  if (mp_cmp_mag (x, n) != MP_LT) {
+    return s_mp_sub (x, n, x);
+  }
+  return MP_OKAY;
+}
+
+
+/* computes xR**-1 == x (mod N) via Montgomery Reduction */
+int
+mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+{
+  int     ix, res, digs;
+  mp_digit mu;
+
+  /* can the fast reduction [comba] method be used?
+   *
+   * Note that unlike in mul you're safely allowed *less*
+   * than the available columns [255 per default] since carries
+   * are fixed up in the inner loop.
+   */
+  digs = n->used * 2 + 1;
+  if ((digs < MP_WARRAY) &&
+      n->used <
+      (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+    return fast_mp_montgomery_reduce (x, n, rho);
+  }
+
+  /* grow the input as required */
+  if (x->alloc < digs) {
+    if ((res = mp_grow (x, digs)) != MP_OKAY) {
+      return res;
+    }
+  }
+  x->used = digs;
+
+  for (ix = 0; ix < n->used; ix++) {
+    /* mu = ai * rho mod b
+     *
+     * The value of rho must be precalculated via
+     * montgomery_setup() such that
+     * it equals -1/n0 mod b this allows the
+     * following inner loop to reduce the
+     * input one digit at a time
+     */
+    mu = (mp_digit) (((mp_word)x->dp[ix]) * ((mp_word)rho) & MP_MASK);
+
+    /* a = a + mu * m * b**i */
+    {
+      register int iy;
+      register mp_digit *tmpn, *tmpx, u;
+      register mp_word r;
+
+      /* alias for digits of the modulus */
+      tmpn = n->dp;
+
+      /* alias for the digits of x [the input] */
+      tmpx = x->dp + ix;
+
+      /* set the carry to zero */
+      u = 0;
+
+      /* Multiply and add in place */
+      for (iy = 0; iy < n->used; iy++) {
+        /* compute product and sum */
+        r       = ((mp_word)mu) * ((mp_word)*tmpn++) +
+                  ((mp_word) u) + ((mp_word) * tmpx);
+
+        /* get carry */
+        u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+
+        /* fix digit */
+        *tmpx++ = (mp_digit)(r & ((mp_word) MP_MASK));
+      }
+      /* At this point the ix'th digit of x should be zero */
+
+
+      /* propagate carries upwards as required*/
+      while (u) {
+        *tmpx   += u;
+        u        = *tmpx >> DIGIT_BIT;
+        *tmpx++ &= MP_MASK;
+      }
+    }
+  }
+
+  /* at this point the n.used'th least
+   * significant digits of x are all zero
+   * which means we can shift x to the
+   * right by n.used digits and the
+   * residue is unchanged.
+   */
+
+  /* x = x/b**n.used */
+  mp_clamp(x);
+  mp_rshd (x, n->used);
+
+  /* if x >= n then x = x - n */
+  if (mp_cmp_mag (x, n) != MP_LT) {
+    return s_mp_sub (x, n, x);
+  }
+
+  return MP_OKAY;
+}
+
+
+/* determines the setup value */
+void mp_dr_setup(mp_int *a, mp_digit *d)
+{
+   /* the casts are required if DIGIT_BIT is one less than
+    * the number of bits in a mp_digit [e.g. DIGIT_BIT==31]
+    */
+   *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) -
+        ((mp_word)a->dp[0]));
+}
+
+
+/* reduce "x" in place modulo "n" using the Diminished Radix algorithm.
+ *
+ * Based on algorithm from the paper
+ *
+ * "Generating Efficient Primes for Discrete Log Cryptosystems"
+ *                 Chae Hoon Lim, Pil Joong Lee,
+ *          POSTECH Information Research Laboratories
+ *
+ * The modulus must be of a special format [see manual]
+ *
+ * Has been modified to use algorithm 7.10 from the LTM book instead
+ *
+ * Input x must be in the range 0 <= x <= (n-1)**2
+ */
+int
+mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k)
+{
+  int      err, i, m;
+  mp_word  r;
+  mp_digit mu, *tmpx1, *tmpx2;
+
+  /* m = digits in modulus */
+  m = n->used;
+
+  /* ensure that "x" has at least 2m digits */
+  if (x->alloc < m + m) {
+    if ((err = mp_grow (x, m + m)) != MP_OKAY) {
+      return err;
+    }
+  }
+
+/* top of loop, this is where the code resumes if
+ * another reduction pass is required.
+ */
+top:
+  /* aliases for digits */
+  /* alias for lower half of x */
+  tmpx1 = x->dp;
+
+  /* alias for upper half of x, or x/B**m */
+  tmpx2 = x->dp + m;
+
+  /* set carry to zero */
+  mu = 0;
+
+  /* compute (x mod B**m) + k * [x/B**m] inline and inplace */
+  for (i = 0; i < m; i++) {
+      r         = ((mp_word)*tmpx2++) * ((mp_word)k) + *tmpx1 + mu;
+      *tmpx1++  = (mp_digit)(r & MP_MASK);
+      mu        = (mp_digit)(r >> ((mp_word)DIGIT_BIT));
+  }
+
+  /* set final carry */
+  *tmpx1++ = mu;
+
+  /* zero words above m */
+  for (i = m + 1; i < x->used; i++) {
+      *tmpx1++ = 0;
+  }
+
+  /* clamp, sub and return */
+  mp_clamp (x);
+
+  /* if x >= n then subtract and reduce again
+   * Each successive "recursion" makes the input smaller and smaller.
+   */
+  if (mp_cmp_mag (x, n) != MP_LT) {
+    s_mp_sub(x, n, x);
+    goto top;
+  }
+  return MP_OKAY;
+}
+
+
+/* reduces a modulo n where n is of the form 2**p - d */
+int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d)
+{
+   mp_int q;
+   int    p, res;
+
+   if ((res = mp_init(&q)) != MP_OKAY) {
+      return res;
+   }
+
+   p = mp_count_bits(n);
+top:
+   /* q = a/2**p, a = a mod 2**p */
+   if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
+      goto ERR;
+   }
+
+   if (d != 1) {
+      /* q = q * d */
+      if ((res = mp_mul_d(&q, d, &q)) != MP_OKAY) {
+         goto ERR;
+      }
+   }
+
+   /* a = a + q */
+   if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
+      goto ERR;
+   }
+
+   if (mp_cmp_mag(a, n) != MP_LT) {
+      s_mp_sub(a, n, a);
+      goto top;
+   }
+
+ERR:
+   mp_clear(&q);
+   return res;
+}
+
+
+/* determines the setup value */
+int mp_reduce_2k_setup(mp_int *a, mp_digit *d)
+{
+   int res, p;
+   mp_int tmp;
+
+   if ((res = mp_init(&tmp)) != MP_OKAY) {
+      return res;
+   }
+
+   p = mp_count_bits(a);
+   if ((res = mp_2expt(&tmp, p)) != MP_OKAY) {
+      mp_clear(&tmp);
+      return res;
+   }
+
+   if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) {
+      mp_clear(&tmp);
+      return res;
+   }
+
+   *d = tmp.dp[0];
+   mp_clear(&tmp);
+   return MP_OKAY;
+}
+
+
+/* computes a = 2**b
+ *
+ * Simple algorithm which zeroes the int, grows it then just sets one bit
+ * as required.
+ */
+int
+mp_2expt (mp_int * a, int b)
+{
+  int     res;
+
+  /* zero a as per default */
+  mp_zero (a);
+
+  /* grow a to accomodate the single bit */
+  if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
+    return res;
+  }
+
+  /* set the used count of where the bit will go */
+  a->used = b / DIGIT_BIT + 1;
+
+  /* put the single bit in its place */
+  a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT);
+
+  return MP_OKAY;
+}
+
+
+/* multiply by a digit */
+int
+mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
+{
+  mp_digit u, *tmpa, *tmpc;
+  mp_word  r;
+  int      ix, res, olduse;
+
+  /* make sure c is big enough to hold a*b */
+  if (c->alloc < a->used + 1) {
+    if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* get the original destinations used count */
+  olduse = c->used;
+
+  /* set the sign */
+  c->sign = a->sign;
+
+  /* alias for a->dp [source] */
+  tmpa = a->dp;
+
+  /* alias for c->dp [dest] */
+  tmpc = c->dp;
+
+  /* zero carry */
+  u = 0;
+
+  /* compute columns */
+  for (ix = 0; ix < a->used; ix++) {
+    /* compute product and carry sum for this term */
+    r       = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
+
+    /* mask off higher bits to get a single digit */
+    *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+    /* send carry into next iteration */
+    u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+  }
+
+  /* store final carry [if any] and increment ix offset  */
+  *tmpc++ = u;
+  ++ix;
+
+  /* now zero digits above the top */
+  while (ix++ < olduse) {
+     *tmpc++ = 0;
+  }
+
+  /* set used count */
+  c->used = a->used + 1;
+  mp_clamp(c);
+
+  return MP_OKAY;
+}
+
+
+/* d = a * b (mod c) */
+int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+  int     res;
+  mp_int  t;
+
+  if ((res = mp_init (&t)) != MP_OKAY) {
+    return res;
+  }
+
+  if ((res = mp_mul (a, b, &t)) != MP_OKAY) {
+    mp_clear (&t);
+    return res;
+  }
+  res = mp_mod (&t, c, d);
+  mp_clear (&t);
+  return res;
+}
+
+
+/* computes b = a*a */
+int
+mp_sqr (mp_int * a, mp_int * b)
+{
+  int     res;
+
+  {
+#ifdef BN_FAST_S_MP_SQR_C
+    /* can we use the fast comba multiplier? */
+    if ((a->used * 2 + 1) < MP_WARRAY &&
+         a->used <
+         (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
+      res = fast_s_mp_sqr (a, b);
+    } else
+#endif
+#ifdef BN_S_MP_SQR_C
+      res = s_mp_sqr (a, b);
+#else
+      res = MP_VAL;
+#endif
+  }
+  b->sign = MP_ZPOS;
+  return res;
+}
+
+
+/* high level multiplication (handles sign) */
+int mp_mul (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     res, neg;
+  neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+
+  {
+    /* can we use the fast multiplier?
+     *
+     * The fast multiplier can be used if the output will
+     * have less than MP_WARRAY digits and the number of
+     * digits won't affect carry propagation
+     */
+    int     digs = a->used + b->used + 1;
+
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
+    if ((digs < MP_WARRAY) &&
+        MIN(a->used, b->used) <=
+        (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+      res = fast_s_mp_mul_digs (a, b, c, digs);
+    } else
+#endif
+#ifdef BN_S_MP_MUL_DIGS_C
+      res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
+#else
+      res = MP_VAL;
+#endif
+
+  }
+  c->sign = (c->used > 0) ? neg : MP_ZPOS;
+  return res;
+}
+
+
+/* b = a*2 */
+int mp_mul_2(mp_int * a, mp_int * b)
+{
+  int     x, res, oldused;
+
+  /* grow to accomodate result */
+  if (b->alloc < a->used + 1) {
+    if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  oldused = b->used;
+  b->used = a->used;
+
+  {
+    register mp_digit r, rr, *tmpa, *tmpb;
+
+    /* alias for source */
+    tmpa = a->dp;
+
+    /* alias for dest */
+    tmpb = b->dp;
+
+    /* carry */
+    r = 0;
+    for (x = 0; x < a->used; x++) {
+
+      /* get what will be the *next* carry bit from the
+       * MSB of the current digit
+       */
+      rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
+
+      /* now shift up this digit, add in the carry [from the previous] */
+      *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
+
+      /* copy the carry that would be from the source
+       * digit into the next iteration
+       */
+      r = rr;
+    }
+
+    /* new leading digit? */
+    if (r != 0) {
+      /* add a MSB which is always 1 at this point */
+      *tmpb = 1;
+      ++(b->used);
+    }
+
+    /* now zero any excess digits on the destination
+     * that we didn't write to
+     */
+    tmpb = b->dp + b->used;
+    for (x = b->used; x < oldused; x++) {
+      *tmpb++ = 0;
+    }
+  }
+  b->sign = a->sign;
+  return MP_OKAY;
+}
+
+
+/* divide by three (based on routine from MPI and the GMP manual) */
+int
+mp_div_3 (mp_int * a, mp_int *c, mp_digit * d)
+{
+  mp_int   q;
+  mp_word  w, t;
+  mp_digit b;
+  int      res, ix;
+
+  /* b = 2**DIGIT_BIT / 3 */
+  b = (mp_digit) ( (((mp_word)1) << ((mp_word)DIGIT_BIT)) / ((mp_word)3) );
+
+  if ((res = mp_init_size(&q, a->used)) != MP_OKAY) {
+     return res;
+  }
+
+  q.used = a->used;
+  q.sign = a->sign;
+  w = 0;
+  for (ix = a->used - 1; ix >= 0; ix--) {
+     w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]);
+
+     if (w >= 3) {
+        /* multiply w by [1/3] */
+        t = (w * ((mp_word)b)) >> ((mp_word)DIGIT_BIT);
+
+        /* now subtract 3 * [w/3] from w, to get the remainder */
+        w -= t+t+t;
+
+        /* fixup the remainder as required since
+         * the optimization is not exact.
+         */
+        while (w >= 3) {
+           t += 1;
+           w -= 3;
+        }
+      } else {
+        t = 0;
+      }
+      q.dp[ix] = (mp_digit)t;
+  }
+
+  /* [optional] store the remainder */
+  if (d != NULL) {
+     *d = (mp_digit)w;
+  }
+
+  /* [optional] store the quotient */
+  if (c != NULL) {
+     mp_clamp(&q);
+     mp_exch(&q, c);
+  }
+  mp_clear(&q);
+
+  return res;
+}
+
+
+/* init an mp_init for a given size */
+int mp_init_size (mp_int * a, int size)
+{
+  int x;
+
+  /* pad size so there are always extra digits */
+  size += (MP_PREC * 2) - (size % MP_PREC);
+
+  /* alloc mem */
+  a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size, 0,
+                                      DYNAMIC_TYPE_BIGINT);
+  if (a->dp == NULL) {
+    return MP_MEM;
+  }
+
+  /* set the members */
+  a->used  = 0;
+  a->alloc = size;
+  a->sign  = MP_ZPOS;
+
+  /* zero the digits */
+  for (x = 0; x < size; x++) {
+      a->dp[x] = 0;
+  }
+
+  return MP_OKAY;
+}
+
+
+/* the jist of squaring...
+ * you do like mult except the offset of the tmpx [one that
+ * starts closer to zero] can't equal the offset of tmpy.
+ * So basically you set up iy like before then you min it with
+ * (ty-tx) so that it never happens.  You double all those
+ * you add in the inner loop
+
+After that loop you do the squares and add them in.
+*/
+
+int fast_s_mp_sqr (mp_int * a, mp_int * b)
+{
+  int       olduse, res, pa, ix, iz;
+#ifdef WOLFSSL_SMALL_STACK
+  mp_digit* W;    /* uses dynamic memory and slower */
+#else
+  mp_digit W[MP_WARRAY];
+#endif
+  mp_digit  *tmpx;
+  mp_word   W1;
+
+  /* grow the destination as required */
+  pa = a->used + a->used;
+  if (b->alloc < pa) {
+    if ((res = mp_grow (b, pa)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  if (pa > MP_WARRAY)
+    return MP_RANGE;  /* TAO range check */
+
+#ifdef WOLFSSL_SMALL_STACK
+  W = (mp_digit*)XMALLOC(sizeof(mp_digit) * MP_WARRAY, 0, DYNAMIC_TYPE_BIGINT);
+  if (W == NULL)
+    return MP_MEM;
+#endif
+
+  /* number of output digits to produce */
+  W1 = 0;
+  for (ix = 0; ix < pa; ix++) {
+      int      tx, ty, iy;
+      mp_word  _W;
+      mp_digit *tmpy;
+
+      /* clear counter */
+      _W = 0;
+
+      /* get offsets into the two bignums */
+      ty = MIN(a->used-1, ix);
+      tx = ix - ty;
+
+      /* setup temp aliases */
+      tmpx = a->dp + tx;
+      tmpy = a->dp + ty;
+
+      /* this is the number of times the loop will iterrate, essentially
+         while (tx++ < a->used && ty-- >= 0) { ... }
+       */
+      iy = MIN(a->used-tx, ty+1);
+
+      /* now for squaring tx can never equal ty
+       * we halve the distance since they approach at a rate of 2x
+       * and we have to round because odd cases need to be executed
+       */
+      iy = MIN(iy, (ty-tx+1)>>1);
+
+      /* execute loop */
+      for (iz = 0; iz < iy; iz++) {
+         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+      }
+
+      /* double the inner product and add carry */
+      _W = _W + _W + W1;
+
+      /* even columns have the square term in them */
+      if ((ix&1) == 0) {
+         _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
+      }
+
+      /* store it */
+      W[ix] = (mp_digit)(_W & MP_MASK);
+
+      /* make next carry */
+      W1 = _W >> ((mp_word)DIGIT_BIT);
+  }
+
+  /* setup dest */
+  olduse  = b->used;
+  b->used = a->used+a->used;
+
+  {
+    mp_digit *tmpb;
+    tmpb = b->dp;
+    for (ix = 0; ix < pa; ix++) {
+      *tmpb++ = W[ix] & MP_MASK;
+    }
+
+    /* clear unused digits [that existed in the old copy of c] */
+    for (; ix < olduse; ix++) {
+      *tmpb++ = 0;
+    }
+  }
+  mp_clamp (b);
+
+#ifdef WOLFSSL_SMALL_STACK
+  XFREE(W, 0, DYNAMIC_TYPE_BIGINT);
+#endif
+
+  return MP_OKAY;
+}
+
+
+/* Fast (comba) multiplier
+ *
+ * This is the fast column-array [comba] multiplier.  It is
+ * designed to compute the columns of the product first
+ * then handle the carries afterwards.  This has the effect
+ * of making the nested loops that compute the columns very
+ * simple and schedulable on super-scalar processors.
+ *
+ * This has been modified to produce a variable number of
+ * digits of output so if say only a half-product is required
+ * you don't have to compute the upper half (a feature
+ * required for fast Barrett reduction).
+ *
+ * Based on Algorithm 14.12 on pp.595 of HAC.
+ *
+ */
+int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+  int     olduse, res, pa, ix, iz;
+#ifdef WOLFSSL_SMALL_STACK
+  mp_digit* W;    /* uses dynamic memory and slower */
+#else
+  mp_digit W[MP_WARRAY];
+#endif
+  register mp_word  _W;
+
+  /* grow the destination as required */
+  if (c->alloc < digs) {
+    if ((res = mp_grow (c, digs)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* number of output digits to produce */
+  pa = MIN(digs, a->used + b->used);
+  if (pa > MP_WARRAY)
+    return MP_RANGE;  /* TAO range check */
+
+#ifdef WOLFSSL_SMALL_STACK
+  W = (mp_digit*)XMALLOC(sizeof(mp_digit) * MP_WARRAY, 0, DYNAMIC_TYPE_BIGINT);
+  if (W == NULL)
+    return MP_MEM;
+#endif
+
+  /* clear the carry */
+  _W = 0;
+  for (ix = 0; ix < pa; ix++) {
+      int      tx, ty;
+      int      iy;
+      mp_digit *tmpx, *tmpy;
+
+      /* get offsets into the two bignums */
+      ty = MIN(b->used-1, ix);
+      tx = ix - ty;
+
+      /* setup temp aliases */
+      tmpx = a->dp + tx;
+      tmpy = b->dp + ty;
+
+      /* this is the number of times the loop will iterrate, essentially
+         while (tx++ < a->used && ty-- >= 0) { ... }
+       */
+      iy = MIN(a->used-tx, ty+1);
+
+      /* execute loop */
+      for (iz = 0; iz < iy; ++iz) {
+         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+
+      }
+
+      /* store term */
+      W[ix] = ((mp_digit)_W) & MP_MASK;
+
+      /* make next carry */
+      _W = _W >> ((mp_word)DIGIT_BIT);
+ }
+
+  /* setup dest */
+  olduse  = c->used;
+  c->used = pa;
+
+  {
+    register mp_digit *tmpc;
+    tmpc = c->dp;
+    for (ix = 0; ix < pa+1; ix++) {
+      /* now extract the previous digit [below the carry] */
+      *tmpc++ = W[ix];
+    }
+
+    /* clear unused digits [that existed in the old copy of c] */
+    for (; ix < olduse; ix++) {
+      *tmpc++ = 0;
+    }
+  }
+  mp_clamp (c);
+
+#ifdef WOLFSSL_SMALL_STACK
+  XFREE(W, 0, DYNAMIC_TYPE_BIGINT);
+#endif
+
+  return MP_OKAY;
+}
+
+
+/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
+int s_mp_sqr (mp_int * a, mp_int * b)
+{
+  mp_int  t;
+  int     res, ix, iy, pa;
+  mp_word r;
+  mp_digit u, tmpx, *tmpt;
+
+  pa = a->used;
+  if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) {
+    return res;
+  }
+
+  /* default used is maximum possible size */
+  t.used = 2*pa + 1;
+
+  for (ix = 0; ix < pa; ix++) {
+    /* first calculate the digit at 2*ix */
+    /* calculate double precision result */
+    r = ((mp_word) t.dp[2*ix]) +
+        ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
+
+    /* store lower part in result */
+    t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
+
+    /* get the carry */
+    u           = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+
+    /* left hand side of A[ix] * A[iy] */
+    tmpx        = a->dp[ix];
+
+    /* alias for where to store the results */
+    tmpt        = t.dp + (2*ix + 1);
+
+    for (iy = ix + 1; iy < pa; iy++) {
+      /* first calculate the product */
+      r       = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
+
+      /* now calculate the double precision result, note we use
+       * addition instead of *2 since it's easier to optimize
+       */
+      r       = ((mp_word) *tmpt) + r + r + ((mp_word) u);
+
+      /* store lower part */
+      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+      /* get carry */
+      u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+    }
+    /* propagate upwards */
+    while (u != ((mp_digit) 0)) {
+      r       = ((mp_word) *tmpt) + ((mp_word) u);
+      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+      u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+    }
+  }
+
+  mp_clamp (&t);
+  mp_exch (&t, b);
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+/* multiplies |a| * |b| and only computes upto digs digits of result
+ * HAC pp. 595, Algorithm 14.12  Modified so you can control how
+ * many digits of output are created.
+ */
+int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+  mp_int  t;
+  int     res, pa, pb, ix, iy;
+  mp_digit u;
+  mp_word r;
+  mp_digit tmpx, *tmpt, *tmpy;
+
+  /* can we use the fast multiplier? */
+  if (((digs) < MP_WARRAY) &&
+      MIN (a->used, b->used) <
+          (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+    return fast_s_mp_mul_digs (a, b, c, digs);
+  }
+
+  if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
+    return res;
+  }
+  t.used = digs;
+
+  /* compute the digits of the product directly */
+  pa = a->used;
+  for (ix = 0; ix < pa; ix++) {
+    /* set the carry to zero */
+    u = 0;
+
+    /* limit ourselves to making digs digits of output */
+    pb = MIN (b->used, digs - ix);
+
+    /* setup some aliases */
+    /* copy of the digit from a used within the nested loop */
+    tmpx = a->dp[ix];
+
+    /* an alias for the destination shifted ix places */
+    tmpt = t.dp + ix;
+
+    /* an alias for the digits of b */
+    tmpy = b->dp;
+
+    /* compute the columns of the output and propagate the carry */
+    for (iy = 0; iy < pb; iy++) {
+      /* compute the column as a mp_word */
+      r       = ((mp_word)*tmpt) +
+                ((mp_word)tmpx) * ((mp_word)*tmpy++) +
+                ((mp_word) u);
+
+      /* the new column is the lower part of the result */
+      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+      /* get the carry word from the result */
+      u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+    }
+    /* set carry if it is placed below digs */
+    if (ix + iy < digs) {
+      *tmpt = u;
+    }
+  }
+
+  mp_clamp (&t);
+  mp_exch (&t, c);
+
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+/*
+ * shifts with subtractions when the result is greater than b.
+ *
+ * The method is slightly modified to shift B unconditionally upto just under
+ * the leading bit of b.  This saves alot of multiple precision shifting.
+ */
+int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
+{
+  int     x, bits, res;
+
+  /* how many bits of last digit does b use */
+  bits = mp_count_bits (b) % DIGIT_BIT;
+
+  if (b->used > 1) {
+     if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
+        return res;
+     }
+  } else {
+     mp_set(a, 1);
+     bits = 1;
+  }
+
+
+  /* now compute C = A * B mod b */
+  for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
+    if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
+      return res;
+    }
+    if (mp_cmp_mag (a, b) != MP_LT) {
+      if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
+        return res;
+      }
+    }
+  }
+
+  return MP_OKAY;
+}
+
+
+#ifdef MP_LOW_MEM
+   #define TAB_SIZE 32
+#else
+   #define TAB_SIZE 256
+#endif
+
+int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
+{
+  mp_int  M[TAB_SIZE], res, mu;
+  mp_digit buf;
+  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+  int (*redux)(mp_int*,mp_int*,mp_int*);
+
+  /* find window size */
+  x = mp_count_bits (X);
+  if (x <= 7) {
+    winsize = 2;
+  } else if (x <= 36) {
+    winsize = 3;
+  } else if (x <= 140) {
+    winsize = 4;
+  } else if (x <= 450) {
+    winsize = 5;
+  } else if (x <= 1303) {
+    winsize = 6;
+  } else if (x <= 3529) {
+    winsize = 7;
+  } else {
+    winsize = 8;
+  }
+
+#ifdef MP_LOW_MEM
+    if (winsize > 5) {
+       winsize = 5;
+    }
+#endif
+
+  /* init M array */
+  /* init first cell */
+  if ((err = mp_init(&M[1])) != MP_OKAY) {
+     return err;
+  }
+
+  /* now init the second half of the array */
+  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+    if ((err = mp_init(&M[x])) != MP_OKAY) {
+      for (y = 1<<(winsize-1); y < x; y++) {
+        mp_clear (&M[y]);
+      }
+      mp_clear(&M[1]);
+      return err;
+    }
+  }
+
+  /* create mu, used for Barrett reduction */
+  if ((err = mp_init (&mu)) != MP_OKAY) {
+    goto LBL_M;
+  }
+
+  if (redmode == 0) {
+     if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
+        goto LBL_MU;
+     }
+     redux = mp_reduce;
+  } else {
+     if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
+        goto LBL_MU;
+     }
+     redux = mp_reduce_2k_l;
+  }
+
+  /* create M table
+   *
+   * The M table contains powers of the base,
+   * e.g. M[x] = G**x mod P
+   *
+   * The first half of the table is not
+   * computed though accept for M[0] and M[1]
+   */
+  if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
+    goto LBL_MU;
+  }
+
+  /* compute the value at M[1<<(winsize-1)] by squaring
+   * M[1] (winsize-1) times
+   */
+  if ((err = mp_copy (&M[1], &M[(mp_digit)(1 << (winsize - 1))])) != MP_OKAY) {
+    goto LBL_MU;
+  }
+
+  for (x = 0; x < (winsize - 1); x++) {
+    /* square it */
+    if ((err = mp_sqr (&M[(mp_digit)(1 << (winsize - 1))],
+                       &M[(mp_digit)(1 << (winsize - 1))])) != MP_OKAY) {
+      goto LBL_MU;
+    }
+
+    /* reduce modulo P */
+    if ((err = redux (&M[(mp_digit)(1 << (winsize - 1))], P, &mu)) != MP_OKAY) {
+      goto LBL_MU;
+    }
+  }
+
+  /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
+   * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
+   */
+  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+    if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
+      goto LBL_MU;
+    }
+    if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
+      goto LBL_MU;
+    }
+  }
+
+  /* setup result */
+  if ((err = mp_init (&res)) != MP_OKAY) {
+    goto LBL_MU;
+  }
+  mp_set (&res, 1);
+
+  /* set initial mode and bit cnt */
+  mode   = 0;
+  bitcnt = 1;
+  buf    = 0;
+  digidx = X->used - 1;
+  bitcpy = 0;
+  bitbuf = 0;
+
+  for (;;) {
+    /* grab next digit as required */
+    if (--bitcnt == 0) {
+      /* if digidx == -1 we are out of digits */
+      if (digidx == -1) {
+        break;
+      }
+      /* read next digit and reset the bitcnt */
+      buf    = X->dp[digidx--];
+      bitcnt = (int) DIGIT_BIT;
+    }
+
+    /* grab the next msb from the exponent */
+    y     = (int)(buf >> (mp_digit)(DIGIT_BIT - 1)) & 1;
+    buf <<= (mp_digit)1;
+
+    /* if the bit is zero and mode == 0 then we ignore it
+     * These represent the leading zero bits before the first 1 bit
+     * in the exponent.  Technically this opt is not required but it
+     * does lower the # of trivial squaring/reductions used
+     */
+    if (mode == 0 && y == 0) {
+      continue;
+    }
+
+    /* if the bit is zero and mode == 1 then we square */
+    if (mode == 1 && y == 0) {
+      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      continue;
+    }
+
+    /* else we add it to the window */
+    bitbuf |= (y << (winsize - ++bitcpy));
+    mode    = 2;
+
+    if (bitcpy == winsize) {
+      /* ok window is filled so square as required and multiply  */
+      /* square first */
+      for (x = 0; x < winsize; x++) {
+        if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+        if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+      }
+
+      /* then multiply */
+      if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+
+      /* empty window and reset */
+      bitcpy = 0;
+      bitbuf = 0;
+      mode   = 1;
+    }
+  }
+
+  /* if bits remain then square/multiply */
+  if (mode == 2 && bitcpy > 0) {
+    /* square then multiply if the bit is set */
+    for (x = 0; x < bitcpy; x++) {
+      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+
+      bitbuf <<= 1;
+      if ((bitbuf & (1 << winsize)) != 0) {
+        /* then multiply */
+        if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+        if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+      }
+    }
+  }
+
+  mp_exch (&res, Y);
+  err = MP_OKAY;
+LBL_RES:mp_clear (&res);
+LBL_MU:mp_clear (&mu);
+LBL_M:
+  mp_clear(&M[1]);
+  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+    mp_clear (&M[x]);
+  }
+  return err;
+}
+
+
+/* pre-calculate the value required for Barrett reduction
+ * For a given modulus "b" it calulates the value required in "a"
+ */
+int mp_reduce_setup (mp_int * a, mp_int * b)
+{
+  int     res;
+
+  if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
+    return res;
+  }
+  return mp_div (a, b, a, NULL);
+}
+
+
+/* reduces x mod m, assumes 0 < x < m**2, mu is
+ * precomputed via mp_reduce_setup.
+ * From HAC pp.604 Algorithm 14.42
+ */
+int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
+{
+  mp_int  q;
+  int     res, um = m->used;
+
+  /* q = x */
+  if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
+    return res;
+  }
+
+  /* q1 = x / b**(k-1)  */
+  mp_rshd (&q, um - 1);
+
+  /* according to HAC this optimization is ok */
+  if (((mp_word) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
+    if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
+      goto CLEANUP;
+    }
+  } else {
+#ifdef BN_S_MP_MUL_HIGH_DIGS_C
+    if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
+      goto CLEANUP;
+    }
+#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
+    if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
+      goto CLEANUP;
+    }
+#else
+    {
+      res = MP_VAL;
+      goto CLEANUP;
+    }
+#endif
+  }
+
+  /* q3 = q2 / b**(k+1) */
+  mp_rshd (&q, um + 1);
+
+  /* x = x mod b**(k+1), quick (no division) */
+  if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
+    goto CLEANUP;
+  }
+
+  /* q = q * m mod b**(k+1), quick (no division) */
+  if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
+    goto CLEANUP;
+  }
+
+  /* x = x - q */
+  if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
+    goto CLEANUP;
+  }
+
+  /* If x < 0, add b**(k+1) to it */
+  if (mp_cmp_d (x, 0) == MP_LT) {
+    mp_set (&q, 1);
+    if ((res = mp_lshd (&q, um + 1)) != MP_OKAY)
+      goto CLEANUP;
+    if ((res = mp_add (x, &q, x)) != MP_OKAY)
+      goto CLEANUP;
+  }
+
+  /* Back off if it's too big */
+  while (mp_cmp (x, m) != MP_LT) {
+    if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
+      goto CLEANUP;
+    }
+  }
+
+CLEANUP:
+  mp_clear (&q);
+
+  return res;
+}
+
+
+/* reduces a modulo n where n is of the form 2**p - d
+   This differs from reduce_2k since "d" can be larger
+   than a single digit.
+*/
+int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
+{
+   mp_int q;
+   int    p, res;
+
+   if ((res = mp_init(&q)) != MP_OKAY) {
+      return res;
+   }
+
+   p = mp_count_bits(n);
+top:
+   /* q = a/2**p, a = a mod 2**p */
+   if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
+      goto ERR;
+   }
+
+   /* q = q * d */
+   if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
+      goto ERR;
+   }
+
+   /* a = a + q */
+   if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
+      goto ERR;
+   }
+
+   if (mp_cmp_mag(a, n) != MP_LT) {
+      s_mp_sub(a, n, a);
+      goto top;
+   }
+
+ERR:
+   mp_clear(&q);
+   return res;
+}
+
+
+/* determines the setup value */
+int mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
+{
+   int    res;
+   mp_int tmp;
+
+   if ((res = mp_init(&tmp)) != MP_OKAY) {
+      return res;
+   }
+
+   if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
+      goto ERR;
+   }
+
+   if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
+      goto ERR;
+   }
+
+ERR:
+   mp_clear(&tmp);
+   return res;
+}
+
+
+/* multiplies |a| * |b| and does not compute the lower digs digits
+ * [meant to get the higher part of the product]
+ */
+int
+s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+  mp_int  t;
+  int     res, pa, pb, ix, iy;
+  mp_digit u;
+  mp_word r;
+  mp_digit tmpx, *tmpt, *tmpy;
+
+  /* can we use the fast multiplier? */
+#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
+  if (((a->used + b->used + 1) < MP_WARRAY)
+      && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+    return fast_s_mp_mul_high_digs (a, b, c, digs);
+  }
+#endif
+
+  if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) {
+    return res;
+  }
+  t.used = a->used + b->used + 1;
+
+  pa = a->used;
+  pb = b->used;
+  for (ix = 0; ix < pa; ix++) {
+    /* clear the carry */
+    u = 0;
+
+    /* left hand side of A[ix] * B[iy] */
+    tmpx = a->dp[ix];
+
+    /* alias to the address of where the digits will be stored */
+    tmpt = &(t.dp[digs]);
+
+    /* alias for where to read the right hand side from */
+    tmpy = b->dp + (digs - ix);
+
+    for (iy = digs - ix; iy < pb; iy++) {
+      /* calculate the double precision result */
+      r       = ((mp_word)*tmpt) +
+                ((mp_word)tmpx) * ((mp_word)*tmpy++) +
+                ((mp_word) u);
+
+      /* get the lower part */
+      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+      /* carry the carry */
+      u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+    }
+    *tmpt = u;
+  }
+  mp_clamp (&t);
+  mp_exch (&t, c);
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+/* this is a modified version of fast_s_mul_digs that only produces
+ * output digits *above* digs.  See the comments for fast_s_mul_digs
+ * to see how it works.
+ *
+ * This is used in the Barrett reduction since for one of the multiplications
+ * only the higher digits were needed.  This essentially halves the work.
+ *
+ * Based on Algorithm 14.12 on pp.595 of HAC.
+ */
+int fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+  int     olduse, res, pa, ix, iz;
+#ifdef WOLFSSL_SMALL_STACK
+  mp_digit* W;    /* uses dynamic memory and slower */
+#else
+  mp_digit W[MP_WARRAY];
+#endif
+  mp_word  _W;
+
+  /* grow the destination as required */
+  pa = a->used + b->used;
+  if (c->alloc < pa) {
+    if ((res = mp_grow (c, pa)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  if (pa > MP_WARRAY)
+    return MP_RANGE;  /* TAO range check */
+
+#ifdef WOLFSSL_SMALL_STACK
+  W = (mp_digit*)XMALLOC(sizeof(mp_digit) * MP_WARRAY, 0, DYNAMIC_TYPE_BIGINT);
+  if (W == NULL)
+    return MP_MEM;
+#endif
+
+  /* number of output digits to produce */
+  pa = a->used + b->used;
+  _W = 0;
+  for (ix = digs; ix < pa; ix++) {
+      int      tx, ty, iy;
+      mp_digit *tmpx, *tmpy;
+
+      /* get offsets into the two bignums */
+      ty = MIN(b->used-1, ix);
+      tx = ix - ty;
+
+      /* setup temp aliases */
+      tmpx = a->dp + tx;
+      tmpy = b->dp + ty;
+
+      /* this is the number of times the loop will iterrate, essentially its
+         while (tx++ < a->used && ty-- >= 0) { ... }
+       */
+      iy = MIN(a->used-tx, ty+1);
+
+      /* execute loop */
+      for (iz = 0; iz < iy; iz++) {
+         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+      }
+
+      /* store term */
+      W[ix] = ((mp_digit)_W) & MP_MASK;
+
+      /* make next carry */
+      _W = _W >> ((mp_word)DIGIT_BIT);
+  }
+
+  /* setup dest */
+  olduse  = c->used;
+  c->used = pa;
+
+  {
+    register mp_digit *tmpc;
+
+    tmpc = c->dp + digs;
+    for (ix = digs; ix <= pa; ix++) {
+      /* now extract the previous digit [below the carry] */
+      *tmpc++ = W[ix];
+    }
+
+    /* clear unused digits [that existed in the old copy of c] */
+    for (; ix < olduse; ix++) {
+      *tmpc++ = 0;
+    }
+  }
+  mp_clamp (c);
+
+#ifdef WOLFSSL_SMALL_STACK
+  XFREE(W, 0, DYNAMIC_TYPE_BIGINT);
+#endif
+
+  return MP_OKAY;
+}
+
+
+/* set a 32-bit const */
+int mp_set_int (mp_int * a, unsigned long b)
+{
+  int     x, res;
+
+  mp_zero (a);
+
+  /* set four bits at a time */
+  for (x = 0; x < 8; x++) {
+    /* shift the number up four bits */
+    if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) {
+      return res;
+    }
+
+    /* OR in the top four bits of the source */
+    a->dp[0] |= (b >> 28) & 15;
+
+    /* shift the source up to the next four bits */
+    b <<= 4;
+
+    /* ensure that digits are not clamped off */
+    a->used += 1;
+  }
+  mp_clamp (a);
+  return MP_OKAY;
+}
+
+
+#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_ECC)
+
+/* c = a * a (mod b) */
+int mp_sqrmod (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     res;
+  mp_int  t;
+
+  if ((res = mp_init (&t)) != MP_OKAY) {
+    return res;
+  }
+
+  if ((res = mp_sqr (a, &t)) != MP_OKAY) {
+    mp_clear (&t);
+    return res;
+  }
+  res = mp_mod (&t, b, c);
+  mp_clear (&t);
+  return res;
+}
+
+#endif
+
+
+#if defined(HAVE_ECC) || !defined(NO_PWDBASED) || defined(WOLFSSL_SNIFFER) || defined(WOLFSSL_HAVE_WOLFSCEP) || defined(WOLFSSL_KEY_GEN)
+
+/* single digit addition */
+int mp_add_d (mp_int* a, mp_digit b, mp_int* c)
+{
+  int     res, ix, oldused;
+  mp_digit *tmpa, *tmpc, mu;
+
+  /* grow c as required */
+  if (c->alloc < a->used + 1) {
+     if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) {
+        return res;
+     }
+  }
+
+  /* if a is negative and |a| >= b, call c = |a| - b */
+  if (a->sign == MP_NEG && (a->used > 1 || a->dp[0] >= b)) {
+     /* temporarily fix sign of a */
+     a->sign = MP_ZPOS;
+
+     /* c = |a| - b */
+     res = mp_sub_d(a, b, c);
+
+     /* fix sign  */
+     a->sign = c->sign = MP_NEG;
+
+     /* clamp */
+     mp_clamp(c);
+
+     return res;
+  }
+
+  /* old number of used digits in c */
+  oldused = c->used;
+
+  /* sign always positive */
+  c->sign = MP_ZPOS;
+
+  /* source alias */
+  tmpa    = a->dp;
+
+  /* destination alias */
+  tmpc    = c->dp;
+
+  /* if a is positive */
+  if (a->sign == MP_ZPOS) {
+     /* add digit, after this we're propagating
+      * the carry.
+      */
+     *tmpc   = *tmpa++ + b;
+     mu      = *tmpc >> DIGIT_BIT;
+     *tmpc++ &= MP_MASK;
+
+     /* now handle rest of the digits */
+     for (ix = 1; ix < a->used; ix++) {
+        *tmpc   = *tmpa++ + mu;
+        mu      = *tmpc >> DIGIT_BIT;
+        *tmpc++ &= MP_MASK;
+     }
+     /* set final carry */
+     if (mu != 0 && ix < c->alloc) {
+        ix++;
+        *tmpc++  = mu;
+     }
+
+     /* setup size */
+     c->used = a->used + 1;
+  } else {
+     /* a was negative and |a| < b */
+     c->used  = 1;
+
+     /* the result is a single digit */
+     if (a->used == 1) {
+        *tmpc++  =  b - a->dp[0];
+     } else {
+        *tmpc++  =  b;
+     }
+
+     /* setup count so the clearing of oldused
+      * can fall through correctly
+      */
+     ix       = 1;
+  }
+
+  /* now zero to oldused */
+  while (ix++ < oldused) {
+     *tmpc++ = 0;
+  }
+  mp_clamp(c);
+
+  return MP_OKAY;
+}
+
+
+/* single digit subtraction */
+int mp_sub_d (mp_int * a, mp_digit b, mp_int * c)
+{
+  mp_digit *tmpa, *tmpc, mu;
+  int       res, ix, oldused;
+
+  /* grow c as required */
+  if (c->alloc < a->used + 1) {
+     if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) {
+        return res;
+     }
+  }
+
+  /* if a is negative just do an unsigned
+   * addition [with fudged signs]
+   */
+  if (a->sign == MP_NEG) {
+     a->sign = MP_ZPOS;
+     res     = mp_add_d(a, b, c);
+     a->sign = c->sign = MP_NEG;
+
+     /* clamp */
+     mp_clamp(c);
+
+     return res;
+  }
+
+  /* setup regs */
+  oldused = c->used;
+  tmpa    = a->dp;
+  tmpc    = c->dp;
+
+  /* if a <= b simply fix the single digit */
+  if ((a->used == 1 && a->dp[0] <= b) || a->used == 0) {
+     if (a->used == 1) {
+        *tmpc++ = b - *tmpa;
+     } else {
+        *tmpc++ = b;
+     }
+     ix      = 1;
+
+     /* negative/1digit */
+     c->sign = MP_NEG;
+     c->used = 1;
+  } else {
+     /* positive/size */
+     c->sign = MP_ZPOS;
+     c->used = a->used;
+
+     /* subtract first digit */
+     *tmpc    = *tmpa++ - b;
+     mu       = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1);
+     *tmpc++ &= MP_MASK;
+
+     /* handle rest of the digits */
+     for (ix = 1; ix < a->used; ix++) {
+        *tmpc    = *tmpa++ - mu;
+        mu       = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1);
+        *tmpc++ &= MP_MASK;
+     }
+  }
+
+  /* zero excess digits */
+  while (ix++ < oldused) {
+     *tmpc++ = 0;
+  }
+  mp_clamp(c);
+  return MP_OKAY;
+}
+
+#endif /* defined(HAVE_ECC) || !defined(NO_PWDBASED) */
+
+
+#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY)
+
+static const int lnz[16] = {
+   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+};
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int mp_cnt_lsb(mp_int *a)
+{
+    int x;
+    mp_digit q, qq;
+
+    /* easy out */
+    if (mp_iszero(a) == 1) {
+        return 0;
+    }
+
+    /* scan lower digits until non-zero */
+    for (x = 0; x < a->used && a->dp[x] == 0; x++);
+    q = a->dp[x];
+    x *= DIGIT_BIT;
+
+    /* now scan this digit until a 1 is found */
+    if ((q & 1) == 0) {
+        do {
+            qq  = q & 15;
+            x  += lnz[qq];
+            q >>= 4;
+        } while (qq == 0);
+    }
+    return x;
+}
+
+
+
+
+static int s_is_power_of_two(mp_digit b, int *p)
+{
+   int x;
+
+   /* fast return if no power of two */
+   if ((b==0) || (b & (b-1))) {
+      return 0;
+   }
+
+   for (x = 0; x < DIGIT_BIT; x++) {
+      if (b == (((mp_digit)1)<<x)) {
+         *p = x;
+         return 1;
+      }
+   }
+   return 0;
+}
+
+/* single digit division (based on routine from MPI) */
+static int mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d)
+{
+  mp_int  q;
+  mp_word w;
+  mp_digit t;
+  int     res, ix;
+
+  /* cannot divide by zero */
+  if (b == 0) {
+     return MP_VAL;
+  }
+
+  /* quick outs */
+  if (b == 1 || mp_iszero(a) == 1) {
+     if (d != NULL) {
+        *d = 0;
+     }
+     if (c != NULL) {
+        return mp_copy(a, c);
+     }
+     return MP_OKAY;
+  }
+
+  /* power of two ? */
+  if (s_is_power_of_two(b, &ix) == 1) {
+     if (d != NULL) {
+        *d = a->dp[0] & ((((mp_digit)1)<<ix) - 1);
+     }
+     if (c != NULL) {
+        return mp_div_2d(a, ix, c, NULL);
+     }
+     return MP_OKAY;
+  }
+
+#ifdef BN_MP_DIV_3_C
+  /* three? */
+  if (b == 3) {
+     return mp_div_3(a, c, d);
+  }
+#endif
+
+  /* no easy answer [c'est la vie].  Just division */
+  if ((res = mp_init_size(&q, a->used)) != MP_OKAY) {
+     return res;
+  }
+
+  q.used = a->used;
+  q.sign = a->sign;
+  w = 0;
+  for (ix = a->used - 1; ix >= 0; ix--) {
+     w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]);
+
+     if (w >= b) {
+        t = (mp_digit)(w / b);
+        w -= ((mp_word)t) * ((mp_word)b);
+      } else {
+        t = 0;
+      }
+      q.dp[ix] = (mp_digit)t;
+  }
+
+  if (d != NULL) {
+     *d = (mp_digit)w;
+  }
+
+  if (c != NULL) {
+     mp_clamp(&q);
+     mp_exch(&q, c);
+  }
+  mp_clear(&q);
+
+  return res;
+}
+
+
+int mp_mod_d (mp_int * a, mp_digit b, mp_digit * c)
+{
+  return mp_div_d(a, b, NULL, c);
+}
+
+#endif /* defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) */
+
+#ifdef WOLFSSL_KEY_GEN
+
+const mp_digit ltm_prime_tab[] = {
+  0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
+  0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
+  0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
+  0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F,
+#ifndef MP_8BIT
+  0x0083,
+  0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD,
+  0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF,
+  0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107,
+  0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137,
+
+  0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167,
+  0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199,
+  0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9,
+  0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7,
+  0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239,
+  0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265,
+  0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293,
+  0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF,
+
+  0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301,
+  0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B,
+  0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371,
+  0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD,
+  0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5,
+  0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419,
+  0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449,
+  0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B,
+
+  0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7,
+  0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503,
+  0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529,
+  0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F,
+  0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3,
+  0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7,
+  0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623,
+  0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653
+#endif
+};
+
+
+/* Miller-Rabin test of "a" to the base of "b" as described in
+ * HAC pp. 139 Algorithm 4.24
+ *
+ * Sets result to 0 if definitely composite or 1 if probably prime.
+ * Randomly the chance of error is no more than 1/4 and often
+ * very much lower.
+ */
+static int mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result)
+{
+  mp_int  n1, y, r;
+  int     s, j, err;
+
+  /* default */
+  *result = MP_NO;
+
+  /* ensure b > 1 */
+  if (mp_cmp_d(b, 1) != MP_GT) {
+     return MP_VAL;
+  }
+
+  /* get n1 = a - 1 */
+  if ((err = mp_init_copy (&n1, a)) != MP_OKAY) {
+    return err;
+  }
+  if ((err = mp_sub_d (&n1, 1, &n1)) != MP_OKAY) {
+    goto LBL_N1;
+  }
+
+  /* set 2**s * r = n1 */
+  if ((err = mp_init_copy (&r, &n1)) != MP_OKAY) {
+    goto LBL_N1;
+  }
+
+  /* count the number of least significant bits
+   * which are zero
+   */
+  s = mp_cnt_lsb(&r);
+
+  /* now divide n - 1 by 2**s */
+  if ((err = mp_div_2d (&r, s, &r, NULL)) != MP_OKAY) {
+    goto LBL_R;
+  }
+
+  /* compute y = b**r mod a */
+  if ((err = mp_init (&y)) != MP_OKAY) {
+    goto LBL_R;
+  }
+  if ((err = mp_exptmod (b, &r, a, &y)) != MP_OKAY) {
+    goto LBL_Y;
+  }
+
+  /* if y != 1 and y != n1 do */
+  if (mp_cmp_d (&y, 1) != MP_EQ && mp_cmp (&y, &n1) != MP_EQ) {
+    j = 1;
+    /* while j <= s-1 and y != n1 */
+    while ((j <= (s - 1)) && mp_cmp (&y, &n1) != MP_EQ) {
+      if ((err = mp_sqrmod (&y, a, &y)) != MP_OKAY) {
+         goto LBL_Y;
+      }
+
+      /* if y == 1 then composite */
+      if (mp_cmp_d (&y, 1) == MP_EQ) {
+         goto LBL_Y;
+      }
+
+      ++j;
+    }
+
+    /* if y != n1 then composite */
+    if (mp_cmp (&y, &n1) != MP_EQ) {
+      goto LBL_Y;
+    }
+  }
+
+  /* probably prime now */
+  *result = MP_YES;
+LBL_Y:mp_clear (&y);
+LBL_R:mp_clear (&r);
+LBL_N1:mp_clear (&n1);
+  return err;
+}
+
+
+/* determines if an integers is divisible by one
+ * of the first PRIME_SIZE primes or not
+ *
+ * sets result to 0 if not, 1 if yes
+ */
+static int mp_prime_is_divisible (mp_int * a, int *result)
+{
+  int     err, ix;
+  mp_digit res;
+
+  /* default to not */
+  *result = MP_NO;
+
+  for (ix = 0; ix < PRIME_SIZE; ix++) {
+    /* what is a mod LBL_prime_tab[ix] */
+    if ((err = mp_mod_d (a, ltm_prime_tab[ix], &res)) != MP_OKAY) {
+      return err;
+    }
+
+    /* is the residue zero? */
+    if (res == 0) {
+      *result = MP_YES;
+      return MP_OKAY;
+    }
+  }
+
+  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 */
+    mp_set (&b, ltm_prime_tab[ix]);
+
+    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;
+}
+
+
+/* computes least common multiple as |a*b|/(a, b) */
+int mp_lcm (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     res;
+  mp_int  t1, t2;
+
+
+  if ((res = mp_init_multi (&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+    return res;
+  }
+
+  /* t1 = get the GCD of the two inputs */
+  if ((res = mp_gcd (a, b, &t1)) != MP_OKAY) {
+    goto LBL_T;
+  }
+
+  /* divide the smallest by the GCD */
+  if (mp_cmp_mag(a, b) == MP_LT) {
+     /* store quotient in t2 such that t2 * b is the LCM */
+     if ((res = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) {
+        goto LBL_T;
+     }
+     res = mp_mul(b, &t2, c);
+  } else {
+     /* store quotient in t2 such that t2 * a is the LCM */
+     if ((res = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) {
+        goto LBL_T;
+     }
+     res = mp_mul(a, &t2, c);
+  }
+
+  /* fix the sign to positive */
+  c->sign = MP_ZPOS;
+
+LBL_T:
+  mp_clear(&t1);
+  mp_clear(&t2);
+  return res;
+}
+
+
+
+/* Greatest Common Divisor using the binary method */
+int mp_gcd (mp_int * a, mp_int * b, mp_int * c)
+{
+    mp_int  u, v;
+    int     k, u_lsb, v_lsb, res;
+
+    /* either zero than gcd is the largest */
+    if (mp_iszero (a) == MP_YES) {
+        return mp_abs (b, c);
+    }
+    if (mp_iszero (b) == MP_YES) {
+        return mp_abs (a, c);
+    }
+
+    /* get copies of a and b we can modify */
+    if ((res = mp_init_copy (&u, a)) != MP_OKAY) {
+        return res;
+    }
+
+    if ((res = mp_init_copy (&v, b)) != MP_OKAY) {
+        goto LBL_U;
+    }
+
+    /* must be positive for the remainder of the algorithm */
+    u.sign = v.sign = MP_ZPOS;
+
+    /* B1.  Find the common power of two for u and v */
+    u_lsb = mp_cnt_lsb(&u);
+    v_lsb = mp_cnt_lsb(&v);
+    k     = MIN(u_lsb, v_lsb);
+
+    if (k > 0) {
+        /* divide the power of two out */
+        if ((res = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) {
+            goto LBL_V;
+        }
+
+        if ((res = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) {
+            goto LBL_V;
+        }
+    }
+
+    /* divide any remaining factors of two out */
+    if (u_lsb != k) {
+        if ((res = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) {
+            goto LBL_V;
+        }
+    }
+
+    if (v_lsb != k) {
+        if ((res = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) {
+            goto LBL_V;
+        }
+    }
+
+    while (mp_iszero(&v) == 0) {
+        /* make sure v is the largest */
+        if (mp_cmp_mag(&u, &v) == MP_GT) {
+            /* swap u and v to make sure v is >= u */
+            mp_exch(&u, &v);
+        }
+
+        /* subtract smallest from largest */
+        if ((res = s_mp_sub(&v, &u, &v)) != MP_OKAY) {
+            goto LBL_V;
+        }
+
+        /* Divide out all factors of two */
+        if ((res = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) {
+            goto LBL_V;
+        }
+    }
+
+    /* multiply by 2**k which we divided out at the beginning */
+    if ((res = mp_mul_2d (&u, k, c)) != MP_OKAY) {
+        goto LBL_V;
+    }
+    c->sign = MP_ZPOS;
+    res = MP_OKAY;
+LBL_V:mp_clear (&u);
+LBL_U:mp_clear (&v);
+    return res;
+}
+
+
+
+#endif /* WOLFSSL_KEY_GEN */
+
+
+#ifdef HAVE_ECC
+
+/* chars used in radix conversions */
+const char *mp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
+
+/* read a string [ASCII] in a given radix */
+int mp_read_radix (mp_int * a, const char *str, int radix)
+{
+  int     y, res, neg;
+  char    ch;
+
+  /* zero the digit bignum */
+  mp_zero(a);
+
+  /* make sure the radix is ok */
+  if (radix < 2 || radix > 64) {
+    return MP_VAL;
+  }
+
+  /* if the leading digit is a
+   * minus set the sign to negative.
+   */
+  if (*str == '-') {
+    ++str;
+    neg = MP_NEG;
+  } else {
+    neg = MP_ZPOS;
+  }
+
+  /* set the integer to the default of zero */
+  mp_zero (a);
+
+  /* process each digit of the string */
+  while (*str) {
+    /* if the radix < 36 the conversion is case insensitive
+     * this allows numbers like 1AB and 1ab to represent the same  value
+     * [e.g. in hex]
+     */
+    ch = (char) ((radix < 36) ? XTOUPPER((unsigned char)*str) : *str);
+    for (y = 0; y < 64; y++) {
+      if (ch == mp_s_rmap[y]) {
+         break;
+      }
+    }
+
+    /* if the char was found in the map
+     * and is less than the given radix add it
+     * to the number, otherwise exit the loop.
+     */
+    if (y < radix) {
+      if ((res = mp_mul_d (a, (mp_digit) radix, a)) != MP_OKAY) {
+         return res;
+      }
+      if ((res = mp_add_d (a, (mp_digit) y, a)) != MP_OKAY) {
+         return res;
+      }
+    } else {
+      break;
+    }
+    ++str;
+  }
+
+  /* set the sign only if a != 0 */
+  if (mp_iszero(a) != 1) {
+     a->sign = neg;
+  }
+  return MP_OKAY;
+}
+
+#endif /* HAVE_ECC */
+
+#endif /* USE_FAST_MATH */
+
+#endif /* NO_BIG_INT */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/logging.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,163 @@
+/* logging.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+/* submitted by eof */
+
+#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
+    } 
+#endif
+
+
+#ifdef DEBUG_WOLFSSL
+
+/* Set these to default values initially. */
+static wolfSSL_Logging_cb log_function = 0;
+static int loggingEnabled = 0;
+
+#endif /* DEBUG_WOLFSSL */
+
+
+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;
+#else
+    (void)f;
+    return NOT_COMPILED_IN;
+#endif
+}
+
+
+int wolfSSL_Debugging_ON(void)
+{
+#ifdef DEBUG_WOLFSSL
+    loggingEnabled = 1;
+    return 0;
+#else
+    return NOT_COMPILED_IN;
+#endif
+}
+
+
+void wolfSSL_Debugging_OFF(void)
+{
+#ifdef DEBUG_WOLFSSL
+    loggingEnabled = 0;
+#endif
+}
+
+
+#ifdef DEBUG_WOLFSSL
+
+#ifdef FREESCALE_MQX
+    #include <fio.h>
+#else
+    #include <stdio.h>   /* for default printf stuff */
+#endif
+
+#ifdef THREADX
+    int dc_log_printf(char*, ...);
+#endif
+
+static void wolfssl_log(const int logLevel, const char *const logMessage)
+{
+    if (log_function)
+        log_function(logLevel, logMessage);
+    else {
+        if (loggingEnabled) {
+#ifdef THREADX
+            dc_log_printf("%s\n", logMessage);
+#elif defined(MICRIUM)
+        #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+            NetSecure_TraceOut((CPU_CHAR *)logMessage);
+        #endif
+#elif defined(WOLFSSL_MDK_ARM)
+            fflush(stdout) ;
+            printf("%s\n", logMessage);
+            fflush(stdout) ;
+#else
+            fprintf(stderr, "%s\n", logMessage);
+#endif
+        }
+    }
+}
+
+
+void WOLFSSL_MSG(const char* msg)
+{
+    if (loggingEnabled)
+        wolfssl_log(INFO_LOG , msg);
+}
+
+
+void WOLFSSL_ENTER(const char* msg)
+{
+    if (loggingEnabled) {
+        char buffer[80];
+        sprintf(buffer, "wolfSSL Entering %s", msg);
+        wolfssl_log(ENTER_LOG , buffer);
+    }
+}
+
+
+void WOLFSSL_LEAVE(const char* msg, int ret)
+{
+    if (loggingEnabled) {
+        char buffer[80];
+        sprintf(buffer, "wolfSSL Leaving %s, return %d", msg, ret);
+        wolfssl_log(LEAVE_LOG , buffer);
+    }
+}
+
+
+void WOLFSSL_ERROR(int error)
+{
+    if (loggingEnabled) {
+        char buffer[80];
+        sprintf(buffer, "wolfSSL error occured, error = %d", error);
+        wolfssl_log(ERROR_LOG , buffer);
+    }
+}
+
+#endif  /* DEBUG_WOLFSSL */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/md2.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,161 @@
+/* md2.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef WOLFSSL_MD2
+
+#include <wolfssl/wolfcrypt/md2.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+
+void wc_InitMd2(Md2* md2)
+{
+    XMEMSET(md2->X, 0, MD2_X_SIZE);
+    XMEMSET(md2->C, 0, MD2_BLOCK_SIZE);
+    XMEMSET(md2->buffer, 0, MD2_BLOCK_SIZE);
+    md2->count = 0;
+}
+
+
+void wc_Md2Update(Md2* md2, const byte* data, word32 len)
+{
+    static const byte S[256] = 
+    {
+        41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
+        19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
+        76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
+        138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
+        245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
+        148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
+        39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
+        181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
+        150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
+        112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
+        96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
+        85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
+        234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
+        129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
+        8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
+        203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
+        166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
+        31, 26, 219, 153, 141, 51, 159, 17, 131, 20
+    };
+
+    while (len) {
+        word32 L = (MD2_PAD_SIZE - md2->count) < len ?
+                   (MD2_PAD_SIZE - md2->count) : len;
+        XMEMCPY(md2->buffer + md2->count, data, L);
+        md2->count += L;
+        data += L;
+        len  -= L;
+
+        if (md2->count == MD2_PAD_SIZE) {
+            int  i;
+            byte t;
+
+            md2->count = 0;
+            XMEMCPY(md2->X + MD2_PAD_SIZE, md2->buffer, MD2_PAD_SIZE);
+            t = md2->C[15];
+
+            for(i = 0; i < MD2_PAD_SIZE; i++) {
+                md2->X[32 + i] = md2->X[MD2_PAD_SIZE + i] ^ md2->X[i];
+                t = md2->C[i] ^= S[md2->buffer[i] ^ t];
+            }
+
+            t=0;
+            for(i = 0; i < 18; i++) {
+                int j;
+                for(j = 0; j < MD2_X_SIZE; j += 8) {
+                    t = md2->X[j+0] ^= S[t];
+                    t = md2->X[j+1] ^= S[t];
+                    t = md2->X[j+2] ^= S[t];
+                    t = md2->X[j+3] ^= S[t];
+                    t = md2->X[j+4] ^= S[t];
+                    t = md2->X[j+5] ^= S[t];
+                    t = md2->X[j+6] ^= S[t];
+                    t = md2->X[j+7] ^= S[t];
+                }
+                t = (t + i) & 0xFF;
+            }
+        }
+    }
+}
+
+
+void wc_Md2Final(Md2* md2, byte* hash)
+{
+    byte   padding[MD2_BLOCK_SIZE];
+    word32 padLen = MD2_PAD_SIZE - md2->count;
+    word32 i;
+
+    for (i = 0; i < padLen; i++)
+        padding[i] = (byte)padLen;
+
+    wc_Md2Update(md2, padding, padLen);
+    wc_Md2Update(md2, md2->C, MD2_BLOCK_SIZE);
+
+    XMEMCPY(hash, md2->X, MD2_DIGEST_SIZE);
+
+    wc_InitMd2(md2);
+}
+
+
+int wc_Md2Hash(const byte* data, word32 len, byte* hash)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    Md2* md2;
+#else
+    Md2 md2[1];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    md2 = (Md2*)XMALLOC(sizeof(Md2), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (md2 == NULL)
+        return MEMORY_E;
+#endif
+
+    wc_InitMd2(md2);
+    wc_Md2Update(md2, data, len);
+    wc_Md2Final(md2, hash);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(md2, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return 0;
+}
+
+
+#endif /* WOLFSSL_MD2 */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/md4.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,221 @@
+/* md4.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifndef NO_MD4
+
+#include <wolfssl/wolfcrypt/md4.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* WOLFSSL_HAVE_MIN */
+
+
+void wc_InitMd4(Md4* md4)
+{
+    md4->digest[0] = 0x67452301L;
+    md4->digest[1] = 0xefcdab89L;
+    md4->digest[2] = 0x98badcfeL;
+    md4->digest[3] = 0x10325476L;
+
+    md4->buffLen = 0;
+    md4->loLen   = 0;
+    md4->hiLen   = 0;
+}
+
+
+static void Transform(Md4* md4)
+{
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+    /* Copy context->state[] to working vars  */
+    word32 A = md4->digest[0];
+    word32 B = md4->digest[1];
+    word32 C = md4->digest[2];
+    word32 D = md4->digest[3];
+
+#define function(a,b,c,d,k,s) a=rotlFixed(a+F(b,c,d)+md4->buffer[k],s);
+    function(A,B,C,D, 0, 3);
+    function(D,A,B,C, 1, 7);
+    function(C,D,A,B, 2,11);
+    function(B,C,D,A, 3,19);
+    function(A,B,C,D, 4, 3);
+    function(D,A,B,C, 5, 7);
+    function(C,D,A,B, 6,11);
+    function(B,C,D,A, 7,19);
+    function(A,B,C,D, 8, 3);
+    function(D,A,B,C, 9, 7);
+    function(C,D,A,B,10,11);
+    function(B,C,D,A,11,19);
+    function(A,B,C,D,12, 3);
+    function(D,A,B,C,13, 7);
+    function(C,D,A,B,14,11);
+    function(B,C,D,A,15,19);
+
+#undef function	  
+#define function(a,b,c,d,k,s) \
+    a=rotlFixed(a+G(b,c,d)+md4->buffer[k]+0x5a827999,s);
+
+    function(A,B,C,D, 0, 3);
+    function(D,A,B,C, 4, 5);
+    function(C,D,A,B, 8, 9);
+    function(B,C,D,A,12,13);
+    function(A,B,C,D, 1, 3);
+    function(D,A,B,C, 5, 5);
+    function(C,D,A,B, 9, 9);
+    function(B,C,D,A,13,13);
+    function(A,B,C,D, 2, 3);
+    function(D,A,B,C, 6, 5);
+    function(C,D,A,B,10, 9);
+    function(B,C,D,A,14,13);
+    function(A,B,C,D, 3, 3);
+    function(D,A,B,C, 7, 5);
+    function(C,D,A,B,11, 9);
+    function(B,C,D,A,15,13);
+
+#undef function	 
+#define function(a,b,c,d,k,s) \
+    a=rotlFixed(a+H(b,c,d)+md4->buffer[k]+0x6ed9eba1,s);
+
+    function(A,B,C,D, 0, 3);
+    function(D,A,B,C, 8, 9);
+    function(C,D,A,B, 4,11);
+    function(B,C,D,A,12,15);
+    function(A,B,C,D, 2, 3);
+    function(D,A,B,C,10, 9);
+    function(C,D,A,B, 6,11);
+    function(B,C,D,A,14,15);
+    function(A,B,C,D, 1, 3);
+    function(D,A,B,C, 9, 9);
+    function(C,D,A,B, 5,11);
+    function(B,C,D,A,13,15);
+    function(A,B,C,D, 3, 3);
+    function(D,A,B,C,11, 9);
+    function(C,D,A,B, 7,11);
+    function(B,C,D,A,15,15);
+    
+    /* Add the working vars back into digest state[]  */
+    md4->digest[0] += A;
+    md4->digest[1] += B;
+    md4->digest[2] += C;
+    md4->digest[3] += D;
+}
+
+
+static INLINE void AddLength(Md4* md4, word32 len)
+{
+    word32 tmp = md4->loLen;
+    if ( (md4->loLen += len) < tmp)
+        md4->hiLen++;                       /* carry low to high */
+}
+
+
+void wc_Md4Update(Md4* md4, const byte* data, word32 len)
+{
+    /* do block size increments */
+    byte* local = (byte*)md4->buffer;
+
+    while (len) {
+        word32 add = min(len, MD4_BLOCK_SIZE - md4->buffLen);
+        XMEMCPY(&local[md4->buffLen], data, add);
+
+        md4->buffLen += add;
+        data         += add;
+        len          -= add;
+
+        if (md4->buffLen == MD4_BLOCK_SIZE) {
+            #ifdef BIG_ENDIAN_ORDER
+                ByteReverseWords(md4->buffer, md4->buffer, MD4_BLOCK_SIZE);
+            #endif
+            Transform(md4);
+            AddLength(md4, MD4_BLOCK_SIZE);
+            md4->buffLen = 0;
+        }
+    }
+}
+
+
+void wc_Md4Final(Md4* md4, byte* hash)
+{
+    byte* local = (byte*)md4->buffer;
+
+    AddLength(md4, md4->buffLen);               /* before adding pads */
+
+    local[md4->buffLen++] = 0x80;  /* add 1 */
+
+    /* pad with zeros */
+    if (md4->buffLen > MD4_PAD_SIZE) {
+        XMEMSET(&local[md4->buffLen], 0, MD4_BLOCK_SIZE - md4->buffLen);
+        md4->buffLen += MD4_BLOCK_SIZE - md4->buffLen;
+
+        #ifdef BIG_ENDIAN_ORDER
+            ByteReverseWords(md4->buffer, md4->buffer, MD4_BLOCK_SIZE);
+        #endif
+        Transform(md4);
+        md4->buffLen = 0;
+    }
+    XMEMSET(&local[md4->buffLen], 0, MD4_PAD_SIZE - md4->buffLen);
+   
+    /* put lengths in bits */
+    md4->hiLen = (md4->loLen >> (8*sizeof(md4->loLen) - 3)) + 
+                 (md4->hiLen << 3);
+    md4->loLen = md4->loLen << 3;
+
+    /* store lengths */
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseWords(md4->buffer, md4->buffer, MD4_BLOCK_SIZE);
+    #endif
+    /* ! length ordering dependent on digest endian type ! */
+    XMEMCPY(&local[MD4_PAD_SIZE], &md4->loLen, sizeof(word32));
+    XMEMCPY(&local[MD4_PAD_SIZE + sizeof(word32)], &md4->hiLen, sizeof(word32));
+
+    Transform(md4);
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseWords(md4->digest, md4->digest, MD4_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, md4->digest, MD4_DIGEST_SIZE);
+
+    wc_InitMd4(md4);  /* reset state */
+}
+
+
+#endif /* NO_MD4 */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/md5.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,398 @@
+/* md5.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#if !defined(NO_MD5)
+
+#if defined(WOLFSSL_TI_HASH)
+    /* #include <wolfcrypt/src/port/ti/ti-hash.c> included by wc_port.c */
+#else
+
+#ifdef WOLFSSL_PIC32MZ_HASH
+#define wc_InitMd5   wc_InitMd5_sw
+#define wc_Md5Update wc_Md5Update_sw
+#define wc_Md5Final  wc_Md5Final_sw
+#endif
+
+#include <wolfssl/wolfcrypt/md5.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+#ifdef FREESCALE_MMCAU
+    #include "cau_api.h"
+    #define XTRANSFORM(S,B)  cau_md5_hash_n((B), 1, (unsigned char*)(S)->digest)
+#else
+    #define XTRANSFORM(S,B)  Transform((S))
+#endif
+
+
+#ifdef STM32F2_HASH
+    /*
+     * STM32F2 hardware MD5 support through the STM32F2 standard peripheral
+     * library. Documentation located in STM32F2xx Standard Peripheral Library
+     * document (See note in README).
+     */
+    #include "stm32f2xx.h"
+
+    void wc_InitMd5(Md5* md5)
+    {
+        /* STM32F2 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
+         */
+        XMEMSET(md5->buffer, 0, MD5_REG_SIZE);
+			
+        md5->buffLen = 0;
+        md5->loLen = 0;
+
+        /* initialize HASH peripheral */
+        HASH_DeInit();
+
+        /* configure algo used, algo mode, datatype */
+        HASH->CR &= ~ (HASH_CR_ALGO | HASH_CR_DATATYPE | HASH_CR_MODE);
+        HASH->CR |= (HASH_AlgoSelection_MD5 | HASH_AlgoMode_HASH 
+                 | HASH_DataType_8b);
+
+        /* reset HASH processor */
+        HASH->CR |= HASH_CR_INIT;
+    }
+
+    void wc_Md5Update(Md5* md5, const byte* data, word32 len)
+    {
+        word32 i = 0;
+        word32 fill = 0;
+        word32 diff = 0;
+
+        /* if saved partial block is available */
+        if (md5->buffLen > 0) {
+            fill = 4 - md5->buffLen;
+
+            /* if enough data to fill, fill and push to FIFO */
+            if (fill <= len) {
+                XMEMCPY((byte*)md5->buffer + md5->buffLen, data, fill);
+                HASH_DataIn(*(uint32_t*)md5->buffer);
+
+                data += fill;
+                len -= fill;
+                md5->loLen += 4;
+                md5->buffLen = 0;
+            } else {
+                /* append partial to existing stored block */
+                XMEMCPY((byte*)md5->buffer + md5->buffLen, data, len);
+                md5->buffLen += len;
+                return;
+            }
+        }
+
+        /* write input block in the IN FIFO */
+        for (i = 0; i < len; i += 4)
+        {
+            diff = len - i;
+            if (diff < 4) {
+                /* store incomplete last block, not yet in FIFO */
+                XMEMSET(md5->buffer, 0, MD5_REG_SIZE);
+                XMEMCPY((byte*)md5->buffer, data, diff);
+                md5->buffLen = diff;
+            } else {
+                HASH_DataIn(*(uint32_t*)data);
+                data+=4;
+            }
+        }
+
+        /* keep track of total data length thus far */
+        md5->loLen += (len - md5->buffLen);
+    }
+
+    void wc_Md5Final(Md5* md5, byte* hash)
+    {
+        __IO uint16_t nbvalidbitsdata = 0;
+
+        /* finish reading any trailing bytes into FIFO */
+        if (md5->buffLen > 0) {
+            HASH_DataIn(*(uint32_t*)md5->buffer);
+            md5->loLen += 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, MD5_DIGEST_SIZE);
+
+        XMEMCPY(hash, md5->digest, MD5_DIGEST_SIZE);
+
+        wc_InitMd5(md5);  /* reset state */
+    }
+
+#else /* CTaoCrypt software implementation */
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* WOLFSSL_HAVE_MIN */
+
+void wc_InitMd5(Md5* md5)
+{
+    md5->digest[0] = 0x67452301L;
+    md5->digest[1] = 0xefcdab89L;
+    md5->digest[2] = 0x98badcfeL;
+    md5->digest[3] = 0x10325476L;
+
+    md5->buffLen = 0;
+    md5->loLen   = 0;
+    md5->hiLen   = 0;
+}
+
+#ifndef FREESCALE_MMCAU
+
+static void Transform(Md5* md5)
+{
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+#define MD5STEP(f, w, x, y, z, data, s) \
+    w = rotlFixed(w + f(x, y, z) + data, s) + x
+
+    /* Copy context->state[] to working vars  */
+    word32 a = md5->digest[0];
+    word32 b = md5->digest[1];
+    word32 c = md5->digest[2];
+    word32 d = md5->digest[3];
+
+    MD5STEP(F1, a, b, c, d, md5->buffer[0]  + 0xd76aa478,  7);
+    MD5STEP(F1, d, a, b, c, md5->buffer[1]  + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, md5->buffer[2]  + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, md5->buffer[3]  + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, md5->buffer[4]  + 0xf57c0faf,  7);
+    MD5STEP(F1, d, a, b, c, md5->buffer[5]  + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, md5->buffer[6]  + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, md5->buffer[7]  + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, md5->buffer[8]  + 0x698098d8,  7);
+    MD5STEP(F1, d, a, b, c, md5->buffer[9]  + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, md5->buffer[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, md5->buffer[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, md5->buffer[12] + 0x6b901122,  7);
+    MD5STEP(F1, d, a, b, c, md5->buffer[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, md5->buffer[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, md5->buffer[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, md5->buffer[1]  + 0xf61e2562,  5);
+    MD5STEP(F2, d, a, b, c, md5->buffer[6]  + 0xc040b340,  9);
+    MD5STEP(F2, c, d, a, b, md5->buffer[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, md5->buffer[0]  + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, md5->buffer[5]  + 0xd62f105d,  5);
+    MD5STEP(F2, d, a, b, c, md5->buffer[10] + 0x02441453,  9);
+    MD5STEP(F2, c, d, a, b, md5->buffer[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, md5->buffer[4]  + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, md5->buffer[9]  + 0x21e1cde6,  5);
+    MD5STEP(F2, d, a, b, c, md5->buffer[14] + 0xc33707d6,  9);
+    MD5STEP(F2, c, d, a, b, md5->buffer[3]  + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, md5->buffer[8]  + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, md5->buffer[13] + 0xa9e3e905,  5);
+    MD5STEP(F2, d, a, b, c, md5->buffer[2]  + 0xfcefa3f8,  9);
+    MD5STEP(F2, c, d, a, b, md5->buffer[7]  + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, md5->buffer[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, md5->buffer[5]  + 0xfffa3942,  4);
+    MD5STEP(F3, d, a, b, c, md5->buffer[8]  + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, md5->buffer[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, md5->buffer[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, md5->buffer[1]  + 0xa4beea44,  4);
+    MD5STEP(F3, d, a, b, c, md5->buffer[4]  + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, md5->buffer[7]  + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, md5->buffer[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, md5->buffer[13] + 0x289b7ec6,  4);
+    MD5STEP(F3, d, a, b, c, md5->buffer[0]  + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, md5->buffer[3]  + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, md5->buffer[6]  + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, md5->buffer[9]  + 0xd9d4d039,  4);
+    MD5STEP(F3, d, a, b, c, md5->buffer[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, md5->buffer[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, md5->buffer[2]  + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, md5->buffer[0]  + 0xf4292244,  6);
+    MD5STEP(F4, d, a, b, c, md5->buffer[7]  + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, md5->buffer[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, md5->buffer[5]  + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, md5->buffer[12] + 0x655b59c3,  6);
+    MD5STEP(F4, d, a, b, c, md5->buffer[3]  + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, md5->buffer[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, md5->buffer[1]  + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, md5->buffer[8]  + 0x6fa87e4f,  6);
+    MD5STEP(F4, d, a, b, c, md5->buffer[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, md5->buffer[6]  + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, md5->buffer[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, md5->buffer[4]  + 0xf7537e82,  6);
+    MD5STEP(F4, d, a, b, c, md5->buffer[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, md5->buffer[2]  + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, md5->buffer[9]  + 0xeb86d391, 21);
+    
+    /* Add the working vars back into digest state[]  */
+    md5->digest[0] += a;
+    md5->digest[1] += b;
+    md5->digest[2] += c;
+    md5->digest[3] += d;
+}
+
+#endif /* FREESCALE_MMCAU */
+
+
+static INLINE void AddLength(Md5* md5, word32 len)
+{
+    word32 tmp = md5->loLen;
+    if ( (md5->loLen += len) < tmp)
+        md5->hiLen++;                       /* carry low to high */
+}
+
+
+void wc_Md5Update(Md5* md5, const byte* data, word32 len)
+{
+    /* do block size increments */
+    byte* local = (byte*)md5->buffer;
+
+    while (len) {
+        word32 add = min(len, MD5_BLOCK_SIZE - md5->buffLen);
+        XMEMCPY(&local[md5->buffLen], data, add);
+
+        md5->buffLen += add;
+        data         += add;
+        len          -= add;
+
+        if (md5->buffLen == MD5_BLOCK_SIZE) {
+            #if defined(BIG_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+                ByteReverseWords(md5->buffer, md5->buffer, MD5_BLOCK_SIZE);
+            #endif
+            XTRANSFORM(md5, local);
+            AddLength(md5, MD5_BLOCK_SIZE);
+            md5->buffLen = 0;
+        }
+    }
+}
+
+
+void wc_Md5Final(Md5* md5, byte* hash)
+{
+    byte* local = (byte*)md5->buffer;
+
+    AddLength(md5, md5->buffLen);  /* before adding pads */
+
+    local[md5->buffLen++] = 0x80;  /* add 1 */
+
+    /* pad with zeros */
+    if (md5->buffLen > MD5_PAD_SIZE) {
+        XMEMSET(&local[md5->buffLen], 0, MD5_BLOCK_SIZE - md5->buffLen);
+        md5->buffLen += MD5_BLOCK_SIZE - md5->buffLen;
+
+        #if defined(BIG_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+            ByteReverseWords(md5->buffer, md5->buffer, MD5_BLOCK_SIZE);
+        #endif
+        XTRANSFORM(md5, local);
+        md5->buffLen = 0;
+    }
+    XMEMSET(&local[md5->buffLen], 0, MD5_PAD_SIZE - md5->buffLen);
+   
+    /* put lengths in bits */
+    md5->hiLen = (md5->loLen >> (8*sizeof(md5->loLen) - 3)) + 
+                 (md5->hiLen << 3);
+    md5->loLen = md5->loLen << 3;
+
+    /* store lengths */
+    #if defined(BIG_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+        ByteReverseWords(md5->buffer, md5->buffer, MD5_BLOCK_SIZE);
+    #endif
+    /* ! length ordering dependent on digest endian type ! */
+    XMEMCPY(&local[MD5_PAD_SIZE], &md5->loLen, sizeof(word32));
+    XMEMCPY(&local[MD5_PAD_SIZE + sizeof(word32)], &md5->hiLen, sizeof(word32));
+
+    XTRANSFORM(md5, local);
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseWords(md5->digest, md5->digest, MD5_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, md5->digest, MD5_DIGEST_SIZE);
+
+    wc_InitMd5(md5);  /* reset state */
+}
+
+#endif /* STM32F2_HASH */
+
+
+int wc_Md5Hash(const byte* data, word32 len, byte* hash)
+{
+#ifdef WOLFSSL_SMALL_STACK
+    Md5* md5;
+#else
+    Md5 md5[1];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    md5 = (Md5*)XMALLOC(sizeof(Md5), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (md5 == NULL)
+        return MEMORY_E;
+#endif
+
+    wc_InitMd5(md5);
+    wc_Md5Update(md5, data, len);
+    wc_Md5Final(md5, hash);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return 0;
+}
+
+#endif /* WOLFSSL_TI_HASH */
+
+#endif /* NO_MD5 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/memory.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,192 @@
+/* memory.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+/* check old macros @wc_fips */
+#if defined(USE_CYASSL_MEMORY) && !defined(USE_WOLFSSL_MEMORY)
+    #define USE_WOLFSSL_MEMORY
+#endif
+#if defined(CYASSL_MALLOC_CHECK) && !defined(WOLFSSL_MALLOC_CHECK)
+    #define WOLFSSL_MALLOC_CHECK
+#endif
+
+#ifdef USE_WOLFSSL_MEMORY
+
+#include <wolfssl/wolfcrypt/memory.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+#ifdef WOLFSSL_MALLOC_CHECK
+    #include <stdio.h>
+#endif
+
+/* 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;
+
+int wolfSSL_SetAllocators(wolfSSL_Malloc_cb  mf,
+                          wolfSSL_Free_cb    ff,
+                          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;
+}
+
+
+void* wolfSSL_Malloc(size_t size)
+{
+    void* res = 0;
+
+    if (malloc_function)
+        res = malloc_function(size);
+    else
+        res = malloc(size);
+
+    #ifdef WOLFSSL_MALLOC_CHECK
+        if (res == NULL)
+            puts("wolfSSL_malloc failed");
+    #endif
+                
+    return res;
+}
+
+void wolfSSL_Free(void *ptr)
+{
+    if (free_function)
+        free_function(ptr);
+    else
+        free(ptr);
+}
+
+void* wolfSSL_Realloc(void *ptr, size_t size)
+{
+    void* res = 0;
+
+    if (realloc_function)
+        res = realloc_function(ptr, size);
+    else
+        res = realloc(ptr, size);
+
+    return res;
+}
+
+#endif /* USE_WOLFSSL_MEMORY */
+
+
+#ifdef HAVE_IO_POOL
+
+/* Example for user io pool, shared build may need definitions in lib proper */
+
+#include <wolfssl/wolfcrypt/types.h>
+#include <stdlib.h>
+
+#ifndef HAVE_THREAD_LS
+    #error "Oops, simple I/O pool example needs thread local storage"
+#endif
+
+
+/* allow simple per thread in and out pools */
+/* use 17k size sense max record size is 16k plus overhead */
+static THREAD_LS_T byte pool_in[17*1024];
+static THREAD_LS_T byte pool_out[17*1024];
+
+
+void* XMALLOC(size_t n, void* heap, int type)
+{
+    (void)heap;
+
+    if (type == DYNAMIC_TYPE_IN_BUFFER) {
+        if (n < sizeof(pool_in))
+            return pool_in;
+        else
+            return NULL;
+    }
+
+    if (type == DYNAMIC_TYPE_OUT_BUFFER) {
+        if (n < sizeof(pool_out))
+            return pool_out;
+        else
+            return NULL;
+    }
+
+    return malloc(n);
+}
+
+void* XREALLOC(void *p, size_t n, void* heap, int type)
+{
+    (void)heap;
+
+    if (type == DYNAMIC_TYPE_IN_BUFFER) {
+        if (n < sizeof(pool_in))
+            return pool_in;
+        else
+            return NULL;
+    }
+
+    if (type == DYNAMIC_TYPE_OUT_BUFFER) {
+        if (n < sizeof(pool_out))
+            return pool_out;
+        else
+            return NULL;
+    }
+
+    return realloc(p, n);
+}
+
+
+/* unit api calls, let's make sure visible with WOLFSSL_API */
+WOLFSSL_API void XFREE(void *p, void* heap, int type)
+{
+    (void)heap;
+
+    if (type == DYNAMIC_TYPE_IN_BUFFER)
+        return;  /* do nothing, static pool */
+
+    if (type == DYNAMIC_TYPE_OUT_BUFFER)
+        return;  /* do nothing, static pool */
+
+    free(p);
+}
+
+#endif /* HAVE_IO_POOL */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/misc.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,202 @@
+/* misc.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifndef WOLF_CRYPT_MISC_C
+#define WOLF_CRYPT_MISC_C
+
+#include <wolfssl/wolfcrypt/misc.h>
+
+/* inlining these functions is a huge speed increase and a small size decrease, 
+   because the functions are smaller than function call setup/cleanup, e.g.,
+   md5 benchmark is twice as fast with inline.  If you don't want it, then
+   define NO_INLINE and compile this file into wolfssl, otherwise it's used as
+   a source header
+ */
+
+#ifdef NO_INLINE
+    #define STATIC
+#else
+    #define STATIC static
+#endif
+
+
+#ifdef INTEL_INTRINSICS
+
+    #include <stdlib.h>      /* get intrinsic definitions */
+
+    /* for non visual studio probably need no long version, 32 bit only
+     * i.e., _rotl and _rotr */
+    #pragma intrinsic(_lrotl, _lrotr)
+
+    STATIC INLINE word32 rotlFixed(word32 x, word32 y)
+    {
+        return y ? _lrotl(x, y) : x;
+    }
+
+    STATIC INLINE word32 rotrFixed(word32 x, word32 y)
+    {
+        return y ? _lrotr(x, y) : x;
+    }
+
+#else /* generic */
+
+    STATIC INLINE word32 rotlFixed(word32 x, word32 y)
+    {
+        return (x << y) | (x >> (sizeof(y) * 8 - y));
+    }   
+
+
+    STATIC INLINE word32 rotrFixed(word32 x, word32 y)
+    {
+        return (x >> y) | (x << (sizeof(y) * 8 - y));
+    }
+
+#endif
+
+
+STATIC INLINE word32 ByteReverseWord32(word32 value)
+{
+#ifdef PPC_INTRINSICS
+    /* PPC: load reverse indexed instruction */
+    return (word32)__lwbrx(&value,0);
+#elif defined(KEIL_INTRINSICS)
+    return (word32)__rev(value);
+#elif defined(FAST_ROTATE)
+    /* 5 instructions with rotate instruction, 9 without */
+    return (rotrFixed(value, 8U) & 0xff00ff00) |
+           (rotlFixed(value, 8U) & 0x00ff00ff);
+#else
+    /* 6 instructions with rotate instruction, 8 without */
+    value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
+    return rotlFixed(value, 16U);
+#endif
+}
+
+
+STATIC INLINE void ByteReverseWords(word32* out, const word32* in,
+                                    word32 byteCount)
+{
+    word32 count = byteCount/(word32)sizeof(word32), i;
+
+    for (i = 0; i < count; i++)
+        out[i] = ByteReverseWord32(in[i]);
+
+}
+
+
+#ifdef WORD64_AVAILABLE
+
+
+STATIC INLINE word64 rotlFixed64(word64 x, word64 y)
+{
+    return (x << y) | (x >> (sizeof(y) * 8 - y));
+}  
+
+
+STATIC INLINE word64 rotrFixed64(word64 x, word64 y)
+{
+    return (x >> y) | (x << (sizeof(y) * 8 - y));
+}
+
+
+STATIC INLINE word64 ByteReverseWord64(word64 value)
+{
+#ifdef WOLFCRYPT_SLOW_WORD64
+	return (word64)(ByteReverseWord32((word32)value)) << 32 | 
+                    ByteReverseWord32((word32)(value>>32));
+#else
+	value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) |
+            ((value & W64LIT(0x00FF00FF00FF00FF)) << 8);
+	value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) |
+            ((value & W64LIT(0x0000FFFF0000FFFF)) << 16);
+	return rotlFixed64(value, 32U);
+#endif
+}
+
+
+STATIC INLINE void ByteReverseWords64(word64* out, const word64* in,
+                                      word32 byteCount)
+{
+    word32 count = byteCount/(word32)sizeof(word64), i;
+
+    for (i = 0; i < count; i++)
+        out[i] = ByteReverseWord64(in[i]);
+
+}
+
+#endif /* WORD64_AVAILABLE */
+
+
+STATIC INLINE void XorWords(wolfssl_word* r, const wolfssl_word* a, word32 n)
+{
+    word32 i;
+
+    for (i = 0; i < n; i++) r[i] ^= a[i];
+}
+
+
+STATIC INLINE void xorbuf(void* buf, const void* mask, word32 count)
+{
+    if (((wolfssl_word)buf | (wolfssl_word)mask | count) % WOLFSSL_WORD_SIZE == 0)
+        XorWords( (wolfssl_word*)buf,
+                  (const wolfssl_word*)mask, count / WOLFSSL_WORD_SIZE);
+    else {
+        word32 i;
+        byte*       b = (byte*)buf;
+        const byte* m = (const byte*)mask;
+
+        for (i = 0; i < count; i++) b[i] ^= m[i];
+    }
+}
+
+
+/* Make sure compiler doesn't skip */
+STATIC INLINE void ForceZero(const void* mem, word32 len)
+{
+    volatile byte* z = (volatile byte*)mem;
+
+    while (len--) *z++ = 0;
+}
+
+
+/* check all length bytes for equality, return 0 on success */
+STATIC INLINE int ConstantCompare(const byte* a, const byte* b, int length)
+{
+    int i;
+    int compareSum = 0;
+
+    for (i = 0; i < length; i++) {
+        compareSum |= a[i] ^ b[i];
+    }
+
+    return compareSum;
+}
+
+#undef STATIC
+
+#endif /* WOLF_CRYPT_MISC_C */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/pkcs7.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,1859 @@
+/* pkcs7.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_PKCS7
+
+#include <wolfssl/wolfcrypt/pkcs7.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/logging.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* WOLFSSL_HAVE_MIN */
+
+
+/* placed ASN.1 contentType OID into *output, return idx on success,
+ * 0 upon failure */
+WOLFSSL_LOCAL int wc_SetContentType(int pkcs7TypeOID, byte* output)
+{
+    /* PKCS#7 content types, RFC 2315, section 14 */
+    static const byte pkcs7[]              = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                               0x0D, 0x01, 0x07 };
+    static const byte data[]               = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                               0x0D, 0x01, 0x07, 0x01 };
+    static const byte signedData[]         = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                               0x0D, 0x01, 0x07, 0x02};
+    static const byte envelopedData[]      = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                               0x0D, 0x01, 0x07, 0x03 };
+    static const byte signedAndEnveloped[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                               0x0D, 0x01, 0x07, 0x04 };
+    static const byte digestedData[]       = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                               0x0D, 0x01, 0x07, 0x05 };
+    static const byte encryptedData[]      = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                               0x0D, 0x01, 0x07, 0x06 };
+
+    int idSz;
+    int typeSz = 0, idx = 0;
+    const byte* typeName = 0;
+    byte ID_Length[MAX_LENGTH_SZ];
+
+    switch (pkcs7TypeOID) {
+        case PKCS7_MSG:
+            typeSz = sizeof(pkcs7);
+            typeName = pkcs7;
+            break;
+
+        case DATA:
+            typeSz = sizeof(data);
+            typeName = data;
+            break;
+
+        case SIGNED_DATA:
+            typeSz = sizeof(signedData);
+            typeName = signedData;
+            break;
+        
+        case ENVELOPED_DATA:
+            typeSz = sizeof(envelopedData);
+            typeName = envelopedData;
+            break;
+
+        case SIGNED_AND_ENVELOPED_DATA:
+            typeSz = sizeof(signedAndEnveloped);
+            typeName = signedAndEnveloped;
+            break;
+
+        case DIGESTED_DATA:
+            typeSz = sizeof(digestedData);
+            typeName = digestedData;
+            break;
+
+        case ENCRYPTED_DATA:
+            typeSz = sizeof(encryptedData);
+            typeName = encryptedData;
+            break;
+
+        default:
+            WOLFSSL_MSG("Unknown PKCS#7 Type");
+            return 0;
+    };
+
+    idSz  = SetLength(typeSz, ID_Length);
+    output[idx++] = ASN_OBJECT_ID;
+    XMEMCPY(output + idx, ID_Length, idSz);
+    idx += idSz;
+    XMEMCPY(output + idx, typeName, typeSz);
+    idx += typeSz;
+
+    return idx;
+
+}
+
+
+/* get ASN.1 contentType OID sum, return 0 on success, <0 on failure */
+int wc_GetContentType(const byte* input, word32* inOutIdx, word32* oid,
+                   word32 maxIdx)
+{
+    int length;
+    word32 i = *inOutIdx;
+    byte b;
+    *oid = 0;
+
+    WOLFSSL_ENTER("wc_GetContentType");
+
+    b = input[i++];
+    if (b != ASN_OBJECT_ID)
+        return ASN_OBJECT_ID_E;
+
+    if (GetLength(input, &i, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    while(length--) {
+        *oid += input[i];
+        i++;
+    }
+
+    *inOutIdx = i;
+
+    return 0;
+}
+
+
+/* init PKCS7 struct with recipient cert, decode into DecodedCert */
+int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz)
+{
+    int ret = 0;
+
+    XMEMSET(pkcs7, 0, sizeof(PKCS7));
+    if (cert != NULL && certSz > 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        DecodedCert* dCert;
+
+        dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        if (dCert == NULL)
+            return MEMORY_E;
+#else
+        DecodedCert stack_dCert;
+        DecodedCert* dCert = &stack_dCert;
+#endif
+
+        pkcs7->singleCert = cert;
+        pkcs7->singleCertSz = certSz;
+        InitDecodedCert(dCert, cert, certSz, 0);
+
+        ret = ParseCert(dCert, CA_TYPE, NO_VERIFY, 0);
+        if (ret < 0) {
+            FreeDecodedCert(dCert);
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ret;
+        }
+
+        XMEMCPY(pkcs7->publicKey, dCert->publicKey, dCert->pubKeySize);
+        pkcs7->publicKeySz = dCert->pubKeySize;
+        XMEMCPY(pkcs7->issuerHash, dCert->issuerHash, KEYID_SIZE);
+        pkcs7->issuer = dCert->issuerRaw;
+        pkcs7->issuerSz = dCert->issuerRawLen;
+        XMEMCPY(pkcs7->issuerSn, dCert->serial, dCert->serialSz);
+        pkcs7->issuerSnSz = dCert->serialSz;
+        FreeDecodedCert(dCert);
+
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+    }
+
+    return ret;
+}
+
+
+/* releases any memory allocated by a PKCS7 initializer */
+void wc_PKCS7_Free(PKCS7* pkcs7)
+{
+    (void)pkcs7;
+}
+
+
+/* build PKCS#7 data content type */
+int wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, word32 outputSz)
+{
+    static const byte oid[] =
+        { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
+                         0x07, 0x01 };
+    byte seq[MAX_SEQ_SZ];
+    byte octetStr[MAX_OCTET_STR_SZ];
+    word32 seqSz;
+    word32 octetStrSz;
+    word32 oidSz = (word32)sizeof(oid);
+    int idx = 0;
+
+    octetStrSz = SetOctetString(pkcs7->contentSz, octetStr);
+    seqSz = SetSequence(pkcs7->contentSz + octetStrSz + oidSz, seq);
+
+    if (outputSz < pkcs7->contentSz + octetStrSz + oidSz + seqSz)
+        return BUFFER_E;
+
+    XMEMCPY(output, seq, seqSz);
+    idx += seqSz;
+    XMEMCPY(output + idx, oid, oidSz);
+    idx += oidSz;
+    XMEMCPY(output + idx, octetStr, octetStrSz);
+    idx += octetStrSz;
+    XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz);
+    idx += pkcs7->contentSz;
+
+    return idx;
+}
+
+
+typedef struct EncodedAttrib {
+    byte valueSeq[MAX_SEQ_SZ];
+        const byte* oid;
+        byte valueSet[MAX_SET_SZ];
+        const byte* value;
+    word32 valueSeqSz, oidSz, idSz, valueSetSz, valueSz, totalSz;
+} EncodedAttrib;
+
+
+typedef struct ESD {
+    Sha sha;
+    byte contentDigest[SHA_DIGEST_SIZE + 2]; /* content only + ASN.1 heading */
+    byte contentAttribsDigest[SHA_DIGEST_SIZE];
+    byte encContentDigest[512];
+
+    byte outerSeq[MAX_SEQ_SZ];
+        byte outerContent[MAX_EXP_SZ];
+            byte innerSeq[MAX_SEQ_SZ];
+                byte version[MAX_VERSION_SZ];
+                byte digAlgoIdSet[MAX_SET_SZ];
+                    byte singleDigAlgoId[MAX_ALGO_SZ];
+
+                byte contentInfoSeq[MAX_SEQ_SZ];
+                    byte innerContSeq[MAX_EXP_SZ];
+                        byte innerOctets[MAX_OCTET_STR_SZ];
+
+                byte certsSet[MAX_SET_SZ];
+
+                byte signerInfoSet[MAX_SET_SZ];
+                    byte signerInfoSeq[MAX_SEQ_SZ];
+                        byte signerVersion[MAX_VERSION_SZ];
+                        byte issuerSnSeq[MAX_SEQ_SZ];
+                            byte issuerName[MAX_SEQ_SZ];
+                            byte issuerSn[MAX_SN_SZ];
+                        byte signerDigAlgoId[MAX_ALGO_SZ];
+                        byte digEncAlgoId[MAX_ALGO_SZ];
+                        byte signedAttribSet[MAX_SET_SZ];
+                            EncodedAttrib signedAttribs[6];
+                        byte signerDigest[MAX_OCTET_STR_SZ];
+    word32 innerOctetsSz, innerContSeqSz, contentInfoSeqSz;
+    word32 outerSeqSz, outerContentSz, innerSeqSz, versionSz, digAlgoIdSetSz,
+           singleDigAlgoIdSz, certsSetSz;
+    word32 signerInfoSetSz, signerInfoSeqSz, signerVersionSz,
+           issuerSnSeqSz, issuerNameSz, issuerSnSz,
+           signerDigAlgoIdSz, digEncAlgoIdSz, signerDigestSz;
+    word32 encContentDigestSz, signedAttribsSz, signedAttribsCount,
+           signedAttribSetSz;
+} ESD;
+
+
+static int EncodeAttributes(EncodedAttrib* ea, int eaSz,
+                                            PKCS7Attrib* attribs, int attribsSz)
+{
+    int i;
+    int maxSz = min(eaSz, attribsSz);
+    int allAttribsSz = 0;
+
+    for (i = 0; i < maxSz; i++)
+    {
+        int attribSz = 0;
+
+        ea[i].value = attribs[i].value;
+        ea[i].valueSz = attribs[i].valueSz;
+        attribSz += ea[i].valueSz;
+        ea[i].valueSetSz = SetSet(attribSz, ea[i].valueSet);
+        attribSz += ea[i].valueSetSz;
+        ea[i].oid = attribs[i].oid;
+        ea[i].oidSz = attribs[i].oidSz;
+        attribSz += ea[i].oidSz;
+        ea[i].valueSeqSz = SetSequence(attribSz, ea[i].valueSeq);
+        attribSz += ea[i].valueSeqSz;
+        ea[i].totalSz = attribSz;
+
+        allAttribsSz += attribSz;
+    }
+    return allAttribsSz;
+}
+
+
+static int FlattenAttributes(byte* output, EncodedAttrib* ea, int eaSz)
+{
+    int i, idx;
+
+    idx = 0;
+    for (i = 0; i < eaSz; i++) {
+        XMEMCPY(output + idx, ea[i].valueSeq, ea[i].valueSeqSz);
+        idx += ea[i].valueSeqSz;
+        XMEMCPY(output + idx, ea[i].oid, ea[i].oidSz);
+        idx += ea[i].oidSz;
+        XMEMCPY(output + idx, ea[i].valueSet, ea[i].valueSetSz);
+        idx += ea[i].valueSetSz;
+        XMEMCPY(output + idx, ea[i].value, ea[i].valueSz);
+        idx += ea[i].valueSz;
+    }
+    return 0;
+}
+
+
+/* build PKCS#7 signedData content type */
+int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz)
+{
+    static const byte outerOid[] =
+        { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
+                         0x07, 0x02 };
+    static const byte innerOid[] =
+        { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
+                         0x07, 0x01 };
+
+#ifdef WOLFSSL_SMALL_STACK
+    ESD* esd = NULL;
+#else
+    ESD stack_esd;
+    ESD* esd = &stack_esd;
+#endif
+
+    word32 signerInfoSz = 0;
+    word32 totalSz = 0;
+    int idx = 0, ret = 0;
+    byte* flatSignedAttribs = NULL;
+    word32 flatSignedAttribsSz = 0;
+    word32 innerOidSz = sizeof(innerOid);
+    word32 outerOidSz = sizeof(outerOid);
+
+    if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 ||
+        pkcs7->encryptOID == 0 || pkcs7->hashOID == 0 || pkcs7->rng == 0 ||
+        pkcs7->singleCert == NULL || pkcs7->singleCertSz == 0 ||
+        pkcs7->privateKey == NULL || pkcs7->privateKeySz == 0 ||
+        output == NULL || outputSz == 0)
+        return BAD_FUNC_ARG;
+
+#ifdef WOLFSSL_SMALL_STACK
+    esd = (ESD*)XMALLOC(sizeof(ESD), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (esd == NULL)
+        return MEMORY_E;
+#endif
+
+    XMEMSET(esd, 0, sizeof(ESD));
+    ret = wc_InitSha(&esd->sha);
+    if (ret != 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ret;
+    }
+
+    if (pkcs7->contentSz != 0)
+    {
+        wc_ShaUpdate(&esd->sha, pkcs7->content, pkcs7->contentSz);
+        esd->contentDigest[0] = ASN_OCTET_STRING;
+        esd->contentDigest[1] = SHA_DIGEST_SIZE;
+        wc_ShaFinal(&esd->sha, &esd->contentDigest[2]);
+    }
+
+    esd->innerOctetsSz = SetOctetString(pkcs7->contentSz, esd->innerOctets);
+    esd->innerContSeqSz = SetExplicit(0, esd->innerOctetsSz + pkcs7->contentSz,
+                                esd->innerContSeq);
+    esd->contentInfoSeqSz = SetSequence(pkcs7->contentSz + esd->innerOctetsSz +
+                                    innerOidSz + esd->innerContSeqSz,
+                                    esd->contentInfoSeq);
+
+    esd->issuerSnSz = SetSerialNumber(pkcs7->issuerSn, pkcs7->issuerSnSz,
+                                     esd->issuerSn);
+    signerInfoSz += esd->issuerSnSz;
+    esd->issuerNameSz = SetSequence(pkcs7->issuerSz, esd->issuerName);
+    signerInfoSz += esd->issuerNameSz + pkcs7->issuerSz;
+    esd->issuerSnSeqSz = SetSequence(signerInfoSz, esd->issuerSnSeq);
+    signerInfoSz += esd->issuerSnSeqSz;
+    esd->signerVersionSz = SetMyVersion(1, esd->signerVersion, 0);
+    signerInfoSz += esd->signerVersionSz;
+    esd->signerDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->signerDigAlgoId,
+                                      hashType, 0);
+    signerInfoSz += esd->signerDigAlgoIdSz;
+    esd->digEncAlgoIdSz = SetAlgoID(pkcs7->encryptOID, esd->digEncAlgoId,
+                                   keyType, 0);
+    signerInfoSz += esd->digEncAlgoIdSz;
+
+    if (pkcs7->signedAttribsSz != 0) {
+        byte contentTypeOid[] =
+                { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0d, 0x01,
+                                 0x09, 0x03 };
+        byte contentType[] =
+                { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+                                 0x07, 0x01 };
+        byte messageDigestOid[] =
+                { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+                                 0x09, 0x04 };
+
+        PKCS7Attrib cannedAttribs[2] =
+        {
+            { contentTypeOid, sizeof(contentTypeOid),
+                             contentType, sizeof(contentType) },
+            { messageDigestOid, sizeof(messageDigestOid),
+                             esd->contentDigest, sizeof(esd->contentDigest) }
+        };
+        word32 cannedAttribsCount = sizeof(cannedAttribs)/sizeof(PKCS7Attrib);
+
+        esd->signedAttribsCount += cannedAttribsCount;
+        esd->signedAttribsSz += EncodeAttributes(&esd->signedAttribs[0], 2,
+                                             cannedAttribs, cannedAttribsCount);
+
+        esd->signedAttribsCount += pkcs7->signedAttribsSz;
+        esd->signedAttribsSz += EncodeAttributes(&esd->signedAttribs[2], 4,
+                                  pkcs7->signedAttribs, pkcs7->signedAttribsSz);
+
+        flatSignedAttribs = (byte*)XMALLOC(esd->signedAttribsSz, 0, NULL);
+        flatSignedAttribsSz = esd->signedAttribsSz;
+        if (flatSignedAttribs == NULL) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif   
+            return MEMORY_E;
+        }
+        FlattenAttributes(flatSignedAttribs,
+                                   esd->signedAttribs, esd->signedAttribsCount);
+        esd->signedAttribSetSz = SetImplicit(ASN_SET, 0, esd->signedAttribsSz,
+                                                          esd->signedAttribSet);
+    }
+    /* Calculate the final hash and encrypt it. */
+    {
+        int result;
+        word32 scratch = 0;
+
+#ifdef WOLFSSL_SMALL_STACK
+        byte* digestInfo;
+        RsaKey* privKey;
+#else
+        RsaKey stack_privKey;
+        RsaKey* privKey = &stack_privKey;
+        byte digestInfo[MAX_SEQ_SZ + MAX_ALGO_SZ +
+                        MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE];
+#endif
+        byte digestInfoSeq[MAX_SEQ_SZ];
+        byte digestStr[MAX_OCTET_STR_SZ];
+        word32 digestInfoSeqSz, digestStrSz;
+        int digIdx = 0;
+
+        if (pkcs7->signedAttribsSz != 0) {
+            byte attribSet[MAX_SET_SZ];
+            word32 attribSetSz;
+
+            attribSetSz = SetSet(flatSignedAttribsSz, attribSet);
+
+            ret = wc_InitSha(&esd->sha);
+            if (ret < 0) {
+                XFREE(flatSignedAttribs, 0, NULL);
+#ifdef WOLFSSL_SMALL_STACK
+                XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+                return ret;
+            }
+            wc_ShaUpdate(&esd->sha, attribSet, attribSetSz);
+            wc_ShaUpdate(&esd->sha, flatSignedAttribs, flatSignedAttribsSz);
+        }
+        wc_ShaFinal(&esd->sha, esd->contentAttribsDigest);
+
+        digestStrSz = SetOctetString(SHA_DIGEST_SIZE, digestStr);
+        digestInfoSeqSz = SetSequence(esd->signerDigAlgoIdSz +
+                                      digestStrSz + SHA_DIGEST_SIZE,
+                                      digestInfoSeq);
+
+#ifdef WOLFSSL_SMALL_STACK
+        digestInfo = (byte*)XMALLOC(MAX_SEQ_SZ + MAX_ALGO_SZ +
+                                    MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE,
+                                    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (digestInfo == NULL) {
+            if (pkcs7->signedAttribsSz != 0)
+                XFREE(flatSignedAttribs, 0, NULL);
+            XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            return MEMORY_E;
+        }
+#endif
+
+        XMEMCPY(digestInfo + digIdx, digestInfoSeq, digestInfoSeqSz);
+        digIdx += digestInfoSeqSz;
+        XMEMCPY(digestInfo + digIdx,
+                                  esd->signerDigAlgoId, esd->signerDigAlgoIdSz);
+        digIdx += esd->signerDigAlgoIdSz;
+        XMEMCPY(digestInfo + digIdx, digestStr, digestStrSz);
+        digIdx += digestStrSz;
+        XMEMCPY(digestInfo + digIdx, esd->contentAttribsDigest,
+                                                               SHA_DIGEST_SIZE);
+        digIdx += SHA_DIGEST_SIZE;
+
+#ifdef WOLFSSL_SMALL_STACK
+        privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        if (privKey == NULL) {
+            if (pkcs7->signedAttribsSz != 0)
+                XFREE(flatSignedAttribs, 0, NULL);
+            XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(esd,        NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            return MEMORY_E;
+        }
+#endif
+
+        result = wc_InitRsaKey(privKey, NULL);
+        if (result == 0)
+            result = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &scratch, privKey,
+                                         pkcs7->privateKeySz);
+        if (result < 0) {
+            if (pkcs7->signedAttribsSz != 0)
+                XFREE(flatSignedAttribs, 0, NULL);
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(privKey,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(esd,        NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return PUBLIC_KEY_E;
+        }
+
+        result = wc_RsaSSL_Sign(digestInfo, digIdx,
+                             esd->encContentDigest,
+                             sizeof(esd->encContentDigest),
+                             privKey, pkcs7->rng);
+
+        wc_FreeRsaKey(privKey);
+
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(privKey,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+        if (result < 0) {
+            if (pkcs7->signedAttribsSz != 0)
+                XFREE(flatSignedAttribs, 0, NULL);
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return result;
+        }
+        esd->encContentDigestSz = (word32)result;
+    }
+    signerInfoSz += flatSignedAttribsSz + esd->signedAttribSetSz;
+
+    esd->signerDigestSz = SetOctetString(esd->encContentDigestSz,
+                                                             esd->signerDigest);
+    signerInfoSz += esd->signerDigestSz + esd->encContentDigestSz;
+
+    esd->signerInfoSeqSz = SetSequence(signerInfoSz, esd->signerInfoSeq);
+    signerInfoSz += esd->signerInfoSeqSz;
+    esd->signerInfoSetSz = SetSet(signerInfoSz, esd->signerInfoSet);
+    signerInfoSz += esd->signerInfoSetSz;
+
+    esd->certsSetSz = SetImplicit(ASN_SET, 0, pkcs7->singleCertSz,
+                                                                 esd->certsSet);
+
+    esd->singleDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->singleDigAlgoId,
+                                      hashType, 0);
+    esd->digAlgoIdSetSz = SetSet(esd->singleDigAlgoIdSz, esd->digAlgoIdSet);
+
+
+    esd->versionSz = SetMyVersion(1, esd->version, 0);
+
+    totalSz = esd->versionSz + esd->singleDigAlgoIdSz + esd->digAlgoIdSetSz +
+              esd->contentInfoSeqSz + esd->certsSetSz + pkcs7->singleCertSz +
+              esd->innerOctetsSz + esd->innerContSeqSz +
+              innerOidSz + pkcs7->contentSz +
+              signerInfoSz;
+    esd->innerSeqSz = SetSequence(totalSz, esd->innerSeq);
+    totalSz += esd->innerSeqSz;
+    esd->outerContentSz = SetExplicit(0, totalSz, esd->outerContent);
+    totalSz += esd->outerContentSz + outerOidSz;
+    esd->outerSeqSz = SetSequence(totalSz, esd->outerSeq);
+    totalSz += esd->outerSeqSz;
+
+    if (outputSz < totalSz) {
+        if (pkcs7->signedAttribsSz != 0)
+            XFREE(flatSignedAttribs, 0, NULL);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return BUFFER_E;
+    }
+
+    idx = 0;
+    XMEMCPY(output + idx, esd->outerSeq, esd->outerSeqSz);
+    idx += esd->outerSeqSz;
+    XMEMCPY(output + idx, outerOid, outerOidSz);
+    idx += outerOidSz;
+    XMEMCPY(output + idx, esd->outerContent, esd->outerContentSz);
+    idx += esd->outerContentSz;
+    XMEMCPY(output + idx, esd->innerSeq, esd->innerSeqSz);
+    idx += esd->innerSeqSz;
+    XMEMCPY(output + idx, esd->version, esd->versionSz);
+    idx += esd->versionSz;
+    XMEMCPY(output + idx, esd->digAlgoIdSet, esd->digAlgoIdSetSz);
+    idx += esd->digAlgoIdSetSz;
+    XMEMCPY(output + idx, esd->singleDigAlgoId, esd->singleDigAlgoIdSz);
+    idx += esd->singleDigAlgoIdSz;
+    XMEMCPY(output + idx, esd->contentInfoSeq, esd->contentInfoSeqSz);
+    idx += esd->contentInfoSeqSz;
+    XMEMCPY(output + idx, innerOid, innerOidSz);
+    idx += innerOidSz;
+    XMEMCPY(output + idx, esd->innerContSeq, esd->innerContSeqSz);
+    idx += esd->innerContSeqSz;
+    XMEMCPY(output + idx, esd->innerOctets, esd->innerOctetsSz);
+    idx += esd->innerOctetsSz;
+    XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz);
+    idx += pkcs7->contentSz;
+    XMEMCPY(output + idx, esd->certsSet, esd->certsSetSz);
+    idx += esd->certsSetSz;
+    XMEMCPY(output + idx, pkcs7->singleCert, pkcs7->singleCertSz);
+    idx += pkcs7->singleCertSz;
+    XMEMCPY(output + idx, esd->signerInfoSet, esd->signerInfoSetSz);
+    idx += esd->signerInfoSetSz;
+    XMEMCPY(output + idx, esd->signerInfoSeq, esd->signerInfoSeqSz);
+    idx += esd->signerInfoSeqSz;
+    XMEMCPY(output + idx, esd->signerVersion, esd->signerVersionSz);
+    idx += esd->signerVersionSz;
+    XMEMCPY(output + idx, esd->issuerSnSeq, esd->issuerSnSeqSz);
+    idx += esd->issuerSnSeqSz;
+    XMEMCPY(output + idx, esd->issuerName, esd->issuerNameSz);
+    idx += esd->issuerNameSz;
+    XMEMCPY(output + idx, pkcs7->issuer, pkcs7->issuerSz);
+    idx += pkcs7->issuerSz;
+    XMEMCPY(output + idx, esd->issuerSn, esd->issuerSnSz);
+    idx += esd->issuerSnSz;
+    XMEMCPY(output + idx, esd->signerDigAlgoId, esd->signerDigAlgoIdSz);
+    idx += esd->signerDigAlgoIdSz;
+
+    /* SignerInfo:Attributes */
+    if (pkcs7->signedAttribsSz != 0) {
+        XMEMCPY(output + idx, esd->signedAttribSet, esd->signedAttribSetSz);
+        idx += esd->signedAttribSetSz;
+        XMEMCPY(output + idx, flatSignedAttribs, flatSignedAttribsSz);
+        idx += flatSignedAttribsSz;
+        XFREE(flatSignedAttribs, 0, NULL);
+    }
+
+    XMEMCPY(output + idx, esd->digEncAlgoId, esd->digEncAlgoIdSz);
+    idx += esd->digEncAlgoIdSz;
+    XMEMCPY(output + idx, esd->signerDigest, esd->signerDigestSz);
+    idx += esd->signerDigestSz;
+    XMEMCPY(output + idx, esd->encContentDigest, esd->encContentDigestSz);
+    idx += esd->encContentDigestSz;
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return idx;
+}
+
+
+/* Finds the certificates in the message and saves it. */
+int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz)
+{
+    word32 idx, contentType;
+    int length, version, ret;
+    byte* content = NULL;
+    byte* sig = NULL;
+    byte* cert = NULL;
+    int contentSz = 0, sigSz = 0, certSz = 0;
+
+    if (pkcs7 == NULL || pkiMsg == NULL || pkiMsgSz == 0)
+        return BAD_FUNC_ARG;
+
+    idx = 0;
+
+    /* Get the contentInfo sequence */
+    if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    /* Get the contentInfo contentType */
+    if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (contentType != SIGNED_DATA) {
+        WOLFSSL_MSG("PKCS#7 input not of type SignedData");
+        return PKCS7_OID_E;
+    }
+
+    /* get the ContentInfo content */
+    if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
+        return ASN_PARSE_E;
+
+    if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    /* Get the signedData sequence */
+    if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    /* Get the version */
+    if (GetMyVersion(pkiMsg, &idx, &version) < 0)
+        return ASN_PARSE_E;
+
+    if (version != 1) {
+        WOLFSSL_MSG("PKCS#7 signedData needs to be of version 1");
+        return ASN_VERSION_E;
+    }
+
+    /* Get the set of DigestAlgorithmIdentifiers */
+    if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    /* Skip the set. */
+    idx += length;
+
+    /* Get the inner ContentInfo sequence */
+    if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    /* Get the inner ContentInfo contentType */
+    if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (contentType != DATA) {
+        WOLFSSL_MSG("PKCS#7 inner input not of type Data");
+        return PKCS7_OID_E;
+    }
+
+    if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
+        return ASN_PARSE_E;
+
+    if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (pkiMsg[idx++] != ASN_OCTET_STRING)
+        return ASN_PARSE_E;
+
+    if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    /* Save the inner data as the content. */
+    if (length > 0) {
+        /* Local pointer for calculating hashes later */
+        pkcs7->content = content = &pkiMsg[idx];
+        pkcs7->contentSz = contentSz = length;
+        idx += length;
+    }
+
+    /* Get the implicit[0] set of certificates */
+    if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
+        idx++;
+        if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        if (length > 0) {
+            /* At this point, idx is at the first certificate in
+             * a set of certificates. There may be more than one,
+             * or none, or they may be a PKCS 6 extended
+             * certificate. We want to save the first cert if it
+             * is X.509. */
+
+            word32 certIdx = idx;
+
+            if (pkiMsg[certIdx++] == (ASN_CONSTRUCTED | ASN_SEQUENCE)) {
+                if (GetLength(pkiMsg, &certIdx, &certSz, pkiMsgSz) < 0)
+                    return ASN_PARSE_E;
+
+                cert = &pkiMsg[idx];
+                certSz += (certIdx - idx);
+            }
+            wc_PKCS7_InitWithCert(pkcs7, cert, certSz);
+        }
+        idx += length;
+    }
+
+    /* Get the implicit[1] set of crls */
+    if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) {
+        idx++;
+        if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        /* Skip the set */
+        idx += length;
+    }
+
+    /* Get the set of signerInfos */
+    if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (length > 0) {
+        /* Get the sequence of the first signerInfo */
+        if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        /* Get the version */
+        if (GetMyVersion(pkiMsg, &idx, &version) < 0)
+            return ASN_PARSE_E;
+
+        if (version != 1) {
+            WOLFSSL_MSG("PKCS#7 signerInfo needs to be of version 1");
+            return ASN_VERSION_E;
+        }
+
+        /* Get the sequence of IssuerAndSerialNumber */
+        if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        /* Skip it */
+        idx += length;
+
+        /* Get the sequence of digestAlgorithm */
+        if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        /* Skip it */
+        idx += length;
+
+        /* Get the IMPLICIT[0] SET OF signedAttributes */
+        if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
+            idx++;
+
+            if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+                return ASN_PARSE_E;
+
+            idx += length;
+        }
+
+        /* Get the sequence of digestEncryptionAlgorithm */
+        if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        /* Skip it */
+        idx += length;
+
+        /* Get the signature */
+        if (pkiMsg[idx] == ASN_OCTET_STRING) {
+            idx++;
+
+            if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+                return ASN_PARSE_E;
+
+            /* save pointer and length */
+            sig = &pkiMsg[idx];
+            sigSz = length;
+
+            idx += length;
+        }
+
+        pkcs7->content = content;
+        pkcs7->contentSz = contentSz;
+
+        {
+            word32 scratch = 0;
+            int plainSz = 0;
+            int digestSz = MAX_SEQ_SZ + MAX_ALGO_SZ +
+                           MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE;
+
+#ifdef WOLFSSL_SMALL_STACK
+            byte* digest;
+            RsaKey* key;
+
+            digest = (byte*)XMALLOC(digestSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+            if (digest == NULL)
+                return MEMORY_E;
+
+            key = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+            if (key == NULL) {
+                XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                return MEMORY_E;
+            }
+#else
+            byte digest[digestSz];
+            RsaKey stack_key;
+            RsaKey* key = &stack_key;
+#endif
+
+            XMEMSET(digest, 0, digestSz);
+
+            ret = wc_InitRsaKey(key, NULL);
+            if (ret != 0) {
+#ifdef WOLFSSL_SMALL_STACK
+                XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(key,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+                return ret;
+            }
+            if (wc_RsaPublicKeyDecode(pkcs7->publicKey, &scratch, key,
+                                   pkcs7->publicKeySz) < 0) {
+                WOLFSSL_MSG("ASN RSA key decode error");
+#ifdef WOLFSSL_SMALL_STACK
+                XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                XFREE(key,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+                return PUBLIC_KEY_E;
+            }
+
+            plainSz = wc_RsaSSL_Verify(sig, sigSz, digest, digestSz, key);
+            wc_FreeRsaKey(key);
+
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(key,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+            if (plainSz < 0)
+                return plainSz;
+        }
+    }
+
+    return 0;
+}
+
+
+/* create ASN.1 fomatted RecipientInfo structure, returns sequence size */
+WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz,
+                                     int keyEncAlgo, int blockKeySz,
+                                     RNG* rng, byte* contentKeyPlain,
+                                     byte* contentKeyEnc,
+                                     int* keyEncSz, byte* out, word32 outSz)
+{
+    word32 idx = 0;
+    int ret = 0, totalSz = 0;
+    int verSz, issuerSz, snSz, keyEncAlgSz;
+    int issuerSeqSz, recipSeqSz, issuerSerialSeqSz;
+    int encKeyOctetStrSz;
+
+    byte ver[MAX_VERSION_SZ];
+    byte issuerSerialSeq[MAX_SEQ_SZ];
+    byte recipSeq[MAX_SEQ_SZ];
+    byte issuerSeq[MAX_SEQ_SZ];
+    byte encKeyOctetStr[MAX_OCTET_STR_SZ];
+
+#ifdef WOLFSSL_SMALL_STACK
+    byte *serial;
+    byte *keyAlgArray;
+    
+    RsaKey* pubKey;
+    DecodedCert* decoded;
+
+    serial = (byte*)XMALLOC(MAX_SN_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    keyAlgArray = (byte*)XMALLOC(MAX_SN_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+
+    if (decoded == NULL || serial == NULL || keyAlgArray == NULL) {
+        if (serial)      XFREE(serial,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (keyAlgArray) XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (decoded)     XFREE(decoded,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+    
+#else
+    byte serial[MAX_SN_SZ];
+    byte keyAlgArray[MAX_ALGO_SZ];
+    
+    RsaKey stack_pubKey;
+    RsaKey* pubKey = &stack_pubKey;
+    DecodedCert stack_decoded;
+    DecodedCert* decoded = &stack_decoded;
+#endif
+
+    InitDecodedCert(decoded, (byte*)cert, certSz, 0);
+    ret = ParseCert(decoded, CA_TYPE, NO_VERIFY, 0);
+    if (ret < 0) {
+        FreeDecodedCert(decoded);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(serial,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(decoded,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ret;
+    }
+
+    /* version */
+    verSz = SetMyVersion(0, ver, 0);
+
+    /* IssuerAndSerialNumber */
+    if (decoded->issuerRaw == NULL || decoded->issuerRawLen == 0) {
+        WOLFSSL_MSG("DecodedCert lacks raw issuer pointer and length");
+        FreeDecodedCert(decoded);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(serial,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(decoded,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return -1;
+    }
+    issuerSz    = decoded->issuerRawLen;
+    issuerSeqSz = SetSequence(issuerSz, issuerSeq);
+
+    if (decoded->serialSz == 0) {
+        WOLFSSL_MSG("DecodedCert missing serial number");
+        FreeDecodedCert(decoded);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(serial,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(decoded,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return -1;
+    }
+    snSz = SetSerialNumber(decoded->serial, decoded->serialSz, serial);
+
+    issuerSerialSeqSz = SetSequence(issuerSeqSz + issuerSz + snSz,
+                                    issuerSerialSeq);
+
+    /* KeyEncryptionAlgorithmIdentifier, only support RSA now */
+    if (keyEncAlgo != RSAk) {
+        FreeDecodedCert(decoded);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(serial,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(decoded,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ALGO_ID_E;
+    }
+
+    keyEncAlgSz = SetAlgoID(keyEncAlgo, keyAlgArray, keyType, 0);
+    if (keyEncAlgSz == 0) {
+        FreeDecodedCert(decoded);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(serial,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(decoded,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return BAD_FUNC_ARG;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    pubKey = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (pubKey == NULL) {
+        FreeDecodedCert(decoded);
+        XFREE(serial,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(decoded,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    /* EncryptedKey */
+    ret = wc_InitRsaKey(pubKey, 0);
+    if (ret != 0) {
+        FreeDecodedCert(decoded);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(pubKey,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(serial,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(decoded,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ret;
+    }
+
+    if (wc_RsaPublicKeyDecode(decoded->publicKey, &idx, pubKey,
+                           decoded->pubKeySize) < 0) {
+        WOLFSSL_MSG("ASN RSA key decode error");
+        wc_FreeRsaKey(pubKey);
+        FreeDecodedCert(decoded);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(pubKey,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(serial,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(decoded,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return PUBLIC_KEY_E;
+    }
+
+    *keyEncSz = wc_RsaPublicEncrypt(contentKeyPlain, blockKeySz, contentKeyEnc,
+                                 MAX_ENCRYPTED_KEY_SZ, pubKey, rng);
+    wc_FreeRsaKey(pubKey);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(pubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    if (*keyEncSz < 0) {
+        WOLFSSL_MSG("RSA Public Encrypt failed");
+        FreeDecodedCert(decoded);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(serial,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(decoded,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return *keyEncSz;
+    }
+
+    encKeyOctetStrSz = SetOctetString(*keyEncSz, encKeyOctetStr);
+
+    /* RecipientInfo */
+    recipSeqSz = SetSequence(verSz + issuerSerialSeqSz + issuerSeqSz +
+                             issuerSz + snSz + keyEncAlgSz + encKeyOctetStrSz +
+                             *keyEncSz, recipSeq);
+
+    if (recipSeqSz + verSz + issuerSerialSeqSz + issuerSeqSz + snSz +
+        keyEncAlgSz + encKeyOctetStrSz + *keyEncSz > (int)outSz) {
+        WOLFSSL_MSG("RecipientInfo output buffer too small");
+        FreeDecodedCert(decoded);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(serial,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(decoded,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return BUFFER_E;
+    }
+
+    XMEMCPY(out + totalSz, recipSeq, recipSeqSz);
+    totalSz += recipSeqSz;
+    XMEMCPY(out + totalSz, ver, verSz);
+    totalSz += verSz;
+    XMEMCPY(out + totalSz, issuerSerialSeq, issuerSerialSeqSz);
+    totalSz += issuerSerialSeqSz;
+    XMEMCPY(out + totalSz, issuerSeq, issuerSeqSz);
+    totalSz += issuerSeqSz;
+    XMEMCPY(out + totalSz, decoded->issuerRaw, issuerSz);
+    totalSz += issuerSz;
+    XMEMCPY(out + totalSz, serial, snSz);
+    totalSz += snSz;
+    XMEMCPY(out + totalSz, keyAlgArray, keyEncAlgSz);
+    totalSz += keyEncAlgSz;
+    XMEMCPY(out + totalSz, encKeyOctetStr, encKeyOctetStrSz);
+    totalSz += encKeyOctetStrSz;
+    XMEMCPY(out + totalSz, contentKeyEnc, *keyEncSz);
+    totalSz += *keyEncSz;
+
+    FreeDecodedCert(decoded);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(serial,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(decoded,     NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return totalSz;
+}
+
+
+/* build PKCS#7 envelopedData content type, return enveloped size */
+int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz)
+{
+    int i, ret = 0, idx = 0;
+    int totalSz = 0, padSz = 0, desOutSz = 0;
+
+    int contentInfoSeqSz, outerContentTypeSz, outerContentSz;
+    byte contentInfoSeq[MAX_SEQ_SZ];
+    byte outerContentType[MAX_ALGO_SZ];
+    byte outerContent[MAX_SEQ_SZ];
+
+    int envDataSeqSz, verSz;
+    byte envDataSeq[MAX_SEQ_SZ];
+    byte ver[MAX_VERSION_SZ];
+
+    RNG rng;
+    int contentKeyEncSz, blockKeySz;
+    int dynamicFlag = 0;
+    byte contentKeyPlain[MAX_CONTENT_KEY_LEN];
+#ifdef WOLFSSL_SMALL_STACK
+    byte* contentKeyEnc;
+#else
+    byte contentKeyEnc[MAX_ENCRYPTED_KEY_SZ];
+#endif
+    byte* plain;
+    byte* encryptedContent;
+
+    int recipSz, recipSetSz;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* recip;
+#else
+    byte recip[MAX_RECIP_SZ];
+#endif
+    byte recipSet[MAX_SET_SZ];
+
+    int encContentOctetSz, encContentSeqSz, contentTypeSz;
+    int contentEncAlgoSz, ivOctetStringSz;
+    byte encContentSeq[MAX_SEQ_SZ];
+    byte contentType[MAX_ALGO_SZ];
+    byte contentEncAlgo[MAX_ALGO_SZ];
+    byte tmpIv[DES_BLOCK_SIZE];
+    byte ivOctetString[MAX_OCTET_STR_SZ];
+    byte encContentOctet[MAX_OCTET_STR_SZ];
+
+    if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 ||
+        pkcs7->encryptOID == 0 || pkcs7->singleCert == NULL)
+        return BAD_FUNC_ARG;
+
+    if (output == NULL || outputSz == 0)
+        return BAD_FUNC_ARG;
+
+    /* PKCS#7 only supports DES, 3DES for now */
+    switch (pkcs7->encryptOID) {
+        case DESb:
+            blockKeySz = DES_KEYLEN;
+            break;
+
+        case DES3b:
+            blockKeySz = DES3_KEYLEN;
+            break;
+
+        default:
+            WOLFSSL_MSG("Unsupported content cipher type");
+            return ALGO_ID_E;
+    };
+
+    /* outer content type */
+    outerContentTypeSz = wc_SetContentType(ENVELOPED_DATA, outerContentType);
+
+    /* version, defined as 0 in RFC 2315 */
+    verSz = SetMyVersion(0, ver, 0);
+
+    /* generate random content encryption key */
+    ret = wc_InitRng(&rng);
+    if (ret != 0)
+        return ret;
+
+    ret = wc_RNG_GenerateBlock(&rng, contentKeyPlain, blockKeySz);
+    if (ret != 0) {
+        wc_FreeRng(&rng);
+        return ret;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    recip         = (byte*)XMALLOC(MAX_RECIP_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    contentKeyEnc = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL, 
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (contentKeyEnc == NULL || recip == NULL) {
+        if (recip)         XFREE(recip,         NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (contentKeyEnc) XFREE(contentKeyEnc, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        wc_FreeRng(&rng);
+        return MEMORY_E;
+    }
+    
+#endif
+
+    /* build RecipientInfo, only handle 1 for now */
+    recipSz = wc_CreateRecipientInfo(pkcs7->singleCert, pkcs7->singleCertSz, RSAk,
+                                  blockKeySz, &rng, contentKeyPlain,
+                                  contentKeyEnc, &contentKeyEncSz, recip,
+                                  MAX_RECIP_SZ);
+                                                                      
+    ForceZero(contentKeyEnc, MAX_ENCRYPTED_KEY_SZ);
+    
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(contentKeyEnc, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    if (recipSz < 0) {
+        WOLFSSL_MSG("Failed to create RecipientInfo");
+        wc_FreeRng(&rng);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+#endif
+        return recipSz;
+    }
+    recipSetSz = SetSet(recipSz, recipSet);
+
+    /* generate IV for block cipher */
+    ret = wc_RNG_GenerateBlock(&rng, tmpIv, DES_BLOCK_SIZE);
+    wc_FreeRng(&rng);
+    if (ret != 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+#endif
+        return ret;
+    }
+
+    /* EncryptedContentInfo */
+    contentTypeSz = wc_SetContentType(pkcs7->contentOID, contentType);
+    if (contentTypeSz == 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+#endif
+        return BAD_FUNC_ARG;
+    }
+
+    /* allocate encrypted content buffer, pad if necessary, PKCS#7 padding */
+    padSz = DES_BLOCK_SIZE - (pkcs7->contentSz % DES_BLOCK_SIZE);
+    desOutSz = pkcs7->contentSz + padSz;
+
+    if (padSz != 0) {
+        plain = (byte*)XMALLOC(desOutSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (plain == NULL) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+#endif
+            return MEMORY_E;
+        }
+        XMEMCPY(plain, pkcs7->content, pkcs7->contentSz);
+        dynamicFlag = 1;
+
+        for (i = 0; i < padSz; i++) {
+            plain[pkcs7->contentSz + i] = padSz;
+        }
+
+    } else {
+        plain = pkcs7->content;
+        desOutSz = pkcs7->contentSz;
+    }
+
+    encryptedContent = (byte*)XMALLOC(desOutSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (encryptedContent == NULL) {
+        if (dynamicFlag)
+            XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+#endif
+        return MEMORY_E;
+    }
+
+    /* put together IV OCTET STRING */
+    ivOctetStringSz = SetOctetString(DES_BLOCK_SIZE, ivOctetString);
+
+    /* build up our ContentEncryptionAlgorithmIdentifier sequence,
+     * adding (ivOctetStringSz + DES_BLOCK_SIZE) for IV OCTET STRING */
+    contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo,
+                                 blkType, ivOctetStringSz + DES_BLOCK_SIZE);
+
+    if (contentEncAlgoSz == 0) {
+        XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (dynamicFlag)
+            XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+#endif
+        return BAD_FUNC_ARG;
+    }
+
+    /* encrypt content */
+    if (pkcs7->encryptOID == DESb) {
+        Des des;
+
+        ret = wc_Des_SetKey(&des, contentKeyPlain, tmpIv, DES_ENCRYPTION);
+
+        if (ret == 0)
+            wc_Des_CbcEncrypt(&des, encryptedContent, plain, desOutSz);
+
+        if (ret != 0) {
+            XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            if (dynamicFlag)
+                XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+#endif
+            return ret;
+        }
+    }
+    else if (pkcs7->encryptOID == DES3b) {
+        Des3 des3;
+
+        ret = wc_Des3_SetKey(&des3, contentKeyPlain, tmpIv, DES_ENCRYPTION);
+
+        if (ret == 0)
+            ret = wc_Des3_CbcEncrypt(&des3, encryptedContent, plain, desOutSz);
+
+        if (ret != 0) {
+            XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            if (dynamicFlag)
+                XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+#endif
+            return ret;
+        }
+    }
+
+    encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0,
+                                    desOutSz, encContentOctet);
+
+    encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz +
+                                  ivOctetStringSz + DES_BLOCK_SIZE +
+                                  encContentOctetSz + desOutSz, encContentSeq);
+
+    /* keep track of sizes for outer wrapper layering */
+    totalSz = verSz + recipSetSz + recipSz + encContentSeqSz + contentTypeSz +
+              contentEncAlgoSz + ivOctetStringSz + DES_BLOCK_SIZE +
+              encContentOctetSz + desOutSz;
+
+    /* EnvelopedData */
+    envDataSeqSz = SetSequence(totalSz, envDataSeq);
+    totalSz += envDataSeqSz;
+
+    /* outer content */
+    outerContentSz = SetExplicit(0, totalSz, outerContent);
+    totalSz += outerContentTypeSz;
+    totalSz += outerContentSz;
+
+    /* ContentInfo */
+    contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq);
+    totalSz += contentInfoSeqSz;
+
+    if (totalSz > (int)outputSz) {
+        WOLFSSL_MSG("Pkcs7_encrypt output buffer too small");
+        XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (dynamicFlag)
+            XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+#endif
+        return BUFFER_E;
+    }
+
+    XMEMCPY(output + idx, contentInfoSeq, contentInfoSeqSz);
+    idx += contentInfoSeqSz;
+    XMEMCPY(output + idx, outerContentType, outerContentTypeSz);
+    idx += outerContentTypeSz;
+    XMEMCPY(output + idx, outerContent, outerContentSz);
+    idx += outerContentSz;
+    XMEMCPY(output + idx, envDataSeq, envDataSeqSz);
+    idx += envDataSeqSz;
+    XMEMCPY(output + idx, ver, verSz);
+    idx += verSz;
+    XMEMCPY(output + idx, recipSet, recipSetSz);
+    idx += recipSetSz;
+    XMEMCPY(output + idx, recip, recipSz);
+    idx += recipSz;
+    XMEMCPY(output + idx, encContentSeq, encContentSeqSz);
+    idx += encContentSeqSz;
+    XMEMCPY(output + idx, contentType, contentTypeSz);
+    idx += contentTypeSz;
+    XMEMCPY(output + idx, contentEncAlgo, contentEncAlgoSz);
+    idx += contentEncAlgoSz;
+    XMEMCPY(output + idx, ivOctetString, ivOctetStringSz);
+    idx += ivOctetStringSz;
+    XMEMCPY(output + idx, tmpIv, DES_BLOCK_SIZE);
+    idx += DES_BLOCK_SIZE;
+    XMEMCPY(output + idx, encContentOctet, encContentOctetSz);
+    idx += encContentOctetSz;
+    XMEMCPY(output + idx, encryptedContent, desOutSz);
+    idx += desOutSz;
+
+    ForceZero(contentKeyPlain, MAX_CONTENT_KEY_LEN);
+
+    if (dynamicFlag)
+        XFREE(plain, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+    XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return idx;
+}
+
+/* unwrap and decrypt PKCS#7 envelopedData object, return decoded size */
+WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg,
+                                         word32 pkiMsgSz, byte* output,
+                                         word32 outputSz)
+{
+    int recipFound = 0;
+    int ret, version, length;
+    word32 savedIdx = 0, idx = 0;
+    word32 contentType, encOID;
+    byte   issuerHash[SHA_DIGEST_SIZE];
+
+    int encryptedKeySz, keySz;
+    byte tmpIv[DES_BLOCK_SIZE];
+    byte* decryptedKey = NULL;
+
+#ifdef WOLFSSL_SMALL_STACK
+    mp_int* serialNum;
+    byte* encryptedKey;
+    RsaKey* privKey;
+#else
+    mp_int stack_serialNum;
+    mp_int* serialNum = &stack_serialNum;
+    byte encryptedKey[MAX_ENCRYPTED_KEY_SZ];
+    
+    RsaKey stack_privKey;
+    RsaKey* privKey = &stack_privKey;
+#endif
+    int encryptedContentSz;
+    byte padLen;
+    byte* encryptedContent = NULL;
+
+    if (pkcs7 == NULL || pkcs7->singleCert == NULL ||
+        pkcs7->singleCertSz == 0 || pkcs7->privateKey == NULL ||
+        pkcs7->privateKeySz == 0)
+        return BAD_FUNC_ARG;
+
+    if (pkiMsg == NULL || pkiMsgSz == 0 ||
+        output == NULL || outputSz == 0)
+        return BAD_FUNC_ARG;
+
+    /* read past ContentInfo, verify type is envelopedData */
+    if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (contentType != ENVELOPED_DATA) {
+        WOLFSSL_MSG("PKCS#7 input not of type EnvelopedData");
+        return PKCS7_OID_E;
+    }
+
+    if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
+        return ASN_PARSE_E;
+
+    if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    /* remove EnvelopedData and version */
+    if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetMyVersion(pkiMsg, &idx, &version) < 0)
+        return ASN_PARSE_E;
+
+    if (version != 0) {
+        WOLFSSL_MSG("PKCS#7 envelopedData needs to be of version 0");
+        return ASN_VERSION_E;
+    }
+
+    /* walk through RecipientInfo set, find correct recipient */
+    if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+    
+#ifdef WOLFSSL_SMALL_STACK
+    encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (encryptedKey == NULL)
+        return MEMORY_E;
+#endif
+    
+    savedIdx = idx;
+    recipFound = 0;
+
+    /* when looking for next recipient, use first sequence and version to
+     * indicate there is another, if not, move on */
+    while(recipFound == 0) {
+
+        /* remove RecipientInfo, if we don't have a SEQUENCE, back up idx to
+         * last good saved one */
+        if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) {
+            idx = savedIdx;
+            break;
+        }
+
+        if (GetMyVersion(pkiMsg, &idx, &version) < 0) {
+            idx = savedIdx;
+            break;
+        }
+
+        if (version != 0) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ASN_VERSION_E;
+        }
+        
+        /* remove IssuerAndSerialNumber */
+        if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ASN_PARSE_E;
+        }
+        
+        if (GetNameHash(pkiMsg, &idx, issuerHash, pkiMsgSz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ASN_PARSE_E;
+        }
+        
+        /* if we found correct recipient, issuer hashes will match */
+        if (XMEMCMP(issuerHash, pkcs7->issuerHash, SHA_DIGEST_SIZE) == 0) {
+            recipFound = 1;
+        }
+        
+#ifdef WOLFSSL_SMALL_STACK
+        serialNum = (mp_int*)XMALLOC(sizeof(mp_int), NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+        if (serialNum == NULL) {
+            XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            return MEMORY_E;
+        }
+#endif
+        
+        if (GetInt(serialNum, pkiMsg, &idx, pkiMsgSz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(serialNum,    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ASN_PARSE_E;
+        }
+        
+        mp_clear(serialNum);
+        
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(serialNum, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        
+        if (GetAlgoId(pkiMsg, &idx, &encOID, pkiMsgSz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ASN_PARSE_E;
+        }
+        
+        /* key encryption algorithm must be RSA for now */
+        if (encOID != RSAk) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ALGO_ID_E;
+        }
+        
+        /* read encryptedKey */
+        if (pkiMsg[idx++] != ASN_OCTET_STRING) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ASN_PARSE_E;
+        }
+        
+        if (GetLength(pkiMsg, &idx, &encryptedKeySz, pkiMsgSz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ASN_PARSE_E;
+        }
+          
+        if (recipFound == 1)
+            XMEMCPY(encryptedKey, &pkiMsg[idx], encryptedKeySz);
+        idx += encryptedKeySz;
+
+        /* update good idx */
+        savedIdx = idx;
+    }
+
+    if (recipFound == 0) {
+        WOLFSSL_MSG("No recipient found in envelopedData that matches input");
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return PKCS7_RECIP_E;
+    }
+
+    /* remove EncryptedContentInfo */
+    if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_PARSE_E;
+    }
+    
+    if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_PARSE_E;
+    }
+
+    if (GetAlgoId(pkiMsg, &idx, &encOID, pkiMsgSz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_PARSE_E;
+    }
+    
+    /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */
+    if (pkiMsg[idx++] != ASN_OCTET_STRING) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_PARSE_E;
+    }
+    
+    if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_PARSE_E;
+    }
+    
+    if (length != DES_BLOCK_SIZE) {
+        WOLFSSL_MSG("Incorrect IV length, must be of DES_BLOCK_SIZE");
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_PARSE_E;
+    }
+
+    XMEMCPY(tmpIv, &pkiMsg[idx], length);
+    idx += length;
+
+    /* read encryptedContent, cont[0] */
+    if (pkiMsg[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_PARSE_E;
+    }
+
+    if (GetLength(pkiMsg, &idx, &encryptedContentSz, pkiMsgSz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_PARSE_E;
+    }
+    
+    encryptedContent = (byte*)XMALLOC(encryptedContentSz, NULL,
+                                                       DYNAMIC_TYPE_TMP_BUFFER);
+    if (encryptedContent == NULL) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return MEMORY_E;
+    }
+
+    XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz);
+
+    /* load private key */
+#ifdef WOLFSSL_SMALL_STACK
+    privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (privKey == NULL) {
+        XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(encryptedKey,     NULL, DYNAMIC_TYPE_TMP_BUFFER);        return MEMORY_E;
+    }
+#endif
+
+    ret = wc_InitRsaKey(privKey, 0);
+    if (ret != 0) {
+        XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(privKey,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ret;
+    }
+
+    idx = 0;
+
+    ret = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &idx, privKey,
+                              pkcs7->privateKeySz);
+    if (ret != 0) {
+        WOLFSSL_MSG("Failed to decode RSA private key");
+        XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(privKey,      NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ret;
+    }
+
+    /* decrypt encryptedKey */
+    keySz = wc_RsaPrivateDecryptInline(encryptedKey, encryptedKeySz,
+                                    &decryptedKey, privKey);
+    wc_FreeRsaKey(privKey);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    if (keySz <= 0) {
+        XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return keySz;
+    }
+
+    /* decrypt encryptedContent */
+    if (encOID == DESb) {
+        Des des;
+        ret = wc_Des_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION);
+
+        if (ret == 0)
+            wc_Des_CbcDecrypt(&des, encryptedContent, encryptedContent,
+                                 encryptedContentSz);
+
+        if (ret != 0) {
+            XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ret;
+        }
+    }
+    else if (encOID == DES3b) {
+        Des3 des;
+        ret = wc_Des3_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION);
+        if (ret == 0)
+            ret = wc_Des3_CbcDecrypt(&des, encryptedContent, encryptedContent,
+                                  encryptedContentSz);
+
+        if (ret != 0) {
+            XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ret;
+        }
+    } else {
+        WOLFSSL_MSG("Unsupported content encryption OID type");
+        XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ALGO_ID_E;
+    }
+
+    padLen = encryptedContent[encryptedContentSz-1];
+
+    /* copy plaintext to output */
+    XMEMCPY(output, encryptedContent, encryptedContentSz - padLen);
+
+    /* free memory, zero out keys */
+    ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ);
+    ForceZero(encryptedContent, encryptedContentSz);
+    XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+    
+    return encryptedContentSz - padLen;
+}
+
+
+#else  /* HAVE_PKCS7 */
+
+
+#ifdef _MSC_VER
+    /* 4206 warning for blank file */
+    #pragma warning(disable: 4206)
+#endif
+
+
+#endif /* HAVE_PKCS7 */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/poly1305.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,555 @@
+/* poly1305.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ *
+ * Based off the public domain implementations by Andrew Moon 
+ * and Daniel J. Bernstein
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_POLY1305
+#include <wolfssl/wolfcrypt/poly1305.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/logging.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+#ifdef CHACHA_AEAD_TEST
+    #include <stdio.h>
+#endif
+
+#ifdef _MSC_VER
+    /* 4127 warning constant while(1)  */
+    #pragma warning(disable: 4127)
+#endif
+
+#if defined(POLY130564)
+	
+	#if defined(_MSC_VER)
+		#define POLY1305_NOINLINE __declspec(noinline)
+	#elif defined(__GNUC__)
+		#define POLY1305_NOINLINE __attribute__((noinline))
+	#else
+		#define POLY1305_NOINLINE
+	#endif
+	
+	#if defined(_MSC_VER)
+	    #include <intrin.h>
+		
+	    typedef struct word128 {
+			word64 lo;
+			word64 hi;
+		} word128;
+	
+		#define MUL(out, x, y) out.lo = _umul128((x), (y), &out.hi)
+		#define ADD(out, in) { word64 t = out.lo; out.lo += in.lo;
+	                           out.hi += (out.lo < t) + in.hi; }
+		#define ADDLO(out, in) { word64 t = out.lo; out.lo += in;
+	                             out.hi += (out.lo < t); }
+		#define SHR(in, shift) (__shiftright128(in.lo, in.hi, (shift)))
+		#define LO(in) (in.lo)
+	
+	#elif defined(__GNUC__)
+		#if defined(__SIZEOF_INT128__)
+			typedef unsigned __int128 word128;
+		#else
+			typedef unsigned word128 __attribute__((mode(TI)));
+		#endif
+	
+		#define MUL(out, x, y) out = ((word128)x * y)
+		#define ADD(out, in) out += in
+		#define ADDLO(out, in) out += in
+		#define SHR(in, shift) (word64)(in >> (shift))
+		#define LO(in) (word64)(in)
+	#endif
+	
+	static word64 U8TO64(const byte* p) {
+		return
+			(((word64)(p[0] & 0xff)      ) |
+		     ((word64)(p[1] & 0xff) <<  8) |
+	         ((word64)(p[2] & 0xff) << 16) |
+	         ((word64)(p[3] & 0xff) << 24) |
+			 ((word64)(p[4] & 0xff) << 32) |
+			 ((word64)(p[5] & 0xff) << 40) |
+			 ((word64)(p[6] & 0xff) << 48) |
+			 ((word64)(p[7] & 0xff) << 56));
+	}
+	
+	static void U64TO8(byte* p, word64 v) {
+		p[0] = (v      ) & 0xff;
+		p[1] = (v >>  8) & 0xff;
+		p[2] = (v >> 16) & 0xff;
+		p[3] = (v >> 24) & 0xff;
+		p[4] = (v >> 32) & 0xff;
+		p[5] = (v >> 40) & 0xff;
+		p[6] = (v >> 48) & 0xff;
+		p[7] = (v >> 56) & 0xff;
+	}
+
+#else /* if not 64 bit then use 32 bit */
+	
+	static word32 U8TO32(const byte *p) {
+		return
+			(((word32)(p[0] & 0xff)      ) |
+		     ((word32)(p[1] & 0xff) <<  8) |
+	         ((word32)(p[2] & 0xff) << 16) |
+	         ((word32)(p[3] & 0xff) << 24));
+	}
+	
+	static void U32TO8(byte *p, word32 v) {
+		p[0] = (v      ) & 0xff;
+		p[1] = (v >>  8) & 0xff;
+		p[2] = (v >> 16) & 0xff;
+		p[3] = (v >> 24) & 0xff;
+	}
+#endif
+
+static void poly1305_blocks(Poly1305* ctx, const unsigned char *m,
+                            size_t bytes) {
+
+#ifdef POLY130564
+
+	const word64 hibit = (ctx->final) ? 0 : ((word64)1 << 40); /* 1 << 128 */
+	word64 r0,r1,r2;
+	word64 s1,s2;
+	word64 h0,h1,h2;
+	word64 c;
+	word128 d0,d1,d2,d;
+
+#else
+
+    const word32 hibit = (ctx->final) ? 0 : (1 << 24); /* 1 << 128 */
+	word32 r0,r1,r2,r3,r4;
+	word32 s1,s2,s3,s4;
+	word32 h0,h1,h2,h3,h4;
+	word64 d0,d1,d2,d3,d4;
+	word32 c;
+
+#endif
+
+#ifdef POLY130564
+
+    r0 = ctx->r[0];
+	r1 = ctx->r[1];
+	r2 = ctx->r[2];
+
+	h0 = ctx->h[0];
+	h1 = ctx->h[1];
+	h2 = ctx->h[2];
+
+	s1 = r1 * (5 << 2);
+	s2 = r2 * (5 << 2);
+
+	while (bytes >= POLY1305_BLOCK_SIZE) {
+		word64 t0,t1;
+
+		/* h += m[i] */
+		t0 = U8TO64(&m[0]);
+		t1 = U8TO64(&m[8]);
+
+		h0 += (( t0                    ) & 0xfffffffffff);
+		h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
+		h2 += (((t1 >> 24)             ) & 0x3ffffffffff) | hibit;
+
+		/* h *= r */
+		MUL(d0, h0, r0); MUL(d, h1, s2); ADD(d0, d); MUL(d, h2, s1); ADD(d0, d);
+		MUL(d1, h0, r1); MUL(d, h1, r0); ADD(d1, d); MUL(d, h2, s2); ADD(d1, d);
+		MUL(d2, h0, r2); MUL(d, h1, r1); ADD(d2, d); MUL(d, h2, r0); ADD(d2, d);
+
+		/* (partial) h %= p */
+		              c = SHR(d0, 44); h0 = LO(d0) & 0xfffffffffff;
+		ADDLO(d1, c); c = SHR(d1, 44); h1 = LO(d1) & 0xfffffffffff;
+		ADDLO(d2, c); c = SHR(d2, 42); h2 = LO(d2) & 0x3ffffffffff;
+		h0  += c * 5; c = (h0 >> 44);  h0 =    h0  & 0xfffffffffff;
+		h1  += c;
+
+		m += POLY1305_BLOCK_SIZE;
+		bytes -= POLY1305_BLOCK_SIZE;
+	}
+
+	ctx->h[0] = h0;
+	ctx->h[1] = h1;
+	ctx->h[2] = h2;
+
+#else /* if not 64 bit then use 32 bit */
+   
+	r0 = ctx->r[0];
+	r1 = ctx->r[1];
+	r2 = ctx->r[2];
+	r3 = ctx->r[3];
+	r4 = ctx->r[4];
+
+	s1 = r1 * 5;
+	s2 = r2 * 5;
+	s3 = r3 * 5;
+	s4 = r4 * 5;
+
+	h0 = ctx->h[0];
+	h1 = ctx->h[1];
+	h2 = ctx->h[2];
+	h3 = ctx->h[3];
+	h4 = ctx->h[4];
+
+	while (bytes >= POLY1305_BLOCK_SIZE) {
+		/* h += m[i] */
+		h0 += (U8TO32(m+ 0)     ) & 0x3ffffff;
+		h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff;
+		h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff;
+		h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff;
+		h4 += (U8TO32(m+12) >> 8) | hibit;
+
+		/* h *= r */
+		d0 = ((word64)h0 * r0) + ((word64)h1 * s4) + ((word64)h2 * s3) +
+             ((word64)h3 * s2) + ((word64)h4 * s1);
+		d1 = ((word64)h0 * r1) + ((word64)h1 * r0) + ((word64)h2 * s4) +
+             ((word64)h3 * s3) + ((word64)h4 * s2);
+		d2 = ((word64)h0 * r2) + ((word64)h1 * r1) + ((word64)h2 * r0) +
+             ((word64)h3 * s4) + ((word64)h4 * s3);
+		d3 = ((word64)h0 * r3) + ((word64)h1 * r2) + ((word64)h2 * r1) +
+             ((word64)h3 * r0) + ((word64)h4 * s4);
+		d4 = ((word64)h0 * r4) + ((word64)h1 * r3) + ((word64)h2 * r2) +
+             ((word64)h3 * r1) + ((word64)h4 * r0);
+
+		/* (partial) h %= p */
+		              c = (word32)(d0 >> 26); h0 = (word32)d0 & 0x3ffffff;
+		d1 += c;      c = (word32)(d1 >> 26); h1 = (word32)d1 & 0x3ffffff;
+		d2 += c;      c = (word32)(d2 >> 26); h2 = (word32)d2 & 0x3ffffff;
+		d3 += c;      c = (word32)(d3 >> 26); h3 = (word32)d3 & 0x3ffffff;
+		d4 += c;      c = (word32)(d4 >> 26); h4 = (word32)d4 & 0x3ffffff;
+		h0 += c * 5;  c =  (h0 >> 26); h0 =                h0 & 0x3ffffff;
+		h1 += c;
+
+		m += POLY1305_BLOCK_SIZE;
+		bytes -= POLY1305_BLOCK_SIZE;
+	}
+
+	ctx->h[0] = h0;
+	ctx->h[1] = h1;
+	ctx->h[2] = h2;
+	ctx->h[3] = h3;
+	ctx->h[4] = h4;
+
+#endif /* end of 64 bit cpu blocks or 32 bit cpu */
+}
+
+
+int wc_Poly1305SetKey(Poly1305* ctx, const byte* key, word32 keySz) {
+
+#if defined(POLY130564)
+    word64 t0,t1;
+#endif
+
+#ifdef CHACHA_AEAD_TEST
+    word32 k;
+    printf("Poly key used:\n");
+    for (k = 0; k < keySz; k++) {
+        printf("%02x", key[k]);
+        if ((k+1) % 8 == 0)
+            printf("\n");
+    }
+	printf("\n");
+#endif
+
+    if (keySz != 32 || ctx == NULL)
+        return BAD_FUNC_ARG;
+
+#if defined(POLY130564)
+
+	/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+	t0 = U8TO64(key + 0);
+	t1 = U8TO64(key + 8);
+
+	ctx->r[0] = ( t0                    ) & 0xffc0fffffff;
+	ctx->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
+	ctx->r[2] = ((t1 >> 24)             ) & 0x00ffffffc0f;
+
+	/* h (accumulator) = 0 */
+	ctx->h[0] = 0;
+	ctx->h[1] = 0;
+	ctx->h[2] = 0;
+
+	/* save pad for later */
+	ctx->pad[0] = U8TO64(key + 16);
+	ctx->pad[1] = U8TO64(key + 24);
+
+#else /* if not 64 bit then use 32 bit */
+	
+    /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+	ctx->r[0] = (U8TO32(key +  0)     ) & 0x3ffffff;
+	ctx->r[1] = (U8TO32(key +  3) >> 2) & 0x3ffff03;
+	ctx->r[2] = (U8TO32(key +  6) >> 4) & 0x3ffc0ff;
+	ctx->r[3] = (U8TO32(key +  9) >> 6) & 0x3f03fff;
+	ctx->r[4] = (U8TO32(key + 12) >> 8) & 0x00fffff;
+
+	/* h = 0 */
+	ctx->h[0] = 0;
+	ctx->h[1] = 0;
+	ctx->h[2] = 0;
+	ctx->h[3] = 0;
+	ctx->h[4] = 0;
+
+	/* save pad for later */
+	ctx->pad[0] = U8TO32(key + 16);
+	ctx->pad[1] = U8TO32(key + 20);
+	ctx->pad[2] = U8TO32(key + 24);
+	ctx->pad[3] = U8TO32(key + 28);
+
+#endif
+
+	ctx->leftover = 0;
+	ctx->final = 0;
+
+    return 0;
+}
+
+
+int wc_Poly1305Final(Poly1305* ctx, byte* mac) {
+
+#if defined(POLY130564)
+
+    word64 h0,h1,h2,c;
+	word64 g0,g1,g2;
+	word64 t0,t1;
+
+#else
+
+    word32 h0,h1,h2,h3,h4,c;
+	word32 g0,g1,g2,g3,g4;
+	word64 f;
+	word32 mask;
+
+#endif
+
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+#if defined(POLY130564)
+
+	/* process the remaining block */
+	if (ctx->leftover) {
+		size_t i = ctx->leftover;
+		ctx->buffer[i] = 1;
+		for (i = i + 1; i < POLY1305_BLOCK_SIZE; i++)
+			ctx->buffer[i] = 0;
+		ctx->final = 1;
+		poly1305_blocks(ctx, ctx->buffer, POLY1305_BLOCK_SIZE);
+	}
+
+	/* fully carry h */
+	h0 = ctx->h[0];
+	h1 = ctx->h[1];
+	h2 = ctx->h[2];
+
+	             c = (h1 >> 44); h1 &= 0xfffffffffff;
+	h2 += c;     c = (h2 >> 42); h2 &= 0x3ffffffffff;
+	h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
+	h1 += c;	 c = (h1 >> 44); h1 &= 0xfffffffffff;
+	h2 += c;     c = (h2 >> 42); h2 &= 0x3ffffffffff;
+	h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
+	h1 += c;
+
+	/* compute h + -p */
+	g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff;
+	g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff;
+	g2 = h2 + c - ((word64)1 << 42);
+
+	/* select h if h < p, or h + -p if h >= p */
+	c = (g2 >> ((sizeof(word64) * 8) - 1)) - 1;
+	g0 &= c;
+	g1 &= c;
+	g2 &= c;
+	c = ~c;
+	h0 = (h0 & c) | g0;
+	h1 = (h1 & c) | g1;
+	h2 = (h2 & c) | g2;
+
+	/* h = (h + pad) */
+	t0 = ctx->pad[0];
+	t1 = ctx->pad[1];
+
+	h0 += (( t0                    ) & 0xfffffffffff)    ;
+    c = (h0 >> 44); h0 &= 0xfffffffffff;
+	h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c;
+    c = (h1 >> 44); h1 &= 0xfffffffffff;
+	h2 += (((t1 >> 24)             ) & 0x3ffffffffff) + c;
+    h2 &= 0x3ffffffffff;
+
+	/* mac = h % (2^128) */
+	h0 = ((h0      ) | (h1 << 44));
+	h1 = ((h1 >> 20) | (h2 << 24));
+
+	U64TO8(mac + 0, h0);
+	U64TO8(mac + 8, h1);
+
+	/* zero out the state */
+	ctx->h[0] = 0;
+	ctx->h[1] = 0;
+	ctx->h[2] = 0;
+	ctx->r[0] = 0;
+	ctx->r[1] = 0;
+	ctx->r[2] = 0;
+	ctx->pad[0] = 0;
+	ctx->pad[1] = 0;
+
+#else /* if not 64 bit then use 32 bit */
+    
+	/* process the remaining block */
+	if (ctx->leftover) {
+		size_t i = ctx->leftover;
+		ctx->buffer[i++] = 1;
+		for (; i < POLY1305_BLOCK_SIZE; i++)
+			ctx->buffer[i] = 0;
+		ctx->final = 1;
+		poly1305_blocks(ctx, ctx->buffer, POLY1305_BLOCK_SIZE);
+	}
+
+	/* fully carry h */
+	h0 = ctx->h[0];
+	h1 = ctx->h[1];
+	h2 = ctx->h[2];
+	h3 = ctx->h[3];
+	h4 = ctx->h[4];
+
+	             c = h1 >> 26; h1 = h1 & 0x3ffffff;
+	h2 +=     c; c = h2 >> 26; h2 = h2 & 0x3ffffff;
+	h3 +=     c; c = h3 >> 26; h3 = h3 & 0x3ffffff;
+	h4 +=     c; c = h4 >> 26; h4 = h4 & 0x3ffffff;
+	h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff;
+	h1 +=     c;
+
+	/* compute h + -p */
+	g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff;
+	g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff;
+	g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff;
+	g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff;
+	g4 = h4 + c - (1 << 26);
+
+	/* select h if h < p, or h + -p if h >= p */
+	mask = (g4 >> ((sizeof(word32) * 8) - 1)) - 1;
+	g0 &= mask;
+	g1 &= mask;
+	g2 &= mask;
+	g3 &= mask;
+	g4 &= mask;
+	mask = ~mask;
+	h0 = (h0 & mask) | g0;
+	h1 = (h1 & mask) | g1;
+	h2 = (h2 & mask) | g2;
+	h3 = (h3 & mask) | g3;
+	h4 = (h4 & mask) | g4;
+
+	/* h = h % (2^128) */
+	h0 = ((h0      ) | (h1 << 26)) & 0xffffffff;
+	h1 = ((h1 >>  6) | (h2 << 20)) & 0xffffffff;
+	h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
+	h3 = ((h3 >> 18) | (h4 <<  8)) & 0xffffffff;
+
+	/* mac = (h + pad) % (2^128) */
+	f = (word64)h0 + ctx->pad[0]            ; h0 = (word32)f;
+	f = (word64)h1 + ctx->pad[1] + (f >> 32); h1 = (word32)f;
+	f = (word64)h2 + ctx->pad[2] + (f >> 32); h2 = (word32)f;
+	f = (word64)h3 + ctx->pad[3] + (f >> 32); h3 = (word32)f;
+
+	U32TO8(mac + 0, h0);
+	U32TO8(mac + 4, h1);
+	U32TO8(mac + 8, h2);
+	U32TO8(mac + 12, h3);
+
+	/* zero out the state */
+	ctx->h[0] = 0;
+	ctx->h[1] = 0;
+	ctx->h[2] = 0;
+	ctx->h[3] = 0;
+	ctx->h[4] = 0;
+	ctx->r[0] = 0;
+	ctx->r[1] = 0;
+	ctx->r[2] = 0;
+	ctx->r[3] = 0;
+	ctx->r[4] = 0;
+	ctx->pad[0] = 0;
+	ctx->pad[1] = 0;
+	ctx->pad[2] = 0;
+	ctx->pad[3] = 0;
+
+#endif
+
+    return 0;
+}
+
+
+int wc_Poly1305Update(Poly1305* ctx, const byte* m, word32 bytes) {
+
+	size_t i;
+
+#ifdef CHACHA_AEAD_TEST
+    word32 k;
+    printf("Raw input to poly:\n");
+    for (k = 0; k < bytes; k++) {
+        printf("%02x", m[k]);
+        if ((k+1) % 16 == 0)
+            printf("\n");
+    }
+	printf("\n");
+#endif
+    
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+	/* handle leftover */
+	if (ctx->leftover) {
+		size_t want = (POLY1305_BLOCK_SIZE - ctx->leftover);
+		if (want > bytes)
+			want = bytes;
+		for (i = 0; i < want; i++)
+			ctx->buffer[ctx->leftover + i] = m[i];
+		bytes -= want;
+		m += want;
+		ctx->leftover += want;
+		if (ctx->leftover < POLY1305_BLOCK_SIZE)
+			return 0;
+		poly1305_blocks(ctx, ctx->buffer, POLY1305_BLOCK_SIZE);
+		ctx->leftover = 0;
+	}
+
+	/* process full blocks */
+	if (bytes >= POLY1305_BLOCK_SIZE) {
+		size_t want = (bytes & ~(POLY1305_BLOCK_SIZE - 1));
+		poly1305_blocks(ctx, m, want);
+		m += want;
+		bytes -= want;
+	}
+
+	/* store leftover */
+	if (bytes) {
+		for (i = 0; i < bytes; i++)
+			ctx->buffer[ctx->leftover + i] = m[i];
+		ctx->leftover += bytes;
+	}
+    return 0;
+}
+#endif /* HAVE_POLY1305 */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/pwdbased.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,563 @@
+/* pwdbased.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifndef NO_PWDBASED
+
+#ifdef WOLFSSL_PIC32MZ_HASH
+    #ifndef NO_MD5
+        #define wc_InitMd5   wc_InitMd5_sw
+        #define wc_Md5Update wc_Md5Update_sw
+        #define wc_Md5Final  wc_Md5Final_sw
+    #endif /* NO_MD5 */
+
+    #define wc_InitSha   wc_InitSha_sw
+    #define wc_ShaUpdate wc_ShaUpdate_sw
+    #define wc_ShaFinal  wc_ShaFinal_sw
+
+    #define wc_InitSha256   wc_InitSha256_sw
+    #define wc_Sha256Update wc_Sha256Update_sw
+    #define wc_Sha256Final  wc_Sha256Final_sw
+#endif
+
+#include <wolfssl/wolfcrypt/pwdbased.h>
+#include <wolfssl/wolfcrypt/hmac.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
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* WOLFSSL_HAVE_MIN */
+
+
+#ifndef NO_SHA
+/* PBKDF1 needs at least SHA available */
+int wc_PBKDF1(byte* output, const byte* passwd, int pLen, const byte* salt,
+           int sLen, int iterations, int kLen, int hashType)
+{
+    Sha  sha;
+#ifndef NO_MD5
+    Md5  md5;
+#endif
+    int  hLen = (int)SHA_DIGEST_SIZE;
+    int  i, ret = 0;
+    byte buffer[SHA_DIGEST_SIZE];  /* max size */
+
+    if (hashType != MD5 && hashType != SHA)
+        return BAD_FUNC_ARG;
+
+#ifndef NO_MD5
+    if (hashType == MD5)
+        hLen = (int)MD5_DIGEST_SIZE;
+#endif
+
+    if (kLen > hLen)
+        return BAD_FUNC_ARG;
+
+    if (iterations < 1)
+        return BAD_FUNC_ARG;
+
+    switch (hashType) {
+#ifndef NO_MD5
+        case MD5:
+            wc_InitMd5(&md5);
+            wc_Md5Update(&md5, passwd, pLen);
+            wc_Md5Update(&md5, salt,   sLen);
+            wc_Md5Final(&md5,  buffer);
+            break;
+#endif /* NO_MD5 */
+        case 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 == SHA) {
+            wc_ShaUpdate(&sha, buffer, hLen);
+            wc_ShaFinal(&sha,  buffer);
+        }
+#ifndef NO_MD5
+        else {
+            wc_Md5Update(&md5, buffer, hLen);
+            wc_Md5Final(&md5,  buffer);
+        }
+#endif
+    }
+    XMEMCPY(output, buffer, kLen);
+
+    return 0;
+}
+#endif /* NO_SHA */
+
+
+int GetDigestSize(int hashType)
+{
+    int hLen;
+
+    switch (hashType) {
+#ifndef NO_MD5
+        case MD5:
+            hLen = MD5_DIGEST_SIZE;
+            break;
+#endif
+#ifndef NO_SHA
+        case SHA:
+            hLen = SHA_DIGEST_SIZE;
+            break;
+#endif
+#ifndef NO_SHA256
+        case SHA256:
+            hLen = SHA256_DIGEST_SIZE;
+            break;
+#endif
+#ifdef WOLFSSL_SHA512
+        case SHA512:
+            hLen = SHA512_DIGEST_SIZE;
+            break;
+#endif
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    return hLen;
+}
+
+
+int wc_PBKDF2(byte* output, const byte* passwd, int pLen, const byte* salt,
+           int sLen, int iterations, int kLen, int hashType)
+{
+    word32 i = 1;
+    int    hLen;
+    int    j, ret;
+    Hmac   hmac;
+#ifdef WOLFSSL_SMALL_STACK
+    byte*  buffer;
+#else
+    byte   buffer[MAX_DIGEST_SIZE];
+#endif
+
+    hLen = GetDigestSize(hashType);
+    if (hLen < 0)
+        return BAD_FUNC_ARG;
+
+#ifdef WOLFSSL_SMALL_STACK
+    buffer = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (buffer == NULL)
+        return MEMORY_E;
+#endif
+
+    ret = wc_HmacSetKey(&hmac, hashType, passwd, pLen);
+
+    if (ret == 0) {
+        while (kLen) {
+            int currentLen;
+
+            ret = wc_HmacUpdate(&hmac, salt, sLen);
+            if (ret != 0)
+                break;
+
+            /* encode i */
+            for (j = 0; j < 4; j++) {
+                byte b = (byte)(i >> ((3-j) * 8));
+
+                ret = wc_HmacUpdate(&hmac, &b, 1);
+                if (ret != 0)
+                    break;
+            }
+
+            /* check ret from inside for loop */
+            if (ret != 0)
+                break;
+
+            ret = wc_HmacFinal(&hmac, buffer);
+            if (ret != 0)
+                break;
+
+            currentLen = min(kLen, hLen);
+            XMEMCPY(output, buffer, currentLen);
+
+            for (j = 1; j < iterations; j++) {
+                ret = wc_HmacUpdate(&hmac, buffer, hLen);
+                if (ret != 0)
+                    break;
+                ret = wc_HmacFinal(&hmac, buffer);
+                if (ret != 0)
+                    break;
+                xorbuf(output, buffer, currentLen);
+            }
+
+            /* check ret from inside for loop */
+            if (ret != 0)
+                break;
+
+            output += currentLen;
+            kLen   -= currentLen;
+            i++;
+        }
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+#ifdef WOLFSSL_SHA512
+    #define PBKDF_DIGEST_SIZE SHA512_BLOCK_SIZE
+#elif !defined(NO_SHA256)
+    #define PBKDF_DIGEST_SIZE SHA256_BLOCK_SIZE
+#else
+    #define PBKDF_DIGEST_SIZE 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 MD5:
+            *v = MD5_BLOCK_SIZE;
+            *u = MD5_DIGEST_SIZE;
+            break;
+#endif
+#ifndef NO_SHA
+        case SHA:
+            *v = SHA_BLOCK_SIZE;
+            *u = SHA_DIGEST_SIZE;
+            break;
+#endif
+#ifndef NO_SHA256
+        case SHA256:
+            *v = SHA256_BLOCK_SIZE;
+            *u = SHA256_DIGEST_SIZE;
+            break;
+#endif
+#ifdef WOLFSSL_SHA512
+        case SHA512:
+            *v = SHA512_BLOCK_SIZE;
+            *u = 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,
+                 byte* Ai, word32 u, int iterations)
+{
+    int i;
+    int ret = 0;
+
+    if (buffer == NULL || Ai == NULL)
+        return BAD_FUNC_ARG;
+
+    switch (hashType) {
+#ifndef NO_MD5
+        case MD5:
+            {
+                Md5 md5;
+                wc_InitMd5(&md5);
+                wc_Md5Update(&md5, buffer, totalLen);
+                wc_Md5Final(&md5, Ai);
+
+                for (i = 1; i < iterations; i++) {
+                    wc_Md5Update(&md5, Ai, u);
+                    wc_Md5Final(&md5, Ai);
+                }
+            }
+            break;
+#endif /* NO_MD5 */
+#ifndef NO_SHA
+        case SHA:
+            {
+                Sha sha;
+                ret = wc_InitSha(&sha);
+                if (ret != 0)
+                    break;
+                wc_ShaUpdate(&sha, buffer, totalLen);
+                wc_ShaFinal(&sha, Ai);
+
+                for (i = 1; i < iterations; i++) {
+                    wc_ShaUpdate(&sha, Ai, u);
+                    wc_ShaFinal(&sha, Ai);
+                }
+            }
+            break;
+#endif /* NO_SHA */
+#ifndef NO_SHA256
+        case SHA256:
+            {
+                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 SHA512:
+            {
+                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;
+    }
+
+    return ret;
+}
+
+int wc_PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,const byte* salt,
+                 int saltLen, int iterations, int kLen, int hashType, int id)
+{
+    /* all in bytes instead of bits */
+    word32 u, v, dLen, pLen, iLen, sLen, totalLen;
+    int    dynamic = 0;
+    int    ret = 0;
+    int    i;
+    byte   *D, *S, *P, *I;
+#ifdef WOLFSSL_SMALL_STACK
+    byte   staticBuffer[1]; /* force dynamic usage */
+#else
+    byte   staticBuffer[1024];
+#endif
+    byte*  buffer = staticBuffer;
+
+#ifdef WOLFSSL_SMALL_STACK
+    byte*  Ai;
+    byte*  B;
+#else
+    byte   Ai[PBKDF_DIGEST_SIZE];
+    byte   B[PBKDF_DIGEST_SIZE];
+#endif
+
+    if (!iterations)
+        iterations = 1;
+
+    ret = GetPKCS12HashSizes(hashType, &v, &u);
+    if (ret < 0)
+        return BAD_FUNC_ARG;
+
+#ifdef WOLFSSL_SMALL_STACK
+    Ai = (byte*)XMALLOC(PBKDF_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (Ai == NULL)
+        return MEMORY_E;
+
+    B = (byte*)XMALLOC(PBKDF_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (B == NULL) {
+        XFREE(Ai, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    XMEMSET(Ai, 0, PBKDF_DIGEST_SIZE);
+    XMEMSET(B,  0, PBKDF_DIGEST_SIZE);
+
+    dLen = v;
+    sLen =  v * ((saltLen + v - 1) / v);
+    if (passLen)
+        pLen = v * ((passLen + v - 1) / v);
+    else
+        pLen = 0;
+    iLen = sLen + pLen;
+
+    totalLen = dLen + sLen + pLen;
+
+    if (totalLen > sizeof(staticBuffer)) {
+        buffer = (byte*)XMALLOC(totalLen, 0, DYNAMIC_TYPE_KEY);
+        if (buffer == NULL) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(Ai, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(B,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return MEMORY_E;
+        }
+        dynamic = 1;
+    }
+
+    D = buffer;
+    S = D + dLen;
+    P = S + sLen;
+    I = S;
+
+    XMEMSET(D, id, dLen);
+
+    for (i = 0; i < (int)sLen; i++)
+        S[i] = salt[i % saltLen];
+    for (i = 0; i < (int)pLen; i++)
+        P[i] = passwd[i % passLen];
+
+    while (kLen > 0) {
+        word32 currentLen;
+        mp_int B1;
+
+        ret = DoPKCS12Hash(hashType, buffer, totalLen, Ai, u, iterations);
+        if (ret < 0)
+            break;
+
+        for (i = 0; i < (int)v; i++)
+            B[i] = Ai[i % u];
+
+        if (mp_init(&B1) != MP_OKAY)
+            ret = MP_INIT_E;
+        else if (mp_read_unsigned_bin(&B1, B, v) != MP_OKAY)
+            ret = MP_READ_E;
+        else if (mp_add_d(&B1, (mp_digit)1, &B1) != MP_OKAY)
+            ret = MP_ADD_E;
+
+        if (ret != 0) {
+            mp_clear(&B1);
+            break;
+        }
+
+        for (i = 0; i < (int)iLen; i += v) {
+            int    outSz;
+            mp_int i1;
+            mp_int res;
+
+            if (mp_init_multi(&i1, &res, NULL, NULL, NULL, NULL) != MP_OKAY) {
+                ret = MP_INIT_E;
+                break;
+            }
+            if (mp_read_unsigned_bin(&i1, I + i, v) != MP_OKAY)
+                ret = MP_READ_E;
+            else if (mp_add(&i1, &B1, &res) != MP_OKAY)
+                ret = MP_ADD_E;
+            else if ( (outSz = mp_unsigned_bin_size(&res)) < 0)
+                ret = MP_TO_E;
+            else {
+                if (outSz > (int)v) {
+                    /* take off MSB */
+                    byte  tmp[129];
+                    ret = mp_to_unsigned_bin(&res, tmp);
+                    XMEMCPY(I + i, tmp + 1, v);
+                }
+                else if (outSz < (int)v) {
+                    XMEMSET(I + i, 0, v - outSz);
+                    ret = mp_to_unsigned_bin(&res, I + i + v - outSz);
+                }
+                else
+                    ret = mp_to_unsigned_bin(&res, I + i);
+            }
+
+            mp_clear(&i1);
+            mp_clear(&res);
+            if (ret < 0) break;
+        }
+
+        currentLen = min(kLen, (int)u);
+        XMEMCPY(output, Ai, currentLen);
+        output += currentLen;
+        kLen   -= currentLen;
+        mp_clear(&B1);
+    }
+
+    if (dynamic) XFREE(buffer, 0, DYNAMIC_TYPE_KEY);
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(Ai, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(B,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+#undef PBKDF_DIGEST_SIZE
+
+#endif /* NO_PWDBASED */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/rabbit.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,311 @@
+/* rabbit.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifndef NO_RABBIT
+
+#include <wolfssl/wolfcrypt/rabbit.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/logging.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+
+#ifdef BIG_ENDIAN_ORDER
+    #define LITTLE32(x) ByteReverseWord32(x)
+#else
+    #define LITTLE32(x) (x)
+#endif
+
+#define U32V(x) ((word32)(x) & 0xFFFFFFFFU)
+
+
+/* Square a 32-bit unsigned integer to obtain the 64-bit result and return */
+/* the upper 32 bits XOR the lower 32 bits */
+static word32 RABBIT_g_func(word32 x)
+{
+    /* Temporary variables */
+    word32 a, b, h, l;
+
+    /* Construct high and low argument for squaring */
+    a = x&0xFFFF;
+    b = x>>16;
+
+    /* Calculate high and low result of squaring */
+    h = (((U32V(a*a)>>17) + U32V(a*b))>>15) + b*b;
+    l = x*x;
+
+    /* Return high XOR low */
+    return U32V(h^l);
+}
+
+
+/* Calculate the next internal state */
+static void RABBIT_next_state(RabbitCtx* ctx)
+{
+    /* Temporary variables */
+    word32 g[8], c_old[8], i;
+
+    /* Save old counter values */
+    for (i=0; i<8; i++)
+        c_old[i] = ctx->c[i];
+
+    /* Calculate new counter values */
+    ctx->c[0] = U32V(ctx->c[0] + 0x4D34D34D + ctx->carry);
+    ctx->c[1] = U32V(ctx->c[1] + 0xD34D34D3 + (ctx->c[0] < c_old[0]));
+    ctx->c[2] = U32V(ctx->c[2] + 0x34D34D34 + (ctx->c[1] < c_old[1]));
+    ctx->c[3] = U32V(ctx->c[3] + 0x4D34D34D + (ctx->c[2] < c_old[2]));
+    ctx->c[4] = U32V(ctx->c[4] + 0xD34D34D3 + (ctx->c[3] < c_old[3]));
+    ctx->c[5] = U32V(ctx->c[5] + 0x34D34D34 + (ctx->c[4] < c_old[4]));
+    ctx->c[6] = U32V(ctx->c[6] + 0x4D34D34D + (ctx->c[5] < c_old[5]));
+    ctx->c[7] = U32V(ctx->c[7] + 0xD34D34D3 + (ctx->c[6] < c_old[6]));
+    ctx->carry = (ctx->c[7] < c_old[7]);
+   
+    /* Calculate the g-values */
+    for (i=0;i<8;i++)
+        g[i] = RABBIT_g_func(U32V(ctx->x[i] + ctx->c[i]));
+
+    /* Calculate new state values */
+    ctx->x[0] = U32V(g[0] + rotlFixed(g[7],16) + rotlFixed(g[6], 16));
+    ctx->x[1] = U32V(g[1] + rotlFixed(g[0], 8) + g[7]);
+    ctx->x[2] = U32V(g[2] + rotlFixed(g[1],16) + rotlFixed(g[0], 16));
+    ctx->x[3] = U32V(g[3] + rotlFixed(g[2], 8) + g[1]);
+    ctx->x[4] = U32V(g[4] + rotlFixed(g[3],16) + rotlFixed(g[2], 16));
+    ctx->x[5] = U32V(g[5] + rotlFixed(g[4], 8) + g[3]);
+    ctx->x[6] = U32V(g[6] + rotlFixed(g[5],16) + rotlFixed(g[4], 16));
+    ctx->x[7] = U32V(g[7] + rotlFixed(g[6], 8) + g[5]);
+}
+
+
+/* IV setup */
+static void wc_RabbitSetIV(Rabbit* ctx, const byte* inIv)
+{
+    /* Temporary variables */
+    word32 i0, i1, i2, i3, i;
+    word32 iv[2];
+
+    if (inIv)
+        XMEMCPY(iv, inIv, sizeof(iv));
+    else
+        XMEMSET(iv,    0, sizeof(iv));
+      
+    /* Generate four subvectors */
+    i0 = LITTLE32(iv[0]);
+    i2 = LITTLE32(iv[1]);
+    i1 = (i0>>16) | (i2&0xFFFF0000);
+    i3 = (i2<<16) | (i0&0x0000FFFF);
+
+    /* Modify counter values */
+    ctx->workCtx.c[0] = ctx->masterCtx.c[0] ^ i0;
+    ctx->workCtx.c[1] = ctx->masterCtx.c[1] ^ i1;
+    ctx->workCtx.c[2] = ctx->masterCtx.c[2] ^ i2;
+    ctx->workCtx.c[3] = ctx->masterCtx.c[3] ^ i3;
+    ctx->workCtx.c[4] = ctx->masterCtx.c[4] ^ i0;
+    ctx->workCtx.c[5] = ctx->masterCtx.c[5] ^ i1;
+    ctx->workCtx.c[6] = ctx->masterCtx.c[6] ^ i2;
+    ctx->workCtx.c[7] = ctx->masterCtx.c[7] ^ i3;
+
+    /* Copy state variables */
+    for (i=0; i<8; i++)
+        ctx->workCtx.x[i] = ctx->masterCtx.x[i];
+    ctx->workCtx.carry = ctx->masterCtx.carry;
+
+    /* Iterate the system four times */
+    for (i=0; i<4; i++)
+        RABBIT_next_state(&(ctx->workCtx));
+}
+
+
+/* Key setup */
+static INLINE int DoKey(Rabbit* ctx, const byte* key, const byte* iv)
+{
+    /* Temporary variables */
+    word32 k0, k1, k2, k3, i;
+
+    /* Generate four subkeys */
+    k0 = LITTLE32(*(word32*)(key+ 0));
+    k1 = LITTLE32(*(word32*)(key+ 4));
+    k2 = LITTLE32(*(word32*)(key+ 8));
+    k3 = LITTLE32(*(word32*)(key+12));
+
+    /* Generate initial state variables */
+    ctx->masterCtx.x[0] = k0;
+    ctx->masterCtx.x[2] = k1;
+    ctx->masterCtx.x[4] = k2;
+    ctx->masterCtx.x[6] = k3;
+    ctx->masterCtx.x[1] = U32V(k3<<16) | (k2>>16);
+    ctx->masterCtx.x[3] = U32V(k0<<16) | (k3>>16);
+    ctx->masterCtx.x[5] = U32V(k1<<16) | (k0>>16);
+    ctx->masterCtx.x[7] = U32V(k2<<16) | (k1>>16);
+
+    /* Generate initial counter values */
+    ctx->masterCtx.c[0] = rotlFixed(k2, 16);
+    ctx->masterCtx.c[2] = rotlFixed(k3, 16);
+    ctx->masterCtx.c[4] = rotlFixed(k0, 16);
+    ctx->masterCtx.c[6] = rotlFixed(k1, 16);
+    ctx->masterCtx.c[1] = (k0&0xFFFF0000) | (k1&0xFFFF);
+    ctx->masterCtx.c[3] = (k1&0xFFFF0000) | (k2&0xFFFF);
+    ctx->masterCtx.c[5] = (k2&0xFFFF0000) | (k3&0xFFFF);
+    ctx->masterCtx.c[7] = (k3&0xFFFF0000) | (k0&0xFFFF);
+
+    /* Clear carry bit */
+    ctx->masterCtx.carry = 0;
+
+    /* Iterate the system four times */
+    for (i=0; i<4; i++)
+        RABBIT_next_state(&(ctx->masterCtx));
+
+    /* Modify the counters */
+    for (i=0; i<8; i++)
+        ctx->masterCtx.c[i] ^= ctx->masterCtx.x[(i+4)&0x7];
+
+    /* Copy master instance to work instance */
+    for (i=0; i<8; i++) {
+        ctx->workCtx.x[i] = ctx->masterCtx.x[i];
+        ctx->workCtx.c[i] = ctx->masterCtx.c[i];
+    }
+    ctx->workCtx.carry = ctx->masterCtx.carry;
+
+    wc_RabbitSetIV(ctx, iv);
+
+    return 0;
+}
+
+
+/* Key setup */
+int wc_RabbitSetKey(Rabbit* ctx, const byte* key, const byte* iv)
+{
+#ifdef XSTREAM_ALIGN
+    if ((wolfssl_word)key % 4) {
+        int alignKey[4];
+
+        /* iv aligned in SetIV */
+        WOLFSSL_MSG("wc_RabbitSetKey unaligned key");
+
+        XMEMCPY(alignKey, key, sizeof(alignKey));
+
+        return DoKey(ctx, (const byte*)alignKey, iv);
+    }
+#endif /* XSTREAM_ALIGN */
+
+    return DoKey(ctx, key, iv);
+}
+
+
+/* Encrypt/decrypt a message of any size */
+static INLINE int DoProcess(Rabbit* ctx, byte* output, const byte* input,
+                            word32 msglen)
+{
+    /* Encrypt/decrypt all full blocks */
+    while (msglen >= 16) {
+        /* Iterate the system */
+        RABBIT_next_state(&(ctx->workCtx));
+
+        /* Encrypt/decrypt 16 bytes of data */
+        *(word32*)(output+ 0) = *(word32*)(input+ 0) ^
+                   LITTLE32(ctx->workCtx.x[0] ^ (ctx->workCtx.x[5]>>16) ^
+                   U32V(ctx->workCtx.x[3]<<16));
+        *(word32*)(output+ 4) = *(word32*)(input+ 4) ^
+                   LITTLE32(ctx->workCtx.x[2] ^ (ctx->workCtx.x[7]>>16) ^
+                   U32V(ctx->workCtx.x[5]<<16));
+        *(word32*)(output+ 8) = *(word32*)(input+ 8) ^
+                   LITTLE32(ctx->workCtx.x[4] ^ (ctx->workCtx.x[1]>>16) ^
+                   U32V(ctx->workCtx.x[7]<<16));
+        *(word32*)(output+12) = *(word32*)(input+12) ^
+                   LITTLE32(ctx->workCtx.x[6] ^ (ctx->workCtx.x[3]>>16) ^
+                   U32V(ctx->workCtx.x[1]<<16));
+
+        /* Increment pointers and decrement length */
+        input  += 16;
+        output += 16;
+        msglen -= 16;
+    }
+
+    /* Encrypt/decrypt remaining data */
+    if (msglen) {
+
+        word32 i;
+        word32 tmp[4];
+        byte*  buffer = (byte*)tmp;
+
+        XMEMSET(tmp, 0, sizeof(tmp));   /* help static analysis */
+
+        /* Iterate the system */
+        RABBIT_next_state(&(ctx->workCtx));
+
+        /* Generate 16 bytes of pseudo-random data */
+        tmp[0] = LITTLE32(ctx->workCtx.x[0] ^
+                  (ctx->workCtx.x[5]>>16) ^ U32V(ctx->workCtx.x[3]<<16));
+        tmp[1] = LITTLE32(ctx->workCtx.x[2] ^ 
+                  (ctx->workCtx.x[7]>>16) ^ U32V(ctx->workCtx.x[5]<<16));
+        tmp[2] = LITTLE32(ctx->workCtx.x[4] ^ 
+                  (ctx->workCtx.x[1]>>16) ^ U32V(ctx->workCtx.x[7]<<16));
+        tmp[3] = LITTLE32(ctx->workCtx.x[6] ^ 
+                  (ctx->workCtx.x[3]>>16) ^ U32V(ctx->workCtx.x[1]<<16));
+
+        /* Encrypt/decrypt the data */
+        for (i=0; i<msglen; i++)
+            output[i] = input[i] ^ buffer[i];
+    }
+
+    return 0;
+}
+
+
+/* Encrypt/decrypt a message of any size */
+int wc_RabbitProcess(Rabbit* ctx, byte* output, const byte* input, word32 msglen)
+{
+#ifdef XSTREAM_ALIGN
+    if ((wolfssl_word)input % 4 || (wolfssl_word)output % 4) {
+        #ifndef NO_WOLFSSL_ALLOC_ALIGN
+            byte* tmp;
+            WOLFSSL_MSG("wc_RabbitProcess unaligned");
+
+            tmp = (byte*)XMALLOC(msglen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            if (tmp == NULL) return MEMORY_E;
+
+            XMEMCPY(tmp, input, msglen);
+            DoProcess(ctx, tmp, tmp, msglen);
+            XMEMCPY(output, tmp, msglen);
+
+            XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+            return 0;
+        #else
+            return BAD_ALIGN_E;
+        #endif
+    }
+#endif /* XSTREAM_ALIGN */
+
+    return DoProcess(ctx, output, input, msglen);
+}
+
+
+#endif /* NO_RABBIT */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/random.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,1340 @@
+/* random.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+ 
+#include <wolfssl/wolfcrypt/settings.h>
+
+/* on HPUX 11 you may need to install /dev/random see
+   http://h20293.www2.hp.com/portal/swdepot/displayProductInfo.do?productNumber=KRNG11I
+
+*/
+
+#include <wolfssl/wolfcrypt/random.h>
+
+#ifdef HAVE_FIPS
+int wc_GenerateSeed(OS_Seed* os, byte* seed, word32 sz)
+{
+    return GenerateSeed(os, seed, sz);
+}
+
+#ifdef HAVE_CAVIUM
+    int  wc_InitRngCavium(RNG* rng, int i)
+    {
+        return InitRngCavium(rng, i);
+    }
+#endif
+
+
+int  wc_InitRng(RNG* rng)
+{
+    return InitRng_fips(rng);
+}
+
+
+int  wc_RNG_GenerateBlock(RNG* rng, byte* b, word32 sz)
+{
+    return RNG_GenerateBlock_fips(rng, b, sz);
+}
+
+
+int  wc_RNG_GenerateByte(RNG* rng, byte* b)
+{
+    return RNG_GenerateByte(rng, b);
+}
+
+#if defined(HAVE_HASHDRBG) || defined(NO_RC4)
+
+    int wc_FreeRng(RNG* rng)
+    {
+        return FreeRng_fips(rng);
+    }
+
+
+    int wc_RNG_HealthTest(int reseed,
+                                        const byte* entropyA, word32 entropyASz,
+                                        const byte* entropyB, word32 entropyBSz,
+                                        byte* output, word32 outputSz)
+    {
+        return RNG_HealthTest_fips(reseed, entropyA, entropyASz,
+                              entropyB, entropyBSz, output, outputSz);
+    }
+#endif /* HAVE_HASHDRBG || NO_RC4 */
+#else /* else build without fips */
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+#if defined(HAVE_HASHDRBG) || defined(NO_RC4)
+
+    #include <wolfssl/wolfcrypt/sha256.h>
+
+    #ifdef NO_INLINE
+        #include <wolfssl/wolfcrypt/misc.h>
+    #else
+        #include <wolfcrypt/src/misc.c>
+    #endif
+#endif /* HAVE_HASHDRBG || NO_RC4 */
+
+#if defined(USE_WINDOWS_API)
+    #ifndef _WIN32_WINNT
+        #define _WIN32_WINNT 0x0400
+    #endif
+    #include <windows.h>
+    #include <wincrypt.h>
+#else
+    #if !defined(NO_DEV_RANDOM) && !defined(CUSTOM_RAND_GENERATE) && \
+                          !defined(WOLFSSL_MDK_ARM) && !defined(WOLFSSL_IAR_ARM)
+            #include <fcntl.h>
+        #ifndef EBSNET
+            #include <unistd.h>
+        #endif
+    #else
+        /* include headers that may be needed to get good seed */
+    #endif
+#endif /* USE_WINDOWS_API */
+    
+#ifdef HAVE_INTEL_RDGEN
+    static int wc_InitRng_IntelRD(void) ;
+    #if defined(HAVE_HASHDRBG) || defined(NO_RC4)
+	static int wc_GenerateSeed_IntelRD(OS_Seed* os, byte* output, word32 sz) ;
+    #else
+    static int wc_GenerateRand_IntelRD(OS_Seed* os, byte* output, word32 sz) ;
+    #endif
+    static word32 cpuid_check = 0 ;
+    static word32 cpuid_flags = 0 ;
+    #define CPUID_RDRAND 0x4
+    #define CPUID_RDSEED 0x8
+    #define IS_INTEL_RDRAND     (cpuid_flags&CPUID_RDRAND)
+    #define IS_INTEL_RDSEED     (cpuid_flags&CPUID_RDSEED)
+#endif
+
+#if defined(HAVE_HASHDRBG) || defined(NO_RC4)
+
+/* Start NIST DRBG code */
+
+#define OUTPUT_BLOCK_LEN  (SHA256_DIGEST_SIZE)
+#define MAX_REQUEST_LEN   (0x10000)
+#define RESEED_INTERVAL   (1000000)
+#define SECURITY_STRENGTH (256)
+#define ENTROPY_SZ        (SECURITY_STRENGTH/8)
+#define NONCE_SZ          (ENTROPY_SZ/2)
+#define ENTROPY_NONCE_SZ  (ENTROPY_SZ+NONCE_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
+
+/* RNG health states */
+#define DRBG_NOT_INIT     0
+#define DRBG_OK           1
+#define DRBG_FAILED       2
+#define DRBG_CONT_FAILED  3
+
+
+enum {
+    drbgInitC     = 0,
+    drbgReseed    = 1,
+    drbgGenerateW = 2,
+    drbgGenerateH = 3,
+    drbgInitV
+};
+
+
+typedef struct DRBG {
+    word32 reseedCtr;
+    word32 lastBlock;
+    byte V[DRBG_SEED_LEN];
+    byte C[DRBG_SEED_LEN];
+    byte   matchCount;
+} DRBG;
+
+
+static int wc_RNG_HealthTestLocal(int reseed);
+
+/* Hash Derivation Function */
+/* Returns: DRBG_SUCCESS or DRBG_FAILURE */
+static int Hash_df(DRBG* drbg, byte* out, word32 outSz, byte type,
+                                                  const byte* inA, word32 inASz,
+                                                  const byte* inB, word32 inBSz)
+{
+    byte ctr;
+    int i;
+    int len;
+    word32 bits = (outSz * 8); /* reverse byte order */
+    Sha256 sha;
+    byte digest[SHA256_DIGEST_SIZE];
+
+    (void)drbg;
+    #ifdef LITTLE_ENDIAN_ORDER
+        bits = ByteReverseWord32(bits);
+    #endif
+    len = (outSz / OUTPUT_BLOCK_LEN)
+        + ((outSz % OUTPUT_BLOCK_LEN) ? 1 : 0);
+
+    for (i = 0, ctr = 1; i < len; i++, ctr++)
+    {
+        if (wc_InitSha256(&sha) != 0)
+            return DRBG_FAILURE;
+
+        if (wc_Sha256Update(&sha, &ctr, sizeof(ctr)) != 0)
+            return DRBG_FAILURE;
+
+        if (wc_Sha256Update(&sha, (byte*)&bits, sizeof(bits)) != 0)
+            return DRBG_FAILURE;
+
+        /* churning V is the only string that doesn't have the type added */
+        if (type != drbgInitV)
+            if (wc_Sha256Update(&sha, &type, sizeof(type)) != 0)
+                return DRBG_FAILURE;
+
+        if (wc_Sha256Update(&sha, inA, inASz) != 0)
+            return DRBG_FAILURE;
+
+        if (inB != NULL && inBSz > 0)
+            if (wc_Sha256Update(&sha, inB, inBSz) != 0)
+                return DRBG_FAILURE;
+
+        if (wc_Sha256Final(&sha, digest) != 0)
+            return DRBG_FAILURE;
+
+        if (outSz > OUTPUT_BLOCK_LEN) {
+            XMEMCPY(out, digest, OUTPUT_BLOCK_LEN);
+            outSz -= OUTPUT_BLOCK_LEN;
+            out += OUTPUT_BLOCK_LEN;
+        }
+        else {
+            XMEMCPY(out, digest, outSz);
+        }
+    }
+    ForceZero(digest, sizeof(digest));
+
+    return DRBG_SUCCESS;
+}
+
+
+/* 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) {
+        return DRBG_FAILURE;
+    }
+
+    XMEMCPY(drbg->V, seed, sizeof(drbg->V));
+    ForceZero(seed, sizeof(seed));
+
+    if (Hash_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V,
+                                    sizeof(drbg->V), NULL, 0) != DRBG_SUCCESS) {
+        return DRBG_FAILURE;
+    }
+
+    drbg->reseedCtr = 1;
+    drbg->lastBlock = 0;
+    drbg->matchCount = 0;
+    return DRBG_SUCCESS;
+}
+
+static INLINE void array_add_one(byte* data, word32 dataSz)
+{
+    int i;
+
+    for (i = dataSz - 1; i >= 0; i--)
+    {
+        data[i]++;
+        if (data[i] != 0) break;
+    }
+}
+
+
+/* Returns: DRBG_SUCCESS or DRBG_FAILURE */
+static int Hash_gen(DRBG* drbg, byte* out, word32 outSz, const byte* V)
+{
+    byte data[DRBG_SEED_LEN];
+    int i;
+    int len;
+    word32 checkBlock;
+    Sha256 sha;
+    byte digest[SHA256_DIGEST_SIZE];
+
+    /* Special case: outSz is 0 and out is NULL. wc_Generate a block to save for
+     * the continuous test. */
+
+    if (outSz == 0) outSz = 1;
+
+    len = (outSz / OUTPUT_BLOCK_LEN) + ((outSz % OUTPUT_BLOCK_LEN) ? 1 : 0);
+
+    XMEMCPY(data, V, sizeof(data));
+    for (i = 0; i < len; i++) {
+        if (wc_InitSha256(&sha) != 0 ||
+            wc_Sha256Update(&sha, data, sizeof(data)) != 0 ||
+            wc_Sha256Final(&sha, digest) != 0) {
+
+            return DRBG_FAILURE;
+        }
+
+        XMEMCPY(&checkBlock, digest, sizeof(word32));
+        if (drbg->reseedCtr > 1 && checkBlock == drbg->lastBlock) {
+            if (drbg->matchCount == 1) {
+                return DRBG_CONT_FAILURE;
+            }
+            else {
+                if (i == len) {
+                    len++;
+                }
+                drbg->matchCount = 1;
+            }
+        }
+        else {
+            drbg->matchCount = 0;
+            drbg->lastBlock = checkBlock;
+        }
+
+        if (outSz >= OUTPUT_BLOCK_LEN) {
+            XMEMCPY(out, digest, OUTPUT_BLOCK_LEN);
+            outSz -= OUTPUT_BLOCK_LEN;
+            out += OUTPUT_BLOCK_LEN;
+            array_add_one(data, DRBG_SEED_LEN);
+        }
+        else if (out != NULL && outSz != 0) {
+            XMEMCPY(out, digest, outSz);
+            outSz = 0;
+        }
+    }
+    ForceZero(data, sizeof(data));
+
+    return DRBG_SUCCESS;
+}
+
+
+static INLINE void array_add(byte* d, word32 dLen, const byte* s, word32 sLen)
+{
+    word16 carry = 0;
+
+    if (dLen > 0 && sLen > 0 && dLen >= sLen) {
+        int sIdx, dIdx;
+
+        for (sIdx = sLen - 1, dIdx = dLen - 1; sIdx >= 0; dIdx--, sIdx--)
+        {
+            carry += d[dIdx] + s[sIdx];
+            d[dIdx] = (byte)carry;
+            carry >>= 8;
+        }
+
+        for (; carry != 0 && dIdx >= 0; dIdx--) {
+            carry += d[dIdx];
+            d[dIdx] = (byte)carry;
+            carry >>= 8;
+        }
+    }
+}
+
+
+/* Returns: DRBG_SUCCESS, DRBG_NEED_RESEED, or DRBG_FAILURE */
+static int Hash_DRBG_Generate(DRBG* drbg, byte* out, word32 outSz)
+{
+    int ret = DRBG_NEED_RESEED;
+    Sha256 sha;
+    byte digest[SHA256_DIGEST_SIZE];
+
+    if (drbg->reseedCtr != RESEED_INTERVAL) {
+        byte type = drbgGenerateH;
+        word32 reseedCtr = drbg->reseedCtr;
+
+        ret = Hash_gen(drbg, out, outSz, drbg->V);
+        if (ret == DRBG_SUCCESS) {
+            if (wc_InitSha256(&sha) != 0 ||
+                wc_Sha256Update(&sha, &type, sizeof(type)) != 0 ||
+                wc_Sha256Update(&sha, drbg->V, sizeof(drbg->V)) != 0 ||
+                wc_Sha256Final(&sha, digest) != 0) {
+
+                ret = DRBG_FAILURE;
+            }
+            else {
+                array_add(drbg->V, sizeof(drbg->V), digest, sizeof(digest));
+                array_add(drbg->V, sizeof(drbg->V), drbg->C, sizeof(drbg->C));
+                #ifdef LITTLE_ENDIAN_ORDER
+                    reseedCtr = ByteReverseWord32(reseedCtr);
+                #endif
+                array_add(drbg->V, sizeof(drbg->V),
+                                          (byte*)&reseedCtr, sizeof(reseedCtr));
+                ret = DRBG_SUCCESS;
+            }
+            drbg->reseedCtr++;
+        }
+    }
+    ForceZero(digest, sizeof(digest));
+
+    return ret;
+}
+
+
+/* Returns: DRBG_SUCCESS or DRBG_FAILURE */
+static int Hash_DRBG_Instantiate(DRBG* drbg, const byte* seed, word32 seedSz,
+                                             const byte* nonce, word32 nonceSz)
+{
+    int ret = DRBG_FAILURE;
+
+    XMEMSET(drbg, 0, sizeof(DRBG));
+
+    if (Hash_df(drbg, drbg->V, sizeof(drbg->V), drbgInitV, seed, seedSz,
+                                              nonce, nonceSz) == DRBG_SUCCESS &&
+        Hash_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V,
+                                    sizeof(drbg->V), NULL, 0) == DRBG_SUCCESS) {
+
+        drbg->reseedCtr = 1;
+        drbg->lastBlock = 0;
+        drbg->matchCount = 0;
+        ret = DRBG_SUCCESS;
+    }
+
+    return ret;
+}
+
+
+/* Returns: DRBG_SUCCESS or DRBG_FAILURE */
+static int Hash_DRBG_Uninstantiate(DRBG* drbg)
+{
+    word32 i;
+    int    compareSum = 0;
+    byte*  compareDrbg = (byte*)drbg;
+
+    ForceZero(drbg, sizeof(DRBG));
+
+    for (i = 0; i < sizeof(DRBG); i++)
+        compareSum |= compareDrbg[i] ^ 0;
+
+    return (compareSum == 0) ? DRBG_SUCCESS : DRBG_FAILURE;
+}
+
+/* End NIST DRBG Code */
+
+
+/* Get seed and key cipher */
+int wc_InitRng(RNG* rng)
+{
+    int ret = BAD_FUNC_ARG;
+
+    if (rng != NULL) {
+        if (wc_RNG_HealthTestLocal(0) == 0) {
+            byte entropy[ENTROPY_NONCE_SZ];
+
+            rng->drbg =
+                    (struct DRBG*)XMALLOC(sizeof(DRBG), NULL, DYNAMIC_TYPE_RNG);
+            if (rng->drbg == NULL) {
+                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) == DRBG_SUCCESS) {
+
+                ret = Hash_DRBG_Generate(rng->drbg, NULL, 0);
+            }
+            else
+                ret = DRBG_FAILURE;
+
+            ForceZero(entropy, ENTROPY_NONCE_SZ);
+        }
+        else
+            ret = DRBG_CONT_FAILURE;
+
+        if (ret == DRBG_SUCCESS) {
+            rng->status = DRBG_OK;
+            ret = 0;
+        }
+        else if (ret == DRBG_CONT_FAILURE) {
+            rng->status = DRBG_CONT_FAILED;
+            ret = DRBG_CONT_FIPS_E;
+        }
+        else if (ret == DRBG_FAILURE) {
+            rng->status = DRBG_FAILED;
+            ret = RNG_FAILURE_E;
+        }
+        else {
+            rng->status = DRBG_FAILED;
+        }
+    }
+
+    return ret;
+}
+
+
+/* place a generated block in output */
+int wc_RNG_GenerateBlock(RNG* rng, byte* output, word32 sz)
+{
+    int ret;
+
+    if (rng == NULL || output == NULL || sz > MAX_REQUEST_LEN)
+        return BAD_FUNC_ARG;
+
+    if (rng->status != DRBG_OK)
+        return RNG_FAILURE_E;
+
+    ret = Hash_DRBG_Generate(rng->drbg, output, sz);
+
+    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) {
+
+                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);
+        }
+        else
+            ret = DRBG_CONT_FAILURE;
+    }
+
+    if (ret == DRBG_SUCCESS) {
+        ret = 0;
+    }
+    else if (ret == DRBG_CONT_FAILURE) {
+        ret = DRBG_CONT_FIPS_E;
+        rng->status = DRBG_CONT_FAILED;
+    }
+    else {
+        ret = RNG_FAILURE_E;
+        rng->status = DRBG_FAILED;
+    }
+
+    return ret;
+}
+
+
+int wc_RNG_GenerateByte(RNG* rng, byte* b)
+{
+    return wc_RNG_GenerateBlock(rng, b, 1);
+}
+
+
+int wc_FreeRng(RNG* rng)
+{
+    int ret = BAD_FUNC_ARG;
+
+    if (rng != NULL) {
+        if (rng->drbg != NULL) {
+            if (Hash_DRBG_Uninstantiate(rng->drbg) == DRBG_SUCCESS)
+                ret = 0;
+            else
+                ret = RNG_FAILURE_E;
+
+            XFREE(rng->drbg, NULL, DYNAMIC_TYPE_RNG);
+            rng->drbg = NULL;
+        }
+
+        rng->status = DRBG_NOT_INIT;
+    }
+
+    return ret;
+}
+
+
+int wc_RNG_HealthTest(int reseed, const byte* entropyA, word32 entropyASz,
+                                  const byte* entropyB, word32 entropyBSz,
+                                  byte* output, word32 outputSz)
+{
+    DRBG drbg;
+
+    if (entropyA == NULL || output == NULL)
+        return BAD_FUNC_ARG;
+
+    if (reseed != 0 && entropyB == NULL)
+        return BAD_FUNC_ARG;
+
+    if (outputSz != (SHA256_DIGEST_SIZE * 4))
+        return -1;
+
+    if (Hash_DRBG_Instantiate(&drbg, entropyA, entropyASz, NULL, 0) != 0)
+        return -1;
+
+    if (reseed) {
+        if (Hash_DRBG_Reseed(&drbg, entropyB, entropyBSz) != 0) {
+            Hash_DRBG_Uninstantiate(&drbg);
+            return -1;
+        }
+    }
+
+    if (Hash_DRBG_Generate(&drbg, output, outputSz) != 0) {
+        Hash_DRBG_Uninstantiate(&drbg);
+        return -1;
+    }
+
+    if (Hash_DRBG_Generate(&drbg, output, outputSz) != 0) {
+        Hash_DRBG_Uninstantiate(&drbg);
+        return -1;
+    }
+
+    if (Hash_DRBG_Uninstantiate(&drbg) != 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+
+const byte entropyA[] = {
+    0x63, 0x36, 0x33, 0x77, 0xe4, 0x1e, 0x86, 0x46, 0x8d, 0xeb, 0x0a, 0xb4,
+    0xa8, 0xed, 0x68, 0x3f, 0x6a, 0x13, 0x4e, 0x47, 0xe0, 0x14, 0xc7, 0x00,
+    0x45, 0x4e, 0x81, 0xe9, 0x53, 0x58, 0xa5, 0x69, 0x80, 0x8a, 0xa3, 0x8f,
+    0x2a, 0x72, 0xa6, 0x23, 0x59, 0x91, 0x5a, 0x9f, 0x8a, 0x04, 0xca, 0x68
+};
+
+const byte reseedEntropyA[] = {
+    0xe6, 0x2b, 0x8a, 0x8e, 0xe8, 0xf1, 0x41, 0xb6, 0x98, 0x05, 0x66, 0xe3,
+    0xbf, 0xe3, 0xc0, 0x49, 0x03, 0xda, 0xd4, 0xac, 0x2c, 0xdf, 0x9f, 0x22,
+    0x80, 0x01, 0x0a, 0x67, 0x39, 0xbc, 0x83, 0xd3
+};
+
+const byte outputA[] = {
+    0x04, 0xee, 0xc6, 0x3b, 0xb2, 0x31, 0xdf, 0x2c, 0x63, 0x0a, 0x1a, 0xfb,
+    0xe7, 0x24, 0x94, 0x9d, 0x00, 0x5a, 0x58, 0x78, 0x51, 0xe1, 0xaa, 0x79,
+    0x5e, 0x47, 0x73, 0x47, 0xc8, 0xb0, 0x56, 0x62, 0x1c, 0x18, 0xbd, 0xdc,
+    0xdd, 0x8d, 0x99, 0xfc, 0x5f, 0xc2, 0xb9, 0x20, 0x53, 0xd8, 0xcf, 0xac,
+    0xfb, 0x0b, 0xb8, 0x83, 0x12, 0x05, 0xfa, 0xd1, 0xdd, 0xd6, 0xc0, 0x71,
+    0x31, 0x8a, 0x60, 0x18, 0xf0, 0x3b, 0x73, 0xf5, 0xed, 0xe4, 0xd4, 0xd0,
+    0x71, 0xf9, 0xde, 0x03, 0xfd, 0x7a, 0xea, 0x10, 0x5d, 0x92, 0x99, 0xb8,
+    0xaf, 0x99, 0xaa, 0x07, 0x5b, 0xdb, 0x4d, 0xb9, 0xaa, 0x28, 0xc1, 0x8d,
+    0x17, 0x4b, 0x56, 0xee, 0x2a, 0x01, 0x4d, 0x09, 0x88, 0x96, 0xff, 0x22,
+    0x82, 0xc9, 0x55, 0xa8, 0x19, 0x69, 0xe0, 0x69, 0xfa, 0x8c, 0xe0, 0x07,
+    0xa1, 0x80, 0x18, 0x3a, 0x07, 0xdf, 0xae, 0x17
+};
+
+const byte entropyB[] = {
+    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
+};
+
+const byte outputB[] = {
+    0xd3, 0xe1, 0x60, 0xc3, 0x5b, 0x99, 0xf3, 0x40, 0xb2, 0x62, 0x82, 0x64,
+    0xd1, 0x75, 0x10, 0x60, 0xe0, 0x04, 0x5d, 0xa3, 0x83, 0xff, 0x57, 0xa5,
+    0x7d, 0x73, 0xa6, 0x73, 0xd2, 0xb8, 0xd8, 0x0d, 0xaa, 0xf6, 0xa6, 0xc3,
+    0x5a, 0x91, 0xbb, 0x45, 0x79, 0xd7, 0x3f, 0xd0, 0xc8, 0xfe, 0xd1, 0x11,
+    0xb0, 0x39, 0x13, 0x06, 0x82, 0x8a, 0xdf, 0xed, 0x52, 0x8f, 0x01, 0x81,
+    0x21, 0xb3, 0xfe, 0xbd, 0xc3, 0x43, 0xe7, 0x97, 0xb8, 0x7d, 0xbb, 0x63,
+    0xdb, 0x13, 0x33, 0xde, 0xd9, 0xd1, 0xec, 0xe1, 0x77, 0xcf, 0xa6, 0xb7,
+    0x1f, 0xe8, 0xab, 0x1d, 0xa4, 0x66, 0x24, 0xed, 0x64, 0x15, 0xe5, 0x1c,
+    0xcd, 0xe2, 0xc7, 0xca, 0x86, 0xe2, 0x83, 0x99, 0x0e, 0xea, 0xeb, 0x91,
+    0x12, 0x04, 0x15, 0x52, 0x8b, 0x22, 0x95, 0x91, 0x02, 0x81, 0xb0, 0x2d,
+    0xd4, 0x31, 0xf4, 0xc9, 0xf7, 0x04, 0x27, 0xdf
+};
+
+
+static int wc_RNG_HealthTestLocal(int reseed)
+{
+    int ret = 0;
+    byte check[SHA256_DIGEST_SIZE * 4];
+
+    if (reseed) {
+        ret = wc_RNG_HealthTest(1, entropyA, sizeof(entropyA),
+                                reseedEntropyA, sizeof(reseedEntropyA),
+                                check, sizeof(check));
+        if (ret == 0) {
+            if (ConstantCompare(check, outputA, sizeof(check)) != 0)
+                ret = -1;
+        }
+    }
+    else {
+        ret = wc_RNG_HealthTest(0, entropyB, sizeof(entropyB),
+                                NULL, 0,
+                                check, sizeof(check));
+        if (ret == 0) {
+            if (ConstantCompare(check, outputB, sizeof(check)) != 0)
+                ret = -1;
+        }
+    }
+
+    return ret;
+}
+
+
+#else /* HAVE_HASHDRBG || NO_RC4 */
+
+/* Get seed and key cipher */
+int wc_InitRng(RNG* rng)
+{
+    int  ret;
+#ifdef WOLFSSL_SMALL_STACK
+    byte* key;
+    byte* junk;
+#else
+    byte key[32];
+    byte junk[256];
+#endif
+
+#ifdef HAVE_INTEL_RDGEN
+    wc_InitRng_IntelRD() ;
+    if(IS_INTEL_RDRAND)return 0 ;
+#endif
+#ifdef HAVE_CAVIUM
+    if (rng->magic == WOLFSSL_RNG_CAVIUM_MAGIC)
+        return 0;
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    key = (byte*)XMALLOC(32, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (key == NULL)
+        return MEMORY_E;
+
+    junk = (byte*)XMALLOC(256, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (junk == NULL) {
+        XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    ret = wc_GenerateSeed(&rng->seed, key, 32);
+
+    if (ret == 0) {
+        wc_Arc4SetKey(&rng->cipher, key, sizeof(key));
+
+        ret = wc_RNG_GenerateBlock(rng, junk, 256); /*rid initial state*/
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(junk, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+#ifdef HAVE_CAVIUM
+    static void CaviumRNG_GenerateBlock(RNG* rng, byte* output, word32 sz);
+#endif
+
+/* place a generated block in output */
+int wc_RNG_GenerateBlock(RNG* rng, byte* output, word32 sz)
+{
+#ifdef HAVE_INTEL_RDGEN
+    if(IS_INTEL_RDRAND)
+        return wc_GenerateRand_IntelRD(NULL, output, sz) ;
+#endif
+#ifdef HAVE_CAVIUM
+    if (rng->magic == WOLFSSL_RNG_CAVIUM_MAGIC)
+        return CaviumRNG_GenerateBlock(rng, output, sz);
+#endif
+    XMEMSET(output, 0, sz);
+    wc_Arc4Process(&rng->cipher, output, output, sz);
+
+    return 0;
+}
+
+
+int wc_RNG_GenerateByte(RNG* rng, byte* b)
+{
+    return wc_RNG_GenerateBlock(rng, b, 1);
+}
+
+
+int wc_FreeRng(RNG* rng)
+{
+    (void)rng;
+    return 0;
+}
+
+
+#ifdef HAVE_CAVIUM
+
+#include <wolfssl/ctaocrypt/logging.h>
+#include "cavium_common.h"
+
+/* Initiliaze RNG for use with Nitrox device */
+int wc_InitRngCavium(RNG* rng, int devId)
+{
+    if (rng == NULL)
+        return -1;
+
+    rng->devId = devId;
+    rng->magic = WOLFSSL_RNG_CAVIUM_MAGIC;
+
+    return 0;
+}
+
+
+static void CaviumRNG_GenerateBlock(RNG* rng, byte* output, word32 sz)
+{
+    wolfssl_word offset = 0;
+    word32      requestId;
+
+    while (sz > WOLFSSL_MAX_16BIT) {
+        word16 slen = (word16)WOLFSSL_MAX_16BIT;
+        if (CspRandom(CAVIUM_BLOCKING, slen, output + offset, &requestId,
+                      rng->devId) != 0) {
+            WOLFSSL_MSG("Cavium RNG failed");
+        }
+        sz     -= WOLFSSL_MAX_16BIT;
+        offset += WOLFSSL_MAX_16BIT;
+    }
+    if (sz) {
+        word16 slen = (word16)sz;
+        if (CspRandom(CAVIUM_BLOCKING, slen, output + offset, &requestId,
+                      rng->devId) != 0) {
+            WOLFSSL_MSG("Cavium RNG failed");
+        }
+    }
+}
+
+#endif /* HAVE_CAVIUM */
+
+#endif /* HAVE_HASHDRBG || NO_RC4 */
+
+
+#if defined(HAVE_INTEL_RDGEN)
+
+#ifndef _MSC_VER
+    #define cpuid(reg, leaf, sub)\
+            __asm__ __volatile__ ("cpuid":\
+             "=a" (reg[0]), "=b" (reg[1]), "=c" (reg[2]), "=d" (reg[3]) :\
+             "a" (leaf), "c"(sub));
+
+    #define XASM_LINK(f) asm(f)
+#else
+
+    #include <intrin.h>
+    #define cpuid(a,b) __cpuid((int*)a,b)
+
+    #define XASM_LINK(f)
+
+#endif /* _MSC_VER */
+
+#define EAX 0
+#define EBX 1
+#define ECX 2 
+#define EDX 3
+
+static word32 cpuid_flag(word32 leaf, word32 sub, word32 num, word32 bit) {
+    int got_intel_cpu=0;
+    unsigned int reg[5]; 
+    
+    reg[4] = '\0' ;
+    cpuid(reg, 0, 0);  
+    if(memcmp((char *)&(reg[EBX]), "Genu", 4) == 0 &&  
+                memcmp((char *)&(reg[EDX]), "ineI", 4) == 0 &&  
+                memcmp((char *)&(reg[ECX]), "ntel", 4) == 0) {  
+        got_intel_cpu = 1;  
+    }    
+    if (got_intel_cpu) {
+        cpuid(reg, leaf, sub);
+        return((reg[num]>>bit)&0x1) ;
+    }
+    return 0 ;
+}
+
+static int wc_InitRng_IntelRD()
+{
+    if(cpuid_check==0) {
+        if(cpuid_flag(1, 0, ECX, 30)){ cpuid_flags |= CPUID_RDRAND ;} 
+        if(cpuid_flag(7, 0, EBX, 18)){ cpuid_flags |= CPUID_RDSEED ;}
+        cpuid_check = 1 ;
+    }
+    return 1 ;
+}
+
+#define INTELRD_RETRY 10
+
+#if defined(HAVE_HASHDRBG) || defined(NO_RC4)
+
+/* return 0 on success */
+static inline int IntelRDseed32(unsigned int *seed)  
+{  
+    int rdseed;  unsigned char ok ;
+
+    __asm__ volatile("rdseed %0; setc %1":"=r"(rdseed), "=qm"(ok));  
+    if(ok){
+        *seed = rdseed ;
+        return 0 ;
+    } else
+        return 1;
+}
+
+/* return 0 on success */
+static inline int IntelRDseed32_r(unsigned int *rnd)  
+{  
+    int i ;
+    for(i=0; i<INTELRD_RETRY;i++) {
+       if(IntelRDseed32(rnd) == 0) return 0 ;
+    }
+    return 1 ;
+}
+
+/* return 0 on success */
+static int wc_GenerateSeed_IntelRD(OS_Seed* os, byte* output, word32 sz)
+{
+    (void) os ;
+    int ret ;
+    unsigned int rndTmp ;
+
+    for(  ; sz/4 > 0; sz-=4, output+=4) {
+        if(IS_INTEL_RDSEED)ret = IntelRDseed32_r((word32 *)output) ;
+        else return 1 ;
+        if(ret)
+             return 1 ;
+    }
+    if(sz == 0)return 0 ;
+
+    if(IS_INTEL_RDSEED)ret = IntelRDseed32_r(&rndTmp) ;
+    else return 1 ;
+    if(ret)
+         return 1 ;
+    XMEMCPY(output, &rndTmp, sz) ;
+    return 0;
+}
+
+#else
+
+/* return 0 on success */
+static inline int IntelRDrand32(unsigned int *rnd)  
+{  
+    int rdrand; unsigned char ok ;  
+    __asm__ volatile("rdrand %0; setc %1":"=r"(rdrand), "=qm"(ok));  
+    if(ok){
+        *rnd = rdrand;
+        return 0 ;
+    } else
+        return 1;
+}
+
+/* return 0 on success */
+static inline int IntelRDrand32_r(unsigned int *rnd)  
+{  
+    int i ;
+    for(i=0; i<INTELRD_RETRY;i++) {
+       if(IntelRDrand32(rnd) == 0) return 0 ;
+    }
+    return 1 ;
+}
+
+/* return 0 on success */
+static int wc_GenerateRand_IntelRD(OS_Seed* os, byte* output, word32 sz)
+{
+    (void) os ;
+    int ret ;
+    unsigned int rndTmp;
+
+    for(  ; sz/4 > 0; sz-=4, output+=4) {
+        if(IS_INTEL_RDRAND)ret = IntelRDrand32_r((word32 *)output);
+        else return 1 ;
+        if(ret)
+             return 1 ;
+    }
+    if(sz == 0)return 0 ;
+
+    if(IS_INTEL_RDRAND)ret = IntelRDrand32_r(&rndTmp);
+    else return 1 ;
+    if(ret)
+         return 1 ;
+    XMEMCPY(output, &rndTmp, sz) ;
+    return 0;
+}
+#endif /* defined(HAVE_HASHDRBG) || defined(NO_RC4) */
+
+#endif /* HAVE_INTEL_RDGEN */
+
+
+#if defined(USE_WINDOWS_API)
+
+
+int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    if(!CryptAcquireContext(&os->handle, 0, 0, PROV_RSA_FULL,
+                            CRYPT_VERIFYCONTEXT))
+        return WINCRYPT_E;
+
+    if (!CryptGenRandom(os->handle, sz, output))
+        return CRYPTGEN_E;
+
+    CryptReleaseContext(os->handle, 0);
+
+    return 0;
+}
+
+
+#elif defined(HAVE_RTP_SYS) || defined(EBSNET)
+
+#include "rtprand.h"   /* rtp_rand () */
+#include "rtptime.h"   /* rtp_get_system_msec() */
+
+
+int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    int i;
+    rtp_srand(rtp_get_system_msec());
+
+    for (i = 0; i < sz; i++ ) {
+        output[i] = rtp_rand() % 256;
+        if ( (i % 8) == 7)
+            rtp_srand(rtp_get_system_msec());
+    }
+
+    return 0;
+}
+
+
+#elif defined(MICRIUM)
+
+int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+        NetSecure_InitSeed(output, sz);
+    #endif
+    return 0;
+}
+
+#elif defined(MBED)
+
+/* write a real one !!!, just for testing board */
+int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    int i;
+    for (i = 0; i < sz; i++ )
+        output[i] = i;
+
+    return 0;
+}
+
+#elif defined(MICROCHIP_PIC32)
+
+#ifdef MICROCHIP_MPLAB_HARMONY
+    #define PIC32_SEED_COUNT _CP0_GET_COUNT
+#else
+    #if !defined(WOLFSSL_MICROCHIP_PIC32MZ)
+        #include <peripheral/timer.h>
+    #endif
+    #define PIC32_SEED_COUNT ReadCoreTimer
+#endif
+    #ifdef WOLFSSL_MIC32MZ_RNG
+        #include "xc.h"
+        int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+        {
+            int i ;
+            byte rnd[8] ;
+            word32 *rnd32 = (word32 *)rnd ;
+            word32 size = sz ;
+            byte* op = output ;
+
+            /* This part has to be replaced with better random seed */
+            RNGNUMGEN1 = ReadCoreTimer();
+            RNGPOLY1 = ReadCoreTimer();
+            RNGPOLY2 = ReadCoreTimer();
+            RNGNUMGEN2 = ReadCoreTimer();
+#ifdef DEBUG_WOLFSSL
+            printf("GenerateSeed::Seed=%08x, %08x\n", RNGNUMGEN1, RNGNUMGEN2) ;
+#endif
+            RNGCONbits.PLEN = 0x40;
+            RNGCONbits.PRNGEN = 1;
+            for(i=0; i<5; i++) { /* wait for RNGNUMGEN ready */
+                volatile int x ;
+                x = RNGNUMGEN1 ;
+                x = RNGNUMGEN2 ;
+            }
+            do {
+                rnd32[0] = RNGNUMGEN1;
+                rnd32[1] = RNGNUMGEN2;
+
+                for(i=0; i<8; i++, op++) {
+                    *op = rnd[i] ;
+                    size -- ;
+                    if(size==0)break ;
+                }
+            } while(size) ;
+            return 0;
+        }
+    #else  /* WOLFSSL_MIC32MZ_RNG */
+        /* uses the core timer, in nanoseconds to seed srand */
+        int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+        {
+            int i;
+            srand(PIC32_SEED_COUNT() * 25);
+
+            for (i = 0; i < sz; i++ ) {
+                output[i] = rand() % 256;
+                if ( (i % 8) == 7)
+                    srand(PIC32_SEED_COUNT() * 25);
+            }
+            return 0;
+        }
+    #endif /* WOLFSSL_MIC32MZ_RNG */
+
+#elif defined(FREESCALE_MQX)
+
+    #ifdef FREESCALE_K70_RNGA
+        /*
+         * wc_Generates a RNG seed using the Random Number Generator Accelerator
+         * on the Kinetis K70. Documentation located in Chapter 37 of
+         * K70 Sub-Family Reference Manual (see Note 3 in the README for link).
+         */
+        int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+        {
+            int i;
+
+            /* turn on RNGA module */
+            SIM_SCGC3 |= SIM_SCGC3_RNGA_MASK;
+
+            /* set SLP bit to 0 - "RNGA is not in sleep mode" */
+            RNG_CR &= ~RNG_CR_SLP_MASK;
+
+            /* set HA bit to 1 - "security violations masked" */
+            RNG_CR |= RNG_CR_HA_MASK;
+
+            /* set GO bit to 1 - "output register loaded with data" */
+            RNG_CR |= RNG_CR_GO_MASK;
+
+            for (i = 0; i < sz; i++) {
+
+                /* wait for RNG FIFO to be full */
+                while((RNG_SR & RNG_SR_OREG_LVL(0xF)) == 0) {}
+
+                /* get value */
+                output[i] = RNG_OR;
+            }
+
+            return 0;
+        }
+
+    #elif defined(FREESCALE_K53_RNGB)
+        /*
+         * wc_Generates a RNG seed using the Random Number Generator (RNGB)
+         * on the Kinetis K53. Documentation located in Chapter 33 of
+         * K53 Sub-Family Reference Manual (see note in the README for link).
+         */
+        int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+        {
+            int i;
+
+            /* turn on RNGB module */
+            SIM_SCGC3 |= SIM_SCGC3_RNGB_MASK;
+
+            /* reset RNGB */
+            RNG_CMD |= RNG_CMD_SR_MASK;
+
+            /* FIFO generate interrupt, return all zeros on underflow,
+             * set auto reseed */
+            RNG_CR |= (RNG_CR_FUFMOD_MASK | RNG_CR_AR_MASK);
+
+            /* gen seed, clear interrupts, clear errors */
+            RNG_CMD |= (RNG_CMD_GS_MASK | RNG_CMD_CI_MASK | RNG_CMD_CE_MASK);
+
+            /* wait for seeding to complete */
+            while ((RNG_SR & RNG_SR_SDN_MASK) == 0) {}
+
+            for (i = 0; i < sz; i++) {
+
+                /* wait for a word to be available from FIFO */
+                while((RNG_SR & RNG_SR_FIFO_LVL_MASK) == 0) {}
+
+                /* get value */
+                output[i] = RNG_OUT;
+            }
+
+            return 0;
+        }
+
+    #else
+        #warning "write a real random seed!!!!, just for testing now"
+
+        int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+        {
+            int i;
+            for (i = 0; i < sz; i++ )
+                output[i] = i;
+
+            return 0;
+        }
+    #endif /* FREESCALE_K70_RNGA */
+
+#elif defined(WOLFSSL_SAFERTOS) || defined(WOLFSSL_LEANPSK) \
+   || defined(WOLFSSL_IAR_ARM)  || defined(WOLFSSL_MDK_ARM) \
+   || defined(WOLFSSL_uITRON4)  || defined(WOLFSSL_uTKERNEL2)
+
+#warning "write a real random seed!!!!, just for testing now"
+
+int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    word32 i;
+    for (i = 0; i < sz; i++ )
+        output[i] = i;
+
+    (void)os;
+
+    return 0;
+}
+
+#elif defined(STM32F2_RNG)
+    #undef RNG
+    #include "stm32f2xx_rng.h"
+    #include "stm32f2xx_rcc.h"
+    /*
+     * wc_Generate a RNG seed using the hardware random number generator
+     * on the STM32F2. Documentation located in STM32F2xx Standard Peripheral
+     * Library document (See note in README).
+     */
+    int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+    {
+        int i;
+
+        /* enable RNG clock source */
+        RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE);
+
+        /* enable RNG peripheral */
+        RNG_Cmd(ENABLE);
+
+        for (i = 0; i < sz; i++) {
+            /* wait until RNG number is ready */
+            while(RNG_GetFlagStatus(RNG_FLAG_DRDY)== RESET) { }
+
+            /* get value */
+            output[i] = RNG_GetRandomNumber();
+        }
+
+        return 0;
+    }
+#elif defined(WOLFSSL_LPC43xx) || defined(WOLFSSL_STM32F2xx)
+
+    #warning "write a real random seed!!!!, just for testing now"
+
+    int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+    {
+        int i;
+
+        for (i = 0; i < sz; i++ )
+            output[i] = i;
+
+        return 0;
+    }
+
+#elif defined(WOLFSSL_TIRTOS)
+
+    #include <xdc/runtime/Timestamp.h>
+    #include <stdlib.h>
+    int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+    {
+        int i;
+        srand(xdc_runtime_Timestamp_get32());
+
+        for (i = 0; i < sz; i++ ) {
+            output[i] = rand() % 256;
+            if ((i % 8) == 7) {
+                srand(xdc_runtime_Timestamp_get32());
+            }
+        }
+
+        return 0;
+    }
+
+#elif defined(CUSTOM_RAND_GENERATE)
+
+   /* Implement your own random generation function
+    * word32 rand_gen(void);
+    * #define CUSTOM_RAND_GENERATE  rand_gen  */
+
+    int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+    {
+        word32 i;
+
+        (void)os;
+
+        for (i = 0; i < sz; i++ )
+            output[i] = CUSTOM_RAND_GENERATE();
+
+        return 0;
+    }
+
+#elif defined(NO_DEV_RANDOM)
+
+#error "you need to write an os specific wc_GenerateSeed() here"
+
+/*
+int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    return 0;
+}
+*/
+
+
+#else /* !USE_WINDOWS_API && !HAVE_RPT_SYS && !MICRIUM && !NO_DEV_RANDOM */
+
+/* may block */
+int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    int ret = 0;
+
+
+#if defined(HAVE_INTEL_RDGEN) && (defined(HAVE_HASHDRBG) || defined(NO_RC4))
+    wc_InitRng_IntelRD() ; /* set cpuid_flags if not yet */
+    if(IS_INTEL_RDSEED)
+         return wc_GenerateSeed_IntelRD(NULL, output, sz) ;
+#endif
+
+    os->fd = open("/dev/urandom",O_RDONLY);
+    if (os->fd == -1) {
+        /* may still have /dev/random */
+        os->fd = open("/dev/random",O_RDONLY);
+        if (os->fd == -1)
+            return OPEN_RAN_E;
+    }
+
+    while (sz) {
+        int len = (int)read(os->fd, output, sz);
+        if (len == -1) {
+            ret = READ_RAN_E;
+            break;
+        }
+
+        sz     -= len;
+        output += len;
+
+        if (sz) {
+#ifdef BLOCKING
+            sleep(0);             /* context switch */
+#else
+            ret = RAN_BLOCK_E;
+            break;
+#endif
+        }
+    }
+    close(os->fd);
+
+    return ret;
+}
+
+#endif /* USE_WINDOWS_API */
+#endif /* HAVE_FIPS */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/ripemd.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,355 @@
+/* ripemd.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef WOLFSSL_RIPEMD
+
+#include <wolfssl/wolfcrypt/ripemd.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* WOLFSSL_HAVE_MIN */
+
+void wc_InitRipeMd(RipeMd* ripemd)
+{
+    ripemd->digest[0] = 0x67452301L;
+    ripemd->digest[1] = 0xEFCDAB89L;
+    ripemd->digest[2] = 0x98BADCFEL;
+    ripemd->digest[3] = 0x10325476L;
+    ripemd->digest[4] = 0xC3D2E1F0L;
+
+    ripemd->buffLen = 0;
+    ripemd->loLen   = 0;
+    ripemd->hiLen   = 0;
+}
+
+
+/* for all */
+#define F(x, y, z)    (x ^ y ^ z) 
+#define G(x, y, z)    (z ^ (x & (y^z)))
+#define H(x, y, z)    (z ^ (x | ~y))
+#define I(x, y, z)    (y ^ (z & (x^y)))
+#define J(x, y, z)    (x ^ (y | ~z))
+
+#define k0 0
+#define k1 0x5a827999
+#define k2 0x6ed9eba1
+#define k3 0x8f1bbcdc
+#define k4 0xa953fd4e
+#define k5 0x50a28be6
+#define k6 0x5c4dd124
+#define k7 0x6d703ef3
+#define k8 0x7a6d76e9
+#define k9 0
+
+/* for 160 and 320 */
+#define Subround(f, a, b, c, d, e, x, s, k) \
+    a += f(b, c, d) + x + k;\
+    a = rotlFixed((word32)a, s) + e;\
+    c = rotlFixed((word32)c, 10U)
+
+static void Transform(RipeMd* ripemd)
+{
+    word32 a1, b1, c1, d1, e1, a2, b2, c2, d2, e2;
+    a1 = a2 = ripemd->digest[0];
+    b1 = b2 = ripemd->digest[1];
+    c1 = c2 = ripemd->digest[2];
+    d1 = d2 = ripemd->digest[3];
+    e1 = e2 = ripemd->digest[4];
+
+    Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[ 0], 11, k0);
+    Subround(F, e1, a1, b1, c1, d1, ripemd->buffer[ 1], 14, k0);
+    Subround(F, d1, e1, a1, b1, c1, ripemd->buffer[ 2], 15, k0);
+    Subround(F, c1, d1, e1, a1, b1, ripemd->buffer[ 3], 12, k0);
+    Subround(F, b1, c1, d1, e1, a1, ripemd->buffer[ 4],  5, k0);
+    Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[ 5],  8, k0);
+    Subround(F, e1, a1, b1, c1, d1, ripemd->buffer[ 6],  7, k0);
+    Subround(F, d1, e1, a1, b1, c1, ripemd->buffer[ 7],  9, k0);
+    Subround(F, c1, d1, e1, a1, b1, ripemd->buffer[ 8], 11, k0);
+    Subround(F, b1, c1, d1, e1, a1, ripemd->buffer[ 9], 13, k0);
+    Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[10], 14, k0);
+    Subround(F, e1, a1, b1, c1, d1, ripemd->buffer[11], 15, k0);
+    Subround(F, d1, e1, a1, b1, c1, ripemd->buffer[12],  6, k0);
+    Subround(F, c1, d1, e1, a1, b1, ripemd->buffer[13],  7, k0);
+    Subround(F, b1, c1, d1, e1, a1, ripemd->buffer[14],  9, k0);
+    Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[15],  8, k0);
+
+    Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 7],  7, k1);
+    Subround(G, d1, e1, a1, b1, c1, ripemd->buffer[ 4],  6, k1);
+    Subround(G, c1, d1, e1, a1, b1, ripemd->buffer[13],  8, k1);
+    Subround(G, b1, c1, d1, e1, a1, ripemd->buffer[ 1], 13, k1);
+    Subround(G, a1, b1, c1, d1, e1, ripemd->buffer[10], 11, k1);
+    Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 6],  9, k1);
+    Subround(G, d1, e1, a1, b1, c1, ripemd->buffer[15],  7, k1);
+    Subround(G, c1, d1, e1, a1, b1, ripemd->buffer[ 3], 15, k1);
+    Subround(G, b1, c1, d1, e1, a1, ripemd->buffer[12],  7, k1);
+    Subround(G, a1, b1, c1, d1, e1, ripemd->buffer[ 0], 12, k1);
+    Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 9], 15, k1);
+    Subround(G, d1, e1, a1, b1, c1, ripemd->buffer[ 5],  9, k1);
+    Subround(G, c1, d1, e1, a1, b1, ripemd->buffer[ 2], 11, k1);
+    Subround(G, b1, c1, d1, e1, a1, ripemd->buffer[14],  7, k1);
+    Subround(G, a1, b1, c1, d1, e1, ripemd->buffer[11], 13, k1);
+    Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 8], 12, k1);
+
+    Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[ 3], 11, k2);
+    Subround(H, c1, d1, e1, a1, b1, ripemd->buffer[10], 13, k2);
+    Subround(H, b1, c1, d1, e1, a1, ripemd->buffer[14],  6, k2);
+    Subround(H, a1, b1, c1, d1, e1, ripemd->buffer[ 4],  7, k2);
+    Subround(H, e1, a1, b1, c1, d1, ripemd->buffer[ 9], 14, k2);
+    Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[15],  9, k2);
+    Subround(H, c1, d1, e1, a1, b1, ripemd->buffer[ 8], 13, k2);
+    Subround(H, b1, c1, d1, e1, a1, ripemd->buffer[ 1], 15, k2);
+    Subround(H, a1, b1, c1, d1, e1, ripemd->buffer[ 2], 14, k2);
+    Subround(H, e1, a1, b1, c1, d1, ripemd->buffer[ 7],  8, k2);
+    Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[ 0], 13, k2);
+    Subround(H, c1, d1, e1, a1, b1, ripemd->buffer[ 6],  6, k2);
+    Subround(H, b1, c1, d1, e1, a1, ripemd->buffer[13],  5, k2);
+    Subround(H, a1, b1, c1, d1, e1, ripemd->buffer[11], 12, k2);
+    Subround(H, e1, a1, b1, c1, d1, ripemd->buffer[ 5],  7, k2);
+    Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[12],  5, k2);
+
+    Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 1], 11, k3);
+    Subround(I, b1, c1, d1, e1, a1, ripemd->buffer[ 9], 12, k3);
+    Subround(I, a1, b1, c1, d1, e1, ripemd->buffer[11], 14, k3);
+    Subround(I, e1, a1, b1, c1, d1, ripemd->buffer[10], 15, k3);
+    Subround(I, d1, e1, a1, b1, c1, ripemd->buffer[ 0], 14, k3);
+    Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 8], 15, k3);
+    Subround(I, b1, c1, d1, e1, a1, ripemd->buffer[12],  9, k3);
+    Subround(I, a1, b1, c1, d1, e1, ripemd->buffer[ 4],  8, k3);
+    Subround(I, e1, a1, b1, c1, d1, ripemd->buffer[13],  9, k3);
+    Subround(I, d1, e1, a1, b1, c1, ripemd->buffer[ 3], 14, k3);
+    Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 7],  5, k3);
+    Subround(I, b1, c1, d1, e1, a1, ripemd->buffer[15],  6, k3);
+    Subround(I, a1, b1, c1, d1, e1, ripemd->buffer[14],  8, k3);
+    Subround(I, e1, a1, b1, c1, d1, ripemd->buffer[ 5],  6, k3);
+    Subround(I, d1, e1, a1, b1, c1, ripemd->buffer[ 6],  5, k3);
+    Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 2], 12, k3);
+
+    Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[ 4],  9, k4);
+    Subround(J, a1, b1, c1, d1, e1, ripemd->buffer[ 0], 15, k4);
+    Subround(J, e1, a1, b1, c1, d1, ripemd->buffer[ 5],  5, k4);
+    Subround(J, d1, e1, a1, b1, c1, ripemd->buffer[ 9], 11, k4);
+    Subround(J, c1, d1, e1, a1, b1, ripemd->buffer[ 7],  6, k4);
+    Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[12],  8, k4);
+    Subround(J, a1, b1, c1, d1, e1, ripemd->buffer[ 2], 13, k4);
+    Subround(J, e1, a1, b1, c1, d1, ripemd->buffer[10], 12, k4);
+    Subround(J, d1, e1, a1, b1, c1, ripemd->buffer[14],  5, k4);
+    Subround(J, c1, d1, e1, a1, b1, ripemd->buffer[ 1], 12, k4);
+    Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[ 3], 13, k4);
+    Subround(J, a1, b1, c1, d1, e1, ripemd->buffer[ 8], 14, k4);
+    Subround(J, e1, a1, b1, c1, d1, ripemd->buffer[11], 11, k4);
+    Subround(J, d1, e1, a1, b1, c1, ripemd->buffer[ 6],  8, k4);
+    Subround(J, c1, d1, e1, a1, b1, ripemd->buffer[15],  5, k4);
+    Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[13],  6, k4);
+
+    Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[ 5],  8, k5);
+    Subround(J, e2, a2, b2, c2, d2, ripemd->buffer[14],  9, k5);
+    Subround(J, d2, e2, a2, b2, c2, ripemd->buffer[ 7],  9, k5);
+    Subround(J, c2, d2, e2, a2, b2, ripemd->buffer[ 0], 11, k5);
+    Subround(J, b2, c2, d2, e2, a2, ripemd->buffer[ 9], 13, k5);
+    Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[ 2], 15, k5);
+    Subround(J, e2, a2, b2, c2, d2, ripemd->buffer[11], 15, k5);
+    Subround(J, d2, e2, a2, b2, c2, ripemd->buffer[ 4],  5, k5);
+    Subround(J, c2, d2, e2, a2, b2, ripemd->buffer[13],  7, k5);
+    Subround(J, b2, c2, d2, e2, a2, ripemd->buffer[ 6],  7, k5);
+    Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[15],  8, k5);
+    Subround(J, e2, a2, b2, c2, d2, ripemd->buffer[ 8], 11, k5);
+    Subround(J, d2, e2, a2, b2, c2, ripemd->buffer[ 1], 14, k5);
+    Subround(J, c2, d2, e2, a2, b2, ripemd->buffer[10], 14, k5);
+    Subround(J, b2, c2, d2, e2, a2, ripemd->buffer[ 3], 12, k5);
+    Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[12],  6, k5);
+
+    Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[ 6],  9, k6); 
+    Subround(I, d2, e2, a2, b2, c2, ripemd->buffer[11], 13, k6);
+    Subround(I, c2, d2, e2, a2, b2, ripemd->buffer[ 3], 15, k6);
+    Subround(I, b2, c2, d2, e2, a2, ripemd->buffer[ 7],  7, k6);
+    Subround(I, a2, b2, c2, d2, e2, ripemd->buffer[ 0], 12, k6);
+    Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[13],  8, k6);
+    Subround(I, d2, e2, a2, b2, c2, ripemd->buffer[ 5],  9, k6);
+    Subround(I, c2, d2, e2, a2, b2, ripemd->buffer[10], 11, k6);
+    Subround(I, b2, c2, d2, e2, a2, ripemd->buffer[14],  7, k6);
+    Subround(I, a2, b2, c2, d2, e2, ripemd->buffer[15],  7, k6);
+    Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[ 8], 12, k6);
+    Subround(I, d2, e2, a2, b2, c2, ripemd->buffer[12],  7, k6);
+    Subround(I, c2, d2, e2, a2, b2, ripemd->buffer[ 4],  6, k6);
+    Subround(I, b2, c2, d2, e2, a2, ripemd->buffer[ 9], 15, k6);
+    Subround(I, a2, b2, c2, d2, e2, ripemd->buffer[ 1], 13, k6);
+    Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[ 2], 11, k6);
+
+    Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[15],  9, k7);
+    Subround(H, c2, d2, e2, a2, b2, ripemd->buffer[ 5],  7, k7);
+    Subround(H, b2, c2, d2, e2, a2, ripemd->buffer[ 1], 15, k7);
+    Subround(H, a2, b2, c2, d2, e2, ripemd->buffer[ 3], 11, k7);
+    Subround(H, e2, a2, b2, c2, d2, ripemd->buffer[ 7],  8, k7);
+    Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[14],  6, k7);
+    Subround(H, c2, d2, e2, a2, b2, ripemd->buffer[ 6],  6, k7);
+    Subround(H, b2, c2, d2, e2, a2, ripemd->buffer[ 9], 14, k7);
+    Subround(H, a2, b2, c2, d2, e2, ripemd->buffer[11], 12, k7);
+    Subround(H, e2, a2, b2, c2, d2, ripemd->buffer[ 8], 13, k7);
+    Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[12],  5, k7);
+    Subround(H, c2, d2, e2, a2, b2, ripemd->buffer[ 2], 14, k7);
+    Subround(H, b2, c2, d2, e2, a2, ripemd->buffer[10], 13, k7);
+    Subround(H, a2, b2, c2, d2, e2, ripemd->buffer[ 0], 13, k7);
+    Subround(H, e2, a2, b2, c2, d2, ripemd->buffer[ 4],  7, k7);
+    Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[13],  5, k7);
+
+    Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[ 8], 15, k8);
+    Subround(G, b2, c2, d2, e2, a2, ripemd->buffer[ 6],  5, k8);
+    Subround(G, a2, b2, c2, d2, e2, ripemd->buffer[ 4],  8, k8);
+    Subround(G, e2, a2, b2, c2, d2, ripemd->buffer[ 1], 11, k8);
+    Subround(G, d2, e2, a2, b2, c2, ripemd->buffer[ 3], 14, k8);
+    Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[11], 14, k8);
+    Subround(G, b2, c2, d2, e2, a2, ripemd->buffer[15],  6, k8);
+    Subround(G, a2, b2, c2, d2, e2, ripemd->buffer[ 0], 14, k8);
+    Subround(G, e2, a2, b2, c2, d2, ripemd->buffer[ 5],  6, k8);
+    Subround(G, d2, e2, a2, b2, c2, ripemd->buffer[12],  9, k8);
+    Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[ 2], 12, k8);
+    Subround(G, b2, c2, d2, e2, a2, ripemd->buffer[13],  9, k8);
+    Subround(G, a2, b2, c2, d2, e2, ripemd->buffer[ 9], 12, k8);
+    Subround(G, e2, a2, b2, c2, d2, ripemd->buffer[ 7],  5, k8);
+    Subround(G, d2, e2, a2, b2, c2, ripemd->buffer[10], 15, k8);
+    Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[14],  8, k8);
+
+    Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[12],  8, k9);
+    Subround(F, a2, b2, c2, d2, e2, ripemd->buffer[15],  5, k9);
+    Subround(F, e2, a2, b2, c2, d2, ripemd->buffer[10], 12, k9);
+    Subround(F, d2, e2, a2, b2, c2, ripemd->buffer[ 4],  9, k9);
+    Subround(F, c2, d2, e2, a2, b2, ripemd->buffer[ 1], 12, k9);
+    Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[ 5],  5, k9);
+    Subround(F, a2, b2, c2, d2, e2, ripemd->buffer[ 8], 14, k9);
+    Subround(F, e2, a2, b2, c2, d2, ripemd->buffer[ 7],  6, k9);
+    Subround(F, d2, e2, a2, b2, c2, ripemd->buffer[ 6],  8, k9);
+    Subround(F, c2, d2, e2, a2, b2, ripemd->buffer[ 2], 13, k9);
+    Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[13],  6, k9);
+    Subround(F, a2, b2, c2, d2, e2, ripemd->buffer[14],  5, k9);
+    Subround(F, e2, a2, b2, c2, d2, ripemd->buffer[ 0], 15, k9);
+    Subround(F, d2, e2, a2, b2, c2, ripemd->buffer[ 3], 13, k9);
+    Subround(F, c2, d2, e2, a2, b2, ripemd->buffer[ 9], 11, k9);
+    Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[11], 11, k9);
+
+    c1                = ripemd->digest[1] + c1 + d2;
+    ripemd->digest[1] = ripemd->digest[2] + d1 + e2;
+    ripemd->digest[2] = ripemd->digest[3] + e1 + a2;
+    ripemd->digest[3] = ripemd->digest[4] + a1 + b2;
+    ripemd->digest[4] = ripemd->digest[0] + b1 + c2;
+    ripemd->digest[0] = c1;
+}
+
+
+static INLINE void AddLength(RipeMd* ripemd, word32 len)
+{
+    word32 tmp = ripemd->loLen;
+    if ( (ripemd->loLen += len) < tmp)
+        ripemd->hiLen++;                       /* carry low to high */
+}
+
+
+void wc_RipeMdUpdate(RipeMd* ripemd, const byte* data, word32 len)
+{
+    /* do block size increments */
+    byte* local = (byte*)ripemd->buffer;
+
+    while (len) {
+        word32 add = min(len, RIPEMD_BLOCK_SIZE - ripemd->buffLen);
+        XMEMCPY(&local[ripemd->buffLen], data, add);
+
+        ripemd->buffLen += add;
+        data         += add;
+        len          -= add;
+
+        if (ripemd->buffLen == RIPEMD_BLOCK_SIZE) {
+            #ifdef BIG_ENDIAN_ORDER
+                ByteReverseWords(ripemd->buffer, ripemd->buffer,
+                                 RIPEMD_BLOCK_SIZE);
+            #endif
+            Transform(ripemd);
+            AddLength(ripemd, RIPEMD_BLOCK_SIZE);
+            ripemd->buffLen = 0;
+        }
+    }
+}
+
+
+void wc_RipeMdFinal(RipeMd* ripemd, byte* hash)
+{
+    byte* local = (byte*)ripemd->buffer;
+
+    AddLength(ripemd, ripemd->buffLen);               /* before adding pads */
+
+    local[ripemd->buffLen++] = 0x80;  /* add 1 */
+
+    /* pad with zeros */
+    if (ripemd->buffLen > RIPEMD_PAD_SIZE) {
+        XMEMSET(&local[ripemd->buffLen], 0, RIPEMD_BLOCK_SIZE - ripemd->buffLen);
+        ripemd->buffLen += RIPEMD_BLOCK_SIZE - ripemd->buffLen;
+
+        #ifdef BIG_ENDIAN_ORDER
+            ByteReverseWords(ripemd->buffer, ripemd->buffer, RIPEMD_BLOCK_SIZE);
+        #endif
+        Transform(ripemd);
+        ripemd->buffLen = 0;
+    }
+    XMEMSET(&local[ripemd->buffLen], 0, RIPEMD_PAD_SIZE - ripemd->buffLen);
+   
+    /* put lengths in bits */
+    ripemd->loLen = ripemd->loLen << 3;
+    ripemd->hiLen = (ripemd->loLen >> (8*sizeof(ripemd->loLen) - 3)) + 
+                 (ripemd->hiLen << 3);
+
+    /* store lengths */
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseWords(ripemd->buffer, ripemd->buffer, RIPEMD_BLOCK_SIZE);
+    #endif
+    /* ! length ordering dependent on digest endian type ! */
+    XMEMCPY(&local[RIPEMD_PAD_SIZE], &ripemd->loLen, sizeof(word32));
+    XMEMCPY(&local[RIPEMD_PAD_SIZE + sizeof(word32)], &ripemd->hiLen, 
+           sizeof(word32));
+
+    Transform(ripemd);
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseWords(ripemd->digest, ripemd->digest, RIPEMD_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, ripemd->digest, RIPEMD_DIGEST_SIZE);
+
+    wc_InitRipeMd(ripemd);  /* reset state */
+}
+
+
+#endif /* WOLFSSL_RIPEMD */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/rsa.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,973 @@
+/* rsa.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifndef NO_RSA
+
+#include <wolfssl/wolfcrypt/rsa.h>
+
+#ifdef HAVE_FIPS
+int  wc_InitRsaKey(RsaKey* key, void* ptr)
+{
+    return InitRsaKey_fips(key, ptr);
+}
+
+
+int  wc_FreeRsaKey(RsaKey* key)
+{
+    return FreeRsaKey_fips(key);
+}
+
+
+int  wc_RsaPublicEncrypt(const byte* in, word32 inLen, byte* out,
+                                 word32 outLen, RsaKey* key, RNG* rng)
+{
+    return RsaPublicEncrypt_fips(in, inLen, out, outLen, key, rng);
+}
+
+
+int  wc_RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out,
+                                        RsaKey* key)
+{
+    return RsaPrivateDecryptInline_fips(in, inLen, out, key);
+}
+
+
+int  wc_RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out,
+                                  word32 outLen, RsaKey* key)
+{
+    return RsaPrivateDecrypt_fips(in, inLen, out, outLen, key);
+}
+
+
+int  wc_RsaSSL_Sign(const byte* in, word32 inLen, byte* out,
+                            word32 outLen, RsaKey* key, RNG* rng)
+{
+    return RsaSSL_Sign_fips(in, inLen, out, outLen, key, rng);
+}
+
+
+int  wc_RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out, RsaKey* key)
+{
+    return RsaSSL_VerifyInline_fips(in, inLen, out, key);
+}
+
+
+int  wc_RsaSSL_Verify(const byte* in, word32 inLen, byte* out,
+                              word32 outLen, RsaKey* key)
+{
+    return RsaSSL_Verify_fips(in, inLen, out, outLen, key);
+}
+
+
+int  wc_RsaEncryptSize(RsaKey* key)
+{
+    return RsaEncryptSize_fips(key);
+}
+
+
+int wc_RsaFlattenPublicKey(RsaKey* key, byte* a, word32* aSz, byte* b,
+                           word32* bSz)
+{
+    /* not specified as fips so not needing _fips */
+    return RsaFlattenPublicKey(key, a, aSz, b, bSz);
+}
+#ifdef WOLFSSL_KEY_GEN
+    int wc_MakeRsaKey(RsaKey* key, int size, long e, RNG* rng)
+    {
+        return MakeRsaKey(key, size, e, rng);
+    }
+#endif
+
+
+#ifdef HAVE_CAVIUM
+    int  wc_RsaInitCavium(RsaKey* key, int i)
+    {
+        return RsaInitCavium(key, i);
+    }
+
+
+    void wc_RsaFreeCavium(RsaKey* key)
+    {
+        RsaFreeCavium(key);
+    }
+#endif
+
+/* these are functions in asn and are routed to wolfssl/wolfcrypt/asn.c
+* wc_RsaPrivateKeyDecode
+* wc_RsaPublicKeyDecode
+*/
+
+#else /* else build without fips */
+#include <wolfssl/wolfcrypt/random.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/logging.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+#ifdef SHOW_GEN
+    #ifdef FREESCALE_MQX
+        #include <fio.h>
+    #else
+        #include <stdio.h>
+    #endif
+#endif
+
+#ifdef HAVE_CAVIUM
+    static int  InitCaviumRsaKey(RsaKey* key, void* heap);
+    static int  FreeCaviumRsaKey(RsaKey* key);
+    static int  CaviumRsaPublicEncrypt(const byte* in, word32 inLen, byte* out,
+                                       word32 outLen, RsaKey* key);
+    static int  CaviumRsaPrivateDecrypt(const byte* in, word32 inLen, byte* out,
+                                        word32 outLen, RsaKey* key);
+    static int  CaviumRsaSSL_Sign(const byte* in, word32 inLen, byte* out,
+                                  word32 outLen, RsaKey* key);
+    static int  CaviumRsaSSL_Verify(const byte* in, word32 inLen, byte* out,
+                                    word32 outLen, RsaKey* key);
+#endif
+
+enum {
+    RSA_PUBLIC_ENCRYPT  = 0,
+    RSA_PUBLIC_DECRYPT  = 1,
+    RSA_PRIVATE_ENCRYPT = 2,
+    RSA_PRIVATE_DECRYPT = 3,
+
+    RSA_BLOCK_TYPE_1 = 1,
+    RSA_BLOCK_TYPE_2 = 2,
+
+    RSA_MIN_SIZE = 512,
+    RSA_MAX_SIZE = 4096,
+
+    RSA_MIN_PAD_SZ   = 11      /* seperator + 0 + pad value + 8 pads */
+};
+
+
+int wc_InitRsaKey(RsaKey* key, void* heap)
+{
+#ifdef HAVE_CAVIUM
+    if (key->magic == WOLFSSL_RSA_CAVIUM_MAGIC)
+        return InitCaviumRsaKey(key, heap);
+#endif
+
+    key->type = -1;  /* haven't decided yet */
+    key->heap = heap;
+
+/* TomsFastMath doesn't use memory allocation */
+#ifndef USE_FAST_MATH
+    key->n.dp = key->e.dp = 0;  /* public  alloc parts */
+
+    key->d.dp = key->p.dp  = 0;  /* private alloc parts */
+    key->q.dp = key->dP.dp = 0;  
+    key->u.dp = key->dQ.dp = 0;
+#else
+    mp_init(&key->n);
+    mp_init(&key->e);
+    mp_init(&key->d);
+    mp_init(&key->p);
+    mp_init(&key->q);
+    mp_init(&key->dP);
+    mp_init(&key->dQ);
+    mp_init(&key->u);
+#endif
+
+    return 0;
+}
+
+
+int wc_FreeRsaKey(RsaKey* key)
+{
+    (void)key;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == WOLFSSL_RSA_CAVIUM_MAGIC)
+        return FreeCaviumRsaKey(key);
+#endif
+
+/* TomsFastMath doesn't use memory allocation */
+#ifndef USE_FAST_MATH
+    if (key->type == RSA_PRIVATE) {
+        mp_clear(&key->u);
+        mp_clear(&key->dQ);
+        mp_clear(&key->dP);
+        mp_clear(&key->q);
+        mp_clear(&key->p);
+        mp_clear(&key->d);
+    }
+    mp_clear(&key->e);
+    mp_clear(&key->n);
+#endif
+
+    return 0;
+}
+
+static int wc_RsaPad(const byte* input, word32 inputLen, byte* pkcsBlock,
+                   word32 pkcsBlockLen, byte padValue, RNG* rng)
+{
+    if (inputLen == 0)
+        return 0;
+
+    pkcsBlock[0] = 0x0;       /* set first byte to zero and advance */
+    pkcsBlock++; pkcsBlockLen--;
+    pkcsBlock[0] = padValue;  /* insert padValue */
+
+    if (padValue == RSA_BLOCK_TYPE_1)
+        /* pad with 0xff bytes */
+        XMEMSET(&pkcsBlock[1], 0xFF, pkcsBlockLen - inputLen - 2);
+    else {
+        /* pad with non-zero random bytes */
+        word32 padLen = pkcsBlockLen - inputLen - 1, i;
+        int    ret    = wc_RNG_GenerateBlock(rng, &pkcsBlock[1], padLen);
+
+        if (ret != 0)
+            return ret;
+
+        /* remove zeros */
+        for (i = 1; i < padLen; i++)
+            if (pkcsBlock[i] == 0) pkcsBlock[i] = 0x01;
+    }
+
+    pkcsBlock[pkcsBlockLen-inputLen-1] = 0;     /* separator */
+    XMEMCPY(pkcsBlock+pkcsBlockLen-inputLen, input, inputLen);
+
+    return 0;
+}
+
+
+/* UnPad plaintext, set start to *output, return length of plaintext,
+ * < 0 on error */
+static int RsaUnPad(const byte *pkcsBlock, unsigned int pkcsBlockLen,
+                       byte **output, byte padValue)
+{
+    word32 maxOutputLen = (pkcsBlockLen > 10) ? (pkcsBlockLen - 10) : 0,
+           invalid = 0,
+           i = 1,
+           outputLen;
+
+    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)) {
+        WOLFSSL_MSG("RsaUnPad error, bad formatting");
+        return RSA_PAD_E;
+    }
+
+    outputLen = pkcsBlockLen - i;
+    invalid = (outputLen > maxOutputLen) || invalid;
+
+    if (invalid) {
+        WOLFSSL_MSG("RsaUnPad error, bad formatting");
+        return RSA_PAD_E;
+    }
+
+    *output = (byte *)(pkcsBlock + i);
+    return outputLen;
+}
+
+
+static int wc_RsaFunction(const byte* in, word32 inLen, byte* out,
+                          word32* outLen, int type, RsaKey* key)
+{
+    #define ERROR_OUT(x) { ret = (x); goto done;}
+
+    mp_int tmp;
+    int    ret = 0;
+    word32 keyLen, len;
+
+    if (mp_init(&tmp) != MP_OKAY)
+        return MP_INIT_E;
+
+    if (mp_read_unsigned_bin(&tmp, (byte*)in, inLen) != MP_OKAY)
+        ERROR_OUT(MP_READ_E);
+
+    if (type == RSA_PRIVATE_DECRYPT || type == RSA_PRIVATE_ENCRYPT) {
+        #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);
+        #else
+            #define INNER_ERROR_OUT(x) { ret = (x); goto inner_done; }
+
+            mp_int tmpa, tmpb;
+
+            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);
+            }
+
+            /* tmpa = tmp^dP mod p */
+            if (mp_exptmod(&tmp, &key->dP, &key->p, &tmpa) != MP_OKAY)
+                INNER_ERROR_OUT(MP_EXPTMOD_E);
+
+            /* tmpb = tmp^dQ mod q */
+            if (mp_exptmod(&tmp, &key->dQ, &key->q, &tmpb) != MP_OKAY)
+                INNER_ERROR_OUT(MP_EXPTMOD_E);
+
+            /* tmp = (tmpa - tmpb) * qInv (mod p) */
+            if (mp_sub(&tmpa, &tmpb, &tmp) != MP_OKAY)
+                INNER_ERROR_OUT(MP_SUB_E);
+
+            if (mp_mulmod(&tmp, &key->u, &key->p, &tmp) != MP_OKAY)
+                INNER_ERROR_OUT(MP_MULMOD_E);
+
+            /* tmp = tmpb + q * tmp */
+            if (mp_mul(&tmp, &key->q, &tmp) != MP_OKAY)
+                INNER_ERROR_OUT(MP_MUL_E);
+
+            if (mp_add(&tmp, &tmpb, &tmp) != MP_OKAY)
+                INNER_ERROR_OUT(MP_ADD_E);
+
+        inner_done:
+            mp_clear(&tmpa);
+            mp_clear(&tmpb);
+
+            if (ret != 0) return ret;
+
+        #endif   /* RSA_LOW_MEM */
+    }
+    else if (type == RSA_PUBLIC_ENCRYPT || type == RSA_PUBLIC_DECRYPT) {
+        if (mp_exptmod(&tmp, &key->e, &key->n, &tmp) != MP_OKAY)
+            ERROR_OUT(MP_EXPTMOD_E);
+    }
+    else
+        ERROR_OUT(RSA_WRONG_TYPE_E);
+
+    keyLen = mp_unsigned_bin_size(&key->n);
+    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++;
+    }
+
+    *outLen = keyLen;
+
+    /* convert */
+    if (mp_to_unsigned_bin(&tmp, out) != MP_OKAY)
+        ERROR_OUT(MP_TO_E);
+
+done:
+    mp_clear(&tmp);
+    if (ret == MP_EXPTMOD_E) {
+        WOLFSSL_MSG("RSA_FUNCTION MP_EXPTMOD_E: memory/config problem");
+    }
+    return ret;
+}
+
+
+int wc_RsaPublicEncrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
+                     RsaKey* key, RNG* rng)
+{
+    int sz, ret;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == WOLFSSL_RSA_CAVIUM_MAGIC)
+        return CaviumRsaPublicEncrypt(in, inLen, out, outLen, key);
+#endif
+
+    sz = mp_unsigned_bin_size(&key->n);
+    if (sz > (int)outLen)
+        return RSA_BUFFER_E;
+
+    if (inLen > (word32)(sz - RSA_MIN_PAD_SZ))
+        return RSA_BUFFER_E;
+
+    ret = wc_RsaPad(in, inLen, out, sz, RSA_BLOCK_TYPE_2, rng);
+    if (ret != 0)
+        return ret;
+
+    if ((ret = wc_RsaFunction(out, sz, out, &outLen,
+                              RSA_PUBLIC_ENCRYPT, key)) < 0)
+        sz = ret;
+
+    return sz;
+}
+
+
+int wc_RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out, RsaKey* key)
+{
+    int ret;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == WOLFSSL_RSA_CAVIUM_MAGIC) {
+        ret = CaviumRsaPrivateDecrypt(in, inLen, in, inLen, key);
+        if (ret > 0)
+            *out = in;
+        return ret;
+    }
+#endif
+
+    if ((ret = wc_RsaFunction(in, inLen, in, &inLen, RSA_PRIVATE_DECRYPT, key))
+            < 0) {
+        return ret;
+    }
+ 
+    return RsaUnPad(in, inLen, out, RSA_BLOCK_TYPE_2);
+}
+
+
+int wc_RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
+                     RsaKey* key)
+{
+    int plainLen;
+    byte*  tmp;
+    byte*  pad = 0;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == WOLFSSL_RSA_CAVIUM_MAGIC)
+        return CaviumRsaPrivateDecrypt(in, inLen, out, outLen, key);
+#endif
+
+    tmp = (byte*)XMALLOC(inLen, key->heap, DYNAMIC_TYPE_RSA);
+    if (tmp == NULL) {
+        return MEMORY_E;
+    }
+
+    XMEMCPY(tmp, in, inLen);
+
+    if ( (plainLen = wc_RsaPrivateDecryptInline(tmp, inLen, &pad, key) ) < 0) {
+        XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+        return plainLen;
+    }
+    if (plainLen > (int)outLen)
+        plainLen = BAD_FUNC_ARG;
+    else
+        XMEMCPY(out, pad, plainLen);
+
+    ForceZero(tmp, inLen);
+    XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+
+    return plainLen;
+}
+
+
+/* for Rsa Verify */
+int wc_RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out, RsaKey* key)
+{
+    int ret;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == WOLFSSL_RSA_CAVIUM_MAGIC) {
+        ret = CaviumRsaSSL_Verify(in, inLen, in, inLen, key);
+        if (ret > 0)
+            *out = in;
+        return ret;
+    }
+#endif
+
+    if ((ret = wc_RsaFunction(in, inLen, in, &inLen, RSA_PUBLIC_DECRYPT, key))
+            < 0) {
+        return ret;
+    }
+  
+    return RsaUnPad(in, inLen, out, RSA_BLOCK_TYPE_1);
+}
+
+
+int wc_RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen,
+                     RsaKey* key)
+{
+    int plainLen;
+    byte*  tmp;
+    byte*  pad = 0;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == WOLFSSL_RSA_CAVIUM_MAGIC)
+        return CaviumRsaSSL_Verify(in, inLen, out, outLen, key);
+#endif
+
+    tmp = (byte*)XMALLOC(inLen, key->heap, DYNAMIC_TYPE_RSA);
+    if (tmp == NULL) {
+        return MEMORY_E;
+    }
+
+    XMEMCPY(tmp, in, inLen);
+
+    if ( (plainLen = wc_RsaSSL_VerifyInline(tmp, inLen, &pad, key) ) < 0) {
+        XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+        return plainLen;
+    }
+
+    if (plainLen > (int)outLen)
+        plainLen = BAD_FUNC_ARG;
+    else
+        XMEMCPY(out, pad, plainLen);
+
+    ForceZero(tmp, inLen);
+    XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+
+    return plainLen;
+}
+
+
+/* for Rsa Sign */
+int wc_RsaSSL_Sign(const byte* in, word32 inLen, byte* out, word32 outLen,
+                      RsaKey* key, RNG* rng)
+{
+    int sz, ret;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == WOLFSSL_RSA_CAVIUM_MAGIC)
+        return CaviumRsaSSL_Sign(in, inLen, out, outLen, key);
+#endif
+
+    sz = mp_unsigned_bin_size(&key->n);
+    if (sz > (int)outLen)
+        return RSA_BUFFER_E;
+
+    if (inLen > (word32)(sz - RSA_MIN_PAD_SZ))
+        return RSA_BUFFER_E;
+
+    ret = wc_RsaPad(in, inLen, out, sz, RSA_BLOCK_TYPE_1, rng);
+    if (ret != 0)
+        return ret;
+
+    if ((ret = wc_RsaFunction(out, sz, out, &outLen,
+                              RSA_PRIVATE_ENCRYPT,key)) < 0)
+        sz = ret;
+    
+    return sz;
+}
+
+
+int wc_RsaEncryptSize(RsaKey* key)
+{
+#ifdef HAVE_CAVIUM
+    if (key->magic == WOLFSSL_RSA_CAVIUM_MAGIC)
+        return key->c_nSz;
+#endif
+    return mp_unsigned_bin_size(&key->n);
+}
+
+/* flatten RsaKey structure into individual elements (e, n) */
+int wc_RsaFlattenPublicKey(RsaKey* key, byte* e, word32* eSz, byte* n,
+                           word32* nSz)
+{
+    int sz, ret;
+
+    if (key == NULL || e == NULL || eSz == NULL || n == NULL || nSz == NULL)
+       return BAD_FUNC_ARG;
+
+    sz = mp_unsigned_bin_size(&key->e);
+    if ((word32)sz > *nSz)
+        return RSA_BUFFER_E;
+    ret = mp_to_unsigned_bin(&key->e, e);
+    if (ret != MP_OKAY)
+        return ret;
+    *eSz = (word32)sz;
+
+    sz = mp_unsigned_bin_size(&key->n);
+    if ((word32)sz > *nSz)
+        return RSA_BUFFER_E;
+    ret = mp_to_unsigned_bin(&key->n, n);
+    if (ret != MP_OKAY)
+        return ret;
+    *nSz = (word32)sz;
+
+    return 0;
+}
+
+
+#ifdef WOLFSSL_KEY_GEN
+
+static const int USE_BBS = 1;
+
+static int rand_prime(mp_int* N, int len, RNG* rng, void* heap)
+{
+    int   err, res, type;
+    byte* buf;
+
+    (void)heap;
+    if (N == NULL || rng == NULL)
+       return BAD_FUNC_ARG; 
+
+    /* get type */
+    if (len < 0) {
+        type = USE_BBS;
+        len = -len;
+    } else {
+        type = 0;
+    }
+
+    /* allow sizes between 2 and 512 bytes for a prime size */
+    if (len < 2 || len > 512) { 
+        return BAD_FUNC_ARG;
+    }
+   
+    /* allocate buffer to work with */
+    buf = (byte*)XMALLOC(len, heap, DYNAMIC_TYPE_RSA);
+    if (buf == NULL) {
+        return MEMORY_E;
+    }
+    XMEMSET(buf, 0, len);
+
+    do {
+#ifdef SHOW_GEN
+        printf(".");
+        fflush(stdout);
+#endif
+        /* generate value */
+        err = wc_RNG_GenerateBlock(rng, buf, len);
+        if (err != 0) {
+            XFREE(buf, heap, DYNAMIC_TYPE_RSA);
+            return err;
+        }
+
+        /* munge bits */
+        buf[0]     |= 0x80 | 0x40;
+        buf[len-1] |= 0x01 | ((type & USE_BBS) ? 0x02 : 0x00);
+ 
+        /* load value */
+        if ((err = mp_read_unsigned_bin(N, buf, len)) != MP_OKAY) {
+            XFREE(buf, heap, DYNAMIC_TYPE_RSA);
+            return err;
+        }
+
+        /* test */
+        if ((err = mp_prime_is_prime(N, 8, &res)) != MP_OKAY) {
+            XFREE(buf, heap, DYNAMIC_TYPE_RSA);
+            return err;
+        }
+    } while (res == MP_NO);
+
+    ForceZero(buf, len);
+    XFREE(buf, heap, DYNAMIC_TYPE_RSA);
+
+    return 0;
+}
+
+
+/* Make an RSA key for size bits, with e specified, 65537 is a good e */
+int wc_MakeRsaKey(RsaKey* key, int size, long e, RNG* rng)
+{
+    mp_int p, q, tmp1, tmp2, tmp3;
+    int    err;
+
+    if (key == NULL || rng == NULL)
+        return BAD_FUNC_ARG;
+
+    if (size < RSA_MIN_SIZE || size > RSA_MAX_SIZE)
+        return BAD_FUNC_ARG;
+
+    if (e < 3 || (e & 1) == 0)
+        return BAD_FUNC_ARG;
+
+    if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != MP_OKAY)
+        return err;
+
+    err = mp_set_int(&tmp3, e);
+
+    /* make p */
+    if (err == MP_OKAY) {
+        do {
+            err = rand_prime(&p, size/16, rng, key->heap); /* size in bytes/2 */
+
+            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 divdes p-1 */
+    }
+
+    /* make q */
+    if (err == MP_OKAY) {
+        do {
+            err = rand_prime(&q, size/16, rng, key->heap); /* size in bytes/2 */
+
+            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 divdes q-1 */
+    }
+
+    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 */
+
+    /* make key */
+    if (err == MP_OKAY)
+        err = mp_set_int(&key->e, e);  /* key->e = 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_mod(&key->d, &tmp1, &key->dP);
+
+    if (err == MP_OKAY)
+        err = mp_mod(&key->d, &tmp2, &key->dQ);
+
+    if (err == MP_OKAY)
+        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);
+
+    if (err == MP_OKAY)
+        key->type = RSA_PRIVATE; 
+
+    mp_clear(&tmp3); 
+    mp_clear(&tmp2); 
+    mp_clear(&tmp1); 
+    mp_clear(&q); 
+    mp_clear(&p);
+
+    if (err != MP_OKAY) {
+        wc_FreeRsaKey(key);        
+        return err;
+    }
+
+    return 0;
+}
+
+
+#endif /* WOLFSSL_KEY_GEN */
+
+
+#ifdef HAVE_CAVIUM
+
+#include <cyassl/ctaocrypt/logging.h>
+#include "cavium_common.h"
+
+/* Initiliaze RSA for use with Nitrox device */
+int RsaInitCavium(RsaKey* rsa, int devId)
+{
+    if (rsa == NULL)
+        return -1;
+
+    if (CspAllocContext(CONTEXT_SSL, &rsa->contextHandle, devId) != 0)
+        return -1;
+
+    rsa->devId = devId;
+    rsa->magic = WOLFSSL_RSA_CAVIUM_MAGIC;
+   
+    return 0;
+}
+
+
+/* Free RSA from use with Nitrox device */
+void wc_RsaFreeCavium(RsaKey* rsa)
+{
+    if (rsa == NULL)
+        return;
+
+    CspFreeContext(CONTEXT_SSL, rsa->contextHandle, rsa->devId);
+    rsa->magic = 0;
+}
+
+
+/* Initialize cavium RSA key */
+static int InitCaviumRsaKey(RsaKey* key, void* heap)
+{
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    key->heap = heap;
+    key->type = -1;   /* don't know yet */
+
+    key->c_n  = NULL;
+    key->c_e  = NULL;
+    key->c_d  = NULL;
+    key->c_p  = NULL;
+    key->c_q  = NULL;
+    key->c_dP = NULL;
+    key->c_dQ = NULL;
+    key->c_u  = NULL;
+
+    key->c_nSz   = 0;
+    key->c_eSz   = 0;
+    key->c_dSz   = 0;
+    key->c_pSz   = 0;
+    key->c_qSz   = 0;
+    key->c_dP_Sz = 0;
+    key->c_dQ_Sz = 0;
+    key->c_uSz   = 0;
+    
+    return 0;
+}
+
+
+/* Free cavium RSA key */
+static int FreeCaviumRsaKey(RsaKey* key)
+{
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    XFREE(key->c_n,  key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+    XFREE(key->c_e,  key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+    XFREE(key->c_d,  key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+    XFREE(key->c_p,  key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+    XFREE(key->c_q,  key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+    XFREE(key->c_dP, key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+    XFREE(key->c_dQ, key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+    XFREE(key->c_u,  key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+
+    return InitCaviumRsaKey(key, key->heap);  /* reset pointers */
+}
+
+
+static int CaviumRsaPublicEncrypt(const byte* in, word32 inLen, byte* out,
+                                   word32 outLen, RsaKey* key)
+{
+    word32 requestId;
+    word32 ret;
+
+    if (key == NULL || in == NULL || out == NULL || outLen < (word32)key->c_nSz)
+        return -1;
+
+    ret = CspPkcs1v15Enc(CAVIUM_BLOCKING, BT2, key->c_nSz, key->c_eSz,
+                         (word16)inLen, key->c_n, key->c_e, (byte*)in, out,
+                         &requestId, key->devId);
+    if (ret != 0) {
+        WOLFSSL_MSG("Cavium Enc BT2 failed");
+        return -1;
+    }
+    return key->c_nSz;
+}
+
+
+static INLINE void ato16(const byte* c, word16* u16)
+{
+    *u16 = (c[0] << 8) | (c[1]);
+}
+
+
+static int CaviumRsaPrivateDecrypt(const byte* in, word32 inLen, byte* out,
+                                    word32 outLen, RsaKey* key)
+{
+    word32 requestId;
+    word32 ret;
+    word16 outSz = (word16)outLen;
+
+    if (key == NULL || in == NULL || out == NULL || inLen != (word32)key->c_nSz)
+        return -1;
+
+    ret = CspPkcs1v15CrtDec(CAVIUM_BLOCKING, BT2, key->c_nSz, key->c_q,
+                            key->c_dQ, key->c_p, key->c_dP, key->c_u,
+                            (byte*)in, &outSz, out, &requestId, key->devId);
+    if (ret != 0) {
+        WOLFSSL_MSG("Cavium CRT Dec BT2 failed");
+        return -1;
+    }
+    ato16((const byte*)&outSz, &outSz); 
+
+    return outSz;
+}
+
+
+static int CaviumRsaSSL_Sign(const byte* in, word32 inLen, byte* out,
+                             word32 outLen, RsaKey* key)
+{
+    word32 requestId;
+    word32 ret;
+
+    if (key == NULL || in == NULL || out == NULL || inLen == 0 || outLen <
+                                                             (word32)key->c_nSz)
+        return -1;
+
+    ret = CspPkcs1v15CrtEnc(CAVIUM_BLOCKING, BT1, key->c_nSz, (word16)inLen,
+                            key->c_q, key->c_dQ, key->c_p, key->c_dP, key->c_u,
+                            (byte*)in, out, &requestId, key->devId);
+    if (ret != 0) {
+        WOLFSSL_MSG("Cavium CRT Enc BT1 failed");
+        return -1;
+    }
+    return key->c_nSz;
+}
+
+
+static int CaviumRsaSSL_Verify(const byte* in, word32 inLen, byte* out,
+                               word32 outLen, RsaKey* key)
+{
+    word32 requestId;
+    word32 ret;
+    word16 outSz = (word16)outLen;
+
+    if (key == NULL || in == NULL || out == NULL || inLen != (word32)key->c_nSz)
+        return -1;
+
+    ret = CspPkcs1v15Dec(CAVIUM_BLOCKING, BT1, key->c_nSz, key->c_eSz,
+                         key->c_n, key->c_e, (byte*)in, &outSz, out,
+                         &requestId, key->devId);
+    if (ret != 0) {
+        WOLFSSL_MSG("Cavium Dec BT1 failed");
+        return -1;
+    }
+    outSz = ntohs(outSz);
+
+    return outSz;
+}
+
+
+#endif /* HAVE_CAVIUM */
+
+#endif /* HAVE_FIPS */
+#endif /* NO_RSA */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/sha.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,459 @@
+/* sha.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#if !defined(NO_SHA)
+
+#include <wolfssl/wolfcrypt/sha.h>
+#include <wolfssl/wolfcrypt/logging.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+/* fips wrapper calls, user can call direct */
+#ifdef HAVE_FIPS
+	int wc_InitSha(Sha* sha)
+	{
+	    return InitSha_fips(sha);
+	}
+
+
+	int wc_ShaUpdate(Sha* sha, const byte* data, word32 len)
+	{
+	    return ShaUpdate_fips(sha, data, len);
+	}
+
+
+	int wc_ShaFinal(Sha* sha, byte* out)
+	{
+	    return ShaFinal_fips(sha,out);
+    }
+
+    int wc_ShaHash(const byte* data, word32 sz, byte* out)
+    {
+        return ShaHash(data, sz, out);
+    }
+
+#else /* else build without fips */
+
+#if defined(WOLFSSL_TI_HASH)
+    /* #include <wolfcrypt/src/port/ti/ti-hash.c> included by wc_port.c */
+#else
+
+#ifdef WOLFSSL_PIC32MZ_HASH
+#define wc_InitSha   wc_InitSha_sw
+#define wc_ShaUpdate wc_ShaUpdate_sw
+#define wc_ShaFinal  wc_ShaFinal_sw
+#endif
+
+
+#ifdef FREESCALE_MMCAU
+    #include "cau_api.h"
+    #define XTRANSFORM(S,B)  cau_sha1_hash_n((B), 1, ((S))->digest)
+#else
+    #define XTRANSFORM(S,B)  Transform((S))
+#endif
+
+#ifdef STM32F2_HASH
+/*
+ * STM32F2 hardware SHA1 support through the STM32F2 standard peripheral
+ * library. Documentation located in STM32F2xx Standard Peripheral Library
+ * document (See note in README).
+ */
+#include "stm32f2xx.h"
+#include "stm32f2xx_hash.h"
+
+int wc_InitSha(Sha* sha)
+{
+    /* STM32F2 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
+     */
+    XMEMSET(sha->buffer, 0, SHA_REG_SIZE);
+    sha->buffLen = 0;
+    sha->loLen = 0;
+
+    /* initialize HASH peripheral */
+    HASH_DeInit();
+
+    /* configure algo used, algo mode, datatype */
+    HASH->CR &= ~ (HASH_CR_ALGO | HASH_CR_DATATYPE | HASH_CR_MODE);
+    HASH->CR |= (HASH_AlgoSelection_SHA1 | HASH_AlgoMode_HASH
+                 | HASH_DataType_8b);
+
+    /* reset HASH processor */
+    HASH->CR |= HASH_CR_INIT;
+
+    return 0;
+}
+
+int wc_ShaUpdate(Sha* sha, const byte* data, word32 len)
+{
+    word32 i = 0;
+    word32 fill = 0;
+    word32 diff = 0;
+
+    /* if saved partial block is available */
+    if (sha->buffLen) {
+        fill = 4 - sha->buffLen;
+
+        /* if enough data to fill, fill and push to FIFO */
+        if (fill <= len) {
+            XMEMCPY((byte*)sha->buffer + sha->buffLen, data, fill);
+            HASH_DataIn(*(uint32_t*)sha->buffer);
+
+            data += fill;
+            len -= fill;
+            sha->loLen += 4;
+            sha->buffLen = 0;
+        } else {
+            /* append partial to existing stored block */
+            XMEMCPY((byte*)sha->buffer + sha->buffLen, data, len);
+            sha->buffLen += len;
+            return;
+        }
+    }
+
+    /* write input block in the IN FIFO */
+    for(i = 0; i < len; i += 4)
+    {
+        diff = len - i;
+        if ( diff < 4) {
+            /* store incomplete last block, not yet in FIFO */
+            XMEMSET(sha->buffer, 0, SHA_REG_SIZE);
+            XMEMCPY((byte*)sha->buffer, data, diff);
+            sha->buffLen = diff;
+        } else {
+            HASH_DataIn(*(uint32_t*)data);
+            data+=4;
+        }
+    }
+
+    /* keep track of total data length thus far */
+    sha->loLen += (len - sha->buffLen);
+
+    return 0;
+}
+
+int wc_ShaFinal(Sha* sha, byte* hash)
+{
+    __IO uint16_t nbvalidbitsdata = 0;
+
+    /* finish reading any trailing bytes into FIFO */
+    if (sha->buffLen) {
+        HASH_DataIn(*(uint32_t*)sha->buffer);
+        sha->loLen += 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, SHA_DIGEST_SIZE);
+
+    XMEMCPY(hash, sha->digest, SHA_DIGEST_SIZE);
+
+    return wc_InitSha(sha);  /* reset state */
+}
+
+#else /* wc_ software implementation */
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* WOLFSSL_HAVE_MIN */
+
+
+int wc_InitSha(Sha* sha)
+{
+#ifdef FREESCALE_MMCAU
+    cau_sha1_initialize_output(sha->digest);
+#else
+    sha->digest[0] = 0x67452301L;
+    sha->digest[1] = 0xEFCDAB89L;
+    sha->digest[2] = 0x98BADCFEL;
+    sha->digest[3] = 0x10325476L;
+    sha->digest[4] = 0xC3D2E1F0L;
+#endif
+
+    sha->buffLen = 0;
+    sha->loLen   = 0;
+    sha->hiLen   = 0;
+
+    return 0;
+}
+
+#ifndef FREESCALE_MMCAU
+
+#define blk0(i) (W[i] = sha->buffer[i])
+#define blk1(i) (W[(i)&15] = \
+rotlFixed(W[((i)+13)&15]^W[((i)+8)&15]^W[((i)+2)&15]^W[(i)&15],1))
+
+#define f1(x,y,z) ((z)^((x) &((y)^(z))))
+#define f2(x,y,z) ((x)^(y)^(z))
+#define f3(x,y,z) (((x)&(y))|((z)&((x)|(y))))
+#define f4(x,y,z) ((x)^(y)^(z))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) (z)+= f1((w),(x),(y)) + blk0((i)) + 0x5A827999+ \
+rotlFixed((v),5); (w) = rotlFixed((w),30);
+#define R1(v,w,x,y,z,i) (z)+= f1((w),(x),(y)) + blk1((i)) + 0x5A827999+ \
+rotlFixed((v),5); (w) = rotlFixed((w),30);
+#define R2(v,w,x,y,z,i) (z)+= f2((w),(x),(y)) + blk1((i)) + 0x6ED9EBA1+ \
+rotlFixed((v),5); (w) = rotlFixed((w),30);
+#define R3(v,w,x,y,z,i) (z)+= f3((w),(x),(y)) + blk1((i)) + 0x8F1BBCDC+ \
+rotlFixed((v),5); (w) = rotlFixed((w),30);
+#define R4(v,w,x,y,z,i) (z)+= f4((w),(x),(y)) + blk1((i)) + 0xCA62C1D6+ \
+rotlFixed((v),5); (w) = rotlFixed((w),30);
+
+static void Transform(Sha* sha)
+{
+    word32 W[SHA_BLOCK_SIZE / sizeof(word32)];
+
+    /* Copy context->state[] to working vars */
+    word32 a = sha->digest[0];
+    word32 b = sha->digest[1];
+    word32 c = sha->digest[2];
+    word32 d = sha->digest[3];
+    word32 e = sha->digest[4];
+
+#ifdef USE_SLOW_SHA
+    word32 t, i;
+
+    for (i = 0; i < 16; i++) {
+        R0(a, b, c, d, e, i);
+        t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 20; i++) {
+        R1(a, b, c, d, e, i);
+        t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 40; i++) {
+        R2(a, b, c, d, e, i);
+        t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 60; i++) {
+        R3(a, b, c, d, e, i);
+        t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 80; i++) {
+        R4(a, b, c, d, e, i);
+        t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+#else
+    /* nearly 1 K bigger in code size but 25% faster  */
+    /* 4 rounds of 20 operations each. Loop unrolled. */
+    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+
+    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+
+    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+
+    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+
+    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+#endif
+
+    /* Add the working vars back into digest state[] */
+    sha->digest[0] += a;
+    sha->digest[1] += b;
+    sha->digest[2] += c;
+    sha->digest[3] += d;
+    sha->digest[4] += e;
+}
+
+#endif /* FREESCALE_MMCAU */
+
+
+static INLINE void AddLength(Sha* sha, word32 len)
+{
+    word32 tmp = sha->loLen;
+    if ( (sha->loLen += len) < tmp)
+        sha->hiLen++;                       /* carry low to high */
+}
+
+
+int wc_ShaUpdate(Sha* sha, const byte* data, word32 len)
+{
+    /* do block size increments */
+    byte* local = (byte*)sha->buffer;
+
+    while (len) {
+        word32 add = min(len, SHA_BLOCK_SIZE - sha->buffLen);
+        XMEMCPY(&local[sha->buffLen], data, add);
+
+        sha->buffLen += add;
+        data         += add;
+        len          -= add;
+
+        if (sha->buffLen == SHA_BLOCK_SIZE) {
+#if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+            ByteReverseWords(sha->buffer, sha->buffer, SHA_BLOCK_SIZE);
+#endif
+            XTRANSFORM(sha, local);
+            AddLength(sha, SHA_BLOCK_SIZE);
+            sha->buffLen = 0;
+        }
+    }
+
+    return 0;
+}
+
+
+int wc_ShaFinal(Sha* sha, byte* hash)
+{
+    byte* local = (byte*)sha->buffer;
+
+    AddLength(sha, sha->buffLen);  /* before adding pads */
+
+    local[sha->buffLen++] = 0x80;  /* add 1 */
+
+    /* pad with zeros */
+    if (sha->buffLen > SHA_PAD_SIZE) {
+        XMEMSET(&local[sha->buffLen], 0, SHA_BLOCK_SIZE - sha->buffLen);
+        sha->buffLen += SHA_BLOCK_SIZE - sha->buffLen;
+
+#if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+        ByteReverseWords(sha->buffer, sha->buffer, SHA_BLOCK_SIZE);
+#endif
+        XTRANSFORM(sha, local);
+        sha->buffLen = 0;
+    }
+    XMEMSET(&local[sha->buffLen], 0, SHA_PAD_SIZE - sha->buffLen);
+
+    /* put lengths in bits */
+    sha->hiLen = (sha->loLen >> (8*sizeof(sha->loLen) - 3)) +
+    (sha->hiLen << 3);
+    sha->loLen = sha->loLen << 3;
+
+    /* store lengths */
+#if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+    ByteReverseWords(sha->buffer, sha->buffer, SHA_BLOCK_SIZE);
+#endif
+    /* ! length ordering dependent on digest endian type ! */
+    XMEMCPY(&local[SHA_PAD_SIZE], &sha->hiLen, sizeof(word32));
+    XMEMCPY(&local[SHA_PAD_SIZE + sizeof(word32)], &sha->loLen, sizeof(word32));
+
+#ifdef FREESCALE_MMCAU
+    /* Kinetis requires only these bytes reversed */
+    ByteReverseWords(&sha->buffer[SHA_PAD_SIZE/sizeof(word32)],
+                     &sha->buffer[SHA_PAD_SIZE/sizeof(word32)],
+                     2 * sizeof(word32));
+#endif
+
+    XTRANSFORM(sha, local);
+#ifdef LITTLE_ENDIAN_ORDER
+    ByteReverseWords(sha->digest, sha->digest, SHA_DIGEST_SIZE);
+#endif
+    XMEMCPY(hash, sha->digest, SHA_DIGEST_SIZE);
+
+    return wc_InitSha(sha);  /* reset state */
+}
+
+#endif /* STM32F2_HASH */
+
+
+int wc_ShaHash(const byte* data, word32 len, byte* hash)
+{
+    int ret = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    Sha* sha;
+#else
+    Sha sha[1];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    sha = (Sha*)XMALLOC(sizeof(Sha), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (sha == NULL)
+        return MEMORY_E;
+#endif
+
+    if ((ret = wc_InitSha(sha)) != 0) {
+        WOLFSSL_MSG("wc_InitSha failed");
+    }
+    else {
+        wc_ShaUpdate(sha, data, len);
+        wc_ShaFinal(sha, hash);
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+
+}
+
+#endif /* HAVE_FIPS */
+#endif /* WOLFSSL_TI_HASH */
+#endif /* NO_SHA */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/sha256.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,1767 @@
+/* sha256.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+/* code submitted by raphael.huck@efixo.com */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+#include <wolfssl/wolfcrypt/sha256.h>
+
+#if !defined(NO_SHA256)
+#ifdef HAVE_FIPS
+
+int wc_InitSha256(Sha256* sha)
+{
+    return InitSha256_fips(sha);
+}
+
+
+int wc_Sha256Update(Sha256* sha, const byte* data, word32 len)
+{
+    return Sha256Update_fips(sha, data, len);
+}
+
+
+int wc_Sha256Final(Sha256* sha, byte* out)
+{
+    return Sha256Final_fips(sha, out);
+}
+
+
+int wc_Sha256Hash(const byte* data, word32 len, byte* out)
+{
+    return Sha256Hash(data, len, out);
+}
+
+#else /* else build without fips */
+
+#if !defined(NO_SHA256) && defined(WOLFSSL_TI_HASH)
+    /* #include <wolfcrypt/src/port/ti/ti-hash.c> included by wc_port.c */
+#else
+
+#if !defined (ALIGN32)
+    #if defined (__GNUC__)
+        #define ALIGN32 __attribute__ ( (aligned (32)))
+    #elif defined(_MSC_VER)
+        /* disable align warning, we want alignment ! */
+        #pragma warning(disable: 4324)
+        #define ALIGN32 __declspec (align (32))
+    #else
+        #define ALIGN32
+    #endif
+#endif
+
+#ifdef WOLFSSL_PIC32MZ_HASH
+#define wc_InitSha256   wc_InitSha256_sw
+#define wc_Sha256Update wc_Sha256Update_sw
+#define wc_Sha256Final  wc_Sha256Final_sw
+#endif
+
+#ifdef HAVE_FIPS
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+#endif
+
+#if defined(USE_INTEL_SPEEDUP)
+#define HAVE_INTEL_AVX1
+#define HAVE_INTEL_AVX2
+
+#if defined(DEBUG_XMM)
+#include "stdio.h"
+#endif
+
+#endif
+
+#if defined(HAVE_INTEL_AVX2)
+#define HAVE_INTEL_RORX
+#endif
+ 
+
+/*****
+Intel AVX1/AVX2 Macro Control Structure
+
+#define HAVE_INTEL_AVX1
+#define HAVE_INTEL_AVX2
+
+#define HAVE_INTEL_RORX
+
+
+int InitSha256(Sha256* sha256) { 
+     Save/Recover XMM, YMM
+     ...
+}
+
+#if defined(HAVE_INTEL_AVX1)|| defined(HAVE_INTEL_AVX2)
+  Transform() ; Function prototype 
+#else
+  Transform() {   }
+  int Sha256Final() { 
+     Save/Recover XMM, YMM
+     ...
+  }
+#endif
+
+#if defined(HAVE_INTEL_AVX1)|| defined(HAVE_INTEL_AVX2)
+    #if defined(HAVE_INTEL_RORX
+         #define RND with rorx instuction
+    #else
+        #define RND
+    #endif
+#endif
+
+#if defined(HAVE_INTEL_AVX1)
+   
+   #define XMM Instructions/inline asm
+   
+   int Transform() {
+       Stitched Message Sched/Round
+    } 
+   
+#elif defined(HAVE_INTEL_AVX2)
+  
+  #define YMM Instructions/inline asm
+  
+  int Transform() {
+      More granural Stitched Message Sched/Round
+  }
+  
+*/
+
+
+#if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+
+/* Each platform needs to query info type 1 from cpuid to see if aesni is
+ * supported. Also, let's setup a macro for proper linkage w/o ABI conflicts
+ */
+
+#ifndef _MSC_VER
+    #define cpuid(reg, leaf, sub)\
+            __asm__ __volatile__ ("cpuid":\
+             "=a" (reg[0]), "=b" (reg[1]), "=c" (reg[2]), "=d" (reg[3]) :\
+             "a" (leaf), "c"(sub));
+
+    #define XASM_LINK(f) asm(f)
+#else
+
+    #include <intrin.h>
+    #define cpuid(a,b) __cpuid((int*)a,b)
+
+    #define XASM_LINK(f)
+
+#endif /* _MSC_VER */
+
+#define EAX 0
+#define EBX 1
+#define ECX 2 
+#define EDX 3
+    
+#define CPUID_AVX1   0x1
+#define CPUID_AVX2   0x2
+#define CPUID_RDRAND 0x4
+#define CPUID_RDSEED 0x8
+#define CPUID_BMI2   0x10   /* MULX, RORX */
+
+#define IS_INTEL_AVX1       (cpuid_flags&CPUID_AVX1)
+#define IS_INTEL_AVX2       (cpuid_flags&CPUID_AVX2)
+#define IS_INTEL_BMI2       (cpuid_flags&CPUID_BMI2)
+#define IS_INTEL_RDRAND     (cpuid_flags&CPUID_RDRAND)
+#define IS_INTEL_RDSEED     (cpuid_flags&CPUID_RDSEED)
+
+static word32 cpuid_check = 0 ;
+static word32 cpuid_flags = 0 ;
+
+static word32 cpuid_flag(word32 leaf, word32 sub, word32 num, word32 bit) {
+    int got_intel_cpu=0;
+    unsigned int reg[5]; 
+    
+    reg[4] = '\0' ;
+    cpuid(reg, 0, 0);  
+    if(memcmp((char *)&(reg[EBX]), "Genu", 4) == 0 &&  
+                memcmp((char *)&(reg[EDX]), "ineI", 4) == 0 &&  
+                memcmp((char *)&(reg[ECX]), "ntel", 4) == 0) {  
+        got_intel_cpu = 1;  
+    }    
+    if (got_intel_cpu) {
+        cpuid(reg, leaf, sub);
+        return((reg[num]>>bit)&0x1) ;
+    }
+    return 0 ;
+}
+
+static int set_cpuid_flags(void) {  
+    if(cpuid_check==0) {
+        if(cpuid_flag(1, 0, ECX, 28)){ cpuid_flags |= CPUID_AVX1 ;}
+        if(cpuid_flag(7, 0, EBX, 5)){  cpuid_flags |= CPUID_AVX2 ; }
+        if(cpuid_flag(7, 0, EBX, 8)) { cpuid_flags |= CPUID_BMI2 ; }
+        if(cpuid_flag(1, 0, ECX, 30)){ cpuid_flags |= CPUID_RDRAND ;  } 
+        if(cpuid_flag(7, 0, EBX, 18)){ cpuid_flags |= CPUID_RDSEED ;  }
+        cpuid_check = 1 ;
+        return 0 ;
+    }
+    return 1 ;
+}
+
+
+/* #if defined(HAVE_INTEL_AVX1/2) at the tail of sha512 */
+static int Transform(Sha256* sha256);
+
+#if defined(HAVE_INTEL_AVX1)
+static int Transform_AVX1(Sha256 *sha256) ;
+#endif
+#if defined(HAVE_INTEL_AVX2)
+static int Transform_AVX2(Sha256 *sha256) ; 
+static int Transform_AVX1_RORX(Sha256 *sha256) ; 
+#endif
+
+static int (*Transform_p)(Sha256* sha256) /* = _Transform */;
+
+#define XTRANSFORM(sha256, B)  (*Transform_p)(sha256)
+
+static void set_Transform(void) {
+     if(set_cpuid_flags())return ;
+
+#if defined(HAVE_INTEL_AVX2)
+     if(IS_INTEL_AVX2 && IS_INTEL_BMI2){ 
+         Transform_p = Transform_AVX1_RORX; return ; 
+         Transform_p = Transform_AVX2      ; 
+                  /* for avoiding warning,"not used" */
+     }
+#endif
+#if defined(HAVE_INTEL_AVX1)
+     Transform_p = ((IS_INTEL_AVX1) ? Transform_AVX1 : Transform) ; return ;
+#endif
+     Transform_p = Transform ; return ;
+}
+
+#else
+   #if defined(FREESCALE_MMCAU)
+      #define XTRANSFORM(sha256, B) Transform(sha256, B)
+   #else
+      #define XTRANSFORM(sha256, B) Transform(sha256)
+   #endif
+#endif
+
+/* 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")
+#else
+#define  SAVE_XMM_YMM
+#endif
+
+#ifdef WOLFSSL_PIC32MZ_HASH
+#define InitSha256   InitSha256_sw
+#define Sha256Update Sha256Update_sw
+#define Sha256Final  Sha256Final_sw
+#endif
+
+#include <wolfssl/wolfcrypt/logging.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+#ifdef FREESCALE_MMCAU
+    #include "cau_api.h"
+#endif
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* WOLFSSL_HAVE_MIN */
+
+
+int wc_InitSha256(Sha256* sha256)
+{
+    #ifdef FREESCALE_MMCAU
+        cau_sha256_initialize_output(sha256->digest);
+    #else
+        sha256->digest[0] = 0x6A09E667L;
+        sha256->digest[1] = 0xBB67AE85L;
+        sha256->digest[2] = 0x3C6EF372L;
+        sha256->digest[3] = 0xA54FF53AL;
+        sha256->digest[4] = 0x510E527FL;
+        sha256->digest[5] = 0x9B05688CL;
+        sha256->digest[6] = 0x1F83D9ABL;
+        sha256->digest[7] = 0x5BE0CD19L;
+    #endif
+
+    sha256->buffLen = 0;
+    sha256->loLen   = 0;
+    sha256->hiLen   = 0;
+    
+#if defined(HAVE_INTEL_AVX1)|| defined(HAVE_INTEL_AVX2)
+    set_Transform() ; /* choose best Transform function under this runtime environment */
+#endif
+
+    return 0;
+}
+
+
+#if !defined(FREESCALE_MMCAU)
+static const ALIGN32 word32 K[64] = {
+    0x428A2F98L, 0x71374491L, 0xB5C0FBCFL, 0xE9B5DBA5L, 0x3956C25BL,
+    0x59F111F1L, 0x923F82A4L, 0xAB1C5ED5L, 0xD807AA98L, 0x12835B01L,
+    0x243185BEL, 0x550C7DC3L, 0x72BE5D74L, 0x80DEB1FEL, 0x9BDC06A7L,
+    0xC19BF174L, 0xE49B69C1L, 0xEFBE4786L, 0x0FC19DC6L, 0x240CA1CCL,
+    0x2DE92C6FL, 0x4A7484AAL, 0x5CB0A9DCL, 0x76F988DAL, 0x983E5152L,
+    0xA831C66DL, 0xB00327C8L, 0xBF597FC7L, 0xC6E00BF3L, 0xD5A79147L,
+    0x06CA6351L, 0x14292967L, 0x27B70A85L, 0x2E1B2138L, 0x4D2C6DFCL,
+    0x53380D13L, 0x650A7354L, 0x766A0ABBL, 0x81C2C92EL, 0x92722C85L,
+    0xA2BFE8A1L, 0xA81A664BL, 0xC24B8B70L, 0xC76C51A3L, 0xD192E819L,
+    0xD6990624L, 0xF40E3585L, 0x106AA070L, 0x19A4C116L, 0x1E376C08L,
+    0x2748774CL, 0x34B0BCB5L, 0x391C0CB3L, 0x4ED8AA4AL, 0x5B9CCA4FL,
+    0x682E6FF3L, 0x748F82EEL, 0x78A5636FL, 0x84C87814L, 0x8CC70208L,
+    0x90BEFFFAL, 0xA4506CEBL, 0xBEF9A3F7L, 0xC67178F2L
+};
+
+#endif
+
+#if defined(FREESCALE_MMCAU)
+
+static int Transform(Sha256* sha256, byte* buf)
+{
+    cau_sha256_hash_n(buf, 1, sha256->digest);
+
+    return 0;
+}
+
+#endif /* FREESCALE_MMCAU */
+
+#define Ch(x,y,z)       ((z) ^ ((x) & ((y) ^ (z))))
+#define Maj(x,y,z)      ((((x) | (y)) & (z)) | ((x) & (y)))
+#define R(x, n)         (((x)&0xFFFFFFFFU)>>(n))
+
+#define S(x, n)         rotrFixed(x, n)
+#define Sigma0(x)       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x)       (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x)       (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#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;
+
+#if !defined(FREESCALE_MMCAU)
+static int Transform(Sha256* sha256)
+{
+    word32 S[8], t0, t1;
+    int i;
+
+#ifdef WOLFSSL_SMALL_STACK
+    word32* W;
+
+    W = (word32*) XMALLOC(sizeof(word32) * 64, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (W == NULL)
+        return MEMORY_E;
+#else
+    word32 W[64];
+#endif
+
+    /* Copy context->state[] to working vars */
+    for (i = 0; i < 8; i++)
+        S[i] = sha256->digest[i];
+
+    for (i = 0; i < 16; i++)
+        W[i] = sha256->buffer[i];
+
+    for (i = 16; i < 64; i++)
+        W[i] = Gamma1(W[i-2]) + W[i-7] + Gamma0(W[i-15]) + W[i-16];
+
+    for (i = 0; i < 64; 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);
+    }
+
+    /* Add the working vars back into digest state[] */
+    for (i = 0; i < 8; i++) {
+        sha256->digest[i] += S[i];
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(W, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return 0;
+}
+
+#endif /* #if !defined(FREESCALE_MMCAU) */
+
+static INLINE void AddLength(Sha256* sha256, word32 len)
+{
+    word32 tmp = sha256->loLen;
+    if ( (sha256->loLen += len) < tmp)
+        sha256->hiLen++;                       /* carry low to high */
+}
+
+int wc_Sha256Update(Sha256* sha256, const byte* data, word32 len)
+{
+
+    /* do block size increments */
+    byte* local = (byte*)sha256->buffer;
+
+    SAVE_XMM_YMM ; /* for Intel AVX */
+
+    while (len) {
+        word32 add = min(len, SHA256_BLOCK_SIZE - sha256->buffLen);
+        XMEMCPY(&local[sha256->buffLen], data, add);
+
+        sha256->buffLen += add;
+        data            += add;
+        len             -= add;
+
+        if (sha256->buffLen == SHA256_BLOCK_SIZE) {
+            int ret;
+
+            #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+                #if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+                if(!IS_INTEL_AVX1 && !IS_INTEL_AVX2)
+                #endif
+                ByteReverseWords(sha256->buffer, sha256->buffer,
+                                 SHA256_BLOCK_SIZE);
+            #endif
+            ret = XTRANSFORM(sha256, local);
+            if (ret != 0)
+                return ret;
+
+            AddLength(sha256, SHA256_BLOCK_SIZE);
+            sha256->buffLen = 0;
+        }
+    }
+
+    return 0;
+}
+
+int wc_Sha256Final(Sha256* sha256, byte* hash)
+{
+    byte* local = (byte*)sha256->buffer;
+    int ret;
+    
+    SAVE_XMM_YMM ; /* for Intel AVX */
+
+    AddLength(sha256, sha256->buffLen);  /* before adding pads */
+
+    local[sha256->buffLen++] = 0x80;     /* add 1 */
+
+    /* pad with zeros */
+    if (sha256->buffLen > SHA256_PAD_SIZE) {
+        XMEMSET(&local[sha256->buffLen], 0, SHA256_BLOCK_SIZE - sha256->buffLen);
+        sha256->buffLen += SHA256_BLOCK_SIZE - sha256->buffLen;
+
+        #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+            #if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+            if(!IS_INTEL_AVX1 && !IS_INTEL_AVX2)
+            #endif
+            ByteReverseWords(sha256->buffer, sha256->buffer, SHA256_BLOCK_SIZE);
+        #endif
+
+        ret = XTRANSFORM(sha256, local);
+        if (ret != 0)
+            return ret;
+
+        sha256->buffLen = 0;
+    }
+    XMEMSET(&local[sha256->buffLen], 0, SHA256_PAD_SIZE - sha256->buffLen);
+
+    /* put lengths in bits */
+    sha256->hiLen = (sha256->loLen >> (8*sizeof(sha256->loLen) - 3)) +
+                 (sha256->hiLen << 3);
+    sha256->loLen = sha256->loLen << 3;
+
+    /* store lengths */
+    #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+        #if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+        if(!IS_INTEL_AVX1 && !IS_INTEL_AVX2)
+        #endif
+            ByteReverseWords(sha256->buffer, sha256->buffer, SHA256_BLOCK_SIZE);
+    #endif
+    /* ! length ordering dependent on digest endian type ! */
+    XMEMCPY(&local[SHA256_PAD_SIZE], &sha256->hiLen, sizeof(word32));
+    XMEMCPY(&local[SHA256_PAD_SIZE + sizeof(word32)], &sha256->loLen,
+            sizeof(word32));
+
+    #if defined(FREESCALE_MMCAU) || defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+        /* Kinetis requires only these bytes reversed */
+        #if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+        if(IS_INTEL_AVX1 || IS_INTEL_AVX2)
+        #endif
+        ByteReverseWords(&sha256->buffer[SHA256_PAD_SIZE/sizeof(word32)],
+                         &sha256->buffer[SHA256_PAD_SIZE/sizeof(word32)],
+                         2 * sizeof(word32));
+    #endif
+
+    ret = XTRANSFORM(sha256, local);
+    if (ret != 0)
+        return ret;
+
+    #if defined(LITTLE_ENDIAN_ORDER)
+        ByteReverseWords(sha256->digest, sha256->digest, SHA256_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, sha256->digest, SHA256_DIGEST_SIZE);
+
+    return wc_InitSha256(sha256);  /* reset state */
+}
+
+
+
+int wc_Sha256Hash(const byte* data, word32 len, byte* hash)
+{
+    int ret = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    Sha256* sha256;
+#else
+    Sha256 sha256[1];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    sha256 = (Sha256*)XMALLOC(sizeof(Sha256), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (sha256 == NULL)
+        return MEMORY_E;
+#endif
+
+    if ((ret = wc_InitSha256(sha256)) != 0) {
+        WOLFSSL_MSG("InitSha256 failed");
+    }
+    else if ((ret = wc_Sha256Update(sha256, data, len)) != 0) {
+        WOLFSSL_MSG("Sha256Update failed");
+    }
+    else if ((ret = wc_Sha256Final(sha256, hash)) != 0) {
+        WOLFSSL_MSG("Sha256Final failed");
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(sha256, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+#if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+
+#define _DigestToReg(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7 )\
+    { word32 d ;\
+    d = sha256->digest[0]; __asm__ volatile("movl %0, %"#S_0::"r"(d):SSE_REGs) ;\
+    d = sha256->digest[1]; __asm__ volatile("movl %0, %"#S_1::"r"(d):SSE_REGs) ;\
+    d = sha256->digest[2]; __asm__ volatile("movl %0, %"#S_2::"r"(d):SSE_REGs) ;\
+    d = sha256->digest[3]; __asm__ volatile("movl %0, %"#S_3::"r"(d):SSE_REGs) ;\
+    d = sha256->digest[4]; __asm__ volatile("movl %0, %"#S_4::"r"(d):SSE_REGs) ;\
+    d = sha256->digest[5]; __asm__ volatile("movl %0, %"#S_5::"r"(d):SSE_REGs) ;\
+    d = sha256->digest[6]; __asm__ volatile("movl %0, %"#S_6::"r"(d):SSE_REGs) ;\
+    d = sha256->digest[7]; __asm__ volatile("movl %0, %"#S_7::"r"(d):SSE_REGs) ;\
+}
+
+#define _RegToDigest(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7 )\
+    { word32 d ; \
+    __asm__ volatile("movl %"#S_0", %0":"=r"(d)::SSE_REGs) ; sha256->digest[0] += d;\
+    __asm__ volatile("movl %"#S_1", %0":"=r"(d)::SSE_REGs) ; sha256->digest[1] += d;\
+    __asm__ volatile("movl %"#S_2", %0":"=r"(d)::SSE_REGs) ; sha256->digest[2] += d;\
+    __asm__ volatile("movl %"#S_3", %0":"=r"(d)::SSE_REGs) ; sha256->digest[3] += d;\
+    __asm__ volatile("movl %"#S_4", %0":"=r"(d)::SSE_REGs) ; sha256->digest[4] += d;\
+    __asm__ volatile("movl %"#S_5", %0":"=r"(d)::SSE_REGs) ; sha256->digest[5] += d;\
+    __asm__ volatile("movl %"#S_6", %0":"=r"(d)::SSE_REGs) ; sha256->digest[6] += d;\
+    __asm__ volatile("movl %"#S_7", %0":"=r"(d)::SSE_REGs) ; sha256->digest[7] += d;\
+}
+
+
+#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", "%ecx", "%esi", "%edx", "%ebx","%r8","%r9","%r10","%r11","%r12","%r13","%r14","%r15"
+
+#if defined(HAVE_INTEL_RORX)
+#define RND_STEP_RORX_1(a,b,c,d,e,f,g,h,i)\
+__asm__ volatile("rorx  $6, %"#e", %%edx\n\t":::"%edx",SSE_REGs);  /* edx = e>>6 */\
+
+#define RND_STEP_RORX_2(a,b,c,d,e,f,g,h,i)\
+__asm__ volatile("rorx  $11, %"#e",%%edi\n\t":::"%edi",SSE_REGs); /* edi = e>>11  */\
+__asm__ volatile("xorl  %%edx, %%edi\n\t":::"%edx","%edi",SSE_REGs); /* edi = (e>>11) ^ (e>>6)  */\
+__asm__ volatile("rorx  $25, %"#e", %%edx\n\t":::"%edx",SSE_REGs);   /* edx = e>>25             */\
+
+#define RND_STEP_RORX_3(a,b,c,d,e,f,g,h,i)\
+__asm__ volatile("movl  %"#f", %%esi\n\t":::"%esi",SSE_REGs);  /* esi = f   */\
+__asm__ volatile("xorl  %"#g", %%esi\n\t":::"%esi",SSE_REGs);  /* esi = f ^ g  */\
+__asm__ volatile("xorl  %%edi, %%edx\n\t":::"%edi","%edx",SSE_REGs);  /* edx = Sigma1(e)  */\
+__asm__ volatile("andl  %"#e", %%esi\n\t":::"%esi",SSE_REGs);  /* esi = (f ^ g) & e       */\
+__asm__ volatile("xorl  %"#g", %%esi\n\t":::"%esi",SSE_REGs);  /* esi = Ch(e,f,g)         */\
+
+#define RND_STEP_RORX_4(a,b,c,d,e,f,g,h,i)\
+/*__asm__ volatile("movl    %0, %%edx\n\t"::"m"(w_k):"%edx");*/\
+__asm__ volatile("addl  %0, %"#h"\n\t"::"r"(W_K[i]):SSE_REGs);    /* h += w_k  */\
+__asm__ volatile("addl  %%edx, %"#h"\n\t":::"%edx",SSE_REGs);     /* h = h + w_k + Sigma1(e) */\
+__asm__ volatile("rorx  $2, %"#a", %%r8d\n\t":::"%r8",SSE_REGs);  /* r8d = a>>2   */\
+__asm__ volatile("rorx  $13, %"#a", %%edi\n\t":::"%edi",SSE_REGs);/* edi = a>>13  */\
+
+#define RND_STEP_RORX_5(a,b,c,d,e,f,g,h,i)\
+__asm__ volatile("rorx  $22, %"#a", %%edx\n\t":::"%edx",SSE_REGs); /* edx = a>>22 */\
+__asm__ volatile("xorl  %%r8d, %%edi\n\t":::"%edi","%r8",SSE_REGs);/* edi = (a>>2) ^ (a>>13)  */\
+__asm__ volatile("xorl  %%edi, %%edx\n\t":::"%edi","%edx",SSE_REGs);  /* edx = Sigma0(a)      */\
+ 
+#define RND_STEP_RORX_6(a,b,c,d,e,f,g,h,i)\
+__asm__ volatile("movl  %"#b", %%edi\n\t":::"%edi",SSE_REGs);  /* edi = b          */\
+__asm__ volatile("orl   %"#a", %%edi\n\t":::"%edi",SSE_REGs);  /* edi = a | b      */\
+__asm__ volatile("andl  %"#c", %%edi\n\t":::"%edi",SSE_REGs);  /* edi = (a | b) & c*/\
+__asm__ volatile("movl  %"#b", %%r8d\n\t":::"%r8",SSE_REGs);  /* r8d = b           */\
+
+#define RND_STEP_RORX_7(a,b,c,d,e,f,g,h,i)\
+__asm__ volatile("addl  %%esi, %"#h"\n\t":::"%esi",SSE_REGs);  /* h += Ch(e,f,g)   */\
+__asm__ volatile("andl  %"#a", %%r8d\n\t":::"%r8",SSE_REGs);  /* r8d = b & a       */\
+__asm__ volatile("orl   %%edi, %%r8d\n\t":::"%edi","%r8",SSE_REGs); /* r8d = Maj(a,b,c) */\
+
+#define RND_STEP_RORX_8(a,b,c,d,e,f,g,h,i)\
+__asm__ volatile("addl  "#h", "#d"\n\t");  /* d += h + w_k + Sigma1(e) + Ch(e,f,g) */\
+__asm__ volatile("addl  %"#h", %%r8d\n\t":::"%r8",SSE_REGs); \
+__asm__ volatile("addl  %%edx, %%r8d\n\t":::"%edx","%r8",SSE_REGs); \
+__asm__ volatile("movl  %r8d, "#h"\n\t");   
+
+#endif
+
+#define RND_STEP_1(a,b,c,d,e,f,g,h,i)\
+__asm__ volatile("movl  %"#e", %%edx\n\t":::"%edx",SSE_REGs);\
+__asm__ volatile("roll  $26, %%edx\n\t":::"%edx",SSE_REGs);  /* edx = e>>6     */\
+__asm__ volatile("movl  %"#e", %%edi\n\t":::"%edi",SSE_REGs);\
+
+#define RND_STEP_2(a,b,c,d,e,f,g,h,i)\
+__asm__ volatile("roll  $21, %%edi\n\t":::"%edi",SSE_REGs);         /* edi = e>>11 */\
+__asm__ volatile("xorl  %%edx, %%edi\n\t":::"%edx","%edi",SSE_REGs); /* edi = (e>>11) ^ (e>>6)  */\
+__asm__ volatile("movl  %"#e", %%edx\n\t":::"%edx",SSE_REGs);   /* edx = e      */\
+__asm__ volatile("roll  $7, %%edx\n\t":::"%edx",SSE_REGs);      /* edx = e>>25  */\
+
+#define RND_STEP_3(a,b,c,d,e,f,g,h,i)\
+__asm__ volatile("movl  %"#f", %%esi\n\t":::"%esi",SSE_REGs);  /* esi = f       */\
+__asm__ volatile("xorl  %"#g", %%esi\n\t":::"%esi",SSE_REGs);  /* esi = f ^ g   */\
+__asm__ volatile("xorl  %%edi, %%edx\n\t":::"%edi","%edx",SSE_REGs); /* edx = Sigma1(e) */\
+__asm__ volatile("andl  %"#e", %%esi\n\t":::"%esi",SSE_REGs);  /* esi = (f ^ g) & e  */\
+__asm__ volatile("xorl  %"#g", %%esi\n\t":::"%esi",SSE_REGs);  /* esi = Ch(e,f,g)    */\
+
+#define RND_STEP_4(a,b,c,d,e,f,g,h,i)\
+__asm__ volatile("addl  %0, %"#h"\n\t"::"r"(W_K[i]):SSE_REGs); /* h += w_k  */\
+__asm__ volatile("addl  %%edx, %"#h"\n\t":::"%edx",SSE_REGs); /* h = h + w_k + Sigma1(e) */\
+__asm__ volatile("movl  %"#a", %%r8d\n\t":::"%r8",SSE_REGs);  /* r8d = a    */\
+__asm__ volatile("roll  $30, %%r8d\n\t":::"%r8",SSE_REGs);    /* r8d = a>>2 */\
+__asm__ volatile("movl  %"#a", %%edi\n\t":::"%edi",SSE_REGs);  /* edi = a   */\
+__asm__ volatile("roll  $19, %%edi\n\t":::"%edi",SSE_REGs);    /* edi = a>>13 */\
+__asm__ volatile("movl  %"#a", %%edx\n\t":::"%edx",SSE_REGs);  /* edx = a     */\
+
+#define RND_STEP_5(a,b,c,d,e,f,g,h,i)\
+__asm__ volatile("roll  $10, %%edx\n\t":::"%edx",SSE_REGs);    /* edx = a>>22 */\
+__asm__ volatile("xorl  %%r8d, %%edi\n\t":::"%edi","%r8",SSE_REGs); /* edi = (a>>2) ^ (a>>13)  */\
+__asm__ volatile("xorl  %%edi, %%edx\n\t":::"%edi","%edx",SSE_REGs);/* edx = Sigma0(a)         */\
+
+#define RND_STEP_6(a,b,c,d,e,f,g,h,i)\
+__asm__ volatile("movl  %"#b", %%edi\n\t":::"%edi",SSE_REGs);  /* edi = b      */\
+__asm__ volatile("orl   %"#a", %%edi\n\t":::"%edi",SSE_REGs);  /* edi = a | b  */\
+__asm__ volatile("andl  %"#c", %%edi\n\t":::"%edi",SSE_REGs);  /* edi = (a | b) & c */\
+__asm__ volatile("movl  %"#b", %%r8d\n\t":::"%r8",SSE_REGs);  /* r8d = b       */\
+
+#define RND_STEP_7(a,b,c,d,e,f,g,h,i)\
+__asm__ volatile("addl  %%esi, %"#h"\n\t":::"%esi",SSE_REGs);  /* h += Ch(e,f,g)        */\
+__asm__ volatile("andl  %"#a", %%r8d\n\t":::"%r8",SSE_REGs);  /* r8d = b & a            */\
+__asm__ volatile("orl   %%edi, %%r8d\n\t":::"%edi","%r8",SSE_REGs); /* r8d = Maj(a,b,c) */\
+
+#define RND_STEP_8(a,b,c,d,e,f,g,h,i)\
+__asm__ volatile("addl  "#h", "#d"\n\t");  /* d += h + w_k + Sigma1(e) + Ch(e,f,g) */\
+__asm__ volatile("addl  %"#h", %%r8d\n\t":::"%r8",SSE_REGs); \
+                 /* r8b = h + w_k + Sigma1(e) + Ch(e,f,g) + Maj(a,b,c) */\
+__asm__ volatile("addl  %%edx, %%r8d\n\t":::"%edx","%r8",SSE_REGs);\
+                 /* r8b = h + w_k + Sigma1(e) Sigma0(a) + Ch(e,f,g) + Maj(a,b,c)     */\
+__asm__ volatile("movl  %%r8d, %"#h"\n\t":::"%r8", SSE_REGs); \
+                 /* h = h + w_k + Sigma1(e) + Sigma0(a) + Ch(e,f,g) + Maj(a,b,c) */ \
+
+#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)::) ;
+
+#endif  /* defined(HAVE_INTEL_AVX1) ||  defined(HAVE_INTEL_AVX2) */
+
+#if defined(HAVE_INTEL_AVX1) /* inline Assember for Intel AVX1 instructions */
+
+#define VPALIGNR(op1,op2,op3,op4) __asm__ volatile("vpalignr $"#op4", %"#op3", %"#op2", %"#op1:::XMM_REGs) 
+#define VPADDD(op1,op2,op3)       __asm__ volatile("vpaddd %"#op3", %"#op2", %"#op1:::XMM_REGs)
+#define VPSRLD(op1,op2,op3)       __asm__ volatile("vpsrld $"#op3", %"#op2", %"#op1:::XMM_REGs)
+#define VPSRLQ(op1,op2,op3)       __asm__ volatile("vpsrlq $"#op3", %"#op2", %"#op1:::XMM_REGs)
+#define VPSLLD(op1,op2,op3)       __asm__ volatile("vpslld $"#op3", %"#op2", %"#op1:::XMM_REGs)
+#define VPOR(op1,op2,op3)         __asm__ volatile("vpor   %"#op3", %"#op2", %"#op1:::XMM_REGs)
+#define VPXOR(op1,op2,op3)        __asm__ volatile("vpxor  %"#op3", %"#op2", %"#op1:::XMM_REGs)
+#define VPSHUFD(op1,op2,op3)      __asm__ volatile("vpshufd $"#op3", %"#op2", %"#op1:::XMM_REGs)
+#define VPSHUFB(op1,op2,op3)      __asm__ volatile("vpshufb %"#op3", %"#op2", %"#op1:::XMM_REGs)
+
+#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);\
+    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);\
+    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);\
+    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_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);\
+    VPSLLD   (XTMP1, XTMP1, 14) ; /* VPSLLD   (XTMP1, XTMP1, (32-18)) */\
+            RND_STEP_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);\
+    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_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);\
+    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);\
+    VPXOR    (XTMP5, XTMP5, XTMP2) ;   /* XTMP5 = s1 {xDxC} */\
+            RND_STEP_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]} */\
+
+#endif
+
+
+#define W_K_from_buff\
+         __asm__ volatile("vmovdqu %0, %%xmm4\n\t"\
+                          "vpshufb %%xmm13, %%xmm4, %%xmm4\n\t"\
+                          :: "m"(sha256->buffer[0]):"%xmm4") ;\
+         __asm__ volatile("vmovdqu %0, %%xmm5\n\t"\
+                          "vpshufb %%xmm13, %%xmm5, %%xmm5\n\t"\
+                          ::"m"(sha256->buffer[4]):"%xmm5") ;\
+         __asm__ volatile("vmovdqu %0, %%xmm6\n\t"\
+                          "vpshufb %%xmm13, %%xmm6, %%xmm6\n\t"\
+                          ::"m"(sha256->buffer[8]):"%xmm6") ;\
+         __asm__ volatile("vmovdqu %0, %%xmm7\n\t"\
+                          "vpshufb %%xmm13, %%xmm7, %%xmm7\n\t"\
+                          ::"m"(sha256->buffer[12]):"%xmm7") ;\
+
+#define _SET_W_K_XFER(reg, i)\
+    __asm__ volatile("vpaddd %0, %"#reg", %%xmm9"::"m"(K[i]):XMM_REGs) ;\
+    __asm__ volatile("vmovdqa %%xmm9, %0":"=m"(W_K[i])::XMM_REGs) ;
+
+#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 _Init_Masks(mask1, mask2, mask3)\
+__asm__ volatile("vmovdqu %0, %"#mask1 ::"m"(mBYTE_FLIP_MASK[0])) ;\
+__asm__ volatile("vmovdqu %0, %"#mask2 ::"m"(mSHUF_00BA[0])) ;\
+__asm__ volatile("vmovdqu %0, %"#mask3 ::"m"(mSHUF_DC00[0])) ;
+
+#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 XTMP4 %xmm8
+#define XTMP5 %xmm9
+#define XFER  %xmm10
+
+#define SHUF_00BA   %xmm11 /* shuffle xBxA -> 00BA */
+#define SHUF_DC00   %xmm12 /* shuffle xDxC -> DC00 */
+#define BYTE_FLIP_MASK  %xmm13
+
+#define XMM_REGs   /* Registers are saved in Sha256Update/Finel */
+                   /*"xmm4","xmm5","xmm6","xmm7","xmm8","xmm9","xmm10","xmm11","xmm12","xmm13" */
+
+static int Transform_AVX1(Sha256* sha256)
+{
+
+    word32 W_K[64] ;  /* temp for W+K */
+
+    #if defined(DEBUG_XMM)
+    int i, j ;
+    word32 xmm[29][4*15] ;
+    #endif
+
+    Init_Masks(BYTE_FLIP_MASK, SHUF_00BA, SHUF_DC00) ;
+    W_K_from_buff ; /* X0, X1, X2, X3 = W[0..15] ; */
+
+    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) ;  
+        
+    #if defined(DEBUG_XMM)
+    for(i=0; i<29; i++) {
+        for(j=0; j<4*14; j+=4)
+            printf("xmm%d[%d]=%08x,%08x,%08x,%08x\n", j/4, i, 
+                   xmm[i][j],xmm[i][j+1],xmm[i][j+2],xmm[i][j+3]) ;
+        printf("\n") ;
+    }
+        
+    for(i=0; i<64; i++)printf("W_K[%d]%08x\n", i, W_K[i]) ;
+    #endif
+
+    return 0;
+}
+
+#if defined(HAVE_INTEL_RORX)
+static int Transform_AVX1_RORX(Sha256* sha256)
+{
+
+    word32 W_K[64] ;  /* temp for W+K */
+
+    #if defined(DEBUG_XMM)
+    int i, j ;
+    word32 xmm[29][4*15] ;
+    #endif
+
+    Init_Masks(BYTE_FLIP_MASK, SHUF_00BA, SHUF_DC00) ;
+    W_K_from_buff ; /* X0, X1, X2, X3 = W[0..15] ; */
+
+    DigestToReg(S_0,S_1,S_2,S_3,S_4,S_5,S_6,S_7) ;
+    SET_W_K_XFER(X0, 0) ;
+    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,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) ;  
+        
+    #if defined(DEBUG_XMM)
+    for(i=0; i<29; i++) {
+        for(j=0; j<4*14; j+=4)
+            printf("xmm%d[%d]=%08x,%08x,%08x,%08x\n", j/4, i, 
+                    xmm[i][j],xmm[i][j+1],xmm[i][j+2],xmm[i][j+3]) ;
+        printf("\n") ;
+    }
+        
+    for(i=0; i<64; i++)printf("W_K[%d]%08x\n", i, W_K[i]) ;
+    #endif
+
+    return 0;
+}
+#endif  /* HAVE_INTEL_RORX */
+
+#endif  /* HAVE_INTEL_AVX1 */
+
+
+#if defined(HAVE_INTEL_AVX2)
+
+#define _MOVE_to_REG(ymm, mem)       __asm__ volatile("vmovdqu %0, %%"#ymm" ":: "m"(mem):YMM_REGs) ;
+#define _MOVE_to_MEM(mem, ymm)       __asm__ volatile("vmovdqu %%"#ymm", %0" : "=m"(mem)::YMM_REGs) ;
+#define _BYTE_SWAP(ymm, map)              __asm__ volatile("vpshufb %0, %%"#ymm", %%"#ymm"\n\t"\
+                                                       :: "m"(map):YMM_REGs) ;
+#define _MOVE_128(ymm0, ymm1, ymm2, map)   __asm__ volatile("vperm2i128  $"#map", %%"\
+                                  #ymm2", %%"#ymm1", %%"#ymm0" ":::YMM_REGs) ;
+#define _MOVE_BYTE(ymm0, ymm1, map)  __asm__ volatile("vpshufb %0, %%"#ymm1", %%"\
+                                  #ymm0"\n\t":: "m"(map):YMM_REGs) ;
+#define _S_TEMP(dest, src, bits, temp)    __asm__ volatile("vpsrld  $"#bits", %%"\
+         #src", %%"#dest"\n\tvpslld  $32-"#bits", %%"#src", %%"#temp"\n\tvpor %%"\
+         #temp",%%"#dest", %%"#dest" ":::YMM_REGs) ;
+#define _AVX2_R(dest, src, bits)          __asm__ volatile("vpsrld  $"#bits", %%"\
+                                  #src", %%"#dest" ":::YMM_REGs) ;
+#define _XOR(dest, src1, src2)       __asm__ volatile("vpxor   %%"#src1", %%"\
+         #src2", %%"#dest" ":::YMM_REGs) ;
+#define _OR(dest, src1, src2)       __asm__ volatile("vpor    %%"#src1", %%"\
+         #src2", %%"#dest" ":::YMM_REGs) ;
+#define _ADD(dest, src1, src2)       __asm__ volatile("vpaddd   %%"#src1", %%"\
+         #src2", %%"#dest" ":::YMM_REGs) ;
+#define _ADD_MEM(dest, src1, mem)    __asm__ volatile("vpaddd   %0, %%"#src1", %%"\
+         #dest" "::"m"(mem):YMM_REGs) ;
+#define _BLEND(map, dest, src1, src2)    __asm__ volatile("vpblendd    $"#map", %%"\
+         #src1",   %%"#src2", %%"#dest" ":::YMM_REGs) ;
+
+#define    _EXTRACT_XMM_0(xmm, mem)  __asm__ volatile("vpextrd $0, %%"#xmm", %0 ":"=r"(mem)::YMM_REGs) ;
+#define    _EXTRACT_XMM_1(xmm, mem)  __asm__ volatile("vpextrd $1, %%"#xmm", %0 ":"=r"(mem)::YMM_REGs) ;
+#define    _EXTRACT_XMM_2(xmm, mem)  __asm__ volatile("vpextrd $2, %%"#xmm", %0 ":"=r"(mem)::YMM_REGs) ;
+#define    _EXTRACT_XMM_3(xmm, mem)  __asm__ volatile("vpextrd $3, %%"#xmm", %0 ":"=r"(mem)::YMM_REGs) ;
+#define    _EXTRACT_XMM_4(ymm, xmm, mem)\
+      __asm__ volatile("vperm2i128 $0x1, %%"#ymm", %%"#ymm", %%"#ymm" ":::YMM_REGs) ;\
+      __asm__ volatile("vpextrd $0, %%"#xmm", %0 ":"=r"(mem)::YMM_REGs) ;
+#define    _EXTRACT_XMM_5(xmm, mem)  __asm__ volatile("vpextrd $1, %%"#xmm", %0 ":"=r"(mem)::YMM_REGs) ;
+#define    _EXTRACT_XMM_6(xmm, mem)  __asm__ volatile("vpextrd $2, %%"#xmm", %0 ":"=r"(mem)::YMM_REGs) ;
+#define    _EXTRACT_XMM_7(xmm, mem)  __asm__ volatile("vpextrd $3, %%"#xmm", %0 ":"=r"(mem)::YMM_REGs) ;
+
+#define    _SWAP_YMM_HL(ymm)   __asm__ volatile("vperm2i128 $0x1, %%"#ymm", %%"#ymm", %%"#ymm" ":::YMM_REGs) ;
+#define     SWAP_YMM_HL(ymm)   _SWAP_YMM_HL(ymm) 
+
+#define MOVE_to_REG(ymm, mem)      _MOVE_to_REG(ymm, mem)
+#define MOVE_to_MEM(mem, ymm)      _MOVE_to_MEM(mem, 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)  _ADD_MEM(dest, src1, mem)
+#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, mMAP1toW_I_2[0]) ; \
+    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, mMAP2toW_I_2[0]) ; BLEND(0x30, W_I_2, YMM_TEMP0, W_I_2) ; 
+#define    FEEDBACK3_to_W_I_2    MOVE_BYTE(YMM_TEMP0, W_I, mMAP3toW_I_2[0]) ; \
+    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, mMAPtoW_I_7[0]) ; 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 YMM_REGs /* Registers are saved in Sha256Update/Finel */
+ /* "%ymm7","%ymm8","%ymm9","%ymm10","%ymm11","%ymm12","%ymm13","%ymm14","%ymm15"*/
+
+
+#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" ":::YMM_REGs) ;\
+    __asm__ volatile("vpblendd    $0x08, %%"#w_i_15", %%"#w_i_7", %%"#w_i_16" ":::YMM_REGs) ;\
+    __asm__ volatile("vperm2i128 $0x01,  %%"#w_i_7",  %%"#w_i_7", %%"#w_i_15" ":::YMM_REGs) ;\
+    __asm__ volatile("vpblendd    $0x80, %%"#w_i_15", %%"#w_i_16", %%"#w_i_16" ":::YMM_REGs) ;\
+    __asm__ volatile("vpshufd    $0x93,  %%"#w_i_16", %%"#w_i_16" ":::YMM_REGs) ;\
+
+#define MOVE_7_to_15(w_i_15, w_i_7)\
+    __asm__ volatile("vmovdqu                 %%"#w_i_7",  %%"#w_i_15" ":::YMM_REGs) ;\
+
+#define MOVE_I_to_7(w_i_7, w_i)\
+    __asm__ volatile("vperm2i128 $0x01,       %%"#w_i",   %%"#w_i",   %%"#w_i_7" ":::YMM_REGs) ;\
+    __asm__ volatile("vpblendd    $0x01,       %%"#w_i_7",   %%"#w_i", %%"#w_i_7" ":::YMM_REGs) ;\
+    __asm__ volatile("vpshufd    $0x39, %%"#w_i_7", %%"#w_i_7" ":::YMM_REGs) ;\
+
+#define MOVE_I_to_2(w_i_2, w_i)\
+    __asm__ volatile("vperm2i128 $0x01,       %%"#w_i", %%"#w_i", %%"#w_i_2" ":::YMM_REGs) ;\
+    __asm__ volatile("vpshufd    $0x0e, %%"#w_i_2", %%"#w_i_2" ":::YMM_REGs) ;\
+
+#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 _RegToDigest(S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7 )\
+    { word32 d ;\
+    __asm__ volatile("movl %"#S_0", %0":"=r"(d)::SSE_REGs) ;\
+    sha256->digest[0] += d;\
+    __asm__ volatile("movl %"#S_1", %0":"=r"(d)::SSE_REGs) ;\
+    sha256->digest[1] += d;\
+    __asm__ volatile("movl %"#S_2", %0":"=r"(d)::SSE_REGs) ;\
+    sha256->digest[2] += d;\
+    __asm__ volatile("movl %"#S_3", %0":"=r"(d)::SSE_REGs) ;\
+    sha256->digest[3] += d;\
+    __asm__ volatile("movl %"#S_4", %0":"=r"(d)::SSE_REGs) ;\
+    sha256->digest[4] += d;\
+    __asm__ volatile("movl %"#S_5", %0":"=r"(d)::SSE_REGs) ;\
+    sha256->digest[5] += d;\
+    __asm__ volatile("movl %"#S_6", %0":"=r"(d)::SSE_REGs) ;\
+    sha256->digest[6] += d;\
+    __asm__ volatile("movl %"#S_7", %0":"=r"(d)::SSE_REGs) ;\
+    sha256->digest[7] += d;\
+}
+
+#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(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
+
+    MOVE_to_REG(W_I_16, sha256->buffer[0]);     BYTE_SWAP(W_I_16, mBYTE_FLIP_MASK_16[0]) ;
+    MOVE_to_REG(W_I_15, sha256->buffer[1]);     BYTE_SWAP(W_I_15, mBYTE_FLIP_MASK_15[0]) ;
+    MOVE_to_REG(W_I,    sha256->buffer[8]) ;    BYTE_SWAP(W_I,    mBYTE_FLIP_MASK_16[0]) ;
+    MOVE_to_REG(W_I_7,  sha256->buffer[16-7]) ; BYTE_SWAP(W_I_7,  mBYTE_FLIP_MASK_7[0])  ;
+    MOVE_to_REG(W_I_2,  sha256->buffer[16-2]) ; BYTE_SWAP(W_I_2,  mBYTE_FLIP_MASK_2[0])  ;
+
+    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) ;  
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(W, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    #endif
+    
+    return 0;
+}
+
+#endif   /* HAVE_INTEL_AVX2 */
+
+#endif   /* HAVE_FIPS */
+
+#endif   /* WOLFSSL_TI_HAHS */
+
+#endif /* NO_SHA256 */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/sha512.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,1806 @@
+/* sha512.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+#include <wolfssl/wolfcrypt/sha512.h>
+
+#ifdef WOLFSSL_SHA512
+
+#ifdef HAVE_FIPS
+int wc_InitSha512(Sha512* sha)
+{
+    return InitSha512_fips(sha);
+}
+
+
+int wc_Sha512Update(Sha512* sha, const byte* data, word32 len)
+{
+    return Sha512Update_fips(sha, data, len);
+}
+
+
+int wc_Sha512Final(Sha512* sha, byte* out)
+{
+    return Sha512Final_fips(sha, out);
+}
+
+
+int wc_Sha512Hash(const byte* data, word32 len, byte* out)
+{
+    return Sha512Hash(data, len, out);
+}
+
+#if defined(WOLFSSL_SHA384) || defined(HAVE_AESGCM)
+
+int wc_InitSha384(Sha384* sha)
+{
+    return InitSha384_fips(sha);
+}
+
+
+int wc_Sha384Update(Sha384* sha, const byte* data, word32 len)
+{
+    return Sha384Update_fips(sha, data, len);
+}
+
+
+int wc_Sha384Final(Sha384* sha, byte* out)
+{
+    return Sha384Final_fips(sha, out);
+}
+
+
+int wc_Sha384Hash(const byte* data, word32 len, byte* out)
+{
+    return Sha384Hash(data, len, out);
+}
+#endif /* WOLFSSL_SHA384 */
+#else /* else build without using fips */
+#include <wolfssl/wolfcrypt/logging.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+
+#ifndef WOLFSSL_HAVE_MIN
+#define WOLFSSL_HAVE_MIN
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* WOLFSSL_HAVE_MIN */
+
+#if defined(USE_INTEL_SPEEDUP)
+  #define HAVE_INTEL_AVX1
+  #define HAVE_INTEL_AVX2
+#endif
+
+#if defined(HAVE_INTEL_AVX1)
+/* #define DEBUG_XMM  */
+#endif
+
+#if defined(HAVE_INTEL_AVX2)
+#define HAVE_INTEL_RORX
+/* #define DEBUG_YMM  */
+#endif
+
+/*****
+Intel AVX1/AVX2 Macro Control Structure
+
+#if defined(HAVE_INteL_SPEEDUP)
+    #define HAVE_INTEL_AVX1
+    #define HAVE_INTEL_AVX2
+#endif
+
+int InitSha512(Sha512* sha512) { 
+     Save/Recover XMM, YMM
+     ...
+
+     Check Intel AVX cpuid flags
+}
+
+#if defined(HAVE_INTEL_AVX1)|| defined(HAVE_INTEL_AVX2)
+  Transform_AVX1() ; # Function prototype 
+  Transform_AVX2() ; #
+#endif
+
+  _Transform() {     # Native Transform Function body
+  
+  }
+  
+  int Sha512Update() { 
+     Save/Recover XMM, YMM
+     ...
+  }
+  
+  int Sha512Final() { 
+     Save/Recover XMM, YMM
+     ...
+  }
+
+
+#if defined(HAVE_INTEL_AVX1)
+   
+   XMM Instructions/inline asm Definitions
+
+#endif
+
+#if defined(HAVE_INTEL_AVX2)
+
+   YMM Instructions/inline asm Definitions
+
+#endif
+
+#if defnied(HAVE_INTEL_AVX1)
+  
+  int Transform_AVX1() {
+      Stitched Message Sched/Round
+  }
+
+#endif
+
+#if defnied(HAVE_INTEL_AVX2)
+  
+  int Transform_AVX2() {
+      Stitched Message Sched/Round
+  }
+#endif
+
+
+*/
+
+#if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+
+
+/* Each platform needs to query info type 1 from cpuid to see if aesni is
+ * supported. Also, let's setup a macro for proper linkage w/o ABI conflicts
+ */
+
+#ifndef _MSC_VER
+    #define cpuid(reg, leaf, sub)\
+            __asm__ __volatile__ ("cpuid":\
+             "=a" (reg[0]), "=b" (reg[1]), "=c" (reg[2]), "=d" (reg[3]) :\
+             "a" (leaf), "c"(sub));
+
+    #define XASM_LINK(f) asm(f)
+#else
+
+    #include <intrin.h>
+    #define cpuid(a,b) __cpuid((int*)a,b)
+
+    #define XASM_LINK(f)
+
+#endif /* _MSC_VER */
+
+#define EAX 0
+#define EBX 1
+#define ECX 2 
+#define EDX 3
+    
+#define CPUID_AVX1   0x1
+#define CPUID_AVX2   0x2
+#define CPUID_RDRAND 0x4
+#define CPUID_RDSEED 0x8
+#define CPUID_BMI2   0x10   /* MULX, RORX */
+
+#define IS_INTEL_AVX1       (cpuid_flags&CPUID_AVX1)
+#define IS_INTEL_AVX2       (cpuid_flags&CPUID_AVX2)
+#define IS_INTEL_BMI2       (cpuid_flags&CPUID_BMI2)
+#define IS_INTEL_RDRAND     (cpuid_flags&CPUID_RDRAND)
+#define IS_INTEL_RDSEED     (cpuid_flags&CPUID_RDSEED)
+
+static word32 cpuid_check = 0 ;
+static word32 cpuid_flags = 0 ;
+
+static word32 cpuid_flag(word32 leaf, word32 sub, word32 num, word32 bit) {
+    int got_intel_cpu=0;
+    unsigned int reg[5]; 
+    
+    reg[4] = '\0' ;
+    cpuid(reg, 0, 0);  
+    if(memcmp((char *)&(reg[EBX]), "Genu", 4) == 0 &&  
+                memcmp((char *)&(reg[EDX]), "ineI", 4) == 0 &&  
+                memcmp((char *)&(reg[ECX]), "ntel", 4) == 0) {  
+        got_intel_cpu = 1;  
+    }    
+    if (got_intel_cpu) {
+        cpuid(reg, leaf, sub);
+        return((reg[num]>>bit)&0x1) ;
+    }
+    return 0 ;
+}
+
+#define CHECK_SHA512 0x1
+#define CHECK_SHA384 0x2
+
+static int set_cpuid_flags(int sha) {  
+    if((cpuid_check & sha) ==0) {
+        if(cpuid_flag(1, 0, ECX, 28)){ cpuid_flags |= CPUID_AVX1 ;}
+        if(cpuid_flag(7, 0, EBX, 5)){  cpuid_flags |= CPUID_AVX2 ; }
+        if(cpuid_flag(7, 0, EBX, 8)) { cpuid_flags |= CPUID_BMI2 ; }
+        if(cpuid_flag(1, 0, ECX, 30)){ cpuid_flags |= CPUID_RDRAND ;  } 
+        if(cpuid_flag(7, 0, EBX, 18)){ cpuid_flags |= CPUID_RDSEED ;  }
+		cpuid_check |= sha ;
+		return 0 ;
+    }
+    return 1 ;
+}
+
+
+/* #if defined(HAVE_INTEL_AVX1/2) at the tail of sha512 */
+
+#if defined(HAVE_INTEL_AVX1)
+static int Transform_AVX1(Sha512 *sha512) ;
+#endif
+
+#if defined(HAVE_INTEL_AVX2)
+static int Transform_AVX2(Sha512 *sha512) ; 
+
+#if defined(HAVE_INTEL_AVX1) && defined(HAVE_INTEL_AVX2) && defined(HAVE_INTEL_RORX)
+static int Transform_AVX1_RORX(Sha512 *sha512) ;
+#endif
+
+#endif
+
+static int _Transform(Sha512 *sha512) ; 
+    
+static int (*Transform_p)(Sha512* sha512) = _Transform ;
+
+#define Transform(sha512) (*Transform_p)(sha512)
+
+static void set_Transform(void) {
+     if(set_cpuid_flags(CHECK_SHA512)) return ;
+
+#if defined(HAVE_INTEL_AVX2)
+     if(IS_INTEL_AVX2 && IS_INTEL_BMI2){ 
+         Transform_p = Transform_AVX1_RORX; return ; 
+         Transform_p = Transform_AVX2      ; 
+                  /* for avoiding warning,"not used" */
+     }
+#endif
+#if defined(HAVE_INTEL_AVX1)
+     Transform_p = ((IS_INTEL_AVX1) ? Transform_AVX1 : _Transform) ; return ;
+#endif
+     Transform_p = _Transform ; return ;
+}
+
+#else
+   #define Transform(sha512) _Transform(sha512)
+#endif
+
+/* 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")
+#else
+#define  SAVE_XMM_YMM
+#endif
+
+#if defined(HAVE_INTEL_AVX1)|| defined(HAVE_INTEL_AVX2)
+
+#include <string.h>
+
+#endif /* defined(HAVE_INTEL_AVX1)|| defined(HAVE_INTEL_AVX2) */
+
+
+#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
+
+#if defined(HAVE_BYTEREVERSE64) && !defined(HAVE_INTEL_AVX1) && !defined(HAVE_INTEL_AVX2)
+#define ByteReverseWords64(out, in, size) ByteReverseWords64_1(out, size)
+#define ByteReverseWords64_1(buf, size)\
+ { unsigned int i ;\
+   for(i=0; i< size/sizeof(word64); i++){\
+       __asm__ volatile("bswapq %0":"+r"(buf[i])::) ;\
+   }\
+}
+#endif
+
+
+int wc_InitSha512(Sha512* sha512)
+{
+    sha512->digest[0] = W64LIT(0x6a09e667f3bcc908);
+    sha512->digest[1] = W64LIT(0xbb67ae8584caa73b);
+    sha512->digest[2] = W64LIT(0x3c6ef372fe94f82b);
+    sha512->digest[3] = W64LIT(0xa54ff53a5f1d36f1);
+    sha512->digest[4] = W64LIT(0x510e527fade682d1);
+    sha512->digest[5] = W64LIT(0x9b05688c2b3e6c1f);
+    sha512->digest[6] = W64LIT(0x1f83d9abfb41bd6b);
+    sha512->digest[7] = W64LIT(0x5be0cd19137e2179);
+
+    sha512->buffLen = 0;
+    sha512->loLen   = 0;
+    sha512->hiLen   = 0;
+    
+#if defined(HAVE_INTEL_AVX1)|| defined(HAVE_INTEL_AVX2)
+    set_Transform() ; /* choose best Transform function under this runtime environment */
+#endif
+    
+    return 0 ;
+}
+
+
+static const word64 K512[80] = {
+	W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd),
+	W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc),
+	W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019),
+	W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118),
+	W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe),
+	W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2),
+	W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1),
+	W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694),
+	W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3),
+	W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65),
+	W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483),
+	W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5),
+	W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210),
+	W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4),
+	W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725),
+	W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70),
+	W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926),
+	W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df),
+	W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8),
+	W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b),
+	W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001),
+	W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30),
+	W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910),
+	W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8),
+	W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53),
+	W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8),
+	W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb),
+	W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3),
+	W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60),
+	W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec),
+	W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9),
+	W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b),
+	W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207),
+	W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178),
+	W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6),
+	W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b),
+	W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493),
+	W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c),
+	W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a),
+	W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817)
+};
+
+
+
+#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 Ch(x,y,z) (z^(x&(y^z)))
+#define Maj(x,y,z) ((x&y)|(z&(x|y)))
+
+#define a(i) T[(0-i)&7]
+#define b(i) T[(1-i)&7]
+#define c(i) T[(2-i)&7]
+#define d(i) T[(3-i)&7]
+#define e(i) T[(4-i)&7]
+#define f(i) T[(5-i)&7]
+#define g(i) T[(6-i)&7]
+#define h(i) T[(7-i)&7]
+
+#define S0(x) (rotrFixed64(x,28)^rotrFixed64(x,34)^rotrFixed64(x,39))
+#define S1(x) (rotrFixed64(x,14)^rotrFixed64(x,18)^rotrFixed64(x,41))
+#define s0(x) (rotrFixed64(x,1)^rotrFixed64(x,8)^(x>>7))
+#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))
+
+#define blk384(i) (W[i] = sha384->buffer[i])
+
+#define R2(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+K[i+j]+(j?blk2(i):blk384(i));\
+    d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i))
+
+static int _Transform(Sha512* sha512)
+{
+    const word64* K = K512;
+
+    word32 j;
+    word64 T[8];
+
+
+#ifdef WOLFSSL_SMALL_STACK
+    word64* W;
+    W = (word64*) XMALLOC(sizeof(word64) * 16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (W == NULL)
+        return MEMORY_E;
+#else
+    word64 W[16];
+#endif
+
+    /* Copy digest to working vars */
+    XMEMCPY(T, sha512->digest, sizeof(T));
+
+#ifdef USE_SLOW_SHA2
+    /* over twice as small, but 50% slower */
+    /* 80 operations, not unrolled */
+    for (j = 0; j < 80; j += 16) {
+        int m; 
+        for (m = 0; m < 16; m++) { /* braces needed here for macros {} */
+            R(m);
+        }
+    }
+#else
+    /* 80 operations, partially loop unrolled */
+    for (j = 0; j < 80; j += 16) {
+        R( 0); R( 1); R( 2); R( 3);
+        R( 4); R( 5); R( 6); R( 7);
+        R( 8); R( 9); R(10); R(11);
+        R(12); R(13); R(14); R(15);
+    }
+#endif /* USE_SLOW_SHA2 */
+
+    /* 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 */
+    ForceZero(W, sizeof(word64) * 16);
+    ForceZero(T, sizeof(T));
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(W, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return 0;
+}
+
+
+static INLINE void AddLength(Sha512* sha512, word32 len)
+{
+    word32 tmp = sha512->loLen;
+    if ( (sha512->loLen += len) < tmp)
+        sha512->hiLen++;                       /* carry low to high */
+}
+
+int wc_Sha512Update(Sha512* sha512, const byte* data, word32 len)
+{
+    /* do block size increments */
+    byte* local = (byte*)sha512->buffer;
+    SAVE_XMM_YMM ; /* for Intel AVX */
+
+    while (len) {
+        word32 add = min(len, SHA512_BLOCK_SIZE - sha512->buffLen);
+        XMEMCPY(&local[sha512->buffLen], data, add);
+
+        sha512->buffLen += add;
+        data         += add;
+        len          -= add;
+
+        if (sha512->buffLen == SHA512_BLOCK_SIZE) {
+            int ret;
+            #if defined(LITTLE_ENDIAN_ORDER)
+                #if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+                if(!IS_INTEL_AVX1 && !IS_INTEL_AVX2) 
+                #endif
+                    ByteReverseWords64(sha512->buffer, sha512->buffer,
+                                   SHA512_BLOCK_SIZE);
+            #endif
+            ret = Transform(sha512);
+            if (ret != 0)
+                return ret;
+
+            AddLength(sha512, SHA512_BLOCK_SIZE);
+            sha512->buffLen = 0;
+        }
+    }
+    return 0;
+}
+
+
+int wc_Sha512Final(Sha512* sha512, byte* hash)
+{
+    byte* local = (byte*)sha512->buffer;
+    int ret;
+
+    SAVE_XMM_YMM ; /* for Intel AVX */
+    AddLength(sha512, sha512->buffLen);               /* before adding pads */
+
+    local[sha512->buffLen++] = 0x80;  /* add 1 */
+
+    /* pad with zeros */
+    if (sha512->buffLen > SHA512_PAD_SIZE) {
+        XMEMSET(&local[sha512->buffLen], 0, SHA512_BLOCK_SIZE -sha512->buffLen);
+        sha512->buffLen += SHA512_BLOCK_SIZE - sha512->buffLen;
+        #if defined(LITTLE_ENDIAN_ORDER) 
+            #if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+            if(!IS_INTEL_AVX1 && !IS_INTEL_AVX2)
+            #endif
+            ByteReverseWords64(sha512->buffer,sha512->buffer,SHA512_BLOCK_SIZE);
+        #endif
+        ret = Transform(sha512);
+        if (ret != 0)
+            return ret;
+
+        sha512->buffLen = 0;
+    }
+    XMEMSET(&local[sha512->buffLen], 0, SHA512_PAD_SIZE - sha512->buffLen);
+   
+    /* put lengths in bits */
+    sha512->hiLen = (sha512->loLen >> (8*sizeof(sha512->loLen) - 3)) + 
+                 (sha512->hiLen << 3);
+    sha512->loLen = sha512->loLen << 3;
+
+    /* store lengths */
+    #if defined(LITTLE_ENDIAN_ORDER)
+        #if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+        if(!IS_INTEL_AVX1 && !IS_INTEL_AVX2)
+        #endif
+        ByteReverseWords64(sha512->buffer, sha512->buffer, SHA512_PAD_SIZE);
+    #endif
+    /* ! length ordering dependent on digest endian type ! */
+
+    sha512->buffer[SHA512_BLOCK_SIZE / sizeof(word64) - 2] = sha512->hiLen;
+    sha512->buffer[SHA512_BLOCK_SIZE / sizeof(word64) - 1] = sha512->loLen;
+    #if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+    if(IS_INTEL_AVX1 || IS_INTEL_AVX2)
+        ByteReverseWords64(&(sha512->buffer[SHA512_BLOCK_SIZE / sizeof(word64) - 2]),
+                           &(sha512->buffer[SHA512_BLOCK_SIZE / sizeof(word64) - 2]),
+                           SHA512_BLOCK_SIZE - SHA512_PAD_SIZE);
+    #endif
+    ret = Transform(sha512);
+    if (ret != 0)
+        return ret;
+
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords64(sha512->digest, sha512->digest, SHA512_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, sha512->digest, SHA512_DIGEST_SIZE);
+
+    return wc_InitSha512(sha512);  /* reset state */
+}
+
+
+int wc_Sha512Hash(const byte* data, word32 len, byte* hash)
+{
+    int ret = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    Sha512* sha512;
+#else
+    Sha512 sha512[1];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    sha512 = (Sha512*)XMALLOC(sizeof(Sha512), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (sha512 == NULL)
+        return MEMORY_E;
+#endif
+    
+    if ((ret = wc_InitSha512(sha512)) != 0) {
+        WOLFSSL_MSG("InitSha512 failed");
+    }
+    else if ((ret = wc_Sha512Update(sha512, data, len)) != 0) {
+        WOLFSSL_MSG("Sha512Update failed");
+    }
+    else if ((ret = wc_Sha512Final(sha512, hash)) != 0) {
+        WOLFSSL_MSG("Sha512Final failed");
+    }
+    
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(sha512, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+    
+    return ret;
+}
+
+#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));
+
+#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
+
+#endif
+
+#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
+
+#if defined(HAVE_INTEL_AVX1) /* inline Assember for Intel AVX1 instructions */
+#if defined(DEBUG_XMM)
+
+#define SAVE_REG(i)     __asm__ volatile("vmovdqu %%xmm"#i", %0 \n\t":"=m"(reg[i][0])::XMM_REGs);
+#define RECV_REG(i)     __asm__ volatile("vmovdqu %0, %%xmm"#i" \n\t"::"m"(reg[i][0]):XMM_REGs);
+
+#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])::XMM_REGs);\
+      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
+
+#define _MOVE_to_REG(xymm, mem)       __asm__ volatile("vmovdqu %0, %%"#xymm" "\
+        :: "m"(mem):XMM_REGs) ;
+#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])::XMM_REGs) ;
+#define _MOVE(dest, src)              __asm__ volatile("vmovdqu %%"#src",  %%"\
+        #dest" ":::XMM_REGs) ;
+
+#define _S_TEMP(dest, src, bits, temp)  __asm__ volatile("vpsrlq  $"#bits", %%"\
+        #src", %%"#dest"\n\tvpsllq  $64-"#bits", %%"#src", %%"#temp"\n\tvpor %%"\
+        #temp",%%"#dest", %%"#dest" ":::XMM_REGs) ;
+#define _AVX1_R(dest, src, bits)      __asm__ volatile("vpsrlq  $"#bits", %%"\
+        #src", %%"#dest" ":::XMM_REGs) ;
+#define _XOR(dest, src1, src2)        __asm__ volatile("vpxor   %%"#src1", %%"\
+        #src2", %%"#dest" ":::XMM_REGs) ;
+#define _OR(dest, src1, src2)         __asm__ volatile("vpor    %%"#src1", %%"\
+        #src2", %%"#dest" ":::XMM_REGs) ;
+#define _ADD(dest, src1, src2)        __asm__ volatile("vpaddq   %%"#src1", %%"\
+        #src2", %%"#dest" ":::XMM_REGs) ;
+#define _ADD_MEM(dest, src1, mem)     __asm__ volatile("vpaddq   %0, %%"#src1", %%"\
+        #dest" "::"m"(mem):XMM_REGs) ;
+
+#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 XMM_REGs
+
+#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
+
+#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]):YMM_REGs) ;\
+     __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]):YMM_REGs) ;\
+     __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]):YMM_REGs) ;\
+    }
+
+#if defined(DEBUG_YMM)
+
+#define SAVE_REG_Y(i) __asm__ volatile("vmovdqu %%ymm"#i", %0 \n\t":"=m"(reg[i-4][0])::YMM_REGs);
+#define RECV_REG_Y(i) __asm__ volatile("vmovdqu %0, %%ymm"#i" \n\t"::"m"(reg[i-4][0]):YMM_REGs);
+
+#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])::YMM_REGs);\
+      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
+
+#define _MOVE_to_REGy(ymm, mem)         __asm__ volatile("vmovdqu %0, %%"#ymm" "\
+                                        :: "m"(mem):YMM_REGs) ;
+#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])::YMM_REGs) ;
+#define _MOVE_128y(ymm0, ymm1, ymm2, map)  __asm__ volatile("vperm2i128  $"\
+        #map", %%"#ymm2", %%"#ymm1", %%"#ymm0" ":::YMM_REGs) ;
+#define _S_TEMPy(dest, src, bits, temp) \
+         __asm__ volatile("vpsrlq  $"#bits", %%"#src", %%"#dest"\n\tvpsllq  $64-"#bits\
+        ", %%"#src", %%"#temp"\n\tvpor %%"#temp",%%"#dest", %%"#dest" ":::YMM_REGs) ;
+#define _AVX2_R(dest, src, bits)        __asm__ volatile("vpsrlq  $"#bits", %%"\
+         #src", %%"#dest" ":::YMM_REGs) ;
+#define _XORy(dest, src1, src2)         __asm__ volatile("vpxor   %%"#src1", %%"\
+         #src2", %%"#dest" ":::YMM_REGs) ;
+#define _ADDy(dest, src1, src2)         __asm__ volatile("vpaddq   %%"#src1", %%"\
+         #src2", %%"#dest" ":::YMM_REGs) ;
+#define _BLENDy(map, dest, src1, src2)  __asm__ volatile("vpblendd    $"#map", %%"\
+         #src1",   %%"#src2", %%"#dest" ":::YMM_REGs) ;
+#define _BLENDQy(map, dest, src1, src2) __asm__ volatile("vblendpd   $"#map", %%"\
+         #src1",   %%"#src2", %%"#dest" ":::YMM_REGs) ;
+#define _PERMQy(map, dest, src)         __asm__ volatile("vpermq  $"#map", %%"\
+         #src", %%"#dest" ":::YMM_REGs) ;
+
+#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 YMM_REGs
+/* Registers are saved in Sha512Update/Final */
+                 /* "%ymm7","%ymm8","%ymm9","%ymm10","%ymm11","%ymm12","%ymm13","%ymm14","%ymm15"*/
+
+#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" ":::YMM_REGs) ;\
+    __asm__ volatile("vpblendd    $0x08, %%"#w_i_15", %%"#w_i_7", %%"#w_i_16" ":::YMM_REGs) ;\
+    __asm__ volatile("vperm2i128 $0x01,  %%"#w_i_7",  %%"#w_i_7", %%"#w_i_15" ":::YMM_REGs) ;\
+    __asm__ volatile("vpblendd    $0x80, %%"#w_i_15", %%"#w_i_16", %%"#w_i_16" ":::YMM_REGs) ;\
+    __asm__ volatile("vpshufd    $0x93,  %%"#w_i_16", %%"#w_i_16" ":::YMM_REGs) ;\
+
+#define MOVE_7_to_15(w_i_15, w_i_7)\
+    __asm__ volatile("vmovdqu                 %%"#w_i_7",  %%"#w_i_15" ":::YMM_REGs) ;\
+
+#define MOVE_I_to_7(w_i_7, w_i)\
+    __asm__ volatile("vperm2i128 $0x01,       %%"#w_i",   %%"#w_i",   %%"#w_i_7" ":::YMM_REGs) ;\
+    __asm__ volatile("vpblendd    $0x01,       %%"#w_i_7",   %%"#w_i", %%"#w_i_7" ":::YMM_REGs) ;\
+    __asm__ volatile("vpshufd    $0x39, %%"#w_i_7", %%"#w_i_7" ":::YMM_REGs) ;\
+
+#define MOVE_I_to_2(w_i_2, w_i)\
+    __asm__ volatile("vperm2i128 $0x01,       %%"#w_i", %%"#w_i", %%"#w_i_2" ":::YMM_REGs) ;\
+    __asm__ volatile("vpshufd    $0x0e, %%"#w_i_2", %%"#w_i_2" ":::YMM_REGs) ;\
+
+#endif
+
+
+/***  Transform Body ***/
+#if defined(HAVE_INTEL_AVX1)
+
+static int Transform_AVX1(Sha512* sha512)
+{
+    const word64* K = K512;
+    word64 W_X[16+4];
+    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));
+
+    return 0;
+}
+
+#endif
+
+#if defined(HAVE_INTEL_AVX2) && defined(HAVE_INTEL_AVX1) && defined(HAVE_INTEL_RORX)
+
+static int Transform_AVX1_RORX(Sha512* sha512)
+{
+    const word64* K = K512;
+    word64 W_X[16+4];
+    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));
+
+    return 0;
+}
+#endif
+
+#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 blk384(i) (W[i] = sha384->buffer[i])
+
+
+#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(Sha512* sha512)
+{
+    const word64* K = K512;
+    word64 w[4] ;
+    word32 j /*, k*/;
+    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));
+
+    return 0;
+}
+
+#endif
+
+
+#ifdef WOLFSSL_SHA384
+
+#if defined(HAVE_INTEL_AVX1) ||  defined(HAVE_INTEL_AVX2) 
+
+#if defined(HAVE_INTEL_AVX1)
+static int Transform384_AVX1(Sha384 *sha384) ;
+#endif
+#if defined(HAVE_INTEL_AVX2)
+static int Transform384_AVX2(Sha384 *sha384) ; 
+#endif
+
+#if defined(HAVE_INTEL_AVX1) &&  defined(HAVE_INTEL_AVX2) &&defined(HAVE_INTEL_RORX)
+static int Transform384_AVX1_RORX(Sha384 *sha384) ; 
+#endif
+
+static int _Transform384(Sha384 *sha384) ; 
+static int (*Transform384_p)(Sha384* sha384) = _Transform384 ;
+
+#define Transform384(sha384) (*Transform384_p)(sha384)
+static void set_Transform384(void) {
+     if(set_cpuid_flags(CHECK_SHA384))return ;
+
+#if defined(HAVE_INTEL_AVX1) && !defined(HAVE_INTEL_AVX2)
+     Transform384_p = ((IS_INTEL_AVX1) ? Transform384_AVX1 : _Transform384) ;
+#elif defined(HAVE_INTEL_AVX2)
+     #if defined(HAVE_INTEL_AVX1) && defined(HAVE_INTEL_RORX)
+     if(IS_INTEL_AVX2 && IS_INTEL_BMI2) { Transform384_p = Transform384_AVX1_RORX ; return ; }
+     #endif
+     if(IS_INTEL_AVX2) { Transform384_p = Transform384_AVX2 ; return ; }
+     #if defined(HAVE_INTEL_AVX1)
+     Transform384_p = ((IS_INTEL_AVX1) ? Transform384_AVX1 : _Transform384) ;
+     #endif
+#else
+     Transform384_p = ((IS_INTEL_AVX1) ? Transform384_AVX1 : _Transform384) ;
+#endif
+}
+
+#else
+   #define Transform384(sha512) _Transform384(sha512)
+#endif
+
+int wc_InitSha384(Sha384* sha384)
+{
+    sha384->digest[0] = W64LIT(0xcbbb9d5dc1059ed8);
+    sha384->digest[1] = W64LIT(0x629a292a367cd507);
+    sha384->digest[2] = W64LIT(0x9159015a3070dd17);
+    sha384->digest[3] = W64LIT(0x152fecd8f70e5939);
+    sha384->digest[4] = W64LIT(0x67332667ffc00b31);
+    sha384->digest[5] = W64LIT(0x8eb44a8768581511);
+    sha384->digest[6] = W64LIT(0xdb0c2e0d64f98fa7);
+    sha384->digest[7] = W64LIT(0x47b5481dbefa4fa4);
+
+    sha384->buffLen = 0;
+    sha384->loLen   = 0;
+    sha384->hiLen   = 0;
+
+#if defined(HAVE_INTEL_AVX1)|| defined(HAVE_INTEL_AVX2)
+    set_Transform384() ;
+#endif
+    
+    return 0;
+}
+
+static int _Transform384(Sha384* sha384)
+{
+    const word64* K = K512;
+
+    word32 j;
+    word64 T[8];
+
+#ifdef WOLFSSL_SMALL_STACK
+    word64* W;
+
+    W = (word64*) XMALLOC(sizeof(word64) * 16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (W == NULL)
+        return MEMORY_E;
+#else
+    word64 W[16];
+#endif
+
+    /* Copy digest to working vars */
+    XMEMCPY(T, sha384->digest, sizeof(T));
+
+#ifdef USE_SLOW_SHA2
+    /* over twice as small, but 50% slower */
+    /* 80 operations, not unrolled */
+    for (j = 0; j < 80; j += 16) {
+        int m;
+        for (m = 0; m < 16; m++) {  /* braces needed for macros {} */
+            R2(m);
+        }
+    }
+#else
+    /* 80 operations, partially loop unrolled */
+    for (j = 0; j < 80; j += 16) {
+        R2( 0); R2( 1); R2( 2); R2( 3);
+        R2( 4); R2( 5); R2( 6); R2( 7);
+        R2( 8); R2( 9); R2(10); R2(11);
+        R2(12); R2(13); R2(14); R2(15);
+    }
+#endif /* USE_SLOW_SHA2 */
+
+    /* Add the working vars back into digest */
+
+    sha384->digest[0] += a(0);
+    sha384->digest[1] += b(0);
+    sha384->digest[2] += c(0);
+    sha384->digest[3] += d(0);
+    sha384->digest[4] += e(0);
+    sha384->digest[5] += f(0);
+    sha384->digest[6] += g(0);
+    sha384->digest[7] += h(0);
+
+    /* Wipe variables */
+    XMEMSET(W, 0, sizeof(word64) * 16);
+    XMEMSET(T, 0, sizeof(T));
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(W, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return 0;
+}
+
+static INLINE void AddLength384(Sha384* sha384, word32 len)
+{
+    word32 tmp = sha384->loLen;
+    if ( (sha384->loLen += len) < tmp)
+        sha384->hiLen++;                       /* carry low to high */
+}
+
+int wc_Sha384Update(Sha384* sha384, const byte* data, word32 len)
+{
+    /* do block size increments */
+    byte* local = (byte*)sha384->buffer;
+	
+    SAVE_XMM_YMM ; /* for Intel AVX */
+    
+    while (len) {
+        word32 add = min(len, SHA384_BLOCK_SIZE - sha384->buffLen);
+        XMEMCPY(&local[sha384->buffLen], data, add);
+
+        sha384->buffLen += add;
+        data         += add;
+        len          -= add;
+
+        if (sha384->buffLen == SHA384_BLOCK_SIZE) {
+            int ret;
+
+            #if defined(LITTLE_ENDIAN_ORDER)
+                #if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+                if(!IS_INTEL_AVX1 && !IS_INTEL_AVX2) 
+                #endif
+                    ByteReverseWords64(sha384->buffer, sha384->buffer,
+                                   SHA384_BLOCK_SIZE);
+            #endif
+            ret = Transform384(sha384);
+            if (ret != 0)
+                return ret;
+
+            AddLength384(sha384, SHA384_BLOCK_SIZE);
+            sha384->buffLen = 0;
+        }
+    }
+    return 0;
+}
+
+
+int wc_Sha384Final(Sha384* sha384, byte* hash)
+{
+    byte* local = (byte*)sha384->buffer;
+    int ret;
+
+    SAVE_XMM_YMM ; /* for Intel AVX */
+    AddLength384(sha384, sha384->buffLen);              /* before adding pads */
+
+    local[sha384->buffLen++] = 0x80;  /* add 1 */
+
+    /* pad with zeros */
+    if (sha384->buffLen > SHA384_PAD_SIZE) {
+        XMEMSET(&local[sha384->buffLen], 0, SHA384_BLOCK_SIZE -sha384->buffLen);
+        sha384->buffLen += SHA384_BLOCK_SIZE - sha384->buffLen;
+
+        #if defined(LITTLE_ENDIAN_ORDER)
+            #if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+            if(!IS_INTEL_AVX1 && !IS_INTEL_AVX2) 
+            #endif
+                 ByteReverseWords64(sha384->buffer, sha384->buffer,
+                               SHA384_BLOCK_SIZE);
+        #endif
+        ret = Transform384(sha384);
+        if (ret !=  0)
+            return ret;
+
+        sha384->buffLen = 0;
+    }
+    XMEMSET(&local[sha384->buffLen], 0, SHA384_PAD_SIZE - sha384->buffLen);
+   
+    /* put lengths in bits */
+    sha384->hiLen = (sha384->loLen >> (8*sizeof(sha384->loLen) - 3)) + 
+                 (sha384->hiLen << 3);
+    sha384->loLen = sha384->loLen << 3;
+
+    /* store lengths */
+    #if defined(LITTLE_ENDIAN_ORDER)
+        #if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+        if(!IS_INTEL_AVX1 && !IS_INTEL_AVX2) 
+        #endif
+             ByteReverseWords64(sha384->buffer, sha384->buffer,
+                           SHA384_BLOCK_SIZE);
+    #endif
+    /* ! length ordering dependent on digest endian type ! */
+    sha384->buffer[SHA384_BLOCK_SIZE / sizeof(word64) - 2] = sha384->hiLen;
+    sha384->buffer[SHA384_BLOCK_SIZE / sizeof(word64) - 1] = sha384->loLen;
+    #if defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)
+    if(IS_INTEL_AVX1 || IS_INTEL_AVX2)
+        ByteReverseWords64(&(sha384->buffer[SHA384_BLOCK_SIZE / sizeof(word64) - 2]),
+                           &(sha384->buffer[SHA384_BLOCK_SIZE / sizeof(word64) - 2]),
+                           SHA384_BLOCK_SIZE - SHA384_PAD_SIZE);
+    #endif
+    ret = Transform384(sha384);
+    if (ret != 0)
+        return ret;
+
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords64(sha384->digest, sha384->digest, SHA384_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, sha384->digest, SHA384_DIGEST_SIZE);
+
+    return wc_InitSha384(sha384);  /* reset state */
+}
+
+
+int wc_Sha384Hash(const byte* data, word32 len, byte* hash)
+{
+    int ret = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    Sha384* sha384;
+#else
+    Sha384 sha384[1];
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+    sha384 = (Sha384*)XMALLOC(sizeof(Sha384), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (sha384 == NULL)
+        return MEMORY_E;
+#endif
+
+    if ((ret = wc_InitSha384(sha384)) != 0) {
+        WOLFSSL_MSG("InitSha384 failed");
+    }
+    else if ((ret = wc_Sha384Update(sha384, data, len)) != 0) {
+        WOLFSSL_MSG("Sha384Update failed");
+    }
+    else if ((ret = wc_Sha384Final(sha384, hash)) != 0) {
+        WOLFSSL_MSG("Sha384Final failed");
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(sha384, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    return ret;
+}
+
+#if defined(HAVE_INTEL_AVX1)
+ 
+static int Transform384_AVX1(Sha384* sha384)
+{
+    const word64* K = K512;
+    word64 W_X[16+4];
+    word32 j;
+    word64 T[8];
+
+    /* Copy digest to working vars */
+    XMEMCPY(T, sha384->digest, sizeof(T));
+    W_from_buff(W_X, sha384->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 */
+
+    sha384->digest[0] += a(0);
+    sha384->digest[1] += b(0);
+    sha384->digest[2] += c(0);
+    sha384->digest[3] += d(0);
+    sha384->digest[4] += e(0);
+    sha384->digest[5] += f(0);
+    sha384->digest[6] += g(0);
+    sha384->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));
+
+    return 0;
+}
+
+#endif
+
+#if defined(HAVE_INTEL_AVX1) && defined(HAVE_INTEL_AVX2) && defined(HAVE_INTEL_RORX)
+static int Transform384_AVX1_RORX(Sha384* sha384)
+{
+    const word64* K = K512;
+    word64 W_X[16+4];
+    word32 j;
+    word64 T[8];
+
+    /* Copy digest to working vars */
+    XMEMCPY(T, sha384->digest, sizeof(T));
+
+    W_from_buff(W_X, sha384->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 */
+
+    sha384->digest[0] += a(0);
+    sha384->digest[1] += b(0);
+    sha384->digest[2] += c(0);
+    sha384->digest[3] += d(0);
+    sha384->digest[4] += e(0);
+    sha384->digest[5] += f(0);
+    sha384->digest[6] += g(0);
+    sha384->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));
+
+    return 0;
+}
+#endif
+
+#if defined(HAVE_INTEL_AVX2)
+
+static int Transform384_AVX2(Sha384* sha384)
+{
+    const word64* K = K512;
+    word64 w[4] ;
+    word32 j;
+    word64 T[8];
+
+    /* Copy digest to working vars */
+    XMEMCPY(T, sha384->digest, sizeof(T));
+
+    /* over twice as small, but 50% slower */
+    /* 80 operations, not unrolled */
+
+    W_from_buff_Y(sha384->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 */
+
+    sha384->digest[0] += a(0);
+    sha384->digest[1] += b(0);
+    sha384->digest[2] += c(0);
+    sha384->digest[3] += d(0);
+    sha384->digest[4] += e(0);
+    sha384->digest[5] += f(0);
+    sha384->digest[6] += g(0);
+    sha384->digest[7] += h(0);
+
+    /* Wipe variables */
+    XMEMSET(T, 0, sizeof(T));
+
+    return 0;
+}
+
+#endif
+
+#endif /* WOLFSSL_SHA384 */
+
+#endif /* HAVE_FIPS */
+
+#endif /* WOLFSSL_SHA512 */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/tfm.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,2702 @@
+/* tfm.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+/*
+ * Based on public domain TomsFastMath 0.10 by Tom St Denis, tomstdenis@iahu.ca,
+ * http://math.libtomcrypt.com
+ */
+
+/**
+ *  Edited by Moisés Guimarães (moisesguimaraesm@gmail.com)
+ *  to fit CyaSSL's needs.
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+/* in case user set USE_FAST_MATH there */
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef USE_FAST_MATH
+
+#include <wolfssl/wolfcrypt/tfm.h>
+#include <wolfcrypt/src/asm.c>  /* will define asm MACROS or C ones */
+
+
+/* math settings check */
+word32 CheckRunTimeSettings(void)
+{
+    return CTC_SETTINGS;
+}
+
+
+/* math settings size check */
+word32 CheckRunTimeFastMath(void)
+{
+    return FP_SIZE;
+}
+
+
+/* Functions */
+
+void fp_add(fp_int *a, fp_int *b, fp_int *c)
+{
+  int     sa, sb;
+
+  /* get sign of both inputs */
+  sa = a->sign;
+  sb = b->sign;
+
+  /* handle two cases, not four */
+  if (sa == sb) {
+    /* both positive or both negative */
+    /* add their magnitudes, copy the sign */
+    c->sign = sa;
+    s_fp_add (a, b, c);
+  } else {
+    /* one positive, the other negative */
+    /* subtract the one with the greater magnitude from */
+    /* the one of the lesser magnitude.  The result gets */
+    /* the sign of the one with the greater magnitude. */
+    if (fp_cmp_mag (a, b) == FP_LT) {
+      c->sign = sb;
+      s_fp_sub (b, a, c);
+    } else {
+      c->sign = sa;
+      s_fp_sub (a, b, c);
+    }
+  }
+}
+
+/* unsigned addition */
+void s_fp_add(fp_int *a, fp_int *b, fp_int *c)
+{
+  int      x, y, oldused;
+  register fp_word  t;
+
+  y       = MAX(a->used, b->used);
+  oldused = MIN(c->used, FP_SIZE);   /* help static analysis w/ largest size */
+  c->used = y;
+ 
+  t = 0;
+  for (x = 0; x < y; x++) {
+      t         += ((fp_word)a->dp[x]) + ((fp_word)b->dp[x]);
+      c->dp[x]   = (fp_digit)t;
+      t        >>= DIGIT_BIT;
+  }
+  if (t != 0 && x < FP_SIZE) {
+     c->dp[c->used++] = (fp_digit)t;
+     ++x;
+  }
+
+  c->used = x;
+  for (; x < oldused; x++) {
+     c->dp[x] = 0;
+  }
+  fp_clamp(c);
+}
+
+/* c = a - b */
+void fp_sub(fp_int *a, fp_int *b, fp_int *c)
+{
+  int     sa, sb;
+
+  sa = a->sign;
+  sb = b->sign;
+
+  if (sa != sb) {
+    /* subtract a negative from a positive, OR */
+    /* subtract a positive from a negative. */
+    /* In either case, ADD their magnitudes, */
+    /* and use the sign of the first number. */
+    c->sign = sa;
+    s_fp_add (a, b, c);
+  } else {
+    /* subtract a positive from a positive, OR */
+    /* subtract a negative from a negative. */
+    /* First, take the difference between their */
+    /* magnitudes, then... */
+    if (fp_cmp_mag (a, b) != FP_LT) {
+      /* Copy the sign from the first */
+      c->sign = sa;
+      /* The first has a larger or equal magnitude */
+      s_fp_sub (a, b, c);
+    } else {
+      /* The result has the *opposite* sign from */
+      /* the first number. */
+      c->sign = (sa == FP_ZPOS) ? FP_NEG : FP_ZPOS;
+      /* The second has a larger magnitude */
+      s_fp_sub (b, a, c);
+    }
+  }
+}
+
+/* unsigned subtraction ||a|| >= ||b|| ALWAYS! */
+void s_fp_sub(fp_int *a, fp_int *b, fp_int *c)
+{
+  int      x, oldbused, oldused;
+  fp_word  t;
+
+  oldused  = c->used;
+  oldbused = b->used;
+  c->used  = a->used;
+  t       = 0;
+  for (x = 0; x < oldbused; x++) {
+     t         = ((fp_word)a->dp[x]) - (((fp_word)b->dp[x]) + t);
+     c->dp[x]  = (fp_digit)t;
+     t         = (t >> DIGIT_BIT)&1;
+  }
+  for (; x < a->used; x++) {
+     t         = ((fp_word)a->dp[x]) - t;
+     c->dp[x]  = (fp_digit)t;
+     t         = (t >> DIGIT_BIT)&1;
+   }
+  for (; x < oldused; x++) {
+     c->dp[x] = 0;
+  }
+  fp_clamp(c);
+}
+
+/* c = a * b */
+void fp_mul(fp_int *A, fp_int *B, fp_int *C)
+{
+    int   y, yy;
+
+    y  = MAX(A->used, B->used);
+    yy = MIN(A->used, B->used);
+
+    /* call generic if we're out of range */
+    if (y + yy > FP_SIZE) {
+       fp_mul_comba(A, B, C);
+       return ;
+    }
+
+    /* pick a comba (unrolled 4/8/16/32 x or rolled) based on the size
+       of the largest input.  We also want to avoid doing excess mults if the 
+       inputs are not close to the next power of two.  That is, for example,
+       if say y=17 then we would do (32-17)^2 = 225 unneeded multiplications 
+    */
+
+#ifdef TFM_MUL3
+        if (y <= 3) {
+           fp_mul_comba3(A,B,C);
+           return;
+        }
+#endif
+#ifdef TFM_MUL4
+        if (y == 4) {
+           fp_mul_comba4(A,B,C);
+           return;
+        }
+#endif
+#ifdef TFM_MUL6
+        if (y <= 6) {
+           fp_mul_comba6(A,B,C);
+           return;
+        }
+#endif
+#ifdef TFM_MUL7
+        if (y == 7) {
+           fp_mul_comba7(A,B,C);
+           return;
+        }
+#endif
+#ifdef TFM_MUL8
+        if (y == 8) {
+           fp_mul_comba8(A,B,C);
+           return;
+        }
+#endif
+#ifdef TFM_MUL9
+        if (y == 9) {
+           fp_mul_comba9(A,B,C);
+           return;
+        }
+#endif
+#ifdef TFM_MUL12
+        if (y <= 12) {
+           fp_mul_comba12(A,B,C);
+           return;
+        }
+#endif
+#ifdef TFM_MUL17
+        if (y <= 17) {
+           fp_mul_comba17(A,B,C);
+           return;
+        }
+#endif
+
+#ifdef TFM_SMALL_SET
+        if (y <= 16) {
+           fp_mul_comba_small(A,B,C);
+           return;
+        }
+#endif        
+#if defined(TFM_MUL20)
+        if (y <= 20) {
+           fp_mul_comba20(A,B,C);
+           return;
+        }
+#endif
+#if defined(TFM_MUL24)
+        if (yy >= 16 && y <= 24) {
+           fp_mul_comba24(A,B,C);
+           return;
+        }
+#endif
+#if defined(TFM_MUL28)
+        if (yy >= 20 && y <= 28) {
+           fp_mul_comba28(A,B,C);
+           return;
+        }
+#endif
+#if defined(TFM_MUL32)
+        if (yy >= 24 && y <= 32) {
+           fp_mul_comba32(A,B,C);
+           return;
+        }
+#endif
+#if defined(TFM_MUL48)
+        if (yy >= 40 && y <= 48) {
+           fp_mul_comba48(A,B,C);
+           return;
+        }
+#endif        
+#if defined(TFM_MUL64)
+        if (yy >= 56 && y <= 64) {
+           fp_mul_comba64(A,B,C);
+           return;
+        }
+#endif
+        fp_mul_comba(A,B,C);
+}
+
+void fp_mul_2(fp_int * a, fp_int * b)
+{
+  int     x, oldused;
+   
+  oldused = b->used;
+  b->used = a->used;
+
+  {
+    register fp_digit r, rr, *tmpa, *tmpb;
+
+    /* alias for source */
+    tmpa = a->dp;
+    
+    /* alias for dest */
+    tmpb = b->dp;
+
+    /* carry */
+    r = 0;
+    for (x = 0; x < a->used; x++) {
+    
+      /* get what will be the *next* carry bit from the 
+       * MSB of the current digit 
+       */
+      rr = *tmpa >> ((fp_digit)(DIGIT_BIT - 1));
+      
+      /* now shift up this digit, add in the carry [from the previous] */
+      *tmpb++ = ((*tmpa++ << ((fp_digit)1)) | r);
+      
+      /* copy the carry that would be from the source 
+       * digit into the next iteration 
+       */
+      r = rr;
+    }
+
+    /* new leading digit? */
+    if (r != 0 && b->used != (FP_SIZE-1)) {
+      /* add a MSB which is always 1 at this point */
+      *tmpb = 1;
+      ++(b->used);
+    }
+
+    /* now zero any excess digits on the destination 
+     * that we didn't write to 
+     */
+    tmpb = b->dp + b->used;
+    for (x = b->used; x < oldused; x++) {
+      *tmpb++ = 0;
+    }
+  }
+  b->sign = a->sign;
+}
+
+/* c = a * b */
+void fp_mul_d(fp_int *a, fp_digit b, fp_int *c)
+{
+   fp_word  w;
+   int      x, oldused;
+
+   oldused = c->used;
+   c->used = a->used;
+   c->sign = a->sign;
+   w       = 0;
+   for (x = 0; x < a->used; x++) {
+       w         = ((fp_word)a->dp[x]) * ((fp_word)b) + w;
+       c->dp[x]  = (fp_digit)w;
+       w         = w >> DIGIT_BIT;
+   }
+   if (w != 0 && (a->used != FP_SIZE)) {
+      c->dp[c->used++] = (fp_digit) w;
+      ++x;
+   }
+   for (; x < oldused; x++) {
+      c->dp[x] = 0;
+   }
+   fp_clamp(c);
+}
+
+/* c = a * 2**d */
+void fp_mul_2d(fp_int *a, int b, fp_int *c)
+{
+   fp_digit carry, carrytmp, shift;
+   int x;
+
+   /* copy it */
+   fp_copy(a, c);
+
+   /* handle whole digits */
+   if (b >= DIGIT_BIT) {
+      fp_lshd(c, b/DIGIT_BIT);
+   }
+   b %= DIGIT_BIT;
+
+   /* shift the digits */
+   if (b != 0) {
+      carry = 0;   
+      shift = DIGIT_BIT - b;
+      for (x = 0; x < c->used; x++) {
+          carrytmp = c->dp[x] >> shift;
+          c->dp[x] = (c->dp[x] << b) + carry;
+          carry = carrytmp;
+      }
+      /* store last carry if room */
+      if (carry && x < FP_SIZE) {
+         c->dp[c->used++] = carry;
+      }
+   }
+   fp_clamp(c);
+}
+
+/* generic PxQ multiplier */
+#if defined(HAVE_INTEL_MULX)
+
+INLINE static void fp_mul_comba_mulx(fp_int *A, fp_int *B, fp_int *C)
+
+{     
+   int       ix, iy, iz, pa;
+   fp_int    tmp, *dst;
+
+   /* get size of output and trim */
+   pa = A->used + B->used;
+   if (pa >= FP_SIZE) {
+      pa = FP_SIZE-1;
+   }
+ 
+   if (A == C || B == C) {
+      fp_init(&tmp);
+      dst = &tmp;
+   } else {
+      fp_zero(C);
+      dst = C;
+   }
+
+   TFM_INTEL_MUL_COMBA(A, B, dst) ;
+
+  dst->used = pa;
+  dst->sign = A->sign ^ B->sign;
+  fp_clamp(dst);
+  fp_copy(dst, C);  
+}
+#endif
+
+void fp_mul_comba(fp_int *A, fp_int *B, fp_int *C)
+{
+   int       ix, iy, iz, tx, ty, pa;
+   fp_digit  c0, c1, c2, *tmpx, *tmpy;
+   fp_int    tmp, *dst;
+
+   IF_HAVE_INTEL_MULX(fp_mul_comba_mulx(A, B, C), return) ;
+
+   COMBA_START;
+   COMBA_CLEAR;
+   
+   /* get size of output and trim */
+   pa = A->used + B->used;
+   if (pa >= FP_SIZE) {
+      pa = FP_SIZE-1;
+   }
+
+   if (A == C || B == C) {
+      fp_init(&tmp);
+      dst = &tmp;
+   } else {
+      fp_zero(C);
+      dst = C;
+   }
+
+   for (ix = 0; ix < pa; ix++) {
+      /* get offsets into the two bignums */
+      ty = MIN(ix, B->used-1);
+      tx = ix - ty;
+
+      /* setup temp aliases */
+      tmpx = A->dp + tx;
+      tmpy = B->dp + ty;
+
+      /* this is the number of times the loop will iterrate, essentially its 
+         while (tx++ < a->used && ty-- >= 0) { ... }
+       */
+      iy = MIN(A->used-tx, ty+1);
+
+      /* execute loop */
+      COMBA_FORWARD;
+      for (iz = 0; iz < iy; ++iz) {
+          /* TAO change COMBA_ADD back to MULADD */
+          MULADD(*tmpx++, *tmpy--);
+      }
+
+      /* store term */
+      COMBA_STORE(dst->dp[ix]);
+  }
+  COMBA_FINI;
+
+  dst->used = pa;
+  dst->sign = A->sign ^ B->sign;
+  fp_clamp(dst);
+  fp_copy(dst, C);
+}
+
+/* a/b => cb + d == a */
+int fp_div(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
+{
+  fp_int  q, x, y, t1, t2;
+  int     n, t, i, norm, neg;
+
+  /* is divisor zero ? */
+  if (fp_iszero (b) == 1) {
+    return FP_VAL;
+  }
+
+  /* if a < b then q=0, r = a */
+  if (fp_cmp_mag (a, b) == FP_LT) {
+    if (d != NULL) {
+      fp_copy (a, d);
+    } 
+    if (c != NULL) {
+      fp_zero (c);
+    }
+    return FP_OKAY;
+  }
+
+  fp_init(&q);
+  q.used = a->used + 2;
+
+  fp_init(&t1);
+  fp_init(&t2);
+  fp_init_copy(&x, a);
+  fp_init_copy(&y, b);
+
+  /* fix the sign */
+  neg = (a->sign == b->sign) ? FP_ZPOS : FP_NEG;
+  x.sign = y.sign = FP_ZPOS;
+
+  /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */
+  norm = fp_count_bits(&y) % DIGIT_BIT;
+  if (norm < (int)(DIGIT_BIT-1)) {
+     norm = (DIGIT_BIT-1) - norm;
+     fp_mul_2d (&x, norm, &x);
+     fp_mul_2d (&y, norm, &y);
+  } else {
+     norm = 0;
+  }
+
+  /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
+  n = x.used - 1;
+  t = y.used - 1;
+
+  /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
+  fp_lshd (&y, n - t);                                             /* y = y*b**{n-t} */
+
+  while (fp_cmp (&x, &y) != FP_LT) {
+    ++(q.dp[n - t]);
+    fp_sub (&x, &y, &x);
+  }
+
+  /* reset y by shifting it back down */
+  fp_rshd (&y, n - t);
+
+  /* step 3. for i from n down to (t + 1) */
+  for (i = n; i >= (t + 1); i--) {
+    if (i > x.used) {
+      continue;
+    }
+
+    /* step 3.1 if xi == yt then set q{i-t-1} to b-1, 
+     * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
+    if (x.dp[i] == y.dp[t]) {
+      q.dp[i - t - 1] = (fp_digit) ((((fp_word)1) << DIGIT_BIT) - 1);
+    } else {
+      fp_word tmp;
+      tmp = ((fp_word) x.dp[i]) << ((fp_word) DIGIT_BIT);
+      tmp |= ((fp_word) x.dp[i - 1]);
+      tmp /= ((fp_word)y.dp[t]);
+      q.dp[i - t - 1] = (fp_digit) (tmp);
+    }
+
+    /* while (q{i-t-1} * (yt * b + y{t-1})) > 
+             xi * b**2 + xi-1 * b + xi-2 
+     
+       do q{i-t-1} -= 1; 
+    */
+    q.dp[i - t - 1] = (q.dp[i - t - 1] + 1);
+    do {
+      q.dp[i - t - 1] = (q.dp[i - t - 1] - 1);
+
+      /* find left hand */
+      fp_zero (&t1);
+      t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
+      t1.dp[1] = y.dp[t];
+      t1.used = 2;
+      fp_mul_d (&t1, q.dp[i - t - 1], &t1);
+
+      /* find right hand */
+      t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
+      t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
+      t2.dp[2] = x.dp[i];
+      t2.used = 3;
+    } while (fp_cmp_mag(&t1, &t2) == FP_GT);
+
+    /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
+    fp_mul_d (&y, q.dp[i - t - 1], &t1);
+    fp_lshd  (&t1, i - t - 1);
+    fp_sub   (&x, &t1, &x);
+
+    /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
+    if (x.sign == FP_NEG) {
+      fp_copy (&y, &t1);
+      fp_lshd (&t1, i - t - 1);
+      fp_add (&x, &t1, &x);
+      q.dp[i - t - 1] = q.dp[i - t - 1] - 1;
+    }
+  }
+
+  /* now q is the quotient and x is the remainder 
+   * [which we have to normalize] 
+   */
+  
+  /* get sign before writing to c */
+  x.sign = x.used == 0 ? FP_ZPOS : a->sign;
+
+  if (c != NULL) {
+    fp_clamp (&q);
+    fp_copy (&q, c);
+    c->sign = neg;
+  }
+
+  if (d != NULL) {
+    fp_div_2d (&x, norm, &x, NULL);
+
+/* the following is a kludge, essentially we were seeing the right remainder but 
+   with excess digits that should have been zero
+ */
+    for (i = b->used; i < x.used; i++) {
+        x.dp[i] = 0;
+    }
+    fp_clamp(&x);
+    fp_copy (&x, d);
+  }
+
+  return FP_OKAY;
+}
+
+/* b = a/2 */
+void fp_div_2(fp_int * a, fp_int * b)
+{
+  int     x, oldused;
+
+  oldused = b->used;
+  b->used = a->used;
+  {
+    register fp_digit r, rr, *tmpa, *tmpb;
+
+    /* source alias */
+    tmpa = a->dp + b->used - 1;
+
+    /* dest alias */
+    tmpb = b->dp + b->used - 1;
+
+    /* carry */
+    r = 0;
+    for (x = b->used - 1; x >= 0; x--) {
+      /* get the carry for the next iteration */
+      rr = *tmpa & 1;
+
+      /* shift the current digit, add in carry and store */
+      *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
+
+      /* forward carry to next iteration */
+      r = rr;
+    }
+
+    /* zero excess digits */
+    tmpb = b->dp + b->used;
+    for (x = b->used; x < oldused; x++) {
+      *tmpb++ = 0;
+    }
+  }
+  b->sign = a->sign;
+  fp_clamp (b);
+}
+
+/* c = a / 2**b */
+void fp_div_2d(fp_int *a, int b, fp_int *c, fp_int *d)
+{
+  int      D;
+  fp_int   t;
+
+  /* if the shift count is <= 0 then we do no work */
+  if (b <= 0) {
+    fp_copy (a, c);
+    if (d != NULL) {
+      fp_zero (d);
+    }
+    return;
+  }
+
+  fp_init(&t);
+
+  /* get the remainder */
+  if (d != NULL) {
+    fp_mod_2d (a, b, &t);
+  }
+
+  /* copy */
+  fp_copy(a, c);
+
+  /* shift by as many digits in the bit count */
+  if (b >= (int)DIGIT_BIT) {
+    fp_rshd (c, b / DIGIT_BIT);
+  }
+
+  /* shift any bit count < DIGIT_BIT */
+  D = (b % DIGIT_BIT);
+  if (D != 0) {
+    fp_rshb(c, D);
+  }
+  fp_clamp (c);
+  if (d != NULL) {
+    fp_copy (&t, d);
+  }
+}
+
+/* c = a mod b, 0 <= c < b  */
+int fp_mod(fp_int *a, fp_int *b, fp_int *c)
+{
+   fp_int t;
+   int    err;
+
+   fp_init(&t);
+   if ((err = fp_div(a, b, NULL, &t)) != FP_OKAY) {
+      return err;
+   }
+   if (t.sign != b->sign) {
+      fp_add(&t, b, c);
+   } else {
+      fp_copy(&t, c);
+  }
+  return FP_OKAY;
+}
+
+/* c = a mod 2**d */
+void fp_mod_2d(fp_int *a, int b, fp_int *c)
+{
+   int x;
+
+   /* zero if count less than or equal to zero */
+   if (b <= 0) {
+      fp_zero(c);
+      return;
+   }
+
+   /* get copy of input */
+   fp_copy(a, c);
+ 
+   /* if 2**d is larger than we just return */
+   if (b >= (DIGIT_BIT * a->used)) {
+      return;
+   }
+
+  /* zero digits above the last digit of the modulus */
+  for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
+    c->dp[x] = 0;
+  }
+  /* clear the digit that is not completely outside/inside the modulus */
+  c->dp[b / DIGIT_BIT] &= ~((fp_digit)0) >> (DIGIT_BIT - b);
+  fp_clamp (c);
+}
+
+static int fp_invmod_slow (fp_int * a, fp_int * b, fp_int * c)
+{
+  fp_int  x, y, u, v, A, B, C, D;
+  int     res;
+
+  /* b cannot be negative */
+  if (b->sign == FP_NEG || fp_iszero(b) == 1) {
+    return FP_VAL;
+  }
+
+  /* init temps */
+  fp_init(&x);    fp_init(&y);
+  fp_init(&u);    fp_init(&v);
+  fp_init(&A);    fp_init(&B);
+  fp_init(&C);    fp_init(&D);
+
+  /* x = a, y = b */
+  if ((res = fp_mod(a, b, &x)) != FP_OKAY) {
+      return res;
+  }
+  fp_copy(b, &y);
+
+  /* 2. [modified] if x,y are both even then return an error! */
+  if (fp_iseven (&x) == 1 && fp_iseven (&y) == 1) {
+    return FP_VAL;
+  }
+
+  /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+  fp_copy (&x, &u);
+  fp_copy (&y, &v);
+  fp_set (&A, 1);
+  fp_set (&D, 1);
+
+top:
+  /* 4.  while u is even do */
+  while (fp_iseven (&u) == 1) {
+    /* 4.1 u = u/2 */
+    fp_div_2 (&u, &u);
+
+    /* 4.2 if A or B is odd then */
+    if (fp_isodd (&A) == 1 || fp_isodd (&B) == 1) {
+      /* A = (A+y)/2, B = (B-x)/2 */
+      fp_add (&A, &y, &A);
+      fp_sub (&B, &x, &B);
+    }
+    /* A = A/2, B = B/2 */
+    fp_div_2 (&A, &A);
+    fp_div_2 (&B, &B);
+  }
+
+  /* 5.  while v is even do */
+  while (fp_iseven (&v) == 1) {
+    /* 5.1 v = v/2 */
+    fp_div_2 (&v, &v);
+
+    /* 5.2 if C or D is odd then */
+    if (fp_isodd (&C) == 1 || fp_isodd (&D) == 1) {
+      /* C = (C+y)/2, D = (D-x)/2 */
+      fp_add (&C, &y, &C);
+      fp_sub (&D, &x, &D);
+    }
+    /* C = C/2, D = D/2 */
+    fp_div_2 (&C, &C);
+    fp_div_2 (&D, &D);
+  }
+
+  /* 6.  if u >= v then */
+  if (fp_cmp (&u, &v) != FP_LT) {
+    /* u = u - v, A = A - C, B = B - D */
+    fp_sub (&u, &v, &u);
+    fp_sub (&A, &C, &A);
+    fp_sub (&B, &D, &B);
+  } else {
+    /* v - v - u, C = C - A, D = D - B */
+    fp_sub (&v, &u, &v);
+    fp_sub (&C, &A, &C);
+    fp_sub (&D, &B, &D);
+  }
+
+  /* if not zero goto step 4 */
+  if (fp_iszero (&u) == 0)
+    goto top;
+
+  /* now a = C, b = D, gcd == g*v */
+
+  /* if v != 1 then there is no inverse */
+  if (fp_cmp_d (&v, 1) != FP_EQ) {
+    return FP_VAL;
+  }
+
+  /* if its too low */
+  while (fp_cmp_d(&C, 0) == FP_LT) {
+      fp_add(&C, b, &C);
+  }
+  
+  /* too big */
+  while (fp_cmp_mag(&C, b) != FP_LT) {
+      fp_sub(&C, b, &C);
+  }
+  
+  /* C is now the inverse */
+  fp_copy(&C, c);
+  return FP_OKAY;
+}
+
+
+/* c = 1/a (mod b) for odd b only */
+int fp_invmod(fp_int *a, fp_int *b, fp_int *c)
+{
+  fp_int  x, y, u, v, B, D;
+  int     neg, loop_check = 0;
+
+  /* 2. [modified] b must be odd   */
+  if (fp_iseven (b) == FP_YES) {
+    return fp_invmod_slow(a,b,c);
+  }
+
+  /* init all our temps */
+  fp_init(&x);  fp_init(&y);
+  fp_init(&u);  fp_init(&v);
+  fp_init(&B);  fp_init(&D);
+
+  /* x == modulus, y == value to invert */
+  fp_copy(b, &x);
+
+  /* we need y = |a| */
+  fp_abs(a, &y);
+
+  /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+  fp_copy(&x, &u);
+  fp_copy(&y, &v);
+  fp_set (&D, 1);
+
+top:
+  /* 4.  while u is even do */
+  while (fp_iseven (&u) == FP_YES) {
+    /* 4.1 u = u/2 */
+    fp_div_2 (&u, &u);
+
+    /* 4.2 if B is odd then */
+    if (fp_isodd (&B) == FP_YES) {
+      fp_sub (&B, &x, &B);
+    }
+    /* B = B/2 */
+    fp_div_2 (&B, &B);
+  }
+
+  /* 5.  while v is even do */
+  while (fp_iseven (&v) == FP_YES) {
+    /* 5.1 v = v/2 */
+    fp_div_2 (&v, &v);
+
+    /* 5.2 if D is odd then */
+    if (fp_isodd (&D) == FP_YES) {
+      /* D = (D-x)/2 */
+      fp_sub (&D, &x, &D);
+    }
+    /* D = D/2 */
+    fp_div_2 (&D, &D);
+  }
+
+  /* 6.  if u >= v then */
+  if (fp_cmp (&u, &v) != FP_LT) {
+    /* u = u - v, B = B - D */
+    fp_sub (&u, &v, &u);
+    fp_sub (&B, &D, &B);
+  } else {
+    /* v - v - u, D = D - B */
+    fp_sub (&v, &u, &v);
+    fp_sub (&D, &B, &D);
+  }
+
+  /* if not zero goto step 4 */
+  if (fp_iszero (&u) == FP_NO) {
+    if (++loop_check > 1024) /* bad input */
+      return FP_VAL;
+    goto top;
+  }
+
+  /* now a = C, b = D, gcd == g*v */
+
+  /* if v != 1 then there is no inverse */
+  if (fp_cmp_d (&v, 1) != FP_EQ) {
+    return FP_VAL;
+  }
+
+  /* b is now the inverse */
+  neg = a->sign;
+  while (D.sign == FP_NEG) {
+    fp_add (&D, b, &D);
+  }
+  fp_copy (&D, c);
+  c->sign = neg;
+  return FP_OKAY;
+}
+
+/* d = a * b (mod c) */
+int fp_mulmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
+{
+  fp_int tmp;
+  fp_init(&tmp);
+  fp_mul(a, b, &tmp);
+  return fp_mod(&tmp, c, d);
+}
+
+#ifdef TFM_TIMING_RESISTANT
+
+/* timing resistant montgomery ladder based exptmod 
+
+   Based on work by Marc Joye, Sung-Ming Yen, "The Montgomery Powering Ladder", Cryptographic Hardware and Embedded Systems, CHES 2002
+*/
+static int _fp_exptmod(fp_int * G, fp_int * X, fp_int * P, fp_int * Y)
+{
+  fp_int   R[2];
+  fp_digit buf, mp;
+  int      err, bitcnt, digidx, y;
+
+  /* now setup montgomery  */
+  if ((err = fp_montgomery_setup (P, &mp)) != FP_OKAY) {
+     return err;
+  }
+
+  fp_init(&R[0]);   
+  fp_init(&R[1]);   
+   
+  /* now we need R mod m */
+  fp_montgomery_calc_normalization (&R[0], P);
+
+  /* now set R[0][1] to G * R mod m */
+  if (fp_cmp_mag(P, G) != FP_GT) {
+     /* G > P so we reduce it first */
+     fp_mod(G, P, &R[1]);
+  } else {
+     fp_copy(G, &R[1]);
+  }
+  fp_mulmod (&R[1], &R[0], P, &R[1]);
+
+  /* for j = t-1 downto 0 do
+        r_!k = R0*R1; r_k = r_k^2
+  */
+  
+  /* set initial mode and bit cnt */
+  bitcnt = 1;
+  buf    = 0;
+  digidx = X->used - 1;
+
+  for (;;) {
+    /* grab next digit as required */
+    if (--bitcnt == 0) {
+      /* if digidx == -1 we are out of digits so break */
+      if (digidx == -1) {
+        break;
+      }
+      /* read next digit and reset bitcnt */
+      buf    = X->dp[digidx--];
+      bitcnt = (int)DIGIT_BIT;
+    }
+
+    /* grab the next msb from the exponent */
+    y     = (int)(buf >> (DIGIT_BIT - 1)) & 1;
+    buf <<= (fp_digit)1;
+
+    /* do ops */
+    fp_mul(&R[0], &R[1], &R[y^1]); fp_montgomery_reduce(&R[y^1], P, mp);
+    fp_sqr(&R[y], &R[y]);          fp_montgomery_reduce(&R[y], P, mp);
+  }
+
+   fp_montgomery_reduce(&R[0], P, mp);
+   fp_copy(&R[0], Y);
+   return FP_OKAY;
+}   
+
+#else
+
+/* y = g**x (mod b) 
+ * Some restrictions... x must be positive and < b
+ */
+static int _fp_exptmod(fp_int * G, fp_int * X, fp_int * P, fp_int * Y)
+{
+  fp_int   M[64], res;
+  fp_digit buf, mp;
+  int      err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+
+  /* find window size */
+  x = fp_count_bits (X);
+  if (x <= 21) {
+    winsize = 1;
+  } else if (x <= 36) {
+    winsize = 3;
+  } else if (x <= 140) {
+    winsize = 4;
+  } else if (x <= 450) {
+    winsize = 5;
+  } else {
+    winsize = 6;
+  } 
+
+  /* init M array */
+  XMEMSET(M, 0, sizeof(M)); 
+
+  /* now setup montgomery  */
+  if ((err = fp_montgomery_setup (P, &mp)) != FP_OKAY) {
+     return err;
+  }
+
+  /* setup result */
+  fp_init(&res);
+
+  /* create M table
+   *
+   * The M table contains powers of the input base, e.g. M[x] = G^x mod P
+   *
+   * The first half of the table is not computed though accept for M[0] and M[1]
+   */
+
+   /* now we need R mod m */
+   fp_montgomery_calc_normalization (&res, P);
+
+   /* now set M[1] to G * R mod m */
+   if (fp_cmp_mag(P, G) != FP_GT) {
+      /* G > P so we reduce it first */
+      fp_mod(G, P, &M[1]);
+   } else {
+      fp_copy(G, &M[1]);
+   }
+   fp_mulmod (&M[1], &res, P, &M[1]);
+
+  /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
+  fp_copy (&M[1], &M[1 << (winsize - 1)]);
+  for (x = 0; x < (winsize - 1); x++) {
+    fp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)]);
+    fp_montgomery_reduce (&M[1 << (winsize - 1)], P, mp);
+  }
+
+  /* create upper table */
+  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+    fp_mul(&M[x - 1], &M[1], &M[x]);
+    fp_montgomery_reduce(&M[x], P, mp);
+  }
+
+  /* set initial mode and bit cnt */
+  mode   = 0;
+  bitcnt = 1;
+  buf    = 0;
+  digidx = X->used - 1;
+  bitcpy = 0;
+  bitbuf = 0;
+
+  for (;;) {
+    /* grab next digit as required */
+    if (--bitcnt == 0) {
+      /* if digidx == -1 we are out of digits so break */
+      if (digidx == -1) {
+        break;
+      }
+      /* read next digit and reset bitcnt */
+      buf    = X->dp[digidx--];
+      bitcnt = (int)DIGIT_BIT;
+    }
+
+    /* grab the next msb from the exponent */
+    y     = (int)(buf >> (DIGIT_BIT - 1)) & 1;
+    buf <<= (fp_digit)1;
+
+    /* if the bit is zero and mode == 0 then we ignore it
+     * These represent the leading zero bits before the first 1 bit
+     * in the exponent.  Technically this opt is not required but it
+     * does lower the # of trivial squaring/reductions used
+     */
+    if (mode == 0 && y == 0) {
+      continue;
+    }
+
+    /* if the bit is zero and mode == 1 then we square */
+    if (mode == 1 && y == 0) {
+      fp_sqr(&res, &res);
+      fp_montgomery_reduce(&res, P, mp);
+      continue;
+    }
+
+    /* else we add it to the window */
+    bitbuf |= (y << (winsize - ++bitcpy));
+    mode    = 2;
+
+    if (bitcpy == winsize) {
+      /* ok window is filled so square as required and multiply  */
+      /* square first */
+      for (x = 0; x < winsize; x++) {
+        fp_sqr(&res, &res);
+        fp_montgomery_reduce(&res, P, mp);
+      }
+
+      /* then multiply */
+      fp_mul(&res, &M[bitbuf], &res);
+      fp_montgomery_reduce(&res, P, mp);
+
+      /* empty window and reset */
+      bitcpy = 0;
+      bitbuf = 0;
+      mode   = 1;
+    }
+  }
+
+  /* if bits remain then square/multiply */
+  if (mode == 2 && bitcpy > 0) {
+    /* square then multiply if the bit is set */
+    for (x = 0; x < bitcpy; x++) {
+      fp_sqr(&res, &res);
+      fp_montgomery_reduce(&res, P, mp);
+
+      /* get next bit of the window */
+      bitbuf <<= 1;
+      if ((bitbuf & (1 << winsize)) != 0) {
+        /* then multiply */
+        fp_mul(&res, &M[1], &res);
+        fp_montgomery_reduce(&res, P, mp);
+      }
+    }
+  }
+
+  /* fixup result if Montgomery reduction is used
+   * recall that any value in a Montgomery system is
+   * actually multiplied by R mod n.  So we have
+   * to reduce one more time to cancel out the factor
+   * of R.
+   */
+  fp_montgomery_reduce(&res, P, mp);
+
+  /* swap res with Y */
+  fp_copy (&res, Y);
+  return FP_OKAY;
+}
+
+#endif
+
+int fp_exptmod(fp_int * G, fp_int * X, fp_int * P, fp_int * Y)
+{
+   /* prevent overflows */
+   if (P->used > (FP_SIZE/2)) {
+      return FP_VAL;
+   }
+
+   if (X->sign == FP_NEG) {
+#ifndef POSITIVE_EXP_ONLY  /* reduce stack if assume no negatives */
+      int    err;
+      fp_int tmp;
+
+      /* yes, copy G and invmod it */
+      fp_copy(G, &tmp);
+      if ((err = fp_invmod(&tmp, P, &tmp)) != FP_OKAY) {
+         return err;
+      }
+      X->sign = FP_ZPOS;
+      err =  _fp_exptmod(&tmp, X, P, Y);
+      if (X != Y) {
+         X->sign = FP_NEG;
+      }
+      return err;
+#else
+      return FP_VAL;
+#endif 
+   }
+   else {
+      /* Positive exponent so just exptmod */
+      return _fp_exptmod(G, X, P, Y);
+   }
+}
+
+/* computes a = 2**b */
+void fp_2expt(fp_int *a, int b)
+{
+   int     z;
+
+   /* zero a as per default */
+   fp_zero (a);
+
+   if (b < 0) { 
+      return;
+   }
+
+   z = b / DIGIT_BIT;
+   if (z >= FP_SIZE) {
+      return; 
+   }
+
+  /* set the used count of where the bit will go */
+  a->used = z + 1;
+
+  /* put the single bit in its place */
+  a->dp[z] = ((fp_digit)1) << (b % DIGIT_BIT);
+}
+
+/* b = a*a  */
+void fp_sqr(fp_int *A, fp_int *B)
+{
+    int y = A->used;
+
+    /* call generic if we're out of range */
+    if (y + y > FP_SIZE) {
+       fp_sqr_comba(A, B);
+       return ;
+    }
+
+#if defined(TFM_SQR3)
+        if (y <= 3) {
+           fp_sqr_comba3(A,B);
+           return;
+        }
+#endif
+#if defined(TFM_SQR4)
+        if (y == 4) {
+           fp_sqr_comba4(A,B);
+           return;
+        }
+#endif
+#if defined(TFM_SQR6)
+        if (y <= 6) {
+           fp_sqr_comba6(A,B);
+           return;
+        }
+#endif
+#if defined(TFM_SQR7)
+        if (y == 7) {
+           fp_sqr_comba7(A,B);
+           return;
+        }
+#endif
+#if defined(TFM_SQR8)
+        if (y == 8) {
+           fp_sqr_comba8(A,B);
+           return;
+        }
+#endif
+#if defined(TFM_SQR9)
+        if (y == 9) {
+           fp_sqr_comba9(A,B);
+           return;
+        }
+#endif
+#if defined(TFM_SQR12)
+        if (y <= 12) {
+           fp_sqr_comba12(A,B);
+           return;
+        }
+#endif
+#if defined(TFM_SQR17)
+        if (y <= 17) {
+           fp_sqr_comba17(A,B);
+           return;
+        }
+#endif
+#if defined(TFM_SMALL_SET)
+        if (y <= 16) {
+           fp_sqr_comba_small(A,B);
+           return;
+        }
+#endif
+#if defined(TFM_SQR20)
+        if (y <= 20) {
+           fp_sqr_comba20(A,B);
+           return;
+        }
+#endif
+#if defined(TFM_SQR24)
+        if (y <= 24) {
+           fp_sqr_comba24(A,B);
+           return;
+        }
+#endif
+#if defined(TFM_SQR28)
+        if (y <= 28) {
+           fp_sqr_comba28(A,B);
+           return;
+        }
+#endif
+#if defined(TFM_SQR32)
+        if (y <= 32) {
+           fp_sqr_comba32(A,B);
+           return;
+        }
+#endif
+#if defined(TFM_SQR48)
+        if (y <= 48) {
+           fp_sqr_comba48(A,B);
+           return;
+        }
+#endif
+#if defined(TFM_SQR64)
+        if (y <= 64) {
+           fp_sqr_comba64(A,B);
+           return;
+        }
+#endif
+       fp_sqr_comba(A, B);
+}
+
+/* generic comba squarer */
+void fp_sqr_comba(fp_int *A, fp_int *B)
+{
+  int       pa, ix, iz;
+  fp_digit  c0, c1, c2;
+  fp_int    tmp, *dst;
+#ifdef TFM_ISO
+  fp_word   tt;
+#endif    
+
+  /* get size of output and trim */
+  pa = A->used + A->used;
+  if (pa >= FP_SIZE) {
+     pa = FP_SIZE-1;
+  }
+
+  /* number of output digits to produce */
+  COMBA_START;
+  COMBA_CLEAR;
+
+  if (A == B) {
+     fp_init(&tmp);
+     dst = &tmp;
+  } else {
+     fp_zero(B);
+     dst = B;
+  }
+
+  for (ix = 0; ix < pa; ix++) { 
+      int      tx, ty, iy;
+      fp_digit *tmpy, *tmpx;
+
+      /* get offsets into the two bignums */
+      ty = MIN(A->used-1, ix);
+      tx = ix - ty;
+
+      /* setup temp aliases */
+      tmpx = A->dp + tx;
+      tmpy = A->dp + ty;
+
+      /* this is the number of times the loop will iterrate,
+         while (tx++ < a->used && ty-- >= 0) { ... }
+       */
+      iy = MIN(A->used-tx, ty+1);
+
+      /* now for squaring tx can never equal ty 
+       * we halve the distance since they approach 
+       * at a rate of 2x and we have to round because 
+       * odd cases need to be executed
+       */
+      iy = MIN(iy, (ty-tx+1)>>1);
+
+      /* forward carries */
+      COMBA_FORWARD;
+
+      /* execute loop */
+      for (iz = 0; iz < iy; iz++) {
+          SQRADD2(*tmpx++, *tmpy--);
+      }
+
+      /* even columns have the square term in them */
+      if ((ix&1) == 0) {
+          /* TAO change COMBA_ADD back to SQRADD */
+          SQRADD(A->dp[ix>>1], A->dp[ix>>1]);
+      }
+
+      /* store it */
+      COMBA_STORE(dst->dp[ix]);
+  }
+
+  COMBA_FINI;
+
+  /* setup dest */
+  dst->used = pa;
+  fp_clamp (dst);
+  if (dst != B) {
+     fp_copy(dst, B);
+  }
+}
+
+int fp_cmp(fp_int *a, fp_int *b)
+{
+   if (a->sign == FP_NEG && b->sign == FP_ZPOS) {
+      return FP_LT;
+   } else if (a->sign == FP_ZPOS && b->sign == FP_NEG) {
+      return FP_GT;
+   } else {
+      /* compare digits */
+      if (a->sign == FP_NEG) {
+         /* if negative compare opposite direction */
+         return fp_cmp_mag(b, a);
+      } else {
+         return fp_cmp_mag(a, b);
+      }
+   }
+}
+
+/* compare against a single digit */
+int fp_cmp_d(fp_int *a, fp_digit b)
+{
+  /* compare based on sign */
+  if ((b && a->used == 0) || a->sign == FP_NEG) {
+    return FP_LT;
+  }
+
+  /* compare based on magnitude */
+  if (a->used > 1) {
+    return FP_GT;
+  }
+
+  /* compare the only digit of a to b */
+  if (a->dp[0] > b) {
+    return FP_GT;
+  } else if (a->dp[0] < b) {
+    return FP_LT;
+  } else {
+    return FP_EQ;
+  }
+
+}
+
+int fp_cmp_mag(fp_int *a, fp_int *b)
+{
+   int x;
+
+   if (a->used > b->used) {
+      return FP_GT;
+   } else if (a->used < b->used) {
+      return FP_LT;
+   } else {
+      for (x = a->used - 1; x >= 0; x--) {
+          if (a->dp[x] > b->dp[x]) {
+             return FP_GT;
+          } else if (a->dp[x] < b->dp[x]) {
+             return FP_LT;
+          }
+      }
+   }
+   return FP_EQ;
+}
+
+/* setups the montgomery reduction */
+int fp_montgomery_setup(fp_int *a, fp_digit *rho)
+{
+  fp_digit x, b;
+
+/* fast inversion mod 2**k
+ *
+ * Based on the fact that
+ *
+ * XA = 1 (mod 2**n)  =>  (X(2-XA)) A = 1 (mod 2**2n)
+ *                    =>  2*X*A - X*X*A*A = 1
+ *                    =>  2*(1) - (1)     = 1
+ */
+  b = a->dp[0];
+
+  if ((b & 1) == 0) {
+    return FP_VAL;
+  }
+
+  x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
+  x *= 2 - b * x;               /* here x*a==1 mod 2**8 */
+  x *= 2 - b * x;               /* here x*a==1 mod 2**16 */
+  x *= 2 - b * x;               /* here x*a==1 mod 2**32 */
+#ifdef FP_64BIT
+  x *= 2 - b * x;               /* here x*a==1 mod 2**64 */
+#endif
+
+  /* rho = -1/m mod b */
+  *rho = (fp_digit) (((fp_word) 1 << ((fp_word) DIGIT_BIT)) - ((fp_word)x));
+
+  return FP_OKAY;
+}
+
+/* computes a = B**n mod b without division or multiplication useful for
+ * normalizing numbers in a Montgomery system.
+ */
+void fp_montgomery_calc_normalization(fp_int *a, fp_int *b)
+{
+  int     x, bits;
+
+  /* how many bits of last digit does b use */
+  bits = fp_count_bits (b) % DIGIT_BIT;
+  if (!bits) bits = DIGIT_BIT;
+
+  /* compute A = B^(n-1) * 2^(bits-1) */
+  if (b->used > 1) {
+     fp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1);
+  } else {
+     fp_set(a, 1);
+     bits = 1;
+  }
+
+  /* now compute C = A * B mod b */
+  for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
+    fp_mul_2 (a, a);
+    if (fp_cmp_mag (a, b) != FP_LT) {
+      s_fp_sub (a, b, a);
+    }
+  }
+}
+
+
+#ifdef TFM_SMALL_MONT_SET
+    #include "fp_mont_small.i"
+#endif
+
+#ifdef HAVE_INTEL_MULX
+static inline void innermul8_mulx(fp_digit *c_mulx, fp_digit *cy_mulx, fp_digit *tmpm, fp_digit mu) 
+{
+    fp_digit _c0, _c1, _c2, _c3, _c4, _c5, _c6, _c7, cy ;
+
+    cy = *cy_mulx ;
+    _c0=c_mulx[0]; _c1=c_mulx[1]; _c2=c_mulx[2]; _c3=c_mulx[3]; _c4=c_mulx[4]; _c5=c_mulx[5]; _c6=c_mulx[6]; _c7=c_mulx[7];    
+    INNERMUL8_MULX ;
+    c_mulx[0]=_c0; c_mulx[1]=_c1; c_mulx[2]=_c2; c_mulx[3]=_c3; c_mulx[4]=_c4; c_mulx[5]=_c5; c_mulx[6]=_c6; c_mulx[7]=_c7; 
+    *cy_mulx = cy ;
+}
+
+/* computes x/R == x (mod N) via Montgomery Reduction */
+static void fp_montgomery_reduce_mulx(fp_int *a, fp_int *m, fp_digit mp)
+{
+   fp_digit c[FP_SIZE], *_c, *tmpm, mu = 0;
+   int      oldused, x, y, pa;
+
+   /* bail if too large */
+   if (m->used > (FP_SIZE/2)) {
+      (void)mu;                     /* shut up compiler */
+      return;
+   }
+
+#ifdef TFM_SMALL_MONT_SET
+   if (m->used <= 16) {
+      fp_montgomery_reduce_small(a, m, mp);
+      return;
+   }
+#endif
+
+
+   /* now zero the buff */
+   XMEMSET(c, 0, sizeof c);
+   pa = m->used;
+
+   /* copy the input */
+   oldused = a->used;
+   for (x = 0; x < oldused; x++) {
+       c[x] = a->dp[x];
+   }
+   MONT_START;
+
+   for (x = 0; x < pa; x++) {
+       fp_digit cy = 0;
+       /* get Mu for this round */
+       LOOP_START;
+       _c   = c + x;
+       tmpm = m->dp;
+       y = 0;
+        for (; y < (pa & ~7); y += 8) {
+              innermul8_mulx(_c, &cy, tmpm, mu) ;
+              _c   += 8;
+              tmpm += 8;
+           }
+       for (; y < pa; y++) {
+          INNERMUL;
+          ++_c;
+       }
+       LOOP_END;
+       while (cy) {
+           PROPCARRY;
+           ++_c;
+       }
+  }         
+
+  /* now copy out */
+  _c   = c + pa;
+  tmpm = a->dp;
+  for (x = 0; x < pa+1; x++) {
+     *tmpm++ = *_c++;
+  }
+
+  for (; x < oldused; x++)   {
+     *tmpm++ = 0;
+  }
+
+  MONT_FINI;
+
+  a->used = pa+1;
+  fp_clamp(a);
+  
+  /* if A >= m then A = A - m */
+  if (fp_cmp_mag (a, m) != FP_LT) {
+    s_fp_sub (a, m, a);
+  }
+}
+#endif
+
+/* computes x/R == x (mod N) via Montgomery Reduction */
+void fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp)
+{
+   fp_digit c[FP_SIZE], *_c, *tmpm, mu = 0;
+   int      oldused, x, y, pa;
+
+   IF_HAVE_INTEL_MULX(fp_montgomery_reduce_mulx(a, m, mp), return) ;
+
+   /* bail if too large */
+   if (m->used > (FP_SIZE/2)) {
+      (void)mu;                     /* shut up compiler */
+      return;
+   }
+
+#ifdef TFM_SMALL_MONT_SET
+   if (m->used <= 16) {
+      fp_montgomery_reduce_small(a, m, mp);
+      return;
+   }
+#endif
+
+
+   /* now zero the buff */
+   XMEMSET(c, 0, sizeof c);
+   pa = m->used;
+
+   /* copy the input */
+   oldused = a->used;
+   for (x = 0; x < oldused; x++) {
+       c[x] = a->dp[x];
+   }
+   MONT_START;
+
+   for (x = 0; x < pa; x++) {
+       fp_digit cy = 0;
+       /* get Mu for this round */
+       LOOP_START;
+       _c   = c + x;
+       tmpm = m->dp;
+       y = 0;
+       #if (defined(TFM_SSE2) || defined(TFM_X86_64))
+        for (; y < (pa & ~7); y += 8) {
+              INNERMUL8 ;
+              _c   += 8;
+              tmpm += 8;
+           }
+       #endif
+       for (; y < pa; y++) {
+          INNERMUL;
+          ++_c;
+       }
+       LOOP_END;
+       while (cy) {
+           PROPCARRY;
+           ++_c;
+       }
+  }         
+
+  /* now copy out */
+  _c   = c + pa;
+  tmpm = a->dp;
+  for (x = 0; x < pa+1; x++) {
+     *tmpm++ = *_c++;
+  }
+
+  for (; x < oldused; x++)   {
+     *tmpm++ = 0;
+  }
+
+  MONT_FINI;
+
+  a->used = pa+1;
+  fp_clamp(a);
+  
+  /* if A >= m then A = A - m */
+  if (fp_cmp_mag (a, m) != FP_LT) {
+    s_fp_sub (a, m, a);
+  }
+}
+
+void fp_read_unsigned_bin(fp_int *a, unsigned char *b, int c)
+{
+  /* zero the int */
+  fp_zero (a);
+
+  /* If we know the endianness of this architecture, and we're using
+     32-bit fp_digits, we can optimize this */
+#if (defined(LITTLE_ENDIAN_ORDER) || defined(BIG_ENDIAN_ORDER)) && defined(FP_32BIT)
+  /* But not for both simultaneously */
+#if defined(LITTLE_ENDIAN_ORDER) && defined(BIG_ENDIAN_ORDER)
+#error Both LITTLE_ENDIAN_ORDER and BIG_ENDIAN_ORDER defined.
+#endif
+  {
+     unsigned char *pd = (unsigned char *)a->dp;
+
+     if ((unsigned)c > (FP_SIZE * sizeof(fp_digit))) {
+        int excess = c - (FP_SIZE * sizeof(fp_digit));
+        c -= excess;
+        b += excess;
+     }
+     a->used = (c + sizeof(fp_digit) - 1)/sizeof(fp_digit);
+     /* read the bytes in */
+#ifdef BIG_ENDIAN_ORDER
+     {
+       /* Use Duff's device to unroll the loop. */
+       int idx = (c - 1) & ~3;
+       switch (c % 4) {
+       case 0:	do { pd[idx+0] = *b++;
+       case 3:	     pd[idx+1] = *b++;
+       case 2:	     pd[idx+2] = *b++;
+       case 1:	     pd[idx+3] = *b++;
+                     idx -= 4;
+	 	        } while ((c -= 4) > 0);
+       }
+     }
+#else
+     for (c -= 1; c >= 0; c -= 1) {
+       pd[c] = *b++;
+     }
+#endif
+  }
+#else
+  /* read the bytes in */
+  for (; c > 0; c--) {
+     fp_mul_2d (a, 8, a);
+     a->dp[0] |= *b++;
+     a->used += 1;
+  }
+#endif
+  fp_clamp (a);
+}
+
+void fp_to_unsigned_bin(fp_int *a, unsigned char *b)
+{
+  int     x;
+  fp_int  t;
+
+  fp_init_copy(&t, a);
+
+  x = 0;
+  while (fp_iszero (&t) == FP_NO) {
+      b[x++] = (unsigned char) (t.dp[0] & 255);
+      fp_div_2d (&t, 8, &t, NULL);
+  }
+  fp_reverse (b, x);
+}
+
+int fp_unsigned_bin_size(fp_int *a)
+{
+  int     size = fp_count_bits (a);
+  return (size / 8 + ((size & 7) != 0 ? 1 : 0));
+}
+
+void fp_set(fp_int *a, fp_digit b)
+{
+   fp_zero(a);
+   a->dp[0] = b;
+   a->used  = a->dp[0] ? 1 : 0;
+}
+
+int fp_count_bits (fp_int * a)
+{
+  int     r;
+  fp_digit q;
+
+  /* shortcut */
+  if (a->used == 0) {
+    return 0;
+  }
+
+  /* get number of digits and add that */
+  r = (a->used - 1) * DIGIT_BIT;
+
+  /* take the last digit and count the bits in it */
+  q = a->dp[a->used - 1];
+  while (q > ((fp_digit) 0)) {
+    ++r;
+    q >>= ((fp_digit) 1);
+  }
+  return r;
+}
+
+int fp_leading_bit(fp_int *a)
+{
+    int bit = 0;
+
+    if (a->used != 0) {
+        fp_digit q = a->dp[a->used - 1];
+        int qSz = sizeof(fp_digit);
+
+        while (qSz > 0) {
+            if ((unsigned char)q != 0)
+                bit = (q & 0x80) != 0;
+            q >>= 8;
+            qSz--;
+        }
+    }
+
+    return bit;
+}
+
+void fp_lshd(fp_int *a, int x)
+{
+   int y;
+
+   /* move up and truncate as required */
+   y = MIN(a->used + x - 1, (int)(FP_SIZE-1));
+
+   /* store new size */
+   a->used = y + 1;
+
+   /* move digits */
+   for (; y >= x; y--) {
+       a->dp[y] = a->dp[y-x];
+   }
+ 
+   /* zero lower digits */
+   for (; y >= 0; y--) {
+       a->dp[y] = 0;
+   }
+
+   /* clamp digits */
+   fp_clamp(a);
+}
+
+
+/* right shift by bit count */
+void fp_rshb(fp_int *c, int x)
+{
+    register fp_digit *tmpc, mask, shift;
+    fp_digit r, rr;
+    fp_digit D = x;
+
+    /* mask */
+    mask = (((fp_digit)1) << D) - 1;
+
+    /* shift for lsb */
+    shift = DIGIT_BIT - D;
+
+    /* alias */
+    tmpc = c->dp + (c->used - 1);
+
+    /* carry */
+    r = 0;
+    for (x = c->used - 1; x >= 0; x--) {
+      /* get the lower  bits of this word in a temp */
+      rr = *tmpc & mask;
+
+      /* shift the current word and mix in the carry bits from previous word */
+      *tmpc = (*tmpc >> D) | (r << shift);
+      --tmpc;
+
+      /* set the carry to the carry bits of the current word found above */
+      r = rr;
+    }
+}
+
+
+void fp_rshd(fp_int *a, int x)
+{
+  int y;
+
+  /* too many digits just zero and return */
+  if (x >= a->used) {
+     fp_zero(a);
+     return;
+  }
+
+   /* shift */
+   for (y = 0; y < a->used - x; y++) {
+      a->dp[y] = a->dp[y+x];
+   }
+
+   /* zero rest */
+   for (; y < a->used; y++) {
+      a->dp[y] = 0;
+   }
+   
+   /* decrement count */
+   a->used -= x;
+   fp_clamp(a);
+}
+
+/* reverse an array, used for radix code */
+void fp_reverse (unsigned char *s, int len)
+{
+  int     ix, iy;
+  unsigned char t;
+
+  ix = 0;
+  iy = len - 1;
+  while (ix < iy) {
+    t     = s[ix];
+    s[ix] = s[iy];
+    s[iy] = t;
+    ++ix;
+    --iy;
+  }
+}
+
+
+/* c = a - b */
+void fp_sub_d(fp_int *a, fp_digit b, fp_int *c)
+{
+   fp_int tmp;
+   fp_init(&tmp);
+   fp_set(&tmp, b);
+   fp_sub(a, &tmp, c);
+}
+
+
+/* CyaSSL callers from normal lib */
+
+/* init a new mp_int */
+int mp_init (mp_int * a)
+{
+  if (a)
+    fp_init(a);
+  return MP_OKAY;
+}
+
+#ifdef ALT_ECC_SIZE
+void fp_init(fp_int *a)
+{
+    a->size = FP_SIZE;
+    fp_zero(a);
+}
+
+void fp_zero(fp_int *a)
+{
+    a->used = 0;
+    a->sign = FP_ZPOS;
+    XMEMSET(a->dp, 0, a->size * sizeof(fp_digit));
+}
+#endif
+
+
+/* clear one (frees)  */
+void mp_clear (mp_int * a)
+{
+  fp_zero(a);
+}
+
+/* handle up to 6 inits */
+int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e, mp_int* f)
+{
+    if (a)
+        fp_init(a);
+    if (b)
+        fp_init(b);
+    if (c)
+        fp_init(c);
+    if (d)
+        fp_init(d);
+    if (e)
+        fp_init(e);
+    if (f)
+        fp_init(f);
+
+    return MP_OKAY;
+}
+
+/* high level addition (handles signs) */
+int mp_add (mp_int * a, mp_int * b, mp_int * c)
+{
+  fp_add(a, b, c);
+  return MP_OKAY;
+}
+
+/* high level subtraction (handles signs) */
+int mp_sub (mp_int * a, mp_int * b, mp_int * c)
+{
+  fp_sub(a, b, c);
+  return MP_OKAY;
+}
+
+/* high level multiplication (handles sign) */
+int mp_mul (mp_int * a, mp_int * b, mp_int * c)
+{
+  fp_mul(a, b, c);
+  return MP_OKAY;
+}
+
+/* d = a * b (mod c) */
+int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+  return fp_mulmod(a, b, c, d);
+}
+
+/* c = a mod b, 0 <= c < b */
+int mp_mod (mp_int * a, mp_int * b, mp_int * c)
+{
+  return fp_mod (a, b, c);
+}
+
+/* hac 14.61, pp608 */
+int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
+{
+  return fp_invmod(a, b, c);
+}
+
+/* this is a shell function that calls either the normal or Montgomery
+ * exptmod functions.  Originally the call to the montgomery code was
+ * embedded in the normal function but that wasted alot of stack space
+ * for nothing (since 99% of the time the Montgomery code would be called)
+ */
+int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
+{
+  return fp_exptmod(G, X, P, Y);
+}
+
+/* compare two ints (signed)*/
+int mp_cmp (mp_int * a, mp_int * b)
+{
+  return fp_cmp(a, b);
+}
+
+/* compare a digit */
+int mp_cmp_d(mp_int * a, mp_digit b)
+{
+  return fp_cmp_d(a, b);
+}
+
+/* get the size for an unsigned equivalent */
+int mp_unsigned_bin_size (mp_int * a)
+{
+  return fp_unsigned_bin_size(a);
+}
+
+/* store in unsigned [big endian] format */
+int mp_to_unsigned_bin (mp_int * a, unsigned char *b)
+{
+  fp_to_unsigned_bin(a,b);
+  return MP_OKAY;
+}
+
+/* reads a unsigned char array, assumes the msb is stored first [big endian] */
+int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
+{
+  fp_read_unsigned_bin(a, (unsigned char *)b, c);
+  return MP_OKAY;
+}
+
+
+int mp_sub_d(fp_int *a, fp_digit b, fp_int *c)
+{
+    fp_sub_d(a, b, c);
+    return MP_OKAY;
+}
+
+
+#ifdef ALT_ECC_SIZE
+void fp_copy(fp_int *a, fp_int* b)
+{
+    if (a != b) {
+        b->used = a->used;
+        b->sign = a->sign;
+        XMEMCPY(b->dp, a->dp, a->used * sizeof(fp_digit));
+    }
+}
+
+void fp_init_copy(fp_int *a, fp_int* b)
+{
+    if (a != b) {
+        fp_init(a);
+        fp_copy(b, a);
+    }
+}
+#endif
+
+/* fast math conversion */
+int mp_copy(fp_int* a, fp_int* b)
+{
+    fp_copy(a, b);
+    return MP_OKAY;
+}
+
+
+/* fast math conversion */
+int mp_isodd(mp_int* a)
+{
+    return fp_isodd(a);
+}
+
+
+/* fast math conversion */
+int mp_iszero(mp_int* a)
+{
+    return fp_iszero(a);
+}
+
+
+/* fast math conversion */
+int mp_count_bits (mp_int* a)
+{
+    return fp_count_bits(a);
+}
+
+
+int mp_leading_bit (mp_int* a)
+{
+    return fp_leading_bit(a);
+}
+
+
+/* fast math conversion */
+void mp_rshb (mp_int* a, int x)
+{
+    fp_rshb(a, x);
+}
+
+
+/* fast math wrappers */
+int mp_set_int(fp_int *a, fp_digit b)
+{
+    fp_set(a, b);
+    return MP_OKAY;
+}
+
+
+#if defined(WOLFSSL_KEY_GEN) || defined (HAVE_ECC)
+
+/* c = a * a (mod b) */
+int fp_sqrmod(fp_int *a, fp_int *b, fp_int *c)
+{
+  fp_int tmp;
+  fp_init(&tmp);
+  fp_sqr(a, &tmp);
+  return fp_mod(&tmp, b, c);
+}
+
+/* fast math conversion */
+int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c)
+{
+    return fp_sqrmod(a, b, c);
+}
+
+/* fast math conversion */
+int mp_montgomery_calc_normalization(mp_int *a, mp_int *b)
+{
+    fp_montgomery_calc_normalization(a, b);
+    return MP_OKAY;
+}
+
+#endif /* WOLFSSL_KEYGEN || HAVE_ECC */
+
+
+#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY)
+
+static const int lnz[16] = {
+   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+};
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int fp_cnt_lsb(fp_int *a)
+{
+   int x;
+   fp_digit q, qq;
+
+   /* easy out */
+   if (fp_iszero(a) == 1) {
+      return 0;
+   }
+
+   /* scan lower digits until non-zero */
+   for (x = 0; x < a->used && a->dp[x] == 0; x++);
+   q = a->dp[x];
+   x *= DIGIT_BIT;
+
+   /* now scan this digit until a 1 is found */
+   if ((q & 1) == 0) {
+      do {
+         qq  = q & 15;
+         x  += lnz[qq];
+         q >>= 4;
+      } while (qq == 0);
+   }
+   return x;
+}
+
+
+
+
+static int s_is_power_of_two(fp_digit b, int *p)
+{
+   int x;
+
+   /* fast return if no power of two */
+   if ((b==0) || (b & (b-1))) {
+      return 0;
+   }
+
+   for (x = 0; x < DIGIT_BIT; x++) {
+      if (b == (((fp_digit)1)<<x)) {
+         *p = x;
+         return 1;
+      }
+   }
+   return 0;
+}
+
+/* a/b => cb + d == a */
+static int fp_div_d(fp_int *a, fp_digit b, fp_int *c, fp_digit *d)
+{
+  fp_int   q;
+  fp_word  w;
+  fp_digit t;
+  int      ix;
+
+  /* cannot divide by zero */
+  if (b == 0) {
+     return FP_VAL;
+  }
+
+  /* quick outs */
+  if (b == 1 || fp_iszero(a) == 1) {
+     if (d != NULL) {
+        *d = 0;
+     }
+     if (c != NULL) {
+        fp_copy(a, c);
+     }
+     return FP_OKAY;
+  }
+
+  /* power of two ? */
+  if (s_is_power_of_two(b, &ix) == 1) {
+     if (d != NULL) {
+        *d = a->dp[0] & ((((fp_digit)1)<<ix) - 1);
+     }
+     if (c != NULL) {
+        fp_div_2d(a, ix, c, NULL);
+     }
+     return FP_OKAY;
+  }
+
+  /* no easy answer [c'est la vie].  Just division */
+  fp_init(&q);
+  
+  q.used = a->used;
+  q.sign = a->sign;
+  w = 0;
+  for (ix = a->used - 1; ix >= 0; ix--) {
+     w = (w << ((fp_word)DIGIT_BIT)) | ((fp_word)a->dp[ix]);
+     
+     if (w >= b) {
+        t = (fp_digit)(w / b);
+        w -= ((fp_word)t) * ((fp_word)b);
+      } else {
+        t = 0;
+      }
+      q.dp[ix] = (fp_digit)t;
+  }
+  
+  if (d != NULL) {
+     *d = (fp_digit)w;
+  }
+  
+  if (c != NULL) {
+     fp_clamp(&q);
+     fp_copy(&q, c);
+  }
+ 
+  return FP_OKAY;
+}
+
+
+/* c = a mod b, 0 <= c < b  */
+static int fp_mod_d(fp_int *a, fp_digit b, fp_digit *c)
+{
+   return fp_div_d(a, b, NULL, c);
+}
+
+int mp_mod_d(fp_int *a, fp_digit b, fp_digit *c)
+{
+   return fp_mod_d(a, b, c);
+}
+
+#endif /* defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) */
+
+#ifdef WOLFSSL_KEY_GEN
+
+void fp_gcd(fp_int *a, fp_int *b, fp_int *c);
+void fp_lcm(fp_int *a, fp_int *b, fp_int *c);
+int  fp_isprime(fp_int *a);
+
+int mp_gcd(fp_int *a, fp_int *b, fp_int *c)
+{
+    fp_gcd(a, b, c);
+    return MP_OKAY;
+}
+
+
+int mp_lcm(fp_int *a, fp_int *b, fp_int *c)
+{
+    fp_lcm(a, b, c);
+    return MP_OKAY;
+}
+
+
+int mp_prime_is_prime(mp_int* a, int t, int* result)
+{
+    (void)t;
+    *result = fp_isprime(a);
+    return MP_OKAY;
+}
+
+/* Miller-Rabin test of "a" to the base of "b" as described in 
+ * HAC pp. 139 Algorithm 4.24
+ *
+ * Sets result to 0 if definitely composite or 1 if probably prime.
+ * Randomly the chance of error is no more than 1/4 and often 
+ * very much lower.
+ */
+static void fp_prime_miller_rabin (fp_int * a, fp_int * b, int *result)
+{
+  fp_int  n1, y, r;
+  int     s, j;
+
+  /* default */
+  *result = FP_NO;
+
+  /* ensure b > 1 */
+  if (fp_cmp_d(b, 1) != FP_GT) {
+     return;
+  }     
+
+  /* get n1 = a - 1 */
+  fp_init_copy(&n1, a);
+  fp_sub_d(&n1, 1, &n1);
+
+  /* set 2**s * r = n1 */
+  fp_init_copy(&r, &n1);
+
+  /* count the number of least significant bits
+   * which are zero
+   */
+  s = fp_cnt_lsb(&r);
+
+  /* now divide n - 1 by 2**s */
+  fp_div_2d (&r, s, &r, NULL);
+
+  /* compute y = b**r mod a */
+  fp_init(&y);
+  fp_exptmod(b, &r, a, &y);
+
+  /* if y != 1 and y != n1 do */
+  if (fp_cmp_d (&y, 1) != FP_EQ && fp_cmp (&y, &n1) != FP_EQ) {
+    j = 1;
+    /* while j <= s-1 and y != n1 */
+    while ((j <= (s - 1)) && fp_cmp (&y, &n1) != FP_EQ) {
+      fp_sqrmod (&y, a, &y);
+
+      /* if y == 1 then composite */
+      if (fp_cmp_d (&y, 1) == FP_EQ) {
+         return;
+      }
+      ++j;
+    }
+
+    /* if y != n1 then composite */
+    if (fp_cmp (&y, &n1) != FP_EQ) {
+       return;
+    }
+  }
+
+  /* probably prime now */
+  *result = FP_YES;
+}
+
+
+/* a few primes */
+static const fp_digit primes[256] = {
+  0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
+  0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
+  0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
+  0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083,
+  0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD,
+  0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF,
+  0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107,
+  0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137,
+
+  0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167,
+  0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199,
+  0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9,
+  0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7,
+  0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239,
+  0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265,
+  0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293,
+  0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF,
+
+  0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301,
+  0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B,
+  0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371,
+  0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD,
+  0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5,
+  0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419,
+  0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449,
+  0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B,
+
+  0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7,
+  0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503,
+  0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529,
+  0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F,
+  0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3,
+  0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7,
+  0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623,
+  0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653
+};
+
+int fp_isprime(fp_int *a)
+{
+   fp_int   b;
+   fp_digit d = 0;
+   int      r, res;
+
+   /* do trial division */
+   for (r = 0; r < 256; r++) {
+       fp_mod_d(a, primes[r], &d);
+       if (d == 0) {
+          return FP_NO;
+       }
+   }
+
+   /* now do 8 miller rabins */
+   fp_init(&b);
+   for (r = 0; r < 8; r++) {
+       fp_set(&b, primes[r]);
+       fp_prime_miller_rabin(a, &b, &res);
+       if (res == FP_NO) {
+          return FP_NO;
+       }
+   }
+   return FP_YES;
+}
+
+
+/* c = [a, b] */
+void fp_lcm(fp_int *a, fp_int *b, fp_int *c)
+{
+   fp_int  t1, t2;
+
+   fp_init(&t1);
+   fp_init(&t2);
+   fp_gcd(a, b, &t1);
+   if (fp_cmp_mag(a, b) == FP_GT) {
+      fp_div(a, &t1, &t2, NULL);
+      fp_mul(b, &t2, c);
+   } else {
+      fp_div(b, &t1, &t2, NULL);
+      fp_mul(a, &t2, c);
+   }   
+}
+
+
+
+/* c = (a, b) */
+void fp_gcd(fp_int *a, fp_int *b, fp_int *c)
+{
+   fp_int u, v, r;
+
+   /* either zero than gcd is the largest */
+   if (fp_iszero (a) == 1 && fp_iszero (b) == 0) {
+     fp_abs (b, c);
+     return;
+   }
+   if (fp_iszero (a) == 0 && fp_iszero (b) == 1) {
+     fp_abs (a, c);
+     return;
+   }
+
+   /* optimized.  At this point if a == 0 then
+    * b must equal zero too
+    */
+   if (fp_iszero (a) == 1) {
+     fp_zero(c);
+     return;
+   }
+
+   /* sort inputs */
+   if (fp_cmp_mag(a, b) != FP_LT) {
+      fp_init_copy(&u, a);
+      fp_init_copy(&v, b);
+   } else {
+      fp_init_copy(&u, b);
+      fp_init_copy(&v, a);
+   }
+ 
+   fp_init(&r);
+   while (fp_iszero(&v) == FP_NO) {
+      fp_mod(&u, &v, &r);
+      fp_copy(&v, &u);
+      fp_copy(&r, &v);
+   }
+   fp_copy(&u, c);
+}
+
+#endif /* WOLFSSL_KEY_GEN */
+
+
+#if defined(HAVE_ECC) || !defined(NO_PWDBASED)
+/* c = a + b */
+void fp_add_d(fp_int *a, fp_digit b, fp_int *c)
+{
+   fp_int tmp;
+   fp_init(&tmp);
+   fp_set(&tmp, b);
+   fp_add(a,&tmp,c);
+}
+
+/* external compatibility */
+int mp_add_d(fp_int *a, fp_digit b, fp_int *c)
+{
+    fp_add_d(a, b, c);
+    return MP_OKAY;
+}
+
+#endif  /* HAVE_ECC || !NO_PWDBASED */
+
+
+#ifdef HAVE_ECC
+
+/* chars used in radix conversions */
+static const char *fp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
+
+static int fp_read_radix(fp_int *a, const char *str, int radix)
+{
+  int     y, neg;
+  char    ch;
+
+  /* make sure the radix is ok */
+  if (radix < 2 || radix > 64) {
+    return FP_VAL;
+  }
+
+  /* if the leading digit is a
+   * minus set the sign to negative.
+   */
+  if (*str == '-') {
+    ++str;
+    neg = FP_NEG;
+  } else {
+    neg = FP_ZPOS;
+  }
+
+  /* set the integer to the default of zero */
+  fp_zero (a);
+
+  /* process each digit of the string */
+  while (*str) {
+    /* if the radix < 36 the conversion is case insensitive
+     * this allows numbers like 1AB and 1ab to represent the same  value
+     * [e.g. in hex]
+     */
+    ch = (char) ((radix < 36) ? XTOUPPER((unsigned char)*str) : *str);
+    for (y = 0; y < 64; y++) {
+      if (ch == fp_s_rmap[y]) {
+         break;
+      }
+    }
+
+    /* if the char was found in the map
+     * and is less than the given radix add it
+     * to the number, otherwise exit the loop.
+     */
+    if (y < radix) {
+      fp_mul_d (a, (fp_digit) radix, a);
+      fp_add_d (a, (fp_digit) y, a);
+    } else {
+      break;
+    }
+    ++str;
+  }
+
+  /* set the sign only if a != 0 */
+  if (fp_iszero(a) != FP_YES) {
+     a->sign = neg;
+  }
+  return FP_OKAY;
+}
+
+/* fast math conversion */
+int mp_read_radix(mp_int *a, const char *str, int radix)
+{
+    return fp_read_radix(a, str, radix);
+}
+
+/* fast math conversion */
+void mp_set(fp_int *a, fp_digit b)
+{
+    fp_set(a,b);
+}
+
+/* fast math conversion */
+int mp_sqr(fp_int *A, fp_int *B)
+{
+    fp_sqr(A, B);
+    return MP_OKAY;
+}
+  
+/* fast math conversion */
+int mp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp)
+{
+    fp_montgomery_reduce(a, m, mp);
+    return MP_OKAY;
+}
+
+
+/* fast math conversion */
+int mp_montgomery_setup(fp_int *a, fp_digit *rho)
+{
+    return fp_montgomery_setup(a, rho);
+}
+
+int mp_div_2(fp_int * a, fp_int * b)
+{
+    fp_div_2(a, b);
+    return MP_OKAY;
+}
+
+
+int mp_init_copy(fp_int * a, fp_int * b)
+{
+    fp_init_copy(a, b);
+    return MP_OKAY;
+}
+
+
+#ifdef HAVE_COMP_KEY
+
+int mp_cnt_lsb(fp_int* a)
+{
+    fp_cnt_lsb(a);
+    return MP_OKAY;
+}
+
+int mp_div_2d(fp_int* a, int b, fp_int* c, fp_int* d)
+{
+    fp_div_2d(a, b, c, d);
+    return MP_OKAY;
+}
+
+#endif /* HAVE_COMP_KEY */
+
+
+#endif /* HAVE_ECC */
+
+#endif /* USE_FAST_MATH */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/wc_port.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,657 @@
+/* port.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+#include <wolfssl/wolfcrypt/types.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+
+#ifdef _MSC_VER
+    /* 4996 warning to use MS extensions e.g., strcpy_s instead of strncpy */
+    #pragma warning(disable: 4996)
+#endif
+
+
+
+#ifdef SINGLE_THREADED
+
+int InitMutex(wolfSSL_Mutex* m)
+{
+    (void)m;
+    return 0;
+}
+
+
+int FreeMutex(wolfSSL_Mutex *m)
+{
+    (void)m;
+    return 0;
+}
+
+
+int LockMutex(wolfSSL_Mutex *m)
+{
+    (void)m;
+    return 0;
+}
+
+
+int UnLockMutex(wolfSSL_Mutex *m)
+{
+    (void)m;
+    return 0;
+}
+
+#else /* MULTI_THREAD */
+
+    #if defined(FREERTOS)
+
+        int InitMutex(wolfSSL_Mutex* m)
+        {
+            int iReturn;
+
+            *m = ( wolfSSL_Mutex ) xSemaphoreCreateMutex();
+            if( *m != NULL )
+                iReturn = 0;
+            else
+                iReturn = BAD_MUTEX_E;
+
+            return iReturn;
+        }
+
+        int FreeMutex(wolfSSL_Mutex* m)
+        {
+            vSemaphoreDelete( *m );
+            return 0;
+        }
+
+        int LockMutex(wolfSSL_Mutex* m)
+        {
+            /* Assume an infinite block, or should there be zero block? */
+            xSemaphoreTake( *m, portMAX_DELAY );
+            return 0;
+        }
+
+        int UnLockMutex(wolfSSL_Mutex* m)
+        {
+            xSemaphoreGive( *m );
+            return 0;
+        }
+
+    #elif defined(WOLFSSL_SAFERTOS)
+
+        int InitMutex(wolfSSL_Mutex* m)
+        {
+            vSemaphoreCreateBinary(m->mutexBuffer, m->mutex);
+            if (m->mutex == NULL)
+                return BAD_MUTEX_E;
+
+            return 0;
+        }
+
+        int FreeMutex(wolfSSL_Mutex* m)
+        {
+            (void)m;
+            return 0;
+        }
+
+        int LockMutex(wolfSSL_Mutex* m)
+        {
+            /* Assume an infinite block */
+            xSemaphoreTake(m->mutex, portMAX_DELAY);
+            return 0;
+        }
+
+        int UnLockMutex(wolfSSL_Mutex* m)
+        {
+            xSemaphoreGive(m->mutex);
+            return 0;
+        }
+
+
+    #elif defined(USE_WINDOWS_API)
+
+        int InitMutex(wolfSSL_Mutex* m)
+        {
+            InitializeCriticalSection(m);
+            return 0;
+        }
+
+
+        int FreeMutex(wolfSSL_Mutex* m)
+        {
+            DeleteCriticalSection(m);
+            return 0;
+        }
+
+
+        int LockMutex(wolfSSL_Mutex* m)
+        {
+            EnterCriticalSection(m);
+            return 0;
+        }
+
+
+        int UnLockMutex(wolfSSL_Mutex* m)
+        {
+            LeaveCriticalSection(m);
+            return 0;
+        }
+
+    #elif defined(WOLFSSL_PTHREADS)
+
+        int InitMutex(wolfSSL_Mutex* m)
+        {
+            if (pthread_mutex_init(m, 0) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+
+        int FreeMutex(wolfSSL_Mutex* m)
+        {
+            if (pthread_mutex_destroy(m) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+
+        int LockMutex(wolfSSL_Mutex* m)
+        {
+            if (pthread_mutex_lock(m) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+
+        int UnLockMutex(wolfSSL_Mutex* m)
+        {
+            if (pthread_mutex_unlock(m) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+    #elif defined(THREADX)
+
+        int InitMutex(wolfSSL_Mutex* m)
+        {
+            if (tx_mutex_create(m, "wolfSSL Mutex", TX_NO_INHERIT) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+
+        int FreeMutex(wolfSSL_Mutex* m)
+        {
+            if (tx_mutex_delete(m) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+
+        int LockMutex(wolfSSL_Mutex* m)
+        {
+            if (tx_mutex_get(m, TX_WAIT_FOREVER) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+
+        int UnLockMutex(wolfSSL_Mutex* m)
+        {
+            if (tx_mutex_put(m) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+    #elif defined(MICRIUM)
+
+        int InitMutex(wolfSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_MutexCreate(m) == 0)
+                    return 0;
+                else
+                    return BAD_MUTEX_E;
+            #else
+                return 0;
+            #endif
+        }
+
+
+        int FreeMutex(wolfSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_FreeMutex(m) == 0)
+                    return 0;
+                else
+                    return BAD_MUTEX_E;
+            #else
+                return 0;
+            #endif
+        }
+
+
+        int LockMutex(wolfSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_LockMutex(m) == 0)
+                    return 0;
+                else
+                    return BAD_MUTEX_E;
+            #else
+                return 0;
+            #endif
+        }
+
+
+        int UnLockMutex(wolfSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_UnLockMutex(m) == 0)
+                    return 0;
+                else
+                    return BAD_MUTEX_E;
+            #else
+                return 0;
+            #endif
+
+        }
+
+    #elif defined(EBSNET)
+
+        int InitMutex(wolfSSL_Mutex* m)
+        {
+            if (rtp_sig_mutex_alloc(m, "wolfSSL Mutex") == -1)
+                return BAD_MUTEX_E;
+            else
+                return 0;
+        }
+
+        int FreeMutex(wolfSSL_Mutex* m)
+        {
+            rtp_sig_mutex_free(*m);
+            return 0;
+        }
+
+        int LockMutex(wolfSSL_Mutex* m)
+        {
+            if (rtp_sig_mutex_claim_timed(*m, RTIP_INF) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+        int UnLockMutex(wolfSSL_Mutex* m)
+        {
+            rtp_sig_mutex_release(*m);
+            return 0;
+        }
+
+    #elif defined(FREESCALE_MQX)
+
+        int InitMutex(wolfSSL_Mutex* m)
+        {
+            if (_mutex_init(m, NULL) == MQX_EOK)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+        int FreeMutex(wolfSSL_Mutex* m)
+        {
+            if (_mutex_destroy(m) == MQX_EOK)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+        int LockMutex(wolfSSL_Mutex* m)
+        {
+            if (_mutex_lock(m) == MQX_EOK)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+        int UnLockMutex(wolfSSL_Mutex* m)
+        {
+            if (_mutex_unlock(m) == MQX_EOK)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+    #elif defined (WOLFSSL_TIRTOS)
+
+        int InitMutex(wolfSSL_Mutex* m)
+        {
+           Semaphore_Params params;
+
+           Semaphore_Params_init(&params);
+           params.mode = Semaphore_Mode_BINARY;
+
+           *m = Semaphore_create(1, &params, NULL);
+
+           return 0;
+        }
+
+        int FreeMutex(wolfSSL_Mutex* m)
+        {
+            Semaphore_delete(m);
+
+            return 0;
+        }
+
+        int LockMutex(wolfSSL_Mutex* m)
+        {
+            Semaphore_pend(*m, BIOS_WAIT_FOREVER);
+
+            return 0;
+        }
+
+        int UnLockMutex(wolfSSL_Mutex* m)
+        {
+            Semaphore_post(*m);
+
+            return 0;
+        }
+
+    #elif defined(WOLFSSL_uITRON4)
+        #include "kernel.h"
+        int InitMutex(wolfSSL_Mutex* m)
+        {
+            int iReturn;
+            m->sem.sematr  = TA_TFIFO ;
+            m->sem.isemcnt = 1 ;
+            m->sem.maxsem  = 1 ;
+            m->sem.name    = NULL ;
+
+            m->id = acre_sem(&m->sem);
+            if( m->id != NULL )
+                iReturn = 0;
+            else
+                iReturn = BAD_MUTEX_E;
+
+            return iReturn;
+        }
+
+        int FreeMutex(wolfSSL_Mutex* m)
+        {
+            del_sem( m->id );
+            return 0;
+        }
+
+        int LockMutex(wolfSSL_Mutex* m)
+        {
+            wai_sem(m->id);
+            return 0;
+        }
+
+        int UnLockMutex(wolfSSL_Mutex* m)
+        {
+            sig_sem(m->id);
+            return 0;
+        }
+
+        /****  uITRON malloc/free ***/
+        static ID ID_wolfssl_MPOOL = 0 ;
+        static T_CMPL wolfssl_MPOOL = {TA_TFIFO, 0, NULL, "wolfSSL_MPOOL"};
+
+        int uITRON4_minit(size_t poolsz) {
+            ER ercd;
+            wolfssl_MPOOL.mplsz = poolsz ;
+            ercd = acre_mpl(&wolfssl_MPOOL);
+            if (ercd > 0) {
+                ID_wolfssl_MPOOL = ercd;
+                return 0;
+            } else {
+                return -1;
+            }
+        }
+
+        void *uITRON4_malloc(size_t sz) {
+            ER ercd;
+            void *p ;
+            ercd = get_mpl(ID_wolfssl_MPOOL, sz, (VP)&p);
+            if (ercd == E_OK) {
+                return p;
+            } else {
+                return 0 ;
+            }
+        }
+
+        void *uITRON4_realloc(void *p, size_t sz) {
+          ER ercd;
+          void *newp ;
+          if(p) {
+              ercd = get_mpl(ID_wolfssl_MPOOL, sz, (VP)&newp);
+              if (ercd == E_OK) {
+                  memcpy(newp, p, sz) ;
+                  ercd = rel_mpl(ID_wolfssl_MPOOL, (VP)p);
+                  if (ercd == E_OK) {
+                      return newp;
+                  }
+              }
+          }
+          return 0 ;
+        }
+
+        void uITRON4_free(void *p) {
+            ER ercd;
+            ercd = rel_mpl(ID_wolfssl_MPOOL, (VP)p);
+            if (ercd == E_OK) {
+                return ;
+            } else {
+                return ;
+            }
+        }
+
+#elif defined(WOLFSSL_uTKERNEL2)
+        #include "tk/tkernel.h"
+        int InitMutex(wolfSSL_Mutex* m)
+        {
+            int iReturn;
+            m->sem.sematr  = TA_TFIFO ;
+            m->sem.isemcnt = 1 ;
+            m->sem.maxsem  = 1 ;
+
+            m->id = tk_cre_sem(&m->sem);
+            if( m->id != NULL )
+                iReturn = 0;
+            else
+                iReturn = BAD_MUTEX_E;
+
+            return iReturn;
+        }
+
+        int FreeMutex(wolfSSL_Mutex* m)
+        {
+            tk_del_sem( m->id );
+            return 0;
+        }
+
+        int LockMutex(wolfSSL_Mutex* m)
+        {
+            tk_wai_sem(m->id, 1, TMO_FEVR);
+            return 0;
+        }
+
+        int UnLockMutex(wolfSSL_Mutex* m)
+        {
+            tk_sig_sem(m->id, 1);
+            return 0;
+        }
+
+        /****  uT-Kernel malloc/free ***/
+        static ID ID_wolfssl_MPOOL = 0 ;
+        static T_CMPL wolfssl_MPOOL =
+                     {(void *)NULL,
+        TA_TFIFO , 0,   "wolfSSL_MPOOL"};
+
+        int uTKernel_init_mpool(unsigned int sz) {
+            ER ercd;
+            wolfssl_MPOOL.mplsz = sz ;
+            ercd = tk_cre_mpl(&wolfssl_MPOOL);
+            if (ercd > 0) {
+                ID_wolfssl_MPOOL = ercd;
+                return 0;
+            } else {
+                return -1;
+            }
+        }
+
+        void *uTKernel_malloc(unsigned int sz) {
+            ER ercd;
+            void *p ;
+            ercd = tk_get_mpl(ID_wolfssl_MPOOL, sz, (VP)&p, TMO_FEVR);
+            if (ercd == E_OK) {
+                return p;
+            } else {
+                return 0 ;
+            }
+        }
+
+        void *uTKernel_realloc(void *p, unsigned int sz) {
+          ER ercd;
+          void *newp ;
+          if(p) {
+              ercd = tk_get_mpl(ID_wolfssl_MPOOL, sz, (VP)&newp, TMO_FEVR);
+              if (ercd == E_OK) {
+                  memcpy(newp, p, sz) ;
+                  ercd = tk_rel_mpl(ID_wolfssl_MPOOL, (VP)p);
+                  if (ercd == E_OK) {
+                      return newp;
+                  }
+              }
+          }
+          return 0 ;
+        }
+
+        void uTKernel_free(void *p) {
+            ER ercd;
+            ercd = tk_rel_mpl(ID_wolfssl_MPOOL, (VP)p);
+            if (ercd == E_OK) {
+                return ;
+            } else {
+                return ;
+            }
+        }
+
+    #elif defined(WOLFSSL_MDK_ARM)|| defined(WOLFSSL_CMSIS_RTOS)
+    
+        #if defined(WOLFSSL_CMSIS_RTOS)
+            #include "cmsis_os.h"
+            #define CMSIS_NMUTEX 10
+            osMutexDef(wolfSSL_mt0) ;  osMutexDef(wolfSSL_mt1) ;  osMutexDef(wolfSSL_mt2) ;
+            osMutexDef(wolfSSL_mt3) ;  osMutexDef(wolfSSL_mt4) ;  osMutexDef(wolfSSL_mt5) ;  
+            osMutexDef(wolfSSL_mt6) ;  osMutexDef(wolfSSL_mt7) ;  osMutexDef(wolfSSL_mt8) ;  
+            osMutexDef(wolfSSL_mt9) ;  
+            
+            static const osMutexDef_t *CMSIS_mutex[] = { osMutex(wolfSSL_mt0),   
+                osMutex(wolfSSL_mt1),    osMutex(wolfSSL_mt2),   osMutex(wolfSSL_mt3),    
+                osMutex(wolfSSL_mt4),    osMutex(wolfSSL_mt5),   osMutex(wolfSSL_mt6),
+                osMutex(wolfSSL_mt7),    osMutex(wolfSSL_mt8),    osMutex(wolfSSL_mt9) } ;                 
+            
+            static osMutexId CMSIS_mutexID[CMSIS_NMUTEX] = {0} ;
+
+            int InitMutex(wolfSSL_Mutex* m)
+            {
+                int i ;
+                for (i=0; i<CMSIS_NMUTEX; i++) {
+                    if(CMSIS_mutexID[i] == 0) {
+                        CMSIS_mutexID[i] = osMutexCreate(CMSIS_mutex[i]) ;
+                        (*m) = CMSIS_mutexID[i] ;
+                    return 0 ;
+                    }
+                }
+                return -1 ;
+            }
+
+            int FreeMutex(wolfSSL_Mutex* m)
+            {
+                int i ;
+                osMutexDelete   (*m) ;
+                for (i=0; i<CMSIS_NMUTEX; i++) {
+                    if(CMSIS_mutexID[i] == (*m)) {
+                        CMSIS_mutexID[i] = 0 ;
+                        return(0) ;
+                    }
+                }
+                return(-1) ;
+            }
+            
+            int LockMutex(wolfSSL_Mutex* m)
+            {
+                osMutexWait(*m, osWaitForever) ;
+                return(0) ;
+            }
+
+            int UnLockMutex(wolfSSL_Mutex* m)
+            {
+                osMutexRelease (*m);
+                return 0;
+            }
+        #else
+        int InitMutex(wolfSSL_Mutex* m)
+        {
+            os_mut_init (m); 
+            return 0;
+        }
+
+        int FreeMutex(wolfSSL_Mutex* m)
+        {
+            return(0) ;
+        }
+
+        int LockMutex(wolfSSL_Mutex* m)
+        {
+            os_mut_wait (m, 0xffff);
+            return(0) ;
+        }
+
+        int UnLockMutex(wolfSSL_Mutex* m)
+        {
+            os_mut_release (m);
+            return 0;
+        }
+        #endif
+    #endif /* USE_WINDOWS_API */
+
+#endif /* SINGLE_THREADED */
+        
+#if defined(WOLFSSL_TI_CRYPT) ||  defined(WOLFSSL_TI_HASH)
+    #include <wolfcrypt/src/port/ti/ti-ccm.c>  /* initialize and Mutex for TI Crypt Engine */
+    #include <wolfcrypt/src/port/ti/ti-hash.c> /* md5, sha1, sha224, sha256 */
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/callbacks.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,81 @@
+/* callbacks.h
+ *
+ * Copyright (C) 2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef WOLFSSL_CALLBACKS_H
+#define WOLFSSL_CALLBACKS_H
+
+#include <sys/time.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+enum { /* CALLBACK CONTSTANTS */
+    MAX_PACKETNAME_SZ     =  24,
+    MAX_CIPHERNAME_SZ     =  24,
+    MAX_TIMEOUT_NAME_SZ   =  24,       
+    MAX_PACKETS_HANDSHAKE =  14,       /* 12 for client auth plus 2 alerts */
+    MAX_VALUE_SZ          = 128,       /* all handshake packets but Cert should
+                                          fit here  */
+};
+
+
+typedef struct handShakeInfo_st {
+    char   cipherName[MAX_CIPHERNAME_SZ + 1];    /* negotiated cipher */
+    char   packetNames[MAX_PACKETS_HANDSHAKE][MAX_PACKETNAME_SZ + 1];
+                                                 /* SSL packet names  */ 
+    int    numberPackets;                        /* actual # of packets */
+    int    negotiationError;                     /* cipher/parameter err */
+} HandShakeInfo;
+
+
+typedef struct timeval Timeval;
+
+
+typedef struct packetInfo_st {
+    char           packetName[MAX_PACKETNAME_SZ + 1]; /* SSL packet name */
+    Timeval        timestamp;                       /* when it occured    */
+    unsigned char  value[MAX_VALUE_SZ];             /* if fits, it's here */ 
+    unsigned char* bufferValue;                     /* otherwise here (non 0) */
+    int            valueSz;                         /* sz of value or buffer */
+} PacketInfo;
+
+
+typedef struct timeoutInfo_st {
+    char       timeoutName[MAX_TIMEOUT_NAME_SZ + 1]; /* timeout Name */
+    int        flags;                              /* for future use */
+    int        numberPackets;                      /* actual # of packets */
+    PacketInfo packets[MAX_PACKETS_HANDSHAKE];     /* list of all packets  */
+    Timeval    timeoutValue;                       /* timer that caused it */
+} TimeoutInfo;
+
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+
+#endif /* WOLFSSL_CALLBACKS_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/certs_test.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,1227 @@
+/* certs_test.h */
+
+#ifndef WOLFSSL_CERTS_TEST_H
+#define WOLFSSL_CERTS_TEST_H
+
+#ifdef USE_CERT_BUFFERS_1024
+
+/* ./certs/1024/client-key.der, 1024-bit */
+static const unsigned char client_key_der_1024[] =
+{
+	0x30, 0x82, 0x02, 0x5C, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 
+	0x00, 0xBC, 0x73, 0x0E, 0xA8, 0x49, 0xF3, 0x74, 0xA2, 0xA9, 
+	0xEF, 0x18, 0xA5, 0xDA, 0x55, 0x99, 0x21, 0xF9, 0xC8, 0xEC, 
+	0xB3, 0x6D, 0x48, 0xE5, 0x35, 0x35, 0x75, 0x77, 0x37, 0xEC, 
+	0xD1, 0x61, 0x90, 0x5F, 0x3E, 0xD9, 0xE4, 0xD5, 0xDF, 0x94, 
+	0xCA, 0xC1, 0xA9, 0xD7, 0x19, 0xDA, 0x86, 0xC9, 0xE8, 0x4D, 
+	0xC4, 0x61, 0x36, 0x82, 0xFE, 0xAB, 0xAD, 0x7E, 0x77, 0x25, 
+	0xBB, 0x8D, 0x11, 0xA5, 0xBC, 0x62, 0x3A, 0xA8, 0x38, 0xCC, 
+	0x39, 0xA2, 0x04, 0x66, 0xB4, 0xF7, 0xF7, 0xF3, 0xAA, 0xDA, 
+	0x4D, 0x02, 0x0E, 0xBB, 0x5E, 0x8D, 0x69, 0x48, 0xDC, 0x77, 
+	0xC9, 0x28, 0x0E, 0x22, 0xE9, 0x6B, 0xA4, 0x26, 0xBA, 0x4C, 
+	0xE8, 0xC1, 0xFD, 0x4A, 0x6F, 0x2B, 0x1F, 0xEF, 0x8A, 0xAE, 
+	0xF6, 0x90, 0x62, 0xE5, 0x64, 0x1E, 0xEB, 0x2B, 0x3C, 0x67, 
+	0xC8, 0xDC, 0x27, 0x00, 0xF6, 0x91, 0x68, 0x65, 0xA9, 0x02, 
+	0x03, 0x01, 0x00, 0x01, 0x02, 0x81, 0x80, 0x13, 0x97, 0xEA, 
+	0xE8, 0x38, 0x78, 0x25, 0xA2, 0x5C, 0x04, 0xCE, 0x0D, 0x40, 
+	0x7C, 0x31, 0xE5, 0xC4, 0x70, 0xCD, 0x9B, 0x82, 0x3B, 0x58, 
+	0x09, 0x86, 0x3B, 0x66, 0x5F, 0xDC, 0x31, 0x90, 0xF1, 0x4F, 
+	0xD5, 0xDB, 0x15, 0xDD, 0xDE, 0xD7, 0x3B, 0x95, 0x93, 0x31, 
+	0x18, 0x31, 0x0E, 0x5E, 0xA3, 0xD6, 0xA2, 0x1A, 0x71, 0x6E, 
+	0x81, 0x48, 0x1C, 0x4B, 0xCF, 0xDB, 0x8E, 0x7A, 0x86, 0x61, 
+	0x32, 0xDC, 0xFB, 0x55, 0xC1, 0x16, 0x6D, 0x27, 0x92, 0x24, 
+	0x45, 0x8B, 0xF1, 0xB8, 0x48, 0xB1, 0x4B, 0x1D, 0xAC, 0xDE, 
+	0xDA, 0xDD, 0x8E, 0x2F, 0xC2, 0x91, 0xFB, 0xA5, 0xA9, 0x6E, 
+	0xF8, 0x3A, 0x6A, 0xF1, 0xFD, 0x50, 0x18, 0xEF, 0x9F, 0xE7, 
+	0xC3, 0xCA, 0x78, 0xEA, 0x56, 0xD3, 0xD3, 0x72, 0x5B, 0x96, 
+	0xDD, 0x4E, 0x06, 0x4E, 0x3A, 0xC3, 0xD9, 0xBE, 0x72, 0xB6, 
+	0x65, 0x07, 0x07, 0x4C, 0x01, 0x02, 0x41, 0x00, 0xFA, 0x47, 
+	0xD4, 0x7A, 0x7C, 0x92, 0x3C, 0x55, 0xEF, 0x81, 0xF0, 0x41, 
+	0x30, 0x2D, 0xA3, 0xCF, 0x8F, 0x1C, 0xE6, 0x87, 0x27, 0x05, 
+	0x70, 0x0D, 0xDF, 0x98, 0x35, 0xD6, 0xF1, 0x8B, 0x38, 0x2F, 
+	0x24, 0xB5, 0xD0, 0x84, 0xB6, 0x79, 0x4F, 0x71, 0x29, 0x94, 
+	0x5A, 0xF0, 0x64, 0x6A, 0xAC, 0xE7, 0x72, 0xC6, 0xED, 0x4D, 
+	0x59, 0x98, 0x3E, 0x67, 0x3A, 0xF3, 0x74, 0x2C, 0xF9, 0x61, 
+	0x17, 0x69, 0x02, 0x41, 0x00, 0xC0, 0xC1, 0x82, 0x0D, 0x0C, 
+	0xEB, 0xC6, 0x2F, 0xDC, 0x92, 0xF9, 0x9D, 0x82, 0x1A, 0x31, 
+	0xE9, 0xE9, 0xF7, 0x4B, 0xF2, 0x82, 0x87, 0x1C, 0xEE, 0x16, 
+	0x6A, 0xD1, 0x1D, 0x18, 0x82, 0x70, 0xF3, 0xC0, 0xB6, 0x2F, 
+	0xF6, 0xF3, 0xF7, 0x1D, 0xF1, 0x86, 0x23, 0xC8, 0x4E, 0xEB, 
+	0x8F, 0x56, 0x8E, 0x8F, 0xF5, 0xBF, 0xF1, 0xF7, 0x2B, 0xB5, 
+	0xCC, 0x3D, 0xC6, 0x57, 0x39, 0x0C, 0x1B, 0x54, 0x41, 0x02, 
+	0x41, 0x00, 0x9D, 0x7E, 0x05, 0xDE, 0xED, 0xF4, 0xB7, 0xB2, 
+	0xFB, 0xFC, 0x30, 0x4B, 0x55, 0x1D, 0xE3, 0x2F, 0x01, 0x47, 
+	0x96, 0x69, 0x05, 0xCD, 0x0E, 0x2E, 0x2C, 0xBD, 0x83, 0x63, 
+	0xB6, 0xAB, 0x7C, 0xB7, 0x6D, 0xCA, 0x5B, 0x64, 0xA7, 0xCE, 
+	0xBE, 0x86, 0xDF, 0x3B, 0x53, 0xDE, 0x61, 0xD2, 0x1E, 0xEB, 
+	0xA5, 0xF6, 0x37, 0xED, 0xAC, 0xAB, 0x78, 0xD9, 0x4C, 0xE7, 
+	0x55, 0xFB, 0xD7, 0x11, 0x99, 0xC1, 0x02, 0x40, 0x18, 0x98, 
+	0x18, 0x29, 0xE6, 0x1E, 0x27, 0x39, 0x70, 0x21, 0x68, 0xAC, 
+	0x0A, 0x2F, 0xA1, 0x72, 0xC1, 0x21, 0x86, 0x95, 0x38, 0xC6, 
+	0x58, 0x90, 0xA0, 0x57, 0x9C, 0xBA, 0xE3, 0xA7, 0xB1, 0x15, 
+	0xC8, 0xDE, 0xF6, 0x1B, 0xC2, 0x61, 0x23, 0x76, 0xEF, 0xB0, 
+	0x9D, 0x1C, 0x44, 0xBE, 0x13, 0x43, 0x39, 0x67, 0x17, 0xC8, 
+	0x9D, 0xCA, 0xFB, 0xF5, 0x45, 0x64, 0x8B, 0x38, 0x82, 0x2C, 
+	0xF2, 0x81, 0x02, 0x40, 0x39, 0x89, 0xE5, 0x9C, 0x19, 0x55, 
+	0x30, 0xBA, 0xB7, 0x48, 0x8C, 0x48, 0x14, 0x0E, 0xF4, 0x9F, 
+	0x7E, 0x77, 0x97, 0x43, 0xE1, 0xB4, 0x19, 0x35, 0x31, 0x23, 
+	0x75, 0x9C, 0x3B, 0x44, 0xAD, 0x69, 0x12, 0x56, 0xEE, 0x00, 
+	0x61, 0x64, 0x16, 0x66, 0xD3, 0x7C, 0x74, 0x2B, 0x15, 0xB4, 
+	0xA2, 0xFE, 0xBF, 0x08, 0x6B, 0x1A, 0x5D, 0x3F, 0x90, 0x12, 
+	0xB1, 0x05, 0x86, 0x31, 0x29, 0xDB, 0xD9, 0xE2
+};
+static const int sizeof_client_key_der_1024 = sizeof(client_key_der_1024);
+
+/* ./certs/1024/client-cert.der, 1024-bit */
+static const unsigned char client_cert_der_1024[] =
+{
+	0x30, 0x82, 0x03, 0xC5, 0x30, 0x82, 0x03, 0x2E, 0xA0, 0x03, 
+	0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xE3, 0xD7, 0xA0, 0xFA, 
+	0x76, 0xDF, 0x2A, 0xFA, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 
+	0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 
+	0x81, 0x9E, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 
+	0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0E, 0x06, 
+	0x03, 0x55, 0x04, 0x08, 0x0C, 0x07, 0x4D, 0x6F, 0x6E, 0x74, 
+	0x61, 0x6E, 0x61, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 
+	0x04, 0x07, 0x0C, 0x07, 0x42, 0x6F, 0x7A, 0x65, 0x6D, 0x61, 
+	0x6E, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0A, 
+	0x0C, 0x0C, 0x77, 0x6F, 0x6C, 0x66, 0x53, 0x53, 0x4C, 0x5F, 
+	0x31, 0x30, 0x32, 0x34, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 
+	0x55, 0x04, 0x0B, 0x0C, 0x10, 0x50, 0x72, 0x6F, 0x67, 0x72, 
+	0x61, 0x6D, 0x6D, 0x69, 0x6E, 0x67, 0x2D, 0x31, 0x30, 0x32, 
+	0x34, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 
+	0x0C, 0x0F, 0x77, 0x77, 0x77, 0x2E, 0x77, 0x6F, 0x6C, 0x66, 
+	0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x1F, 0x30, 
+	0x1D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 
+	0x09, 0x01, 0x16, 0x10, 0x69, 0x6E, 0x66, 0x6F, 0x40, 0x77, 
+	0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 
+	0x30, 0x1E, 0x17, 0x0D, 0x31, 0x35, 0x30, 0x35, 0x30, 0x37, 
+	0x31, 0x38, 0x32, 0x31, 0x30, 0x31, 0x5A, 0x17, 0x0D, 0x31, 
+	0x38, 0x30, 0x31, 0x33, 0x31, 0x31, 0x38, 0x32, 0x31, 0x30, 
+	0x31, 0x5A, 0x30, 0x81, 0x9E, 0x31, 0x0B, 0x30, 0x09, 0x06, 
+	0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 
+	0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x07, 0x4D, 
+	0x6F, 0x6E, 0x74, 0x61, 0x6E, 0x61, 0x31, 0x10, 0x30, 0x0E, 
+	0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x07, 0x42, 0x6F, 0x7A, 
+	0x65, 0x6D, 0x61, 0x6E, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 
+	0x55, 0x04, 0x0A, 0x0C, 0x0C, 0x77, 0x6F, 0x6C, 0x66, 0x53, 
+	0x53, 0x4C, 0x5F, 0x31, 0x30, 0x32, 0x34, 0x31, 0x19, 0x30, 
+	0x17, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x10, 0x50, 0x72, 
+	0x6F, 0x67, 0x72, 0x61, 0x6D, 0x6D, 0x69, 0x6E, 0x67, 0x2D, 
+	0x31, 0x30, 0x32, 0x34, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 
+	0x55, 0x04, 0x03, 0x0C, 0x0F, 0x77, 0x77, 0x77, 0x2E, 0x77, 
+	0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 
+	0x31, 0x1F, 0x30, 0x1D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 
+	0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6E, 0x66, 
+	0x6F, 0x40, 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 
+	0x63, 0x6F, 0x6D, 0x30, 0x81, 0x9F, 0x30, 0x0D, 0x06, 0x09, 
+	0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 
+	0x00, 0x03, 0x81, 0x8D, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 
+	0x81, 0x00, 0xBC, 0x73, 0x0E, 0xA8, 0x49, 0xF3, 0x74, 0xA2, 
+	0xA9, 0xEF, 0x18, 0xA5, 0xDA, 0x55, 0x99, 0x21, 0xF9, 0xC8, 
+	0xEC, 0xB3, 0x6D, 0x48, 0xE5, 0x35, 0x35, 0x75, 0x77, 0x37, 
+	0xEC, 0xD1, 0x61, 0x90, 0x5F, 0x3E, 0xD9, 0xE4, 0xD5, 0xDF, 
+	0x94, 0xCA, 0xC1, 0xA9, 0xD7, 0x19, 0xDA, 0x86, 0xC9, 0xE8, 
+	0x4D, 0xC4, 0x61, 0x36, 0x82, 0xFE, 0xAB, 0xAD, 0x7E, 0x77, 
+	0x25, 0xBB, 0x8D, 0x11, 0xA5, 0xBC, 0x62, 0x3A, 0xA8, 0x38, 
+	0xCC, 0x39, 0xA2, 0x04, 0x66, 0xB4, 0xF7, 0xF7, 0xF3, 0xAA, 
+	0xDA, 0x4D, 0x02, 0x0E, 0xBB, 0x5E, 0x8D, 0x69, 0x48, 0xDC, 
+	0x77, 0xC9, 0x28, 0x0E, 0x22, 0xE9, 0x6B, 0xA4, 0x26, 0xBA, 
+	0x4C, 0xE8, 0xC1, 0xFD, 0x4A, 0x6F, 0x2B, 0x1F, 0xEF, 0x8A, 
+	0xAE, 0xF6, 0x90, 0x62, 0xE5, 0x64, 0x1E, 0xEB, 0x2B, 0x3C, 
+	0x67, 0xC8, 0xDC, 0x27, 0x00, 0xF6, 0x91, 0x68, 0x65, 0xA9, 
+	0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x82, 0x01, 0x07, 0x30, 
+	0x82, 0x01, 0x03, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 
+	0x04, 0x16, 0x04, 0x14, 0x81, 0x69, 0x0F, 0xF8, 0xDF, 0xDD, 
+	0xCF, 0x34, 0x29, 0xD5, 0x67, 0x75, 0x71, 0x85, 0xC7, 0x75, 
+	0x10, 0x69, 0x59, 0xEC, 0x30, 0x81, 0xD3, 0x06, 0x03, 0x55, 
+	0x1D, 0x23, 0x04, 0x81, 0xCB, 0x30, 0x81, 0xC8, 0x80, 0x14, 
+	0x81, 0x69, 0x0F, 0xF8, 0xDF, 0xDD, 0xCF, 0x34, 0x29, 0xD5, 
+	0x67, 0x75, 0x71, 0x85, 0xC7, 0x75, 0x10, 0x69, 0x59, 0xEC, 
+	0xA1, 0x81, 0xA4, 0xA4, 0x81, 0xA1, 0x30, 0x81, 0x9E, 0x31, 
+	0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 
+	0x55, 0x53, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 
+	0x08, 0x0C, 0x07, 0x4D, 0x6F, 0x6E, 0x74, 0x61, 0x6E, 0x61, 
+	0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 
+	0x07, 0x42, 0x6F, 0x7A, 0x65, 0x6D, 0x61, 0x6E, 0x31, 0x15, 
+	0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x0C, 0x77, 
+	0x6F, 0x6C, 0x66, 0x53, 0x53, 0x4C, 0x5F, 0x31, 0x30, 0x32, 
+	0x34, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0B, 
+	0x0C, 0x10, 0x50, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x6D, 
+	0x69, 0x6E, 0x67, 0x2D, 0x31, 0x30, 0x32, 0x34, 0x31, 0x18, 
+	0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0F, 0x77, 
+	0x77, 0x77, 0x2E, 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 
+	0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x1F, 0x30, 0x1D, 0x06, 0x09, 
+	0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 
+	0x10, 0x69, 0x6E, 0x66, 0x6F, 0x40, 0x77, 0x6F, 0x6C, 0x66, 
+	0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x82, 0x09, 0x00, 
+	0xE3, 0xD7, 0xA0, 0xFA, 0x76, 0xDF, 0x2A, 0xFA, 0x30, 0x0C, 
+	0x06, 0x03, 0x55, 0x1D, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 
+	0x01, 0xFF, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 
+	0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 0x81, 0x81, 
+	0x00, 0x1D, 0xB7, 0xD5, 0x7C, 0xE1, 0xB1, 0xD8, 0xC0, 0x67, 
+	0x5D, 0xB5, 0xD3, 0x88, 0xE7, 0x50, 0x29, 0x71, 0x63, 0x8F, 
+	0xCC, 0x26, 0x1F, 0x33, 0x09, 0x55, 0x43, 0x9B, 0xAB, 0xC6, 
+	0x1B, 0xBC, 0xC7, 0x01, 0x95, 0x1A, 0xFA, 0x65, 0xE0, 0xFD, 
+	0x9C, 0xEB, 0x6F, 0x0A, 0x0F, 0x14, 0xEC, 0xB5, 0x2F, 0xDC, 
+	0x1C, 0x30, 0xDD, 0x52, 0x97, 0xD4, 0x1C, 0x09, 0x00, 0x33, 
+	0x38, 0x5F, 0xCB, 0xA8, 0x16, 0x8F, 0x11, 0xB7, 0xB8, 0xD0, 
+	0x66, 0xE1, 0x54, 0x28, 0xF3, 0x3F, 0xBF, 0x6A, 0x6F, 0x76, 
+	0x48, 0x2A, 0x5E, 0x56, 0xA7, 0xCE, 0x1C, 0xF0, 0x04, 0xDD, 
+	0x17, 0xBD, 0x06, 0x78, 0x21, 0x6D, 0xD6, 0xB1, 0x9B, 0x75, 
+	0x31, 0x92, 0xC1, 0xFE, 0xD4, 0x8D, 0xD4, 0x67, 0x2F, 0x03, 
+	0x1B, 0x27, 0x8D, 0xAB, 0xFF, 0x30, 0x3B, 0xC3, 0x7F, 0x23, 
+	0xE4, 0xAB, 0x5B, 0x91, 0xE1, 0x1B, 0x66, 0xE6, 0xED
+};
+static const int sizeof_client_cert_der_1024 = sizeof(client_cert_der_1024);
+
+/* ./certs/1024/dh1024.der, 1024-bit */
+static const unsigned char dh_key_der_1024[] =
+{
+	0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0xA4, 0xD2, 0xB8, 
+	0x6E, 0x78, 0xF5, 0xD9, 0xED, 0x2D, 0x7C, 0xDD, 0xB6, 0x16, 
+	0x86, 0x5A, 0x4B, 0x05, 0x76, 0x90, 0xDD, 0x66, 0x61, 0xB9, 
+	0x6D, 0x52, 0xA7, 0x1C, 0xAF, 0x62, 0xC6, 0x69, 0x47, 0x7B, 
+	0x39, 0xF2, 0xFB, 0x94, 0xEC, 0xBC, 0x79, 0xFF, 0x24, 0x5E, 
+	0xEF, 0x79, 0xBB, 0x59, 0xB2, 0xFC, 0xCA, 0x07, 0xD6, 0xF4, 
+	0xE9, 0x34, 0xF7, 0xE8, 0x38, 0xE7, 0xD7, 0x33, 0x44, 0x1D, 
+	0xA3, 0x64, 0x76, 0x1A, 0x84, 0x97, 0x54, 0x74, 0x40, 0x84, 
+	0x1F, 0x15, 0xFE, 0x7C, 0x25, 0x2A, 0x2B, 0x25, 0xFD, 0x9E, 
+	0xC1, 0x89, 0x33, 0x8C, 0x39, 0x25, 0x2B, 0x40, 0xE6, 0xCD, 
+	0xF8, 0xA8, 0xA1, 0x8A, 0x53, 0xC6, 0x47, 0xB2, 0xA0, 0xD7, 
+	0x8F, 0xEB, 0x2E, 0x60, 0x0A, 0x0D, 0x4B, 0xF8, 0xB4, 0x94, 
+	0x8C, 0x63, 0x0A, 0xAD, 0xC7, 0x10, 0xEA, 0xC7, 0xA1, 0xB9, 
+	0x9D, 0xF2, 0xA8, 0x37, 0x73, 0x02, 0x01, 0x02
+};
+static const int sizeof_dh_key_der_1024 = sizeof(dh_key_der_1024);
+
+/* ./certs/1024/dsa1024.der, 1024-bit */
+static const unsigned char dsa_key_der_1024[] =
+{
+	0x30, 0x82, 0x01, 0xBC, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 
+	0x00, 0xF7, 0x4B, 0xF9, 0xBB, 0x15, 0x98, 0xEB, 0xDD, 0xDE, 
+	0x1E, 0x4E, 0x71, 0x88, 0x85, 0xF2, 0xB7, 0xBA, 0xE2, 0x4A, 
+	0xDA, 0x76, 0x40, 0xCD, 0x69, 0x48, 0x9E, 0x83, 0x7C, 0x11, 
+	0xF7, 0x65, 0x31, 0x78, 0xF5, 0x25, 0x2D, 0xF7, 0xB7, 0xF8, 
+	0x52, 0x3F, 0xBE, 0xD8, 0xB6, 0xC5, 0xFE, 0x18, 0x15, 0x5B, 
+	0xB9, 0xD5, 0x92, 0x86, 0xBC, 0xB2, 0x17, 0x7C, 0xD8, 0xB0, 
+	0xBE, 0xA0, 0x7C, 0xF2, 0xD5, 0x73, 0x7A, 0x58, 0x8F, 0x8D, 
+	0xE5, 0x4A, 0x00, 0x99, 0x83, 0x4A, 0xC0, 0x9E, 0x16, 0x09, 
+	0xA1, 0x10, 0x34, 0xD5, 0x19, 0xBB, 0x63, 0xE3, 0xDD, 0x83, 
+	0x74, 0x7F, 0x10, 0xCA, 0x73, 0x75, 0xEE, 0x31, 0x4A, 0xDD, 
+	0x9F, 0xE0, 0x02, 0x6A, 0x9D, 0xEE, 0xB2, 0x4B, 0xA7, 0x6B, 
+	0x2A, 0x6C, 0xC7, 0x86, 0x77, 0xE8, 0x04, 0x15, 0xDC, 0x92, 
+	0xB4, 0x7A, 0x29, 0x1F, 0x4E, 0x83, 0x63, 0x85, 0x55, 0x02, 
+	0x15, 0x00, 0xD2, 0x05, 0xE4, 0x73, 0xFB, 0xC1, 0x99, 0xC5, 
+	0xDC, 0x68, 0xA4, 0x8D, 0x92, 0x27, 0x3D, 0xE2, 0x52, 0x5F, 
+	0x89, 0x8B, 0x02, 0x81, 0x81, 0x00, 0xAA, 0x21, 0x02, 0x09, 
+	0x43, 0x6E, 0xFB, 0xA2, 0x54, 0x14, 0x85, 0x0A, 0xF4, 0x28, 
+	0x7C, 0xCB, 0xCC, 0xDB, 0xF5, 0x1E, 0xA2, 0x18, 0xA9, 0x21, 
+	0xDE, 0x88, 0x88, 0x33, 0x8C, 0x2E, 0xEB, 0x8D, 0xA3, 0xF0, 
+	0x1D, 0xC8, 0x8F, 0xF6, 0x7E, 0xF8, 0xCF, 0x12, 0xF5, 0xB4, 
+	0xA1, 0x11, 0x6F, 0x0C, 0xD4, 0xF0, 0x06, 0xAD, 0xC4, 0xFC, 
+	0x14, 0x45, 0xC7, 0x94, 0x15, 0xBC, 0x19, 0x4B, 0xAE, 0xEF, 
+	0x93, 0x6A, 0x4F, 0xCC, 0x14, 0xD8, 0x47, 0x8B, 0x39, 0x66, 
+	0x87, 0x02, 0xD4, 0x28, 0x0A, 0xB8, 0xEE, 0x09, 0x37, 0xF4, 
+	0x00, 0xA0, 0x04, 0xA7, 0x79, 0xA7, 0xD2, 0x3C, 0xF7, 0x34, 
+	0x43, 0x56, 0x8E, 0xD0, 0x7C, 0xC2, 0xD8, 0x4D, 0x0F, 0x89, 
+	0xED, 0x14, 0xC1, 0x2C, 0x9C, 0x4C, 0x19, 0x9B, 0x9E, 0xDC, 
+	0x53, 0x09, 0x9F, 0xDF, 0x2D, 0xF0, 0x0C, 0x27, 0x54, 0x3A, 
+	0x77, 0x14, 0x2D, 0xDE, 0x02, 0x81, 0x81, 0x00, 0xE8, 0x1F, 
+	0x7C, 0xB7, 0xC0, 0x54, 0x51, 0xA7, 0x28, 0x2D, 0x58, 0x7C, 
+	0xDE, 0xD4, 0x5C, 0xDD, 0xD5, 0x76, 0x84, 0x3C, 0x36, 0x20, 
+	0xC0, 0xC3, 0x25, 0xD7, 0x3A, 0x38, 0xE1, 0x54, 0xC8, 0xFD, 
+	0x40, 0x68, 0x1A, 0x21, 0x54, 0x26, 0x39, 0x14, 0xBF, 0xF6, 
+	0xA3, 0x9C, 0x5E, 0xD9, 0x2B, 0xF7, 0xC9, 0x25, 0xBA, 0x00, 
+	0x09, 0xCB, 0x7F, 0x0C, 0x4A, 0x24, 0xFD, 0x15, 0x16, 0x15, 
+	0x48, 0xCD, 0x0B, 0x52, 0x44, 0x40, 0x7B, 0x90, 0x63, 0x2B, 
+	0x90, 0x22, 0xC5, 0x18, 0x05, 0x80, 0x53, 0xAF, 0x83, 0x1F, 
+	0x54, 0xE2, 0xB0, 0xA2, 0x0B, 0x5A, 0x92, 0x24, 0xE1, 0x62, 
+	0x28, 0x3F, 0xB7, 0xCA, 0xB9, 0x89, 0xD6, 0xA0, 0xB7, 0xAD, 
+	0xAE, 0x05, 0xE1, 0xC1, 0x59, 0x40, 0xED, 0x4A, 0x1B, 0x68, 
+	0xA7, 0x7B, 0xFB, 0xC3, 0x20, 0x81, 0xEF, 0x4B, 0xF3, 0x69, 
+	0x91, 0xB0, 0xCE, 0x3A, 0xB0, 0x38, 0x02, 0x14, 0x25, 0x38, 
+	0x3B, 0xA1, 0x19, 0x75, 0xDF, 0x9B, 0xF5, 0x72, 0x53, 0x4F, 
+	0x39, 0xE1, 0x1C, 0xEC, 0x13, 0x84, 0x82, 0x18
+};
+static const int sizeof_dsa_key_der_1024 = sizeof(dsa_key_der_1024);
+
+/* ./certs/1024/rsa1024.der, 1024-bit */
+static const unsigned char rsa_key_der_1024[] =
+{
+	0x30, 0x82, 0x02, 0x5D, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 
+	0x00, 0xBE, 0x70, 0x70, 0xB8, 0x04, 0x18, 0xE5, 0x28, 0xFE, 
+	0x66, 0xD8, 0x90, 0x88, 0xE0, 0xF1, 0xB7, 0xC3, 0xD0, 0xD2, 
+	0x3E, 0xE6, 0x4B, 0x94, 0x74, 0xB0, 0xFF, 0xB0, 0xF7, 0x63, 
+	0xA5, 0xAB, 0x7E, 0xAF, 0xB6, 0x2B, 0xB7, 0x38, 0x16, 0x1A, 
+	0x50, 0xBF, 0xF1, 0xCA, 0x87, 0x3A, 0xD5, 0xB0, 0xDA, 0xF8, 
+	0x43, 0x7A, 0x15, 0xB9, 0x7E, 0xEA, 0x2A, 0x80, 0xD2, 0x51, 
+	0xB0, 0x35, 0xAF, 0x07, 0xF3, 0xF2, 0x5D, 0x24, 0x3A, 0x4B, 
+	0x87, 0x56, 0x48, 0x1B, 0x3C, 0x24, 0x9A, 0xDA, 0x70, 0x80, 
+	0xBD, 0x3C, 0x8B, 0x03, 0x4A, 0x0C, 0x83, 0x71, 0xDE, 0xE3, 
+	0x03, 0x70, 0xA2, 0xB7, 0x60, 0x09, 0x1B, 0x5E, 0xC7, 0x3D, 
+	0xA0, 0x64, 0x60, 0xE3, 0xA9, 0x06, 0x8D, 0xD3, 0xFF, 0x42, 
+	0xBB, 0x0A, 0x94, 0x27, 0x2D, 0x57, 0x42, 0x0D, 0xB0, 0x2D, 
+	0xE0, 0xBA, 0x18, 0x25, 0x60, 0x92, 0x11, 0x92, 0xF3, 0x02, 
+	0x03, 0x01, 0x00, 0x01, 0x02, 0x81, 0x80, 0x0E, 0xEE, 0x1D, 
+	0xC8, 0x2F, 0x7A, 0x0C, 0x2D, 0x44, 0x94, 0xA7, 0x91, 0xDD, 
+	0x49, 0x55, 0x6A, 0x04, 0xCE, 0x10, 0x4D, 0xA2, 0x1C, 0x76, 
+	0xCD, 0x17, 0x3B, 0x54, 0x92, 0x70, 0x9B, 0x82, 0x70, 0x72, 
+	0x32, 0x24, 0x07, 0x3F, 0x3C, 0x6C, 0x5F, 0xBC, 0x4C, 0xA6, 
+	0x86, 0x27, 0x94, 0xAD, 0x42, 0xDD, 0x87, 0xDC, 0xC0, 0x6B, 
+	0x44, 0x89, 0xF3, 0x3F, 0x1A, 0x3E, 0x11, 0x44, 0x84, 0x2E, 
+	0x69, 0x4C, 0xBB, 0x4A, 0x71, 0x1A, 0xBB, 0x9A, 0x52, 0x3C, 
+	0x6B, 0xDE, 0xBC, 0xB2, 0x7C, 0x51, 0xEF, 0x4F, 0x8F, 0x3A, 
+	0xDC, 0x50, 0x04, 0x4E, 0xB6, 0x31, 0x66, 0xA8, 0x8E, 0x06, 
+	0x3B, 0x51, 0xA9, 0xC1, 0x8A, 0xCB, 0xC4, 0x81, 0xCA, 0x2D, 
+	0x69, 0xEC, 0x88, 0xFC, 0x33, 0x88, 0xD1, 0xD4, 0x29, 0x47, 
+	0x87, 0x37, 0xF9, 0x6A, 0x22, 0x69, 0xB9, 0xC9, 0xFE, 0xEB, 
+	0x8C, 0xC5, 0x21, 0x41, 0x71, 0x02, 0x41, 0x00, 0xFD, 0x17, 
+	0x98, 0x42, 0x54, 0x1C, 0x23, 0xF8, 0xD7, 0x5D, 0xEF, 0x49, 
+	0x4F, 0xAF, 0xD9, 0x35, 0x6F, 0x08, 0xC6, 0xC7, 0x40, 0x5C, 
+	0x7E, 0x58, 0x86, 0xC2, 0xB2, 0x16, 0x39, 0x24, 0xC5, 0x06, 
+	0xB0, 0x3D, 0xAF, 0x02, 0xD2, 0x87, 0x77, 0xD2, 0x76, 0xBA, 
+	0xE3, 0x59, 0x60, 0x42, 0xF1, 0x16, 0xEF, 0x33, 0x0B, 0xF2, 
+	0x0B, 0xBA, 0x99, 0xCC, 0xB6, 0x4C, 0x46, 0x3F, 0x33, 0xE4, 
+	0xD4, 0x67, 0x02, 0x41, 0x00, 0xC0, 0xA0, 0x91, 0x6D, 0xFE, 
+	0x28, 0xE0, 0x81, 0x5A, 0x15, 0xA7, 0xC9, 0xA8, 0x98, 0xC6, 
+	0x0A, 0xAB, 0x00, 0xC5, 0x40, 0xC9, 0x21, 0xBB, 0xB2, 0x33, 
+	0x5A, 0xA7, 0xCB, 0x6E, 0xB8, 0x08, 0x56, 0x4A, 0x76, 0x28, 
+	0xE8, 0x6D, 0xBD, 0xF5, 0x26, 0x7B, 0xBF, 0xC5, 0x46, 0x45, 
+	0x0D, 0xEC, 0x7D, 0xEE, 0x82, 0xD6, 0xCA, 0x5F, 0x3D, 0x6E, 
+	0xCC, 0x94, 0x73, 0xCD, 0xCE, 0x86, 0x6E, 0x95, 0x95, 0x02, 
+	0x40, 0x38, 0xFD, 0x28, 0x1E, 0xBF, 0x5B, 0xBA, 0xC9, 0xDC, 
+	0x8C, 0xDD, 0x45, 0xAF, 0xB8, 0xD3, 0xFB, 0x11, 0x2E, 0x73, 
+	0xBC, 0x08, 0x05, 0x0B, 0xBA, 0x19, 0x56, 0x1B, 0xCD, 0x9F, 
+	0x3E, 0x65, 0x53, 0x15, 0x3A, 0x3E, 0x7F, 0x2F, 0x32, 0xAB, 
+	0xCB, 0x6B, 0x4A, 0xB7, 0xC8, 0xB7, 0x41, 0x3B, 0x92, 0x43, 
+	0x78, 0x46, 0x17, 0x51, 0x86, 0xC9, 0xFC, 0xEB, 0x8B, 0x8F, 
+	0x41, 0xCA, 0x08, 0x9B, 0xBF, 0x02, 0x41, 0x00, 0xAD, 0x9B, 
+	0x89, 0xB6, 0xF2, 0x8C, 0x70, 0xDA, 0xE4, 0x10, 0x04, 0x6B, 
+	0x11, 0x92, 0xAF, 0x5A, 0xCA, 0x08, 0x25, 0xBF, 0x60, 0x07, 
+	0x11, 0x1D, 0x68, 0x7F, 0x5A, 0x1F, 0x55, 0x28, 0x74, 0x0B, 
+	0x21, 0x8D, 0x21, 0x0D, 0x6A, 0x6A, 0xFB, 0xD9, 0xB5, 0x4A, 
+	0x7F, 0x47, 0xF7, 0xD0, 0xB6, 0xC6, 0x41, 0x02, 0x97, 0x07, 
+	0x49, 0x93, 0x1A, 0x9B, 0x33, 0x68, 0xB3, 0xA2, 0x61, 0x32, 
+	0xA5, 0x89, 0x02, 0x41, 0x00, 0x8F, 0xEF, 0xAD, 0xB5, 0xB0, 
+	0xB0, 0x7E, 0x86, 0x03, 0x43, 0x93, 0x6E, 0xDD, 0x3C, 0x2D, 
+	0x9B, 0x6A, 0x55, 0xFF, 0x6F, 0x3E, 0x70, 0x2A, 0xD4, 0xBF, 
+	0x1F, 0x8C, 0x93, 0x60, 0x9E, 0x6D, 0x2F, 0x18, 0x6C, 0x11, 
+	0x36, 0x98, 0x3F, 0x10, 0x78, 0xE8, 0x3E, 0x8F, 0xFE, 0x55, 
+	0xB9, 0x9E, 0xD5, 0x5B, 0x2E, 0x87, 0x1C, 0x58, 0xD0, 0x37, 
+	0x89, 0x96, 0xEC, 0x48, 0x54, 0xF5, 0x9F, 0x0F, 0xB3
+};
+static const int sizeof_rsa_key_der_1024 = sizeof(rsa_key_der_1024);
+
+#elif defined(USE_CERT_BUFFERS_2048)
+
+/* ./certs/client-key.der, 2048-bit */
+static const unsigned char client_key_der_2048[] =
+{
+	0x30, 0x82, 0x04, 0xA4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 
+	0x01, 0x00, 0xC3, 0x03, 0xD1, 0x2B, 0xFE, 0x39, 0xA4, 0x32, 
+	0x45, 0x3B, 0x53, 0xC8, 0x84, 0x2B, 0x2A, 0x7C, 0x74, 0x9A, 
+	0xBD, 0xAA, 0x2A, 0x52, 0x07, 0x47, 0xD6, 0xA6, 0x36, 0xB2, 
+	0x07, 0x32, 0x8E, 0xD0, 0xBA, 0x69, 0x7B, 0xC6, 0xC3, 0x44, 
+	0x9E, 0xD4, 0x81, 0x48, 0xFD, 0x2D, 0x68, 0xA2, 0x8B, 0x67, 
+	0xBB, 0xA1, 0x75, 0xC8, 0x36, 0x2C, 0x4A, 0xD2, 0x1B, 0xF7, 
+	0x8B, 0xBA, 0xCF, 0x0D, 0xF9, 0xEF, 0xEC, 0xF1, 0x81, 0x1E, 
+	0x7B, 0x9B, 0x03, 0x47, 0x9A, 0xBF, 0x65, 0xCC, 0x7F, 0x65, 
+	0x24, 0x69, 0xA6, 0xE8, 0x14, 0x89, 0x5B, 0xE4, 0x34, 0xF7, 
+	0xC5, 0xB0, 0x14, 0x93, 0xF5, 0x67, 0x7B, 0x3A, 0x7A, 0x78, 
+	0xE1, 0x01, 0x56, 0x56, 0x91, 0xA6, 0x13, 0x42, 0x8D, 0xD2, 
+	0x3C, 0x40, 0x9C, 0x4C, 0xEF, 0xD1, 0x86, 0xDF, 0x37, 0x51, 
+	0x1B, 0x0C, 0xA1, 0x3B, 0xF5, 0xF1, 0xA3, 0x4A, 0x35, 0xE4, 
+	0xE1, 0xCE, 0x96, 0xDF, 0x1B, 0x7E, 0xBF, 0x4E, 0x97, 0xD0, 
+	0x10, 0xE8, 0xA8, 0x08, 0x30, 0x81, 0xAF, 0x20, 0x0B, 0x43, 
+	0x14, 0xC5, 0x74, 0x67, 0xB4, 0x32, 0x82, 0x6F, 0x8D, 0x86, 
+	0xC2, 0x88, 0x40, 0x99, 0x36, 0x83, 0xBA, 0x1E, 0x40, 0x72, 
+	0x22, 0x17, 0xD7, 0x52, 0x65, 0x24, 0x73, 0xB0, 0xCE, 0xEF, 
+	0x19, 0xCD, 0xAE, 0xFF, 0x78, 0x6C, 0x7B, 0xC0, 0x12, 0x03, 
+	0xD4, 0x4E, 0x72, 0x0D, 0x50, 0x6D, 0x3B, 0xA3, 0x3B, 0xA3, 
+	0x99, 0x5E, 0x9D, 0xC8, 0xD9, 0x0C, 0x85, 0xB3, 0xD9, 0x8A, 
+	0xD9, 0x54, 0x26, 0xDB, 0x6D, 0xFA, 0xAC, 0xBB, 0xFF, 0x25, 
+	0x4C, 0xC4, 0xD1, 0x79, 0xF4, 0x71, 0xD3, 0x86, 0x40, 0x18, 
+	0x13, 0xB0, 0x63, 0xB5, 0x72, 0x4E, 0x30, 0xC4, 0x97, 0x84, 
+	0x86, 0x2D, 0x56, 0x2F, 0xD7, 0x15, 0xF7, 0x7F, 0xC0, 0xAE, 
+	0xF5, 0xFC, 0x5B, 0xE5, 0xFB, 0xA1, 0xBA, 0xD3, 0x02, 0x03, 
+	0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x01, 0x00, 0xA2, 0xE6, 
+	0xD8, 0x5F, 0x10, 0x71, 0x64, 0x08, 0x9E, 0x2E, 0x6D, 0xD1, 
+	0x6D, 0x1E, 0x85, 0xD2, 0x0A, 0xB1, 0x8C, 0x47, 0xCE, 0x2C, 
+	0x51, 0x6A, 0xA0, 0x12, 0x9E, 0x53, 0xDE, 0x91, 0x4C, 0x1D, 
+	0x6D, 0xEA, 0x59, 0x7B, 0xF2, 0x77, 0xAA, 0xD9, 0xC6, 0xD9, 
+	0x8A, 0xAB, 0xD8, 0xE1, 0x16, 0xE4, 0x63, 0x26, 0xFF, 0xB5, 
+	0x6C, 0x13, 0x59, 0xB8, 0xE3, 0xA5, 0xC8, 0x72, 0x17, 0x2E, 
+	0x0C, 0x9F, 0x6F, 0xE5, 0x59, 0x3F, 0x76, 0x6F, 0x49, 0xB1, 
+	0x11, 0xC2, 0x5A, 0x2E, 0x16, 0x29, 0x0D, 0xDE, 0xB7, 0x8E, 
+	0xDC, 0x40, 0xD5, 0xA2, 0xEE, 0xE0, 0x1E, 0xA1, 0xF4, 0xBE, 
+	0x97, 0xDB, 0x86, 0x63, 0x96, 0x14, 0xCD, 0x98, 0x09, 0x60, 
+	0x2D, 0x30, 0x76, 0x9C, 0x3C, 0xCD, 0xE6, 0x88, 0xEE, 0x47, 
+	0x92, 0x79, 0x0B, 0x5A, 0x00, 0xE2, 0x5E, 0x5F, 0x11, 0x7C, 
+	0x7D, 0xF9, 0x08, 0xB7, 0x20, 0x06, 0x89, 0x2A, 0x5D, 0xFD, 
+	0x00, 0xAB, 0x22, 0xE1, 0xF0, 0xB3, 0xBC, 0x24, 0xA9, 0x5E, 
+	0x26, 0x0E, 0x1F, 0x00, 0x2D, 0xFE, 0x21, 0x9A, 0x53, 0x5B, 
+	0x6D, 0xD3, 0x2B, 0xAB, 0x94, 0x82, 0x68, 0x43, 0x36, 0xD8, 
+	0xF6, 0x2F, 0xC6, 0x22, 0xFC, 0xB5, 0x41, 0x5D, 0x0D, 0x33, 
+	0x60, 0xEA, 0xA4, 0x7D, 0x7E, 0xE8, 0x4B, 0x55, 0x91, 0x56, 
+	0xD3, 0x5C, 0x57, 0x8F, 0x1F, 0x94, 0x17, 0x2F, 0xAA, 0xDE, 
+	0xE9, 0x9E, 0xA8, 0xF4, 0xCF, 0x8A, 0x4C, 0x8E, 0xA0, 0xE4, 
+	0x56, 0x73, 0xB2, 0xCF, 0x4F, 0x86, 0xC5, 0x69, 0x3C, 0xF3, 
+	0x24, 0x20, 0x8B, 0x5C, 0x96, 0x0C, 0xFA, 0x6B, 0x12, 0x3B, 
+	0x9A, 0x67, 0xC1, 0xDF, 0xC6, 0x96, 0xB2, 0xA5, 0xD5, 0x92, 
+	0x0D, 0x9B, 0x09, 0x42, 0x68, 0x24, 0x10, 0x45, 0xD4, 0x50, 
+	0xE4, 0x17, 0x39, 0x48, 0xD0, 0x35, 0x8B, 0x94, 0x6D, 0x11, 
+	0xDE, 0x8F, 0xCA, 0x59, 0x02, 0x81, 0x81, 0x00, 0xEA, 0x24, 
+	0xA7, 0xF9, 0x69, 0x33, 0xE9, 0x71, 0xDC, 0x52, 0x7D, 0x88, 
+	0x21, 0x28, 0x2F, 0x49, 0xDE, 0xBA, 0x72, 0x16, 0xE9, 0xCC, 
+	0x47, 0x7A, 0x88, 0x0D, 0x94, 0x57, 0x84, 0x58, 0x16, 0x3A, 
+	0x81, 0xB0, 0x3F, 0xA2, 0xCF, 0xA6, 0x6C, 0x1E, 0xB0, 0x06, 
+	0x29, 0x00, 0x8F, 0xE7, 0x77, 0x76, 0xAC, 0xDB, 0xCA, 0xC7, 
+	0xD9, 0x5E, 0x9B, 0x3F, 0x26, 0x90, 0x52, 0xAE, 0xFC, 0x38, 
+	0x90, 0x00, 0x14, 0xBB, 0xB4, 0x0F, 0x58, 0x94, 0xE7, 0x2F, 
+	0x6A, 0x7E, 0x1C, 0x4F, 0x41, 0x21, 0xD4, 0x31, 0x59, 0x1F, 
+	0x4E, 0x8A, 0x1A, 0x8D, 0xA7, 0x57, 0x6C, 0x22, 0xD8, 0xE5, 
+	0xF4, 0x7E, 0x32, 0xA6, 0x10, 0xCB, 0x64, 0xA5, 0x55, 0x03, 
+	0x87, 0xA6, 0x27, 0x05, 0x8C, 0xC3, 0xD7, 0xB6, 0x27, 0xB2, 
+	0x4D, 0xBA, 0x30, 0xDA, 0x47, 0x8F, 0x54, 0xD3, 0x3D, 0x8B, 
+	0x84, 0x8D, 0x94, 0x98, 0x58, 0xA5, 0x02, 0x81, 0x81, 0x00, 
+	0xD5, 0x38, 0x1B, 0xC3, 0x8F, 0xC5, 0x93, 0x0C, 0x47, 0x0B, 
+	0x6F, 0x35, 0x92, 0xC5, 0xB0, 0x8D, 0x46, 0xC8, 0x92, 0x18, 
+	0x8F, 0xF5, 0x80, 0x0A, 0xF7, 0xEF, 0xA1, 0xFE, 0x80, 0xB9, 
+	0xB5, 0x2A, 0xBA, 0xCA, 0x18, 0xB0, 0x5D, 0xA5, 0x07, 0xD0, 
+	0x93, 0x8D, 0xD8, 0x9C, 0x04, 0x1C, 0xD4, 0x62, 0x8E, 0xA6, 
+	0x26, 0x81, 0x01, 0xFF, 0xCE, 0x8A, 0x2A, 0x63, 0x34, 0x35, 
+	0x40, 0xAA, 0x6D, 0x80, 0xDE, 0x89, 0x23, 0x6A, 0x57, 0x4D, 
+	0x9E, 0x6E, 0xAD, 0x93, 0x4E, 0x56, 0x90, 0x0B, 0x6D, 0x9D, 
+	0x73, 0x8B, 0x0C, 0xAE, 0x27, 0x3D, 0xDE, 0x4E, 0xF0, 0xAA, 
+	0xC5, 0x6C, 0x78, 0x67, 0x6C, 0x94, 0x52, 0x9C, 0x37, 0x67, 
+	0x6C, 0x2D, 0xEF, 0xBB, 0xAF, 0xDF, 0xA6, 0x90, 0x3C, 0xC4, 
+	0x47, 0xCF, 0x8D, 0x96, 0x9E, 0x98, 0xA9, 0xB4, 0x9F, 0xC5, 
+	0xA6, 0x50, 0xDC, 0xB3, 0xF0, 0xFB, 0x74, 0x17, 0x02, 0x81, 
+	0x80, 0x5E, 0x83, 0x09, 0x62, 0xBD, 0xBA, 0x7C, 0xA2, 0xBF, 
+	0x42, 0x74, 0xF5, 0x7C, 0x1C, 0xD2, 0x69, 0xC9, 0x04, 0x0D, 
+	0x85, 0x7E, 0x3E, 0x3D, 0x24, 0x12, 0xC3, 0x18, 0x7B, 0xF3, 
+	0x29, 0xF3, 0x5F, 0x0E, 0x76, 0x6C, 0x59, 0x75, 0xE4, 0x41, 
+	0x84, 0x69, 0x9D, 0x32, 0xF3, 0xCD, 0x22, 0xAB, 0xB0, 0x35, 
+	0xBA, 0x4A, 0xB2, 0x3C, 0xE5, 0xD9, 0x58, 0xB6, 0x62, 0x4F, 
+	0x5D, 0xDE, 0xE5, 0x9E, 0x0A, 0xCA, 0x53, 0xB2, 0x2C, 0xF7, 
+	0x9E, 0xB3, 0x6B, 0x0A, 0x5B, 0x79, 0x65, 0xEC, 0x6E, 0x91, 
+	0x4E, 0x92, 0x20, 0xF6, 0xFC, 0xFC, 0x16, 0xED, 0xD3, 0x76, 
+	0x0C, 0xE2, 0xEC, 0x7F, 0xB2, 0x69, 0x13, 0x6B, 0x78, 0x0E, 
+	0x5A, 0x46, 0x64, 0xB4, 0x5E, 0xB7, 0x25, 0xA0, 0x5A, 0x75, 
+	0x3A, 0x4B, 0xEF, 0xC7, 0x3C, 0x3E, 0xF7, 0xFD, 0x26, 0xB8, 
+	0x20, 0xC4, 0x99, 0x0A, 0x9A, 0x73, 0xBE, 0xC3, 0x19, 0x02, 
+	0x81, 0x81, 0x00, 0xBA, 0x44, 0x93, 0x14, 0xAC, 0x34, 0x19, 
+	0x3B, 0x5F, 0x91, 0x60, 0xAC, 0xF7, 0xB4, 0xD6, 0x81, 0x05, 
+	0x36, 0x51, 0x53, 0x3D, 0xE8, 0x65, 0xDC, 0xAF, 0x2E, 0xDC, 
+	0x61, 0x3E, 0xC9, 0x7D, 0xB8, 0x7F, 0x87, 0xF0, 0x3B, 0x9B, 
+	0x03, 0x82, 0x29, 0x37, 0xCE, 0x72, 0x4E, 0x11, 0xD5, 0xB1, 
+	0xC1, 0x0C, 0x07, 0xA0, 0x99, 0x91, 0x4A, 0x8D, 0x7F, 0xEC, 
+	0x79, 0xCF, 0xF1, 0x39, 0xB5, 0xE9, 0x85, 0xEC, 0x62, 0xF7, 
+	0xDA, 0x7D, 0xBC, 0x64, 0x4D, 0x22, 0x3C, 0x0E, 0xF2, 0xD6, 
+	0x51, 0xF5, 0x87, 0xD8, 0x99, 0xC0, 0x11, 0x20, 0x5D, 0x0F, 
+	0x29, 0xFD, 0x5B, 0xE2, 0xAE, 0xD9, 0x1C, 0xD9, 0x21, 0x56, 
+	0x6D, 0xFC, 0x84, 0xD0, 0x5F, 0xED, 0x10, 0x15, 0x1C, 0x18, 
+	0x21, 0xE7, 0xC4, 0x3D, 0x4B, 0xD7, 0xD0, 0x9E, 0x6A, 0x95, 
+	0xCF, 0x22, 0xC9, 0x03, 0x7B, 0x9E, 0xE3, 0x60, 0x01, 0xFC, 
+	0x2F, 0x02, 0x81, 0x80, 0x11, 0xD0, 0x4B, 0xCF, 0x1B, 0x67, 
+	0xB9, 0x9F, 0x10, 0x75, 0x47, 0x86, 0x65, 0xAE, 0x31, 0xC2, 
+	0xC6, 0x30, 0xAC, 0x59, 0x06, 0x50, 0xD9, 0x0F, 0xB5, 0x70, 
+	0x06, 0xF7, 0xF0, 0xD3, 0xC8, 0x62, 0x7C, 0xA8, 0xDA, 0x6E, 
+	0xF6, 0x21, 0x3F, 0xD3, 0x7F, 0x5F, 0xEA, 0x8A, 0xAB, 0x3F, 
+	0xD9, 0x2A, 0x5E, 0xF3, 0x51, 0xD2, 0xC2, 0x30, 0x37, 0xE3, 
+	0x2D, 0xA3, 0x75, 0x0D, 0x1E, 0x4D, 0x21, 0x34, 0xD5, 0x57, 
+	0x70, 0x5C, 0x89, 0xBF, 0x72, 0xEC, 0x4A, 0x6E, 0x68, 0xD5, 
+	0xCD, 0x18, 0x74, 0x33, 0x4E, 0x8C, 0x3A, 0x45, 0x8F, 0xE6, 
+	0x96, 0x40, 0xEB, 0x63, 0xF9, 0x19, 0x86, 0x3A, 0x51, 0xDD, 
+	0x89, 0x4B, 0xB0, 0xF3, 0xF9, 0x9F, 0x5D, 0x28, 0x95, 0x38, 
+	0xBE, 0x35, 0xAB, 0xCA, 0x5C, 0xE7, 0x93, 0x53, 0x34, 0xA1, 
+	0x45, 0x5D, 0x13, 0x39, 0x65, 0x42, 0x46, 0xA1, 0x9F, 0xCD, 
+	0xF5, 0xBF
+};
+static const int sizeof_client_key_der_2048 = sizeof(client_key_der_2048);
+
+/* ./certs/client-cert.der, 2048-bit */
+static const unsigned char client_cert_der_2048[] =
+{
+	0x30, 0x82, 0x04, 0xCA, 0x30, 0x82, 0x03, 0xB2, 0xA0, 0x03, 
+	0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xAA, 0x27, 0xB3, 0xC5, 
+	0xA9, 0x72, 0x6E, 0x0D, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 
+	0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 
+	0x81, 0x9E, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 
+	0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0E, 0x06, 
+	0x03, 0x55, 0x04, 0x08, 0x0C, 0x07, 0x4D, 0x6F, 0x6E, 0x74, 
+	0x61, 0x6E, 0x61, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 
+	0x04, 0x07, 0x0C, 0x07, 0x42, 0x6F, 0x7A, 0x65, 0x6D, 0x61, 
+	0x6E, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0A, 
+	0x0C, 0x0C, 0x77, 0x6F, 0x6C, 0x66, 0x53, 0x53, 0x4C, 0x5F, 
+	0x32, 0x30, 0x34, 0x38, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 
+	0x55, 0x04, 0x0B, 0x0C, 0x10, 0x50, 0x72, 0x6F, 0x67, 0x72, 
+	0x61, 0x6D, 0x6D, 0x69, 0x6E, 0x67, 0x2D, 0x32, 0x30, 0x34, 
+	0x38, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 
+	0x0C, 0x0F, 0x77, 0x77, 0x77, 0x2E, 0x77, 0x6F, 0x6C, 0x66, 
+	0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x1F, 0x30, 
+	0x1D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 
+	0x09, 0x01, 0x16, 0x10, 0x69, 0x6E, 0x66, 0x6F, 0x40, 0x77, 
+	0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 
+	0x30, 0x1E, 0x17, 0x0D, 0x31, 0x35, 0x30, 0x35, 0x30, 0x37, 
+	0x31, 0x38, 0x32, 0x31, 0x30, 0x31, 0x5A, 0x17, 0x0D, 0x31, 
+	0x38, 0x30, 0x31, 0x33, 0x31, 0x31, 0x38, 0x32, 0x31, 0x30, 
+	0x31, 0x5A, 0x30, 0x81, 0x9E, 0x31, 0x0B, 0x30, 0x09, 0x06, 
+	0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 
+	0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x07, 0x4D, 
+	0x6F, 0x6E, 0x74, 0x61, 0x6E, 0x61, 0x31, 0x10, 0x30, 0x0E, 
+	0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x07, 0x42, 0x6F, 0x7A, 
+	0x65, 0x6D, 0x61, 0x6E, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 
+	0x55, 0x04, 0x0A, 0x0C, 0x0C, 0x77, 0x6F, 0x6C, 0x66, 0x53, 
+	0x53, 0x4C, 0x5F, 0x32, 0x30, 0x34, 0x38, 0x31, 0x19, 0x30, 
+	0x17, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x10, 0x50, 0x72, 
+	0x6F, 0x67, 0x72, 0x61, 0x6D, 0x6D, 0x69, 0x6E, 0x67, 0x2D, 
+	0x32, 0x30, 0x34, 0x38, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 
+	0x55, 0x04, 0x03, 0x0C, 0x0F, 0x77, 0x77, 0x77, 0x2E, 0x77, 
+	0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 
+	0x31, 0x1F, 0x30, 0x1D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 
+	0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6E, 0x66, 
+	0x6F, 0x40, 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 
+	0x63, 0x6F, 0x6D, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 
+	0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 
+	0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01, 
+	0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xC3, 0x03, 0xD1, 0x2B, 
+	0xFE, 0x39, 0xA4, 0x32, 0x45, 0x3B, 0x53, 0xC8, 0x84, 0x2B, 
+	0x2A, 0x7C, 0x74, 0x9A, 0xBD, 0xAA, 0x2A, 0x52, 0x07, 0x47, 
+	0xD6, 0xA6, 0x36, 0xB2, 0x07, 0x32, 0x8E, 0xD0, 0xBA, 0x69, 
+	0x7B, 0xC6, 0xC3, 0x44, 0x9E, 0xD4, 0x81, 0x48, 0xFD, 0x2D, 
+	0x68, 0xA2, 0x8B, 0x67, 0xBB, 0xA1, 0x75, 0xC8, 0x36, 0x2C, 
+	0x4A, 0xD2, 0x1B, 0xF7, 0x8B, 0xBA, 0xCF, 0x0D, 0xF9, 0xEF, 
+	0xEC, 0xF1, 0x81, 0x1E, 0x7B, 0x9B, 0x03, 0x47, 0x9A, 0xBF, 
+	0x65, 0xCC, 0x7F, 0x65, 0x24, 0x69, 0xA6, 0xE8, 0x14, 0x89, 
+	0x5B, 0xE4, 0x34, 0xF7, 0xC5, 0xB0, 0x14, 0x93, 0xF5, 0x67, 
+	0x7B, 0x3A, 0x7A, 0x78, 0xE1, 0x01, 0x56, 0x56, 0x91, 0xA6, 
+	0x13, 0x42, 0x8D, 0xD2, 0x3C, 0x40, 0x9C, 0x4C, 0xEF, 0xD1, 
+	0x86, 0xDF, 0x37, 0x51, 0x1B, 0x0C, 0xA1, 0x3B, 0xF5, 0xF1, 
+	0xA3, 0x4A, 0x35, 0xE4, 0xE1, 0xCE, 0x96, 0xDF, 0x1B, 0x7E, 
+	0xBF, 0x4E, 0x97, 0xD0, 0x10, 0xE8, 0xA8, 0x08, 0x30, 0x81, 
+	0xAF, 0x20, 0x0B, 0x43, 0x14, 0xC5, 0x74, 0x67, 0xB4, 0x32, 
+	0x82, 0x6F, 0x8D, 0x86, 0xC2, 0x88, 0x40, 0x99, 0x36, 0x83, 
+	0xBA, 0x1E, 0x40, 0x72, 0x22, 0x17, 0xD7, 0x52, 0x65, 0x24, 
+	0x73, 0xB0, 0xCE, 0xEF, 0x19, 0xCD, 0xAE, 0xFF, 0x78, 0x6C, 
+	0x7B, 0xC0, 0x12, 0x03, 0xD4, 0x4E, 0x72, 0x0D, 0x50, 0x6D, 
+	0x3B, 0xA3, 0x3B, 0xA3, 0x99, 0x5E, 0x9D, 0xC8, 0xD9, 0x0C, 
+	0x85, 0xB3, 0xD9, 0x8A, 0xD9, 0x54, 0x26, 0xDB, 0x6D, 0xFA, 
+	0xAC, 0xBB, 0xFF, 0x25, 0x4C, 0xC4, 0xD1, 0x79, 0xF4, 0x71, 
+	0xD3, 0x86, 0x40, 0x18, 0x13, 0xB0, 0x63, 0xB5, 0x72, 0x4E, 
+	0x30, 0xC4, 0x97, 0x84, 0x86, 0x2D, 0x56, 0x2F, 0xD7, 0x15, 
+	0xF7, 0x7F, 0xC0, 0xAE, 0xF5, 0xFC, 0x5B, 0xE5, 0xFB, 0xA1, 
+	0xBA, 0xD3, 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x82, 0x01, 
+	0x07, 0x30, 0x82, 0x01, 0x03, 0x30, 0x1D, 0x06, 0x03, 0x55, 
+	0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0x33, 0xD8, 0x45, 0x66, 
+	0xD7, 0x68, 0x87, 0x18, 0x7E, 0x54, 0x0D, 0x70, 0x27, 0x91, 
+	0xC7, 0x26, 0xD7, 0x85, 0x65, 0xC0, 0x30, 0x81, 0xD3, 0x06, 
+	0x03, 0x55, 0x1D, 0x23, 0x04, 0x81, 0xCB, 0x30, 0x81, 0xC8, 
+	0x80, 0x14, 0x33, 0xD8, 0x45, 0x66, 0xD7, 0x68, 0x87, 0x18, 
+	0x7E, 0x54, 0x0D, 0x70, 0x27, 0x91, 0xC7, 0x26, 0xD7, 0x85, 
+	0x65, 0xC0, 0xA1, 0x81, 0xA4, 0xA4, 0x81, 0xA1, 0x30, 0x81, 
+	0x9E, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 
+	0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 
+	0x55, 0x04, 0x08, 0x0C, 0x07, 0x4D, 0x6F, 0x6E, 0x74, 0x61, 
+	0x6E, 0x61, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 
+	0x07, 0x0C, 0x07, 0x42, 0x6F, 0x7A, 0x65, 0x6D, 0x61, 0x6E, 
+	0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 
+	0x0C, 0x77, 0x6F, 0x6C, 0x66, 0x53, 0x53, 0x4C, 0x5F, 0x32, 
+	0x30, 0x34, 0x38, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 
+	0x04, 0x0B, 0x0C, 0x10, 0x50, 0x72, 0x6F, 0x67, 0x72, 0x61, 
+	0x6D, 0x6D, 0x69, 0x6E, 0x67, 0x2D, 0x32, 0x30, 0x34, 0x38, 
+	0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 
+	0x0F, 0x77, 0x77, 0x77, 0x2E, 0x77, 0x6F, 0x6C, 0x66, 0x73, 
+	0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x1F, 0x30, 0x1D, 
+	0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 
+	0x01, 0x16, 0x10, 0x69, 0x6E, 0x66, 0x6F, 0x40, 0x77, 0x6F, 
+	0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x82, 
+	0x09, 0x00, 0xAA, 0x27, 0xB3, 0xC5, 0xA9, 0x72, 0x6E, 0x0D, 
+	0x30, 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x04, 0x05, 0x30, 
+	0x03, 0x01, 0x01, 0xFF, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 
+	0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 
+	0x82, 0x01, 0x01, 0x00, 0x51, 0x96, 0xA7, 0x1C, 0x26, 0x5D, 
+	0x1C, 0x90, 0xC6, 0x32, 0x9F, 0x96, 0x15, 0xF2, 0x1D, 0xE7, 
+	0x93, 0x9C, 0xAC, 0x75, 0x56, 0x95, 0xFD, 0x20, 0x70, 0xAB, 
+	0x45, 0x6A, 0x09, 0xB0, 0xF3, 0xF2, 0x03, 0xA8, 0xDB, 0xDC, 
+	0x2F, 0xBC, 0x1F, 0x87, 0x7A, 0xA3, 0xD4, 0x8F, 0xD5, 0x49, 
+	0x97, 0x7E, 0x3C, 0x54, 0xAC, 0xB1, 0xE3, 0xF0, 0x39, 0x0D, 
+	0xFE, 0x09, 0x9A, 0x23, 0xF6, 0x32, 0xA6, 0x41, 0x59, 0xBD, 
+	0x60, 0xE8, 0xBD, 0xDE, 0x00, 0x36, 0x6F, 0x3E, 0xE9, 0x41, 
+	0x6F, 0xA9, 0x63, 0xC7, 0xAA, 0xD5, 0x7B, 0xF3, 0xE4, 0x39, 
+	0x48, 0x9E, 0xF6, 0x60, 0xC6, 0xC6, 0x86, 0xD5, 0x72, 0x86, 
+	0x23, 0xCD, 0xF5, 0x6A, 0x63, 0x53, 0xA4, 0xF8, 0xFC, 0x51, 
+	0x6A, 0xCD, 0x60, 0x74, 0x8E, 0xA3, 0x86, 0x61, 0x01, 0x34, 
+	0x78, 0xF7, 0x29, 0x97, 0xB3, 0xA7, 0x34, 0xB6, 0x0A, 0xDE, 
+	0xB5, 0x71, 0x7A, 0x09, 0xA6, 0x3E, 0xD6, 0x82, 0x58, 0x89, 
+	0x67, 0x9C, 0xC5, 0x68, 0x62, 0xBA, 0x06, 0xD6, 0x39, 0xBB, 
+	0xCB, 0x3A, 0xC0, 0xE0, 0x63, 0x1F, 0xC7, 0x0C, 0x9C, 0x12, 
+	0x86, 0xEC, 0xF7, 0x39, 0x6A, 0x61, 0x93, 0xD0, 0x33, 0x14, 
+	0xC6, 0x55, 0x3B, 0xB6, 0xCF, 0x80, 0x5B, 0x8C, 0x43, 0xEF, 
+	0x43, 0x44, 0x0B, 0x3C, 0x93, 0x39, 0xA3, 0x4E, 0x15, 0xD1, 
+	0x0B, 0x5F, 0x84, 0x98, 0x1D, 0xCD, 0x9F, 0xA9, 0x47, 0xEB, 
+	0x3B, 0x56, 0x30, 0xB6, 0x76, 0x92, 0xC1, 0x48, 0x5F, 0xBC, 
+	0x95, 0xB0, 0x50, 0x1A, 0x55, 0xC8, 0x4E, 0x62, 0x47, 0x87, 
+	0x54, 0x64, 0x0C, 0x9B, 0x91, 0xFA, 0x43, 0xB3, 0x29, 0x48, 
+	0xBE, 0xE6, 0x12, 0xEB, 0xE3, 0x44, 0xC6, 0x52, 0xE4, 0x40, 
+	0xC6, 0x83, 0x95, 0x1B, 0xA7, 0x65, 0x27, 0x69, 0x73, 0x2F, 
+	0xC8, 0xA0, 0x4D, 0x7F, 0xBE, 0xEA, 0x9B, 0x67, 0xB2, 0x7B
+
+};
+static const int sizeof_client_cert_der_2048 = sizeof(client_cert_der_2048);
+
+/* ./certs/dh2048.der, 2048-bit */
+static const unsigned char dh_key_der_2048[] =
+{
+	0x30, 0x82, 0x01, 0x08, 0x02, 0x82, 0x01, 0x01, 0x00, 0xB0, 
+	0xA1, 0x08, 0x06, 0x9C, 0x08, 0x13, 0xBA, 0x59, 0x06, 0x3C, 
+	0xBC, 0x30, 0xD5, 0xF5, 0x00, 0xC1, 0x4F, 0x44, 0xA7, 0xD6, 
+	0xEF, 0x4A, 0xC6, 0x25, 0x27, 0x1C, 0xE8, 0xD2, 0x96, 0x53, 
+	0x0A, 0x5C, 0x91, 0xDD, 0xA2, 0xC2, 0x94, 0x84, 0xBF, 0x7D, 
+	0xB2, 0x44, 0x9F, 0x9B, 0xD2, 0xC1, 0x8A, 0xC5, 0xBE, 0x72, 
+	0x5C, 0xA7, 0xE7, 0x91, 0xE6, 0xD4, 0x9F, 0x73, 0x07, 0x85, 
+	0x5B, 0x66, 0x48, 0xC7, 0x70, 0xFA, 0xB4, 0xEE, 0x02, 0xC9, 
+	0x3D, 0x9A, 0x4A, 0xDA, 0x3D, 0xC1, 0x46, 0x3E, 0x19, 0x69, 
+	0xD1, 0x17, 0x46, 0x07, 0xA3, 0x4D, 0x9F, 0x2B, 0x96, 0x17, 
+	0x39, 0x6D, 0x30, 0x8D, 0x2A, 0xF3, 0x94, 0xD3, 0x75, 0xCF, 
+	0xA0, 0x75, 0xE6, 0xF2, 0x92, 0x1F, 0x1A, 0x70, 0x05, 0xAA, 
+	0x04, 0x83, 0x57, 0x30, 0xFB, 0xDA, 0x76, 0x93, 0x38, 0x50, 
+	0xE8, 0x27, 0xFD, 0x63, 0xEE, 0x3C, 0xE5, 0xB7, 0xC8, 0x09, 
+	0xAE, 0x6F, 0x50, 0x35, 0x8E, 0x84, 0xCE, 0x4A, 0x00, 0xE9, 
+	0x12, 0x7E, 0x5A, 0x31, 0xD7, 0x33, 0xFC, 0x21, 0x13, 0x76, 
+	0xCC, 0x16, 0x30, 0xDB, 0x0C, 0xFC, 0xC5, 0x62, 0xA7, 0x35, 
+	0xB8, 0xEF, 0xB7, 0xB0, 0xAC, 0xC0, 0x36, 0xF6, 0xD9, 0xC9, 
+	0x46, 0x48, 0xF9, 0x40, 0x90, 0x00, 0x2B, 0x1B, 0xAA, 0x6C, 
+	0xE3, 0x1A, 0xC3, 0x0B, 0x03, 0x9E, 0x1B, 0xC2, 0x46, 0xE4, 
+	0x48, 0x4E, 0x22, 0x73, 0x6F, 0xC3, 0x5F, 0xD4, 0x9A, 0xD6, 
+	0x30, 0x07, 0x48, 0xD6, 0x8C, 0x90, 0xAB, 0xD4, 0xF6, 0xF1, 
+	0xE3, 0x48, 0xD3, 0x58, 0x4B, 0xA6, 0xB9, 0xCD, 0x29, 0xBF, 
+	0x68, 0x1F, 0x08, 0x4B, 0x63, 0x86, 0x2F, 0x5C, 0x6B, 0xD6, 
+	0xB6, 0x06, 0x65, 0xF7, 0xA6, 0xDC, 0x00, 0x67, 0x6B, 0xBB, 
+	0xC3, 0xA9, 0x41, 0x83, 0xFB, 0xC7, 0xFA, 0xC8, 0xE2, 0x1E, 
+	0x7E, 0xAF, 0x00, 0x3F, 0x93, 0x02, 0x01, 0x02
+};
+static const int sizeof_dh_key_der_2048 = sizeof(dh_key_der_2048);
+
+/* ./certs/dsa2048.der, 2048-bit */
+static const unsigned char dsa_key_der_2048[] =
+{
+	0x30, 0x82, 0x03, 0x3F, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 
+	0x01, 0x00, 0xCC, 0x8E, 0xC9, 0xA0, 0xD5, 0x9A, 0x27, 0x1C, 
+	0xDA, 0x52, 0xDF, 0xC7, 0xC0, 0xE6, 0x06, 0xA4, 0x3E, 0x8A, 
+	0x66, 0x49, 0xD0, 0x59, 0x33, 0x51, 0x69, 0xC4, 0x9C, 0x5E, 
+	0x64, 0x85, 0xC7, 0xF1, 0xAB, 0xD5, 0xD9, 0x62, 0xAC, 0xFD, 
+	0xA1, 0xE0, 0x1B, 0x57, 0xFF, 0x96, 0xEF, 0x0C, 0x9F, 0xC8, 
+	0x44, 0x87, 0xEB, 0x5C, 0x91, 0xD0, 0x46, 0x42, 0x09, 0x50, 
+	0x6A, 0x23, 0xCB, 0x89, 0x6F, 0x55, 0xE9, 0x6A, 0x11, 0xA9, 
+	0xA8, 0x32, 0xAB, 0x33, 0x0D, 0x51, 0xB5, 0x79, 0x51, 0xB4, 
+	0xAB, 0xA2, 0x25, 0x11, 0x8D, 0xE5, 0x24, 0xBE, 0xD8, 0xF1, 
+	0x9D, 0x4E, 0x12, 0x6F, 0xAC, 0x44, 0x54, 0x80, 0xA9, 0xB4, 
+	0x81, 0x68, 0x4E, 0x44, 0x0E, 0xB8, 0x39, 0xF3, 0xBE, 0x83, 
+	0x08, 0x74, 0xA2, 0xC6, 0x7A, 0xD7, 0x6A, 0x7D, 0x0A, 0x88, 
+	0x57, 0x83, 0x48, 0xDC, 0xCF, 0x5E, 0x6F, 0xEE, 0x68, 0x0C, 
+	0xF7, 0xFF, 0x03, 0x04, 0x90, 0xAA, 0xF7, 0x07, 0x98, 0xF8, 
+	0x67, 0x5A, 0x83, 0x23, 0x66, 0x47, 0x60, 0xC3, 0x43, 0x6E, 
+	0x03, 0x91, 0xAC, 0x28, 0x66, 0xCB, 0xF0, 0xD3, 0x05, 0xC8, 
+	0x09, 0x97, 0xB5, 0xAE, 0x01, 0x5E, 0x80, 0x3B, 0x9D, 0x4F, 
+	0xDE, 0x3E, 0x94, 0xFE, 0xCB, 0x82, 0xB0, 0xB1, 0xFC, 0x91, 
+	0x8B, 0x1D, 0x8A, 0xEE, 0xC6, 0x06, 0x1F, 0x37, 0x91, 0x48, 
+	0xD2, 0xF8, 0x6C, 0x5D, 0x60, 0x13, 0x83, 0xA7, 0x81, 0xAC, 
+	0xCA, 0x8D, 0xD0, 0x6A, 0x04, 0x0A, 0xEA, 0x3E, 0x22, 0x4E, 
+	0x13, 0xF1, 0x0D, 0xBB, 0x60, 0x6B, 0xCD, 0xBC, 0x5C, 0x87, 
+	0xA3, 0x67, 0x2B, 0x42, 0xA1, 0x9F, 0xCD, 0x39, 0x58, 0xBE, 
+	0x55, 0xB1, 0x93, 0x84, 0xCE, 0xB2, 0x10, 0x4E, 0xE4, 0xC3, 
+	0x9F, 0xB2, 0x53, 0x61, 0x01, 0x29, 0xAA, 0x96, 0xCB, 0x20, 
+	0x60, 0x42, 0x1D, 0xBA, 0x75, 0x4B, 0x63, 0xC1, 0x02, 0x15, 
+	0x00, 0xE7, 0xA5, 0x39, 0xD4, 0x6A, 0x37, 0x5E, 0x95, 0x06, 
+	0x39, 0x07, 0x77, 0x0A, 0xEB, 0xA0, 0x03, 0xEB, 0x78, 0x82, 
+	0x9B, 0x02, 0x82, 0x01, 0x01, 0x00, 0x9A, 0xD4, 0x4C, 0x71, 
+	0x2F, 0xEC, 0xFA, 0x32, 0xB2, 0x80, 0x7E, 0x61, 0x4A, 0x6B, 
+	0x5F, 0x18, 0x76, 0x43, 0xC3, 0x69, 0xBA, 0x41, 0xC7, 0xA7, 
+	0x1D, 0x79, 0x01, 0xEC, 0xAF, 0x34, 0x87, 0x67, 0x4F, 0x29, 
+	0x80, 0xA8, 0x3B, 0x87, 0xF6, 0xE8, 0xA1, 0xE8, 0xCD, 0x1B, 
+	0x1C, 0x86, 0x38, 0xF6, 0xD1, 0x0C, 0x46, 0x2E, 0xC8, 0xE0, 
+	0xC9, 0x30, 0x26, 0xD5, 0x2C, 0x7F, 0xC1, 0x08, 0xBF, 0xCC, 
+	0x5A, 0x82, 0x8E, 0xD4, 0xD4, 0x49, 0xAA, 0xA2, 0xFA, 0xE6, 
+	0xC1, 0x9D, 0xF0, 0xD9, 0x96, 0xB0, 0xFF, 0x0C, 0x5B, 0x33, 
+	0x8E, 0x06, 0xDD, 0x9D, 0x28, 0xA9, 0xE9, 0x80, 0x41, 0x3B, 
+	0xD8, 0x7A, 0x94, 0x21, 0x8F, 0x56, 0xF1, 0xA2, 0xB4, 0x2B, 
+	0x89, 0x1C, 0x74, 0xFF, 0x7E, 0x91, 0xDC, 0x1F, 0x91, 0x13, 
+	0x98, 0xAF, 0xC7, 0x06, 0xD2, 0x4C, 0x90, 0xA2, 0xBD, 0xDA, 
+	0x16, 0xBA, 0x65, 0xB0, 0x2D, 0x68, 0x87, 0x3C, 0x6E, 0x25, 
+	0x8D, 0x90, 0xC7, 0xBC, 0x0D, 0xA9, 0x43, 0x03, 0xC9, 0xBE, 
+	0xCF, 0x85, 0x6F, 0xDB, 0x07, 0x7B, 0x8C, 0xF8, 0xB1, 0xC2, 
+	0x49, 0x10, 0x69, 0x63, 0x56, 0x37, 0xC5, 0x30, 0xD2, 0xFB, 
+	0x71, 0x9A, 0xE8, 0x82, 0x07, 0x2E, 0x3E, 0x95, 0x50, 0xF3, 
+	0x73, 0xCF, 0x34, 0x5B, 0xD5, 0xAB, 0x02, 0x15, 0xF2, 0xCC, 
+	0xD7, 0x52, 0xC5, 0x28, 0xD8, 0x41, 0x19, 0x55, 0x6F, 0xB8, 
+	0x5F, 0xF1, 0x99, 0xB3, 0xC7, 0xD9, 0xB3, 0x71, 0xF4, 0x2D, 
+	0xDF, 0x22, 0x59, 0x35, 0x86, 0xDB, 0x39, 0xCA, 0x1B, 0x4D, 
+	0x35, 0x90, 0x19, 0x6B, 0x31, 0xE3, 0xC8, 0xC6, 0x09, 0xBF, 
+	0x7C, 0xED, 0x01, 0xB4, 0xB2, 0xF5, 0x6E, 0xDA, 0x63, 0x41, 
+	0x3C, 0xE6, 0x3A, 0x72, 0x2D, 0x65, 0x48, 0xF6, 0x07, 0xCD, 
+	0x92, 0x84, 0x8B, 0x1D, 0xA7, 0x31, 0x6B, 0xD6, 0xF0, 0xFB, 
+	0xD9, 0xF4, 0x02, 0x82, 0x01, 0x00, 0x66, 0x4B, 0xBB, 0xB7, 
+	0xC9, 0x48, 0x95, 0x0D, 0x5A, 0xA6, 0x2D, 0xA1, 0x7F, 0xDF, 
+	0x1F, 0x67, 0x6D, 0xED, 0x52, 0x4B, 0x16, 0x6C, 0x17, 0xC6, 
+	0xAE, 0xF8, 0x6A, 0xC4, 0x57, 0xED, 0x2F, 0xB3, 0xF0, 0x2A, 
+	0x55, 0xAB, 0xBA, 0xCA, 0xEA, 0x17, 0xE8, 0x35, 0x7C, 0xE5, 
+	0x31, 0x0D, 0x4A, 0x95, 0xFC, 0x43, 0x6F, 0x97, 0x3C, 0x5C, 
+	0x67, 0xAC, 0xBE, 0x67, 0x7F, 0xE9, 0x4E, 0xAA, 0x48, 0xB3, 
+	0x92, 0xA1, 0x76, 0x75, 0xEA, 0x04, 0x34, 0x7F, 0x87, 0x33, 
+	0x2D, 0x24, 0xB6, 0x29, 0x97, 0xE3, 0x04, 0x77, 0x93, 0x89, 
+	0x13, 0xDB, 0x1B, 0x93, 0xB8, 0x2C, 0x90, 0x1A, 0x09, 0x3B, 
+	0x26, 0xD9, 0x59, 0xF3, 0x2A, 0x09, 0x58, 0xDC, 0xAC, 0x25, 
+	0xB4, 0xA9, 0x45, 0x3B, 0xA2, 0x3A, 0x6C, 0x61, 0x84, 0xBF, 
+	0x68, 0xD4, 0xEA, 0x9B, 0xC5, 0x29, 0x48, 0x60, 0x15, 0x10, 
+	0x35, 0x2C, 0x44, 0x1D, 0xB5, 0x9A, 0xEE, 0xAC, 0xC1, 0x68, 
+	0xE8, 0x47, 0xB7, 0x41, 0x34, 0x39, 0x9A, 0xF8, 0xA5, 0x20, 
+	0xE9, 0x24, 0xC4, 0x2C, 0x58, 0x3F, 0x4C, 0x41, 0x30, 0x3A, 
+	0x14, 0x6E, 0x8D, 0xEA, 0xAD, 0xBA, 0x9B, 0x43, 0xD3, 0x98, 
+	0x2F, 0x83, 0xD8, 0x14, 0x67, 0xE8, 0xF8, 0xD5, 0x4F, 0xAC, 
+	0xE0, 0x3B, 0xBF, 0xA7, 0x54, 0x16, 0x5E, 0x49, 0x64, 0x26, 
+	0x54, 0xA4, 0x6B, 0x69, 0x7C, 0xBA, 0x8A, 0x83, 0xD9, 0x2E, 
+	0x65, 0x0A, 0xA2, 0x27, 0xEF, 0x99, 0x99, 0x08, 0xD7, 0xB5, 
+	0x9F, 0xA0, 0x01, 0xEF, 0x7E, 0x17, 0xBF, 0x83, 0x6B, 0x2E, 
+	0xDD, 0xC0, 0x39, 0x38, 0x23, 0x68, 0xB4, 0x76, 0x6B, 0xE5, 
+	0xCA, 0xF7, 0x7C, 0xEE, 0xC0, 0x52, 0xE2, 0xDD, 0xAD, 0x59, 
+	0x3A, 0x42, 0x06, 0x45, 0xB0, 0xC7, 0xC1, 0x77, 0x05, 0xB2, 
+	0x0C, 0x32, 0x40, 0x46, 0xAA, 0xDA, 0x79, 0x77, 0x04, 0x71, 
+	0xDF, 0x7A, 0x02, 0x15, 0x00, 0x98, 0xEE, 0xB9, 0x51, 0x37, 
+	0x3E, 0x75, 0x13, 0x13, 0x06, 0x8F, 0x94, 0xD3, 0xE6, 0xE9, 
+	0x00, 0xCB, 0x62, 0x6D, 0x9A
+};
+static const int sizeof_dsa_key_der_2048 = sizeof(dsa_key_der_2048);
+
+/* ./certs/rsa2048.der, 2048-bit */
+static const unsigned char rsa_key_der_2048[] =
+{
+	0x30, 0x82, 0x04, 0xA3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 
+	0x01, 0x00, 0xE9, 0x8A, 0x5D, 0x15, 0xA4, 0xD4, 0x34, 0xB9, 
+	0x59, 0xA2, 0xDA, 0xAF, 0x74, 0xC8, 0xC9, 0x03, 0x26, 0x38, 
+	0xFA, 0x48, 0xFC, 0x4D, 0x30, 0x6E, 0xEA, 0x76, 0x89, 0xCE, 
+	0x4F, 0xF6, 0x87, 0xDE, 0x32, 0x3A, 0x46, 0x6E, 0x38, 0x12, 
+	0x58, 0x37, 0x22, 0x0D, 0x80, 0xAC, 0x2D, 0xAF, 0x2F, 0x12, 
+	0x3E, 0x62, 0x73, 0x60, 0x66, 0x68, 0x90, 0xB2, 0x6F, 0x47, 
+	0x17, 0x04, 0x2B, 0xCA, 0xB7, 0x26, 0xB7, 0x10, 0xC2, 0x13, 
+	0xF9, 0x7A, 0x62, 0x0A, 0x93, 0x32, 0x90, 0x42, 0x0D, 0x16, 
+	0x2E, 0xFA, 0xD7, 0x29, 0xD7, 0x9F, 0x54, 0xE4, 0xFC, 0x65, 
+	0x74, 0xF8, 0xF6, 0x43, 0x6B, 0x4E, 0x9E, 0x34, 0x7F, 0xCB, 
+	0x6B, 0x1C, 0x1A, 0xDE, 0x82, 0x81, 0xBF, 0x08, 0x5D, 0x3F, 
+	0xC0, 0xB6, 0xB1, 0xA8, 0xA5, 0x9C, 0x81, 0x70, 0xA7, 0x4E, 
+	0x32, 0x87, 0x15, 0x1C, 0x78, 0x0E, 0xF0, 0x18, 0xFE, 0xEB, 
+	0x4B, 0x37, 0x2B, 0xE9, 0xE1, 0xF7, 0xFA, 0x51, 0xC6, 0x58, 
+	0xB9, 0xD8, 0x06, 0x03, 0xED, 0xC0, 0x03, 0x18, 0x55, 0x8B, 
+	0x98, 0xFE, 0xB1, 0xF6, 0xD0, 0x3D, 0xFA, 0x63, 0xC0, 0x38, 
+	0x19, 0xC7, 0x00, 0xEF, 0x4D, 0x99, 0x60, 0xB4, 0xBA, 0xCE, 
+	0xE3, 0xCE, 0xD9, 0x6B, 0x2D, 0x76, 0x94, 0xFF, 0xFB, 0x77, 
+	0x18, 0x4A, 0xFE, 0x65, 0xF0, 0x0A, 0x91, 0x5C, 0x3B, 0x22, 
+	0x94, 0x85, 0xD0, 0x20, 0x18, 0x59, 0x2E, 0xA5, 0x33, 0x03, 
+	0xAC, 0x1B, 0x5F, 0x78, 0x32, 0x11, 0x25, 0xEE, 0x7F, 0x96, 
+	0x21, 0xA9, 0xD6, 0x76, 0x97, 0x8D, 0x66, 0x7E, 0xB2, 0x91, 
+	0xD0, 0x36, 0x2E, 0xA3, 0x1D, 0xBF, 0xF1, 0x85, 0xED, 0xC0, 
+	0x3E, 0x60, 0xB8, 0x5A, 0x9F, 0xAB, 0x80, 0xE0, 0xEA, 0x5D, 
+	0x5F, 0x75, 0x56, 0xC7, 0x4D, 0x51, 0x8E, 0xD4, 0x1F, 0x34, 
+	0xA6, 0x36, 0xF1, 0x30, 0x1F, 0x51, 0x99, 0x2F, 0x02, 0x03, 
+	0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x00, 0x52, 0x11, 0x33, 
+	0x40, 0xC5, 0xD9, 0x64, 0x65, 0xB5, 0xE0, 0x0A, 0xA5, 0x19, 
+	0x8E, 0xED, 0x44, 0x54, 0x0C, 0x35, 0xB7, 0xAC, 0x21, 0x9B, 
+	0xE1, 0x7E, 0x37, 0x05, 0x9A, 0x20, 0x73, 0x6B, 0xAF, 0x63, 
+	0x4B, 0x23, 0x30, 0xDC, 0x37, 0x66, 0x14, 0x89, 0xBC, 0xE0, 
+	0xF8, 0xA0, 0x5D, 0x2D, 0x57, 0x65, 0xE0, 0xC6, 0xD6, 0x9B, 
+	0x66, 0x27, 0x62, 0xEC, 0xC3, 0xB8, 0x8C, 0xD8, 0xAE, 0xB5, 
+	0xC9, 0xBF, 0x0E, 0xFE, 0x84, 0x72, 0x68, 0xD5, 0x47, 0x0E, 
+	0x0E, 0xF8, 0xAE, 0x9D, 0x56, 0xAC, 0x4F, 0xAD, 0x88, 0xA0, 
+	0xA2, 0xF6, 0xFC, 0x38, 0xCD, 0x96, 0x5B, 0x5E, 0x7E, 0xB6, 
+	0x98, 0xBB, 0xF3, 0x8A, 0xEC, 0xFA, 0xC8, 0xB7, 0x90, 0x75, 
+	0xA0, 0x0E, 0x77, 0x6B, 0xFD, 0x59, 0x45, 0x5A, 0x0C, 0xFF, 
+	0x95, 0x8D, 0xCE, 0xFE, 0x9B, 0xF6, 0x19, 0x8E, 0x0B, 0xA1, 
+	0x0C, 0xEE, 0xC6, 0x79, 0xDD, 0x9D, 0x61, 0x85, 0x5C, 0x19, 
+	0x6C, 0x47, 0xCC, 0x08, 0xFF, 0xA5, 0x62, 0xDB, 0xE4, 0x2D, 
+	0x2D, 0xDD, 0x14, 0x67, 0xD6, 0x4A, 0x64, 0x2A, 0x66, 0x49, 
+	0x54, 0x9C, 0xE3, 0x85, 0x18, 0xE7, 0x31, 0x42, 0xE2, 0xD0, 
+	0x2C, 0x20, 0xA0, 0x74, 0x0F, 0x1F, 0x20, 0x89, 0xBA, 0xAB, 
+	0x80, 0xD8, 0x38, 0xD9, 0x46, 0x69, 0xBB, 0xEF, 0xCC, 0x8B, 
+	0xA1, 0x73, 0xA7, 0xF2, 0xE4, 0x38, 0x5D, 0xD6, 0x75, 0x9F, 
+	0x88, 0x0E, 0x56, 0xCD, 0xD8, 0x84, 0x59, 0x29, 0x73, 0xF5, 
+	0xA1, 0x79, 0xDA, 0x7A, 0x1F, 0xBF, 0x73, 0x83, 0xC0, 0x6D, 
+	0x9F, 0x8B, 0x34, 0x15, 0xC0, 0x6D, 0x69, 0x6A, 0x20, 0xE6, 
+	0x51, 0xCF, 0x45, 0x6E, 0xCC, 0x05, 0xC4, 0x3A, 0xC0, 0x9E, 
+	0xAA, 0xC1, 0x06, 0x2F, 0xAB, 0x99, 0x30, 0xE1, 0x6E, 0x9D, 
+	0x45, 0x7A, 0xFF, 0xA9, 0xCE, 0x70, 0xB8, 0x16, 0x1A, 0x0E, 
+	0x20, 0xFA, 0xC1, 0x02, 0x81, 0x81, 0x00, 0xFF, 0x30, 0x11, 
+	0xC2, 0x3C, 0x6B, 0xB4, 0xD6, 0x9E, 0x6B, 0xC1, 0x93, 0xD1, 
+	0x48, 0xCE, 0x80, 0x2D, 0xBE, 0xAF, 0xF7, 0xBA, 0xB2, 0xD7, 
+	0xC3, 0xC4, 0x53, 0x6E, 0x15, 0x02, 0xAA, 0x61, 0xB9, 0xEA, 
+	0x05, 0x9B, 0x79, 0x67, 0x0B, 0xCE, 0xD9, 0xFB, 0x98, 0x8C, 
+	0x1D, 0x6B, 0xF4, 0x5A, 0xA7, 0xA0, 0x5E, 0x54, 0x18, 0xE9, 
+	0x31, 0x44, 0x7C, 0xC7, 0x52, 0xD8, 0x6D, 0xA0, 0x3E, 0xD6, 
+	0x14, 0x2D, 0x7B, 0x15, 0x9D, 0x1E, 0x39, 0x87, 0x96, 0xDD, 
+	0xA8, 0x33, 0x55, 0x2A, 0x8E, 0x32, 0xC0, 0xC4, 0xE5, 0xB8, 
+	0xCB, 0xCD, 0x32, 0x8D, 0xAD, 0x7B, 0xE5, 0xC6, 0x7E, 0x4D, 
+	0x6F, 0xF3, 0xA4, 0xC5, 0xA6, 0x40, 0xBE, 0x90, 0x3A, 0x33, 
+	0x6A, 0x24, 0xB2, 0x80, 0x81, 0x12, 0xAC, 0xE3, 0x7B, 0x26, 
+	0x63, 0xCF, 0x88, 0xB9, 0xFF, 0x74, 0x23, 0x37, 0x52, 0xF0, 
+	0xC4, 0x27, 0x5D, 0x45, 0x1F, 0x02, 0x81, 0x81, 0x00, 0xEA, 
+	0x48, 0xA7, 0xDD, 0x73, 0x41, 0x56, 0x21, 0x15, 0xF7, 0x42, 
+	0x45, 0x4D, 0xA9, 0xE1, 0x66, 0x5B, 0xBD, 0x25, 0x7D, 0xF7, 
+	0xA8, 0x65, 0x13, 0xAE, 0x2D, 0x38, 0x11, 0xCD, 0x93, 0xFC, 
+	0x30, 0xA3, 0x2C, 0x44, 0xBB, 0xCF, 0xD0, 0x21, 0x8F, 0xFB, 
+	0xC1, 0xF9, 0xAD, 0x1D, 0xEE, 0x96, 0xCF, 0x97, 0x49, 0x60, 
+	0x53, 0x80, 0xA5, 0xA2, 0xF8, 0xEE, 0xB9, 0xD5, 0x77, 0x44, 
+	0xDD, 0xFD, 0x19, 0x2A, 0xF1, 0x81, 0xF4, 0xD9, 0x3C, 0xEC, 
+	0x73, 0xD0, 0x2A, 0xD8, 0x3C, 0x27, 0x87, 0x79, 0x12, 0x86, 
+	0xE7, 0x57, 0x0C, 0x59, 0xD1, 0x44, 0x55, 0xAE, 0xC3, 0x4D, 
+	0x42, 0xAD, 0xA9, 0xB3, 0x28, 0x61, 0xB4, 0x9C, 0xA6, 0x63, 
+	0xD3, 0x96, 0xB1, 0x75, 0x9F, 0x2A, 0x78, 0x99, 0xE3, 0x1E, 
+	0x71, 0x47, 0x39, 0xF4, 0x52, 0xE3, 0x66, 0xF1, 0xEB, 0x7F, 
+	0xEF, 0xC6, 0x81, 0x93, 0x4C, 0x99, 0xF1, 0x02, 0x81, 0x81, 
+	0x00, 0xC5, 0xB6, 0x20, 0x8C, 0x34, 0xF3, 0xDD, 0xF0, 0x4A, 
+	0x5D, 0x82, 0x65, 0x5C, 0x48, 0xE4, 0x75, 0x3A, 0xFB, 0xFA, 
+	0xAA, 0x1C, 0xE4, 0x63, 0x77, 0x31, 0xAC, 0xD2, 0x25, 0x45, 
+	0x23, 0x6D, 0x03, 0xF5, 0xE4, 0xD2, 0x48, 0x85, 0x26, 0x08, 
+	0xE5, 0xAA, 0xA0, 0xCE, 0x2E, 0x1D, 0x6D, 0xFC, 0xAE, 0xD2, 
+	0xF9, 0x42, 0x7E, 0xEA, 0x6D, 0x59, 0x7A, 0xB3, 0x93, 0xE4, 
+	0x4B, 0x4B, 0x54, 0x63, 0xD8, 0xCE, 0x44, 0x06, 0xC2, 0xEC, 
+	0x9F, 0xF6, 0x05, 0x55, 0x46, 0xF4, 0x3E, 0x8F, 0xF2, 0x0C, 
+	0x30, 0x7E, 0x5C, 0xDD, 0x88, 0x49, 0x3B, 0x59, 0xB9, 0x87, 
+	0xBC, 0xC6, 0xC5, 0x24, 0x8A, 0x10, 0x63, 0x21, 0x1F, 0x66, 
+	0x1A, 0x3E, 0xF4, 0x58, 0xD1, 0x6C, 0x0D, 0x40, 0xB2, 0xC0, 
+	0x1D, 0x63, 0x42, 0x0E, 0xC4, 0x56, 0x0E, 0xC0, 0xCC, 0xC2, 
+	0xD6, 0x66, 0x0E, 0xC4, 0xAB, 0xB5, 0x33, 0xF6, 0x51, 0x02, 
+	0x81, 0x80, 0x19, 0x7E, 0xE6, 0xA5, 0xB6, 0xD1, 0x39, 0x6A, 
+	0x48, 0x55, 0xAC, 0x24, 0x96, 0x9B, 0x12, 0x28, 0x6D, 0x7B, 
+	0x5C, 0x05, 0x25, 0x5A, 0x72, 0x05, 0x7E, 0x42, 0xF5, 0x83, 
+	0x1A, 0x78, 0x2C, 0x4D, 0xAE, 0xB4, 0x36, 0x96, 0xA9, 0xBA, 
+	0xE0, 0xAC, 0x26, 0x9D, 0xA9, 0x6A, 0x29, 0x83, 0xB9, 0x6D, 
+	0xC5, 0xEC, 0xFA, 0x4A, 0x9C, 0x09, 0x6A, 0x7E, 0xE4, 0x9B, 
+	0xDC, 0x9B, 0x2A, 0x27, 0x6E, 0x4F, 0xBA, 0xD8, 0xA5, 0x67, 
+	0xDB, 0xEC, 0x41, 0x5F, 0x29, 0x1C, 0x40, 0x83, 0xEB, 0x59, 
+	0x56, 0xD7, 0xA9, 0x4E, 0xAB, 0xAE, 0x70, 0x67, 0xD1, 0xA3, 
+	0xF1, 0x6C, 0xD7, 0x8F, 0x96, 0x0E, 0x8D, 0xAC, 0xAB, 0x55, 
+	0x58, 0x66, 0xD3, 0x1E, 0x47, 0x9B, 0xF0, 0x4C, 0xED, 0xF6, 
+	0x49, 0xE8, 0xE9, 0x7B, 0x32, 0x61, 0x20, 0x31, 0x95, 0x05, 
+	0xB2, 0xF6, 0x09, 0xEA, 0x32, 0x14, 0x0F, 0xCF, 0x9A, 0x41, 
+	0x02, 0x81, 0x80, 0x77, 0x3F, 0xB6, 0x14, 0x8D, 0xC5, 0x13, 
+	0x08, 0x7E, 0xC9, 0xC4, 0xEA, 0xD4, 0xBA, 0x0D, 0xA4, 0x9E, 
+	0xB3, 0x6E, 0xDE, 0x1A, 0x7A, 0xF8, 0x89, 0x88, 0xEF, 0x36, 
+	0x3C, 0x11, 0xBC, 0x83, 0xE8, 0x30, 0x6C, 0x81, 0x7C, 0x47, 
+	0xF3, 0x4D, 0xCA, 0xEA, 0x56, 0x01, 0x62, 0x55, 0x2E, 0x4B, 
+	0x89, 0xA9, 0xBD, 0x6F, 0x01, 0xF6, 0x74, 0x02, 0xAA, 0xE3, 
+	0x84, 0x66, 0x06, 0x95, 0x34, 0xA1, 0xE2, 0xCA, 0x65, 0xFE, 
+	0xA3, 0x2D, 0x43, 0x97, 0x95, 0x6C, 0x6F, 0xD5, 0xB4, 0x38, 
+	0xF6, 0xF9, 0x95, 0x30, 0xFA, 0xF8, 0x9C, 0x25, 0x2B, 0xB6, 
+	0x14, 0x51, 0xCC, 0x2E, 0xB3, 0x5B, 0xD6, 0xDC, 0x1A, 0xEC, 
+	0x2D, 0x09, 0x5B, 0x3F, 0x3A, 0xD0, 0xB8, 0x4E, 0x27, 0x1F, 
+	0xDC, 0x2A, 0xEE, 0xAC, 0xA9, 0x59, 0x5D, 0x07, 0x63, 0x11, 
+	0x83, 0x0B, 0xD4, 0x74, 0x80, 0xB6, 0x7D, 0x62, 0x45, 0xBF, 
+	0x56
+};
+static const int sizeof_rsa_key_der_2048 = sizeof(rsa_key_der_2048);
+
+/* ./certs/ca-cert.der, 2048-bit */
+static const unsigned char ca_cert_der_2048[] =
+{
+	0x30, 0x82, 0x04, 0xAA, 0x30, 0x82, 0x03, 0x92, 0xA0, 0x03, 
+	0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xD9, 0x80, 0x3A, 0xC3, 
+	0xD2, 0xF4, 0xDA, 0x37, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 
+	0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 
+	0x81, 0x94, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 
+	0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0E, 0x06, 
+	0x03, 0x55, 0x04, 0x08, 0x0C, 0x07, 0x4D, 0x6F, 0x6E, 0x74, 
+	0x61, 0x6E, 0x61, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 
+	0x04, 0x07, 0x0C, 0x07, 0x42, 0x6F, 0x7A, 0x65, 0x6D, 0x61, 
+	0x6E, 0x31, 0x11, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x04, 0x0A, 
+	0x0C, 0x08, 0x53, 0x61, 0x77, 0x74, 0x6F, 0x6F, 0x74, 0x68, 
+	0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 
+	0x0A, 0x43, 0x6F, 0x6E, 0x73, 0x75, 0x6C, 0x74, 0x69, 0x6E, 
+	0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 
+	0x0C, 0x0F, 0x77, 0x77, 0x77, 0x2E, 0x77, 0x6F, 0x6C, 0x66, 
+	0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x1F, 0x30, 
+	0x1D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 
+	0x09, 0x01, 0x16, 0x10, 0x69, 0x6E, 0x66, 0x6F, 0x40, 0x77, 
+	0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 
+	0x30, 0x1E, 0x17, 0x0D, 0x31, 0x35, 0x30, 0x35, 0x30, 0x37, 
+	0x31, 0x38, 0x32, 0x31, 0x30, 0x31, 0x5A, 0x17, 0x0D, 0x31, 
+	0x38, 0x30, 0x31, 0x33, 0x31, 0x31, 0x38, 0x32, 0x31, 0x30, 
+	0x31, 0x5A, 0x30, 0x81, 0x94, 0x31, 0x0B, 0x30, 0x09, 0x06, 
+	0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 
+	0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x07, 0x4D, 
+	0x6F, 0x6E, 0x74, 0x61, 0x6E, 0x61, 0x31, 0x10, 0x30, 0x0E, 
+	0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x07, 0x42, 0x6F, 0x7A, 
+	0x65, 0x6D, 0x61, 0x6E, 0x31, 0x11, 0x30, 0x0F, 0x06, 0x03, 
+	0x55, 0x04, 0x0A, 0x0C, 0x08, 0x53, 0x61, 0x77, 0x74, 0x6F, 
+	0x6F, 0x74, 0x68, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 
+	0x04, 0x0B, 0x0C, 0x0A, 0x43, 0x6F, 0x6E, 0x73, 0x75, 0x6C, 
+	0x74, 0x69, 0x6E, 0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 
+	0x55, 0x04, 0x03, 0x0C, 0x0F, 0x77, 0x77, 0x77, 0x2E, 0x77, 
+	0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 
+	0x31, 0x1F, 0x30, 0x1D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 
+	0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6E, 0x66, 
+	0x6F, 0x40, 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 
+	0x63, 0x6F, 0x6D, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 
+	0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 
+	0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01, 
+	0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xBF, 0x0C, 0xCA, 0x2D, 
+	0x14, 0xB2, 0x1E, 0x84, 0x42, 0x5B, 0xCD, 0x38, 0x1F, 0x4A, 
+	0xF2, 0x4D, 0x75, 0x10, 0xF1, 0xB6, 0x35, 0x9F, 0xDF, 0xCA, 
+	0x7D, 0x03, 0x98, 0xD3, 0xAC, 0xDE, 0x03, 0x66, 0xEE, 0x2A, 
+	0xF1, 0xD8, 0xB0, 0x7D, 0x6E, 0x07, 0x54, 0x0B, 0x10, 0x98, 
+	0x21, 0x4D, 0x80, 0xCB, 0x12, 0x20, 0xE7, 0xCC, 0x4F, 0xDE, 
+	0x45, 0x7D, 0xC9, 0x72, 0x77, 0x32, 0xEA, 0xCA, 0x90, 0xBB, 
+	0x69, 0x52, 0x10, 0x03, 0x2F, 0xA8, 0xF3, 0x95, 0xC5, 0xF1, 
+	0x8B, 0x62, 0x56, 0x1B, 0xEF, 0x67, 0x6F, 0xA4, 0x10, 0x41, 
+	0x95, 0xAD, 0x0A, 0x9B, 0xE3, 0xA5, 0xC0, 0xB0, 0xD2, 0x70, 
+	0x76, 0x50, 0x30, 0x5B, 0xA8, 0xE8, 0x08, 0x2C, 0x7C, 0xED, 
+	0xA7, 0xA2, 0x7A, 0x8D, 0x38, 0x29, 0x1C, 0xAC, 0xC7, 0xED, 
+	0xF2, 0x7C, 0x95, 0xB0, 0x95, 0x82, 0x7D, 0x49, 0x5C, 0x38, 
+	0xCD, 0x77, 0x25, 0xEF, 0xBD, 0x80, 0x75, 0x53, 0x94, 0x3C, 
+	0x3D, 0xCA, 0x63, 0x5B, 0x9F, 0x15, 0xB5, 0xD3, 0x1D, 0x13, 
+	0x2F, 0x19, 0xD1, 0x3C, 0xDB, 0x76, 0x3A, 0xCC, 0xB8, 0x7D, 
+	0xC9, 0xE5, 0xC2, 0xD7, 0xDA, 0x40, 0x6F, 0xD8, 0x21, 0xDC, 
+	0x73, 0x1B, 0x42, 0x2D, 0x53, 0x9C, 0xFE, 0x1A, 0xFC, 0x7D, 
+	0xAB, 0x7A, 0x36, 0x3F, 0x98, 0xDE, 0x84, 0x7C, 0x05, 0x67, 
+	0xCE, 0x6A, 0x14, 0x38, 0x87, 0xA9, 0xF1, 0x8C, 0xB5, 0x68, 
+	0xCB, 0x68, 0x7F, 0x71, 0x20, 0x2B, 0xF5, 0xA0, 0x63, 0xF5, 
+	0x56, 0x2F, 0xA3, 0x26, 0xD2, 0xB7, 0x6F, 0xB1, 0x5A, 0x17, 
+	0xD7, 0x38, 0x99, 0x08, 0xFE, 0x93, 0x58, 0x6F, 0xFE, 0xC3, 
+	0x13, 0x49, 0x08, 0x16, 0x0B, 0xA7, 0x4D, 0x67, 0x00, 0x52, 
+	0x31, 0x67, 0x23, 0x4E, 0x98, 0xED, 0x51, 0x45, 0x1D, 0xB9, 
+	0x04, 0xD9, 0x0B, 0xEC, 0xD8, 0x28, 0xB3, 0x4B, 0xBD, 0xED, 
+	0x36, 0x79, 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x81, 0xFC, 
+	0x30, 0x81, 0xF9, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 
+	0x04, 0x16, 0x04, 0x14, 0x27, 0x8E, 0x67, 0x11, 0x74, 0xC3, 
+	0x26, 0x1D, 0x3F, 0xED, 0x33, 0x63, 0xB3, 0xA4, 0xD8, 0x1D, 
+	0x30, 0xE5, 0xE8, 0xD5, 0x30, 0x81, 0xC9, 0x06, 0x03, 0x55, 
+	0x1D, 0x23, 0x04, 0x81, 0xC1, 0x30, 0x81, 0xBE, 0x80, 0x14, 
+	0x27, 0x8E, 0x67, 0x11, 0x74, 0xC3, 0x26, 0x1D, 0x3F, 0xED, 
+	0x33, 0x63, 0xB3, 0xA4, 0xD8, 0x1D, 0x30, 0xE5, 0xE8, 0xD5, 
+	0xA1, 0x81, 0x9A, 0xA4, 0x81, 0x97, 0x30, 0x81, 0x94, 0x31, 
+	0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 
+	0x55, 0x53, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 
+	0x08, 0x0C, 0x07, 0x4D, 0x6F, 0x6E, 0x74, 0x61, 0x6E, 0x61, 
+	0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 
+	0x07, 0x42, 0x6F, 0x7A, 0x65, 0x6D, 0x61, 0x6E, 0x31, 0x11, 
+	0x30, 0x0F, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x08, 0x53, 
+	0x61, 0x77, 0x74, 0x6F, 0x6F, 0x74, 0x68, 0x31, 0x13, 0x30, 
+	0x11, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x0A, 0x43, 0x6F, 
+	0x6E, 0x73, 0x75, 0x6C, 0x74, 0x69, 0x6E, 0x67, 0x31, 0x18, 
+	0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0F, 0x77, 
+	0x77, 0x77, 0x2E, 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 
+	0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x1F, 0x30, 0x1D, 0x06, 0x09, 
+	0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 
+	0x10, 0x69, 0x6E, 0x66, 0x6F, 0x40, 0x77, 0x6F, 0x6C, 0x66, 
+	0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x82, 0x09, 0x00, 
+	0xD9, 0x80, 0x3A, 0xC3, 0xD2, 0xF4, 0xDA, 0x37, 0x30, 0x0C, 
+	0x06, 0x03, 0x55, 0x1D, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 
+	0x01, 0xFF, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 
+	0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 0x01, 
+	0x01, 0x00, 0x7A, 0xAF, 0x44, 0x3B, 0xAA, 0x6F, 0x53, 0x42, 
+	0xB2, 0x33, 0xAA, 0x43, 0x5F, 0x56, 0x30, 0xD3, 0xB9, 0x96, 
+	0x0B, 0x9A, 0x55, 0x5A, 0x39, 0x2A, 0x0B, 0x4E, 0xE4, 0x2E, 
+	0xF1, 0x95, 0x66, 0xC9, 0x86, 0x36, 0x82, 0x8D, 0x63, 0x7C, 
+	0x4D, 0xA2, 0xEE, 0x48, 0xBA, 0x03, 0xC7, 0x90, 0xD7, 0xA7, 
+	0xC6, 0x74, 0x60, 0x48, 0x5F, 0x31, 0xA2, 0xF9, 0x5E, 0x3E, 
+	0xC3, 0x82, 0xE1, 0xE5, 0x2F, 0x41, 0x81, 0x83, 0x29, 0x25, 
+	0x79, 0xD1, 0x53, 0x00, 0x69, 0x3C, 0xED, 0x0A, 0x30, 0x3B, 
+	0x41, 0x1D, 0x92, 0xA1, 0x2C, 0xA8, 0x9D, 0x2C, 0xE3, 0x23, 
+	0x87, 0x79, 0xE0, 0x55, 0x6E, 0x91, 0xA8, 0x50, 0xDA, 0x46, 
+	0x2F, 0xC2, 0x20, 0x50, 0x3E, 0x2B, 0x47, 0x97, 0x14, 0xB0, 
+	0x7D, 0x04, 0xBA, 0x45, 0x51, 0xD0, 0x6E, 0xE1, 0x5A, 0xA2, 
+	0x4B, 0x84, 0x9C, 0x4D, 0xCD, 0x85, 0x04, 0xF9, 0x28, 0x31, 
+	0x82, 0x93, 0xBC, 0xC7, 0x59, 0x49, 0x91, 0x03, 0xE8, 0xDF, 
+	0x6A, 0xE4, 0x56, 0xAD, 0x6A, 0xCB, 0x1F, 0x0D, 0x37, 0xE4, 
+	0x5E, 0xBD, 0xE7, 0x9F, 0xD5, 0xEC, 0x9D, 0x3C, 0x18, 0x25, 
+	0x9B, 0xF1, 0x2F, 0x50, 0x7D, 0xEB, 0x31, 0xCB, 0xF1, 0x63, 
+	0x22, 0x9D, 0x57, 0xFC, 0xF3, 0x84, 0x20, 0x1A, 0xC6, 0x07, 
+	0x87, 0x92, 0x26, 0x9E, 0x15, 0x18, 0x59, 0x33, 0x06, 0xDC, 
+	0xFB, 0xB0, 0xB6, 0x76, 0x5D, 0xF1, 0xC1, 0x2F, 0xC8, 0x2F, 
+	0x62, 0x9C, 0xC0, 0xD6, 0xDE, 0xEB, 0x65, 0x77, 0xF3, 0x5C, 
+	0xA6, 0xC3, 0x88, 0x27, 0x96, 0x75, 0xB4, 0xF4, 0x54, 0xCD, 
+	0xFF, 0x2D, 0x21, 0x2E, 0x96, 0xF0, 0x07, 0x73, 0x4B, 0xE9, 
+	0x93, 0x92, 0x90, 0xDE, 0x62, 0xD9, 0xA3, 0x3B, 0xAC, 0x6E, 
+	0x24, 0x5F, 0x27, 0x4A, 0xB3, 0x94, 0x70, 0xFF, 0x30, 0x17, 
+	0xE7, 0x7E, 0x32, 0x8F, 0x65, 0xB7, 0x75, 0x58
+};
+static const int sizeof_ca_cert_der_2048 = sizeof(ca_cert_der_2048);
+
+/* ./certs/server-key.der, 2048-bit */
+static const unsigned char server_key_der_2048[] =
+{
+	0x30, 0x82, 0x04, 0xA5, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 
+	0x01, 0x00, 0xC0, 0x95, 0x08, 0xE1, 0x57, 0x41, 0xF2, 0x71, 
+	0x6D, 0xB7, 0xD2, 0x45, 0x41, 0x27, 0x01, 0x65, 0xC6, 0x45, 
+	0xAE, 0xF2, 0xBC, 0x24, 0x30, 0xB8, 0x95, 0xCE, 0x2F, 0x4E, 
+	0xD6, 0xF6, 0x1C, 0x88, 0xBC, 0x7C, 0x9F, 0xFB, 0xA8, 0x67, 
+	0x7F, 0xFE, 0x5C, 0x9C, 0x51, 0x75, 0xF7, 0x8A, 0xCA, 0x07, 
+	0xE7, 0x35, 0x2F, 0x8F, 0xE1, 0xBD, 0x7B, 0xC0, 0x2F, 0x7C, 
+	0xAB, 0x64, 0xA8, 0x17, 0xFC, 0xCA, 0x5D, 0x7B, 0xBA, 0xE0, 
+	0x21, 0xE5, 0x72, 0x2E, 0x6F, 0x2E, 0x86, 0xD8, 0x95, 0x73, 
+	0xDA, 0xAC, 0x1B, 0x53, 0xB9, 0x5F, 0x3F, 0xD7, 0x19, 0x0D, 
+	0x25, 0x4F, 0xE1, 0x63, 0x63, 0x51, 0x8B, 0x0B, 0x64, 0x3F, 
+	0xAD, 0x43, 0xB8, 0xA5, 0x1C, 0x5C, 0x34, 0xB3, 0xAE, 0x00, 
+	0xA0, 0x63, 0xC5, 0xF6, 0x7F, 0x0B, 0x59, 0x68, 0x78, 0x73, 
+	0xA6, 0x8C, 0x18, 0xA9, 0x02, 0x6D, 0xAF, 0xC3, 0x19, 0x01, 
+	0x2E, 0xB8, 0x10, 0xE3, 0xC6, 0xCC, 0x40, 0xB4, 0x69, 0xA3, 
+	0x46, 0x33, 0x69, 0x87, 0x6E, 0xC4, 0xBB, 0x17, 0xA6, 0xF3, 
+	0xE8, 0xDD, 0xAD, 0x73, 0xBC, 0x7B, 0x2F, 0x21, 0xB5, 0xFD, 
+	0x66, 0x51, 0x0C, 0xBD, 0x54, 0xB3, 0xE1, 0x6D, 0x5F, 0x1C, 
+	0xBC, 0x23, 0x73, 0xD1, 0x09, 0x03, 0x89, 0x14, 0xD2, 0x10, 
+	0xB9, 0x64, 0xC3, 0x2A, 0xD0, 0xA1, 0x96, 0x4A, 0xBC, 0xE1, 
+	0xD4, 0x1A, 0x5B, 0xC7, 0xA0, 0xC0, 0xC1, 0x63, 0x78, 0x0F, 
+	0x44, 0x37, 0x30, 0x32, 0x96, 0x80, 0x32, 0x23, 0x95, 0xA1, 
+	0x77, 0xBA, 0x13, 0xD2, 0x97, 0x73, 0xE2, 0x5D, 0x25, 0xC9, 
+	0x6A, 0x0D, 0xC3, 0x39, 0x60, 0xA4, 0xB4, 0xB0, 0x69, 0x42, 
+	0x42, 0x09, 0xE9, 0xD8, 0x08, 0xBC, 0x33, 0x20, 0xB3, 0x58, 
+	0x22, 0xA7, 0xAA, 0xEB, 0xC4, 0xE1, 0xE6, 0x61, 0x83, 0xC5, 
+	0xD2, 0x96, 0xDF, 0xD9, 0xD0, 0x4F, 0xAD, 0xD7, 0x02, 0x03, 
+	0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x01, 0x00, 0x9A, 0xD0, 
+	0x34, 0x0F, 0x52, 0x62, 0x05, 0x50, 0x01, 0xEF, 0x9F, 0xED, 
+	0x64, 0x6E, 0xC2, 0xC4, 0xDA, 0x1A, 0xF2, 0x84, 0xD7, 0x92, 
+	0x10, 0x48, 0x92, 0xC4, 0xE9, 0x6A, 0xEB, 0x8B, 0x75, 0x6C, 
+	0xC6, 0x79, 0x38, 0xF2, 0xC9, 0x72, 0x4A, 0x86, 0x64, 0x54, 
+	0x95, 0x77, 0xCB, 0xC3, 0x9A, 0x9D, 0xB7, 0xD4, 0x1D, 0xA4, 
+	0x00, 0xC8, 0x9E, 0x4E, 0xE4, 0xDD, 0xC7, 0xBA, 0x67, 0x16, 
+	0xC1, 0x74, 0xBC, 0xA9, 0xD6, 0x94, 0x8F, 0x2B, 0x30, 0x1A, 
+	0xFB, 0xED, 0xDF, 0x21, 0x05, 0x23, 0xD9, 0x4A, 0x39, 0xBD, 
+	0x98, 0x6B, 0x65, 0x9A, 0xB8, 0xDC, 0xC4, 0x7D, 0xEE, 0xA6, 
+	0x43, 0x15, 0x2E, 0x3D, 0xBE, 0x1D, 0x22, 0x60, 0x2A, 0x73, 
+	0x30, 0xD5, 0x3E, 0xD8, 0xA2, 0xAC, 0x86, 0x43, 0x2E, 0xC4, 
+	0xF5, 0x64, 0x5E, 0x3F, 0x89, 0x75, 0x0F, 0x11, 0xD8, 0x51, 
+	0x25, 0x4E, 0x9F, 0xD8, 0xAA, 0xA3, 0xCE, 0x60, 0xB3, 0xE2, 
+	0x8A, 0xD9, 0x7E, 0x1B, 0xF0, 0x64, 0xCA, 0x9A, 0x5B, 0x05, 
+	0x0B, 0x5B, 0xAA, 0xCB, 0xE5, 0xE3, 0x3F, 0x6E, 0x32, 0x22, 
+	0x05, 0xF3, 0xD0, 0xFA, 0xEF, 0x74, 0x52, 0x81, 0xE2, 0x5F, 
+	0x74, 0xD3, 0xBD, 0xFF, 0x31, 0x83, 0x45, 0x75, 0xFA, 0x63, 
+	0x7A, 0x97, 0x2E, 0xD6, 0xB6, 0x19, 0xC6, 0x92, 0x26, 0xE4, 
+	0x28, 0x06, 0x50, 0x50, 0x0E, 0x78, 0x2E, 0xA9, 0x78, 0x0D, 
+	0x14, 0x97, 0xB4, 0x12, 0xD8, 0x31, 0x40, 0xAB, 0xA1, 0x01, 
+	0x41, 0xC2, 0x30, 0xF8, 0x07, 0x5F, 0x16, 0xE4, 0x61, 0x77, 
+	0xD2, 0x60, 0xF2, 0x9F, 0x8D, 0xE8, 0xF4, 0xBA, 0xEB, 0x63, 
+	0xDE, 0x2A, 0x97, 0x81, 0xEF, 0x4C, 0x6C, 0xE6, 0x55, 0x34, 
+	0x51, 0x2B, 0x28, 0x34, 0xF4, 0x53, 0x1C, 0xC4, 0x58, 0x0A, 
+	0x3F, 0xBB, 0xAF, 0xB5, 0xF7, 0x4A, 0x85, 0x43, 0x2D, 0x3C, 
+	0xF1, 0x58, 0x58, 0x81, 0x02, 0x81, 0x81, 0x00, 0xF2, 0x2C, 
+	0x54, 0x76, 0x39, 0x23, 0x63, 0xC9, 0x10, 0x32, 0xB7, 0x93, 
+	0xAD, 0xAF, 0xBE, 0x19, 0x75, 0x96, 0x81, 0x64, 0xE6, 0xB5, 
+	0xB8, 0x89, 0x42, 0x41, 0xD1, 0x6D, 0xD0, 0x1C, 0x1B, 0xF8, 
+	0x1B, 0xAC, 0x69, 0xCB, 0x36, 0x3C, 0x64, 0x7D, 0xDC, 0xF4, 
+	0x19, 0xB8, 0xC3, 0x60, 0xB1, 0x57, 0x48, 0x5F, 0x52, 0x4F, 
+	0x59, 0x3A, 0x55, 0x7F, 0x32, 0xC0, 0x19, 0x43, 0x50, 0x3F, 
+	0xAE, 0xCE, 0x6F, 0x17, 0xF3, 0x0E, 0x9F, 0x40, 0xCA, 0x4E, 
+	0xAD, 0x15, 0x3B, 0xC9, 0x79, 0xE9, 0xC0, 0x59, 0x38, 0x73, 
+	0x70, 0x9C, 0x0A, 0x7C, 0xC9, 0x3A, 0x48, 0x32, 0xA7, 0xD8, 
+	0x49, 0x75, 0x0A, 0x85, 0xC2, 0xC2, 0xFD, 0x15, 0x73, 0xDA, 
+	0x99, 0x09, 0x2A, 0x69, 0x9A, 0x9F, 0x0A, 0x71, 0xBF, 0xB0, 
+	0x04, 0xA6, 0x8C, 0x7A, 0x5A, 0x6F, 0x48, 0x5A, 0x54, 0x3B, 
+	0xC6, 0xB1, 0x53, 0x17, 0xDF, 0xE7, 0x02, 0x81, 0x81, 0x00, 
+	0xCB, 0x93, 0xDE, 0x77, 0x15, 0x5D, 0xB7, 0x5C, 0x5C, 0x7C, 
+	0xD8, 0x90, 0xA9, 0x98, 0x2D, 0xD6, 0x69, 0x0E, 0x63, 0xB3, 
+	0xA3, 0xDC, 0xA6, 0xCC, 0x8B, 0x6A, 0xA4, 0xA2, 0x12, 0x8C, 
+	0x8E, 0x7B, 0x48, 0x2C, 0xB2, 0x4B, 0x37, 0xDC, 0x06, 0x18, 
+	0x7D, 0xEA, 0xFE, 0x76, 0xA1, 0xD4, 0xA1, 0xE9, 0x3F, 0x0D, 
+	0xCD, 0x1B, 0x5F, 0xAF, 0x5F, 0x9E, 0x96, 0x5B, 0x5B, 0x0F, 
+	0xA1, 0x7C, 0xAF, 0xB3, 0x9B, 0x90, 0xDB, 0x57, 0x73, 0x3A, 
+	0xED, 0xB0, 0x23, 0x44, 0xAE, 0x41, 0x4F, 0x1F, 0x07, 0x42, 
+	0x13, 0x23, 0x4C, 0xCB, 0xFA, 0xF4, 0x14, 0xA4, 0xD5, 0xF7, 
+	0x9E, 0x36, 0x7C, 0x5B, 0x9F, 0xA8, 0x3C, 0xC1, 0x85, 0x5F, 
+	0x74, 0xD2, 0x39, 0x2D, 0xFF, 0xD0, 0x84, 0xDF, 0xFB, 0xB3, 
+	0x20, 0x7A, 0x2E, 0x9B, 0x17, 0xAE, 0xE6, 0xBA, 0x0B, 0xAE, 
+	0x5F, 0x53, 0xA4, 0x52, 0xED, 0x1B, 0xC4, 0x91, 0x02, 0x81, 
+	0x81, 0x00, 0xEC, 0x98, 0xDA, 0xBB, 0xD5, 0xFE, 0xF9, 0x52, 
+	0x4A, 0x7D, 0x02, 0x55, 0x49, 0x6F, 0x55, 0x6E, 0x52, 0x2F, 
+	0x84, 0xA3, 0x2B, 0xB3, 0x86, 0x62, 0xB3, 0x54, 0xD2, 0x63, 
+	0x52, 0xDA, 0xE3, 0x88, 0x76, 0xA0, 0xEF, 0x8B, 0x15, 0xA5, 
+	0xD3, 0x18, 0x14, 0x72, 0x77, 0x5E, 0xC7, 0xA3, 0x04, 0x1F, 
+	0x9E, 0x19, 0x62, 0xB5, 0x1B, 0x1B, 0x9E, 0xC3, 0xF2, 0xB5, 
+	0x32, 0xF9, 0x4C, 0xC1, 0xAA, 0xEB, 0x0C, 0x26, 0x7D, 0xD4, 
+	0x5F, 0x4A, 0x51, 0x5C, 0xA4, 0x45, 0x06, 0x70, 0x44, 0xA7, 
+	0x56, 0xC0, 0xD4, 0x22, 0x14, 0x76, 0x9E, 0xD8, 0x63, 0x50, 
+	0x89, 0x90, 0xD3, 0xE2, 0xBF, 0x81, 0x95, 0x92, 0x31, 0x41, 
+	0x87, 0x39, 0x1A, 0x43, 0x0B, 0x18, 0xA5, 0x53, 0x1F, 0x39, 
+	0x1A, 0x5F, 0x1F, 0x43, 0xBC, 0x87, 0x6A, 0xDF, 0x6E, 0xD3, 
+	0x22, 0x00, 0xFE, 0x22, 0x98, 0x70, 0x4E, 0x1A, 0x19, 0x29, 
+	0x02, 0x81, 0x81, 0x00, 0x8A, 0x41, 0x56, 0x28, 0x51, 0x9E, 
+	0x5F, 0xD4, 0x9E, 0x0B, 0x3B, 0x98, 0xA3, 0x54, 0xF2, 0x6C, 
+	0x56, 0xD4, 0xAA, 0xE9, 0x69, 0x33, 0x85, 0x24, 0x0C, 0xDA, 
+	0xD4, 0x0C, 0x2D, 0xC4, 0xBF, 0x4F, 0x02, 0x69, 0x38, 0x7C, 
+	0xD4, 0xE6, 0xDC, 0x4C, 0xED, 0xD7, 0x16, 0x11, 0xC3, 0x3E, 
+	0x00, 0xE7, 0xC3, 0x26, 0xC0, 0x51, 0x02, 0xDE, 0xBB, 0x75, 
+	0x9C, 0x6F, 0x56, 0x9C, 0x7A, 0xF3, 0x8E, 0xEF, 0xCF, 0x8A, 
+	0xC5, 0x2B, 0xD2, 0xDA, 0x06, 0x6A, 0x44, 0xC9, 0x73, 0xFE, 
+	0x6E, 0x99, 0x87, 0xF8, 0x5B, 0xBE, 0xF1, 0x7C, 0xE6, 0x65, 
+	0xB5, 0x4F, 0x6C, 0xF0, 0xC9, 0xC5, 0xFF, 0x16, 0xCA, 0x8B, 
+	0x1B, 0x17, 0xE2, 0x58, 0x3D, 0xA2, 0x37, 0xAB, 0x01, 0xBC, 
+	0xBF, 0x40, 0xCE, 0x53, 0x8C, 0x8E, 0xED, 0xEF, 0xEE, 0x59, 
+	0x9D, 0xE0, 0x63, 0xE6, 0x7C, 0x5E, 0xF5, 0x8E, 0x4B, 0xF1, 
+	0x3B, 0xC1, 0x02, 0x81, 0x80, 0x4D, 0x45, 0xF9, 0x40, 0x8C, 
+	0xC5, 0x5B, 0xF4, 0x2A, 0x1A, 0x8A, 0xB4, 0xF2, 0x1C, 0xAC, 
+	0x6B, 0xE9, 0x0C, 0x56, 0x36, 0xB7, 0x4E, 0x72, 0x96, 0xD5, 
+	0xE5, 0x8A, 0xD2, 0xE2, 0xFF, 0xF1, 0xF1, 0x18, 0x13, 0x3D, 
+	0x86, 0x09, 0xB8, 0xD8, 0x76, 0xA7, 0xC9, 0x1C, 0x71, 0x52, 
+	0x94, 0x30, 0x43, 0xE0, 0xF1, 0x78, 0x74, 0xFD, 0x61, 0x1B, 
+	0x4C, 0x09, 0xCC, 0xE6, 0x68, 0x2A, 0x71, 0xAD, 0x1C, 0xDF, 
+	0x43, 0xBC, 0x56, 0xDB, 0xA5, 0xA4, 0xBE, 0x35, 0x70, 0xA4, 
+	0x5E, 0xCF, 0x4F, 0xFC, 0x00, 0x55, 0x99, 0x3A, 0x3D, 0x23, 
+	0xCF, 0x67, 0x5A, 0xF5, 0x22, 0xF8, 0xB5, 0x29, 0xD0, 0x44, 
+	0x11, 0xEB, 0x35, 0x2E, 0x46, 0xBE, 0xFD, 0x8E, 0x18, 0xB2, 
+	0x5F, 0xA8, 0xBF, 0x19, 0x32, 0xA1, 0xF5, 0xDC, 0x03, 0xE6, 
+	0x7C, 0x9A, 0x1F, 0x0C, 0x7C, 0xA9, 0xB0, 0x0E, 0x21, 0x37, 
+	0x3B, 0xF1, 0xB0
+};
+static const int sizeof_server_key_der_2048 = sizeof(server_key_der_2048);
+
+/* ./certs/server-cert.der, 2048-bit */
+static const unsigned char server_cert_der_2048[] =
+{
+	0x30, 0x82, 0x04, 0x9E, 0x30, 0x82, 0x03, 0x86, 0xA0, 0x03, 
+	0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0D, 0x06, 0x09, 
+	0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 
+	0x00, 0x30, 0x81, 0x94, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 
+	0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 
+	0x0E, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x07, 0x4D, 0x6F, 
+	0x6E, 0x74, 0x61, 0x6E, 0x61, 0x31, 0x10, 0x30, 0x0E, 0x06, 
+	0x03, 0x55, 0x04, 0x07, 0x0C, 0x07, 0x42, 0x6F, 0x7A, 0x65, 
+	0x6D, 0x61, 0x6E, 0x31, 0x11, 0x30, 0x0F, 0x06, 0x03, 0x55, 
+	0x04, 0x0A, 0x0C, 0x08, 0x53, 0x61, 0x77, 0x74, 0x6F, 0x6F, 
+	0x74, 0x68, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 
+	0x0B, 0x0C, 0x0A, 0x43, 0x6F, 0x6E, 0x73, 0x75, 0x6C, 0x74, 
+	0x69, 0x6E, 0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 
+	0x04, 0x03, 0x0C, 0x0F, 0x77, 0x77, 0x77, 0x2E, 0x77, 0x6F, 
+	0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 
+	0x1F, 0x30, 0x1D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 
+	0x0D, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6E, 0x66, 0x6F, 
+	0x40, 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 
+	0x6F, 0x6D, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x35, 0x30, 0x35, 
+	0x30, 0x37, 0x31, 0x38, 0x32, 0x31, 0x30, 0x31, 0x5A, 0x17, 
+	0x0D, 0x31, 0x38, 0x30, 0x31, 0x33, 0x31, 0x31, 0x38, 0x32, 
+	0x31, 0x30, 0x31, 0x5A, 0x30, 0x81, 0x90, 0x31, 0x0B, 0x30, 
+	0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 
+	0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 
+	0x07, 0x4D, 0x6F, 0x6E, 0x74, 0x61, 0x6E, 0x61, 0x31, 0x10, 
+	0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x07, 0x42, 
+	0x6F, 0x7A, 0x65, 0x6D, 0x61, 0x6E, 0x31, 0x10, 0x30, 0x0E, 
+	0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x07, 0x77, 0x6F, 0x6C, 
+	0x66, 0x53, 0x53, 0x4C, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 
+	0x55, 0x04, 0x0B, 0x0C, 0x07, 0x53, 0x75, 0x70, 0x70, 0x6F, 
+	0x72, 0x74, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 
+	0x03, 0x0C, 0x0F, 0x77, 0x77, 0x77, 0x2E, 0x77, 0x6F, 0x6C, 
+	0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x1F, 
+	0x30, 0x1D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 
+	0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6E, 0x66, 0x6F, 0x40, 
+	0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 
+	0x6D, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 
+	0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 
+	0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01, 0x0A, 0x02, 
+	0x82, 0x01, 0x01, 0x00, 0xC0, 0x95, 0x08, 0xE1, 0x57, 0x41, 
+	0xF2, 0x71, 0x6D, 0xB7, 0xD2, 0x45, 0x41, 0x27, 0x01, 0x65, 
+	0xC6, 0x45, 0xAE, 0xF2, 0xBC, 0x24, 0x30, 0xB8, 0x95, 0xCE, 
+	0x2F, 0x4E, 0xD6, 0xF6, 0x1C, 0x88, 0xBC, 0x7C, 0x9F, 0xFB, 
+	0xA8, 0x67, 0x7F, 0xFE, 0x5C, 0x9C, 0x51, 0x75, 0xF7, 0x8A, 
+	0xCA, 0x07, 0xE7, 0x35, 0x2F, 0x8F, 0xE1, 0xBD, 0x7B, 0xC0, 
+	0x2F, 0x7C, 0xAB, 0x64, 0xA8, 0x17, 0xFC, 0xCA, 0x5D, 0x7B, 
+	0xBA, 0xE0, 0x21, 0xE5, 0x72, 0x2E, 0x6F, 0x2E, 0x86, 0xD8, 
+	0x95, 0x73, 0xDA, 0xAC, 0x1B, 0x53, 0xB9, 0x5F, 0x3F, 0xD7, 
+	0x19, 0x0D, 0x25, 0x4F, 0xE1, 0x63, 0x63, 0x51, 0x8B, 0x0B, 
+	0x64, 0x3F, 0xAD, 0x43, 0xB8, 0xA5, 0x1C, 0x5C, 0x34, 0xB3, 
+	0xAE, 0x00, 0xA0, 0x63, 0xC5, 0xF6, 0x7F, 0x0B, 0x59, 0x68, 
+	0x78, 0x73, 0xA6, 0x8C, 0x18, 0xA9, 0x02, 0x6D, 0xAF, 0xC3, 
+	0x19, 0x01, 0x2E, 0xB8, 0x10, 0xE3, 0xC6, 0xCC, 0x40, 0xB4, 
+	0x69, 0xA3, 0x46, 0x33, 0x69, 0x87, 0x6E, 0xC4, 0xBB, 0x17, 
+	0xA6, 0xF3, 0xE8, 0xDD, 0xAD, 0x73, 0xBC, 0x7B, 0x2F, 0x21, 
+	0xB5, 0xFD, 0x66, 0x51, 0x0C, 0xBD, 0x54, 0xB3, 0xE1, 0x6D, 
+	0x5F, 0x1C, 0xBC, 0x23, 0x73, 0xD1, 0x09, 0x03, 0x89, 0x14, 
+	0xD2, 0x10, 0xB9, 0x64, 0xC3, 0x2A, 0xD0, 0xA1, 0x96, 0x4A, 
+	0xBC, 0xE1, 0xD4, 0x1A, 0x5B, 0xC7, 0xA0, 0xC0, 0xC1, 0x63, 
+	0x78, 0x0F, 0x44, 0x37, 0x30, 0x32, 0x96, 0x80, 0x32, 0x23, 
+	0x95, 0xA1, 0x77, 0xBA, 0x13, 0xD2, 0x97, 0x73, 0xE2, 0x5D, 
+	0x25, 0xC9, 0x6A, 0x0D, 0xC3, 0x39, 0x60, 0xA4, 0xB4, 0xB0, 
+	0x69, 0x42, 0x42, 0x09, 0xE9, 0xD8, 0x08, 0xBC, 0x33, 0x20, 
+	0xB3, 0x58, 0x22, 0xA7, 0xAA, 0xEB, 0xC4, 0xE1, 0xE6, 0x61, 
+	0x83, 0xC5, 0xD2, 0x96, 0xDF, 0xD9, 0xD0, 0x4F, 0xAD, 0xD7, 
+	0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x81, 0xFC, 0x30, 0x81, 
+	0xF9, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 
+	0x04, 0x14, 0xB3, 0x11, 0x32, 0xC9, 0x92, 0x98, 0x84, 0xE2, 
+	0xC9, 0xF8, 0xD0, 0x3B, 0x6E, 0x03, 0x42, 0xCA, 0x1F, 0x0E, 
+	0x8E, 0x3C, 0x30, 0x81, 0xC9, 0x06, 0x03, 0x55, 0x1D, 0x23, 
+	0x04, 0x81, 0xC1, 0x30, 0x81, 0xBE, 0x80, 0x14, 0x27, 0x8E, 
+	0x67, 0x11, 0x74, 0xC3, 0x26, 0x1D, 0x3F, 0xED, 0x33, 0x63, 
+	0xB3, 0xA4, 0xD8, 0x1D, 0x30, 0xE5, 0xE8, 0xD5, 0xA1, 0x81, 
+	0x9A, 0xA4, 0x81, 0x97, 0x30, 0x81, 0x94, 0x31, 0x0B, 0x30, 
+	0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 
+	0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 
+	0x07, 0x4D, 0x6F, 0x6E, 0x74, 0x61, 0x6E, 0x61, 0x31, 0x10, 
+	0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x07, 0x42, 
+	0x6F, 0x7A, 0x65, 0x6D, 0x61, 0x6E, 0x31, 0x11, 0x30, 0x0F, 
+	0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x08, 0x53, 0x61, 0x77, 
+	0x74, 0x6F, 0x6F, 0x74, 0x68, 0x31, 0x13, 0x30, 0x11, 0x06, 
+	0x03, 0x55, 0x04, 0x0B, 0x0C, 0x0A, 0x43, 0x6F, 0x6E, 0x73, 
+	0x75, 0x6C, 0x74, 0x69, 0x6E, 0x67, 0x31, 0x18, 0x30, 0x16, 
+	0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0F, 0x77, 0x77, 0x77, 
+	0x2E, 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 
+	0x6F, 0x6D, 0x31, 0x1F, 0x30, 0x1D, 0x06, 0x09, 0x2A, 0x86, 
+	0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 
+	0x6E, 0x66, 0x6F, 0x40, 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73, 
+	0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x82, 0x09, 0x00, 0xD9, 0x80, 
+	0x3A, 0xC3, 0xD2, 0xF4, 0xDA, 0x37, 0x30, 0x0C, 0x06, 0x03, 
+	0x55, 0x1D, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 
+	0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 
+	0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 
+	0x67, 0xC0, 0x2C, 0xA9, 0x43, 0x47, 0xE7, 0x11, 0x14, 0x77, 
+	0xAE, 0xCC, 0xD8, 0xE0, 0x6B, 0x23, 0x82, 0x91, 0x63, 0xE8, 
+	0xA8, 0x0D, 0x21, 0xC5, 0xC8, 0x47, 0x97, 0x2F, 0xD5, 0xF3, 
+	0x86, 0xFB, 0x6C, 0xCE, 0x25, 0xF9, 0x7C, 0x78, 0xC8, 0x3A, 
+	0x22, 0x68, 0xF2, 0x16, 0x1E, 0xD2, 0xD2, 0x3F, 0x24, 0x04, 
+	0x87, 0xF2, 0xB7, 0xC1, 0x62, 0x63, 0xBA, 0xC5, 0xFA, 0xAE, 
+	0xD2, 0x20, 0x81, 0x1A, 0xD2, 0x0C, 0xAE, 0x26, 0x6B, 0x1B, 
+	0x2B, 0x10, 0xD3, 0xE1, 0x9A, 0x4E, 0x64, 0x6C, 0x97, 0xDB, 
+	0x36, 0xA8, 0x8F, 0xF8, 0x05, 0x63, 0xBF, 0xBA, 0x0D, 0x88, 
+	0x0B, 0x87, 0x46, 0xC9, 0xE4, 0x64, 0xE3, 0xD7, 0xBD, 0xB8, 
+	0x2D, 0xD5, 0xC1, 0xC3, 0xC4, 0xDB, 0x55, 0x68, 0xDC, 0xA3, 
+	0x7A, 0x40, 0xB9, 0xA9, 0xF6, 0x04, 0x4A, 0x22, 0xCF, 0x98, 
+	0x76, 0x1C, 0xE4, 0xA3, 0xFF, 0x79, 0x19, 0x96, 0x57, 0x63, 
+	0x07, 0x6F, 0xF6, 0x32, 0x77, 0x16, 0x50, 0x9B, 0xE3, 0x34, 
+	0x18, 0xD4, 0xEB, 0xBE, 0xFD, 0xB6, 0x6F, 0xE3, 0xC7, 0xF6, 
+	0x85, 0xBF, 0xAC, 0x32, 0xAD, 0x98, 0x57, 0xBE, 0x13, 0x92, 
+	0x44, 0x10, 0xA5, 0xF3, 0xAE, 0xE2, 0x66, 0xDA, 0x44, 0xA9, 
+	0x94, 0x71, 0x3F, 0xD0, 0x2F, 0x20, 0x59, 0x87, 0xE4, 0x5A, 
+	0x40, 0xEE, 0xD2, 0xE4, 0x0C, 0xCE, 0x25, 0x94, 0xDC, 0x0F, 
+	0xFE, 0x38, 0xE0, 0x41, 0x52, 0x34, 0x5C, 0xBB, 0xC3, 0xDB, 
+	0xC1, 0x5F, 0x76, 0xC3, 0x5D, 0x0E, 0x32, 0x69, 0x2B, 0x9D, 
+	0x01, 0xED, 0x50, 0x1B, 0x4F, 0x77, 0xA9, 0xA9, 0xD8, 0x71, 
+	0x30, 0xCB, 0x2E, 0x2C, 0x70, 0x00, 0xAB, 0x78, 0x4B, 0xD7, 
+	0x15, 0xD9, 0x17, 0xF8, 0x64, 0xB2, 0xF7, 0x3A, 0xDA, 0xE1, 
+	0x0B, 0x8B, 0x0A, 0xE1, 0x4E, 0xB1, 0x03, 0x46, 0x14, 0xCA, 
+	0x94, 0xE3, 0x44, 0x77, 0xD7, 0x59
+};
+static const int sizeof_server_cert_der_2048 = sizeof(server_cert_der_2048);
+
+#endif /* USE_CERT_BUFFERS_1024 */
+
+/* dh1024 p */
+static const unsigned char dh_p[] =
+{
+    0xE6, 0x96, 0x9D, 0x3D, 0x49, 0x5B, 0xE3, 0x2C, 0x7C, 0xF1, 0x80, 0xC3,
+    0xBD, 0xD4, 0x79, 0x8E, 0x91, 0xB7, 0x81, 0x82, 0x51, 0xBB, 0x05, 0x5E,
+    0x2A, 0x20, 0x64, 0x90, 0x4A, 0x79, 0xA7, 0x70, 0xFA, 0x15, 0xA2, 0x59,
+    0xCB, 0xD5, 0x23, 0xA6, 0xA6, 0xEF, 0x09, 0xC4, 0x30, 0x48, 0xD5, 0xA2,
+    0x2F, 0x97, 0x1F, 0x3C, 0x20, 0x12, 0x9B, 0x48, 0x00, 0x0E, 0x6E, 0xDD,
+    0x06, 0x1C, 0xBC, 0x05, 0x3E, 0x37, 0x1D, 0x79, 0x4E, 0x53, 0x27, 0xDF,
+    0x61, 0x1E, 0xBB, 0xBE, 0x1B, 0xAC, 0x9B, 0x5C, 0x60, 0x44, 0xCF, 0x02,
+    0x3D, 0x76, 0xE0, 0x5E, 0xEA, 0x9B, 0xAD, 0x99, 0x1B, 0x13, 0xA6, 0x3C,
+    0x97, 0x4E, 0x9E, 0xF1, 0x83, 0x9E, 0xB5, 0xDB, 0x12, 0x51, 0x36, 0xF7,
+    0x26, 0x2E, 0x56, 0xA8, 0x87, 0x15, 0x38, 0xDF, 0xD8, 0x23, 0xC6, 0x50,
+    0x50, 0x85, 0xE2, 0x1F, 0x0D, 0xD5, 0xC8, 0x6B,
+};
+
+/* dh1024 g */
+static const unsigned char dh_g[] =
+{
+  0x02,
+};
+
+
+#endif /* WOLFSSL_CERTS_TEST_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/crl.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,52 @@
+/* crl.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef WOLFSSL_CRL_H
+#define WOLFSSL_CRL_H
+
+
+#ifdef HAVE_CRL
+
+#include <wolfssl/ssl.h>
+#include <wolfssl/wolfcrypt/asn.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+typedef struct WOLFSSL_CRL WOLFSSL_CRL;
+
+WOLFSSL_LOCAL int  InitCRL(WOLFSSL_CRL*, WOLFSSL_CERT_MANAGER*);
+WOLFSSL_LOCAL void FreeCRL(WOLFSSL_CRL*, int dynamic);
+
+WOLFSSL_LOCAL int  LoadCRL(WOLFSSL_CRL* crl, const char* path, int type, int mon);
+WOLFSSL_LOCAL int  BufferLoadCRL(WOLFSSL_CRL*, const byte*, long, int);
+WOLFSSL_LOCAL int  CheckCertCRL(WOLFSSL_CRL*, DecodedCert*);
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+#endif /* HAVE_CRL */
+#endif /* WOLFSSL_CRL_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/error-ssl.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,170 @@
+/* error-ssl.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef WOLFSSL_ERROR_H
+#define WOLFSSL_ERROR_H
+
+#include <wolfssl/wolfcrypt/error-crypt.h>   /* pull in wolfCrypt errors */
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+enum wolfSSL_ErrorCodes {
+    INPUT_CASE_ERROR        = -301,        /* process input state error */
+    PREFIX_ERROR            = -302,        /* bad index to key rounds  */
+    MEMORY_ERROR            = -303,        /* out of memory            */
+    VERIFY_FINISHED_ERROR   = -304,        /* verify problem on finished */
+    VERIFY_MAC_ERROR        = -305,        /* verify mac problem       */
+    PARSE_ERROR             = -306,        /* parse error on header    */
+    UNKNOWN_HANDSHAKE_TYPE  = -307,        /* weird handshake type     */
+    SOCKET_ERROR_E          = -308,        /* error state on socket    */
+    SOCKET_NODATA           = -309,        /* expected data, not there */
+    INCOMPLETE_DATA         = -310,        /* don't have enough data to
+                                              complete task            */
+    UNKNOWN_RECORD_TYPE     = -311,        /* unknown type in record hdr */
+    DECRYPT_ERROR           = -312,        /* error during decryption  */
+    FATAL_ERROR             = -313,        /* recvd alert fatal error  */
+    ENCRYPT_ERROR           = -314,        /* error during encryption  */
+    FREAD_ERROR             = -315,        /* fread problem            */
+    NO_PEER_KEY             = -316,        /* need peer's key          */
+    NO_PRIVATE_KEY          = -317,        /* need the private key     */
+    RSA_PRIVATE_ERROR       = -318,        /* error during rsa priv op */
+    NO_DH_PARAMS            = -319,        /* server missing DH params */
+    BUILD_MSG_ERROR         = -320,        /* build message failure    */
+
+    BAD_HELLO               = -321,        /* client hello malformed   */
+    DOMAIN_NAME_MISMATCH    = -322,        /* peer subject name mismatch */
+    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   */
+    BUFFER_ERROR            = -328,        /* malformed buffer input   */
+    VERIFY_CERT_ERROR       = -329,        /* verify cert error        */
+    VERIFY_SIGN_ERROR       = -330,        /* verify sign error        */
+    CLIENT_ID_ERROR         = -331,        /* psk client identity error  */
+    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 ??? */
+    GETITIMER_ERROR         = -338,        /* getitimer failed ??? */
+    SIGACT_ERROR            = -339,        /* sigaction failed ??? */
+    SETITIMER_ERROR         = -340,        /* setitimer failed ??? */
+    LENGTH_ERROR            = -341,        /* record layer length error */
+    PEER_KEY_ERROR          = -342,        /* can't decode peer key */
+    ZERO_RETURN             = -343,        /* peer sent close notify */
+    SIDE_ERROR              = -344,        /* wrong client/server type */
+    NO_PEER_CERT            = -345,        /* peer didn't send key */
+    NTRU_KEY_ERROR          = -346,        /* NTRU key error  */
+    NTRU_DRBG_ERROR         = -347,        /* NTRU drbg error  */
+    NTRU_ENCRYPT_ERROR      = -348,        /* NTRU encrypt error  */
+    NTRU_DECRYPT_ERROR      = -349,        /* NTRU decrypt error  */
+    ECC_CURVETYPE_ERROR     = -350,        /* Bad ECC Curve Type */
+    ECC_CURVE_ERROR         = -351,        /* Bad ECC Curve */
+    ECC_PEERKEY_ERROR       = -352,        /* Bad Peer ECC Key */
+    ECC_MAKEKEY_ERROR       = -353,        /* Bad Make ECC Key */
+    ECC_EXPORT_ERROR        = -354,        /* Bad ECC Export Key */
+    ECC_SHARED_ERROR        = -355,        /* Bad ECC Shared Secret */
+    NOT_CA_ERROR            = -357,        /* Not a CA cert error */
+    BAD_PATH_ERROR          = -358,        /* Bad path for opendir */
+    BAD_CERT_MANAGER_ERROR  = -359,        /* Bad Cert Manager */
+    OCSP_CERT_REVOKED       = -360,        /* OCSP Certificate revoked */
+    CRL_CERT_REVOKED        = -361,        /* CRL Certificate revoked */
+    CRL_MISSING             = -362,        /* CRL Not loaded */
+    MONITOR_RUNNING_E       = -363,        /* CRL Monitor already running */
+    THREAD_CREATE_E         = -364,        /* Thread Create Error */
+    OCSP_NEED_URL           = -365,        /* OCSP need an URL for lookup */
+    OCSP_CERT_UNKNOWN       = -366,        /* OCSP responder doesn't know */
+    OCSP_LOOKUP_FAIL        = -367,        /* OCSP lookup not successful */
+    MAX_CHAIN_ERROR         = -368,        /* max chain depth exceeded */
+    COOKIE_ERROR            = -369,        /* dtls cookie error */
+    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 */
+    SANITY_CIPHER_E         = -375,        /* sanity check on cipher error */
+    RECV_OVERFLOW_E         = -376,        /* RXCB returned more than rqed */
+    GEN_COOKIE_E            = -377,        /* Generate Cookie Error */
+    NO_PEER_VERIFY          = -378,        /* Need peer cert verify Error */
+    FWRITE_ERROR            = -379,        /* fwrite problem */
+    CACHE_MATCH_ERROR       = -380,        /* chache hdr match error */
+    UNKNOWN_SNI_HOST_NAME_E = -381,        /* Unrecognized host name Error */
+    UNKNOWN_MAX_FRAG_LEN_E  = -382,        /* Unrecognized max frag len Error */
+    KEYUSE_SIGNATURE_E      = -383,        /* KeyUse digSignature error */
+    KEYUSE_ENCIPHER_E       = -385,        /* KeyUse keyEncipher error */
+    EXTKEYUSE_AUTH_E        = -386,        /* ExtKeyUse server|client_auth */
+    SEND_OOB_READ_E         = -387,        /* Send Cb out of bounds read */
+    SECURE_RENEGOTIATION_E  = -388,        /* Invalid Renegotiation Info */
+    SESSION_TICKET_LEN_E    = -389,        /* Session Ticket too large */
+    SESSION_TICKET_EXPECT_E = -390,        /* Session Ticket missing   */
+    SCR_DIFFERENT_CERT_E    = -391,        /* SCR Different cert error  */
+    SESSION_SECRET_CB_E     = -392,        /* Session secret Cb fcn failure */
+    NO_CHANGE_CIPHER_E      = -393,        /* Finished before change cipher */
+    SANITY_MSG_E            = -394,        /* Sanity check on msg order error */
+    DUPLICATE_MSG_E         = -395,        /* Duplicate message error */
+    SNI_UNSUPPORTED         = -396,        /* SSL 3.0 does not support SNI */
+    SOCKET_PEER_CLOSED_E    = -397,        /* Underlying transport closed */
+
+    BAD_TICKET_KEY_CB_SZ    = -398,        /* Bad session ticket key cb size */
+    BAD_TICKET_MSG_SZ       = -399,        /* Bad session ticket msg size    */
+    BAD_TICKET_ENCRYPT      = -400,        /* Bad user ticket encrypt        */
+
+    DH_KEY_SIZE_E           = -401,        /* DH Key too small */
+
+    /* add strings to SetErrorString !!!!! */
+
+    /* begin negotiation parameter errors */
+    UNSUPPORTED_SUITE       = -500,        /* unsupported cipher suite */
+    MATCH_SUITE_ERROR       = -501         /* can't match cipher suite */
+    /* end negotiation parameter errors only 10 for now */
+    /* add strings to SetErrorString !!!!! */
+
+    /* no error stings go down here, add above negotiation errors !!!! */
+};
+
+
+#ifdef WOLFSSL_CALLBACKS
+    enum {
+        MIN_PARAM_ERR = UNSUPPORTED_SUITE,
+        MAX_PARAM_ERR = MIN_PARAM_ERR - 10
+    };
+#endif
+
+
+WOLFSSL_LOCAL
+void SetErrorString(int err, char* buff);
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+
+#endif /* wolfSSL_ERROR_H */
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/internal.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,2514 @@
+/* internal.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as 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-1301, USA
+ */
+
+
+#ifndef WOLFSSL_INT_H
+#define WOLFSSL_INT_H
+
+
+#include <wolfssl/wolfcrypt/types.h>
+#include <wolfssl/ssl.h>
+#ifdef HAVE_CRL
+    #include <wolfssl/crl.h>
+#endif
+#include <wolfssl/wolfcrypt/random.h>
+#ifndef NO_DES3
+    #include <wolfssl/wolfcrypt/des3.h>
+#endif
+#ifndef NO_HC128
+    #include <wolfssl/wolfcrypt/hc128.h>
+#endif
+#ifndef NO_RABBIT
+    #include <wolfssl/wolfcrypt/rabbit.h>
+#endif
+#ifdef HAVE_CHACHA
+    #include <wolfssl/wolfcrypt/chacha.h>
+#endif
+#ifndef NO_ASN
+    #include <wolfssl/wolfcrypt/asn.h>
+#endif
+#ifndef NO_MD5
+    #include <wolfssl/wolfcrypt/md5.h>
+#endif
+#ifndef NO_SHA
+    #include <wolfssl/wolfcrypt/sha.h>
+#endif
+#ifndef NO_AES
+    #include <wolfssl/wolfcrypt/aes.h>
+#endif
+#ifdef HAVE_POLY1305
+    #include <wolfssl/wolfcrypt/poly1305.h>
+#endif
+#ifdef HAVE_CAMELLIA
+    #include <wolfssl/wolfcrypt/camellia.h>
+#endif
+#include <wolfssl/wolfcrypt/logging.h>
+#ifndef NO_HMAC
+    #include <wolfssl/wolfcrypt/hmac.h>
+#endif
+#ifndef NO_RC4
+    #include <wolfssl/wolfcrypt/arc4.h>
+#endif
+#ifdef HAVE_ECC
+    #include <wolfssl/wolfcrypt/ecc.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
+
+#include <wolfssl/wolfcrypt/hash.h>
+
+#ifdef WOLFSSL_CALLBACKS
+    #include <wolfssl/callbacks.h>
+    #include <signal.h>
+#endif
+
+#ifdef USE_WINDOWS_API
+    #ifdef WOLFSSL_GAME_BUILD
+        #include "system/xtl.h"
+    #else
+        #if defined(_WIN32_WCE) || defined(WIN32_LEAN_AND_MEAN)
+            /* On WinCE winsock2.h must be included before windows.h */
+            #include <winsock2.h>
+        #endif
+        #include <windows.h>
+    #endif
+#elif defined(THREADX)
+    #ifndef SINGLE_THREADED
+        #include "tx_api.h"
+    #endif
+#elif defined(MICRIUM)
+    /* do nothing, just don't pick Unix */
+#elif defined(FREERTOS) || defined(WOLFSSL_SAFERTOS)
+    /* do nothing */
+#elif defined(EBSNET)
+    /* do nothing */
+#elif defined(FREESCALE_MQX)
+    /* do nothing */
+#elif defined(WOLFSSL_MDK_ARM)
+    #if defined(WOLFSSL_MDK5)
+         #include "cmsis_os.h"
+    #else
+        #include <rtl.h>
+    #endif
+#elif defined(MBED)
+#elif defined(WOLFSSL_TIRTOS)
+    /* do nothing */
+#else
+    #ifndef SINGLE_THREADED
+        #define WOLFSSL_PTHREADS
+        #include <pthread.h>
+    #endif
+    #if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+        #include <unistd.h>      /* for close of BIO */
+    #endif
+#endif
+
+
+#ifdef HAVE_LIBZ
+    #include "zlib.h"
+#endif
+
+#ifdef _MSC_VER
+    /* 4996 warning to use MS extensions e.g., strcpy_s instead of strncpy */
+    #pragma warning(disable: 4996)
+#endif
+
+#ifdef NO_AES
+    #if !defined (ALIGN16)
+        #define ALIGN16
+    #endif
+#endif
+
+#ifdef NO_SHA
+    #define SHA_DIGEST_SIZE 20
+#endif
+
+#ifdef NO_SHA256
+    #define SHA256_DIGEST_SIZE 32
+#endif
+
+#ifdef NO_MD5
+    #define MD5_DIGEST_SIZE 16
+#endif
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#ifdef USE_WINDOWS_API
+    typedef unsigned int SOCKET_T;
+#else
+    typedef int SOCKET_T;
+#endif
+
+
+typedef byte word24[3];
+
+/* Define or comment out the cipher suites you'd like to be compiled in
+   make sure to use at least one BUILD_SSL_xxx or BUILD_TLS_xxx is defined
+
+   When adding cipher suites, add name to cipher_names, idx to cipher_name_idx
+
+   Now that there is a maximum strength crypto build, the following BUILD_XXX
+   flags need to be divided into two groups selected by WOLFSSL_MAX_STRENGTH.
+   Those that do not use Perfect Forward Security and do not use AEAD ciphers
+   need to be switched off. Allowed suites use (EC)DHE, AES-GCM|CCM, or
+   CHACHA-POLY.
+*/
+
+/* Check that if WOLFSSL_MAX_STRENGTH is set that all the required options are
+ * not turned off. */
+#if defined(WOLFSSL_MAX_STRENGTH) && \
+    ((!defined(HAVE_ECC) && (defined(NO_DH) || defined(NO_RSA))) || \
+     (!defined(HAVE_AESGCM) && !defined(HAVE_AESCCM) && \
+      (!defined(HAVE_POLY1305) || !defined(HAVE_CHACHA))) || \
+     (defined(NO_SHA256) && !defined(WOLFSSL_SHA384)) || \
+     !defined(NO_OLD_TLS))
+
+    #error "You are trying to build max strength with requirements disabled."
+#endif
+
+#ifndef WOLFSSL_MAX_STRENGTH
+
+    #if !defined(NO_RSA) && !defined(NO_RC4)
+        #if !defined(NO_SHA)
+            #define BUILD_SSL_RSA_WITH_RC4_128_SHA
+        #endif
+        #if !defined(NO_MD5)
+            #define BUILD_SSL_RSA_WITH_RC4_128_MD5
+        #endif
+        #if !defined(NO_TLS) && defined(HAVE_NTRU) && !defined(NO_SHA)
+            #define BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+        #endif
+    #endif
+
+    #if !defined(NO_RSA) && !defined(NO_DES3)
+        #if !defined(NO_SHA)
+            #define BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+            #if !defined(NO_TLS) && defined(HAVE_NTRU)
+                    #define BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+            #endif
+        #endif
+    #endif
+
+    #if !defined(NO_RSA) && !defined(NO_AES) && !defined(NO_TLS)
+        #if !defined(NO_SHA)
+            #define BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+            #define BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
+            #if defined(HAVE_NTRU)
+                    #define BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+                    #define BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+            #endif
+        #endif
+        #if !defined (NO_SHA256)
+            #define BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256
+            #define BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256
+        #endif
+        #if defined (HAVE_AESGCM)
+            #define BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256
+            #if defined (WOLFSSL_SHA384)
+                #define BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384
+            #endif
+        #endif
+        #if defined (HAVE_AESCCM)
+            #define BUILD_TLS_RSA_WITH_AES_128_CCM_8
+            #define BUILD_TLS_RSA_WITH_AES_256_CCM_8
+        #endif
+        #if defined(HAVE_BLAKE2)
+            #define BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
+            #define BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
+        #endif
+    #endif
+
+    #if defined(HAVE_CAMELLIA) && !defined(NO_TLS)
+        #ifndef NO_RSA
+          #if !defined(NO_SHA)
+            #define BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+            #define BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
+          #endif
+            #ifndef NO_SHA256
+                #define BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
+                #define BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
+            #endif
+            #if !defined(NO_DH)
+              #if !defined(NO_SHA)
+                #define BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+                #define BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+              #endif
+                #ifndef NO_SHA256
+                    #define BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+                    #define BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
+                #endif
+            #endif
+        #endif
+    #endif
+
+    #if !defined(NO_PSK) && !defined(NO_AES) && !defined(NO_TLS)
+        #if !defined(NO_SHA)
+            #define BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
+            #define BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
+        #endif
+        #ifndef NO_SHA256
+            #define BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256
+            #ifdef HAVE_AESGCM
+                #define BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256
+            #endif
+            #ifdef HAVE_AESCCM
+                #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
+                #define BUILD_TLS_PSK_WITH_AES_256_CCM
+            #endif
+        #endif
+        #ifdef WOLFSSL_SHA384
+            #define BUILD_TLS_PSK_WITH_AES_256_CBC_SHA384
+            #ifdef HAVE_AESGCM
+                #define BUILD_TLS_PSK_WITH_AES_256_GCM_SHA384
+            #endif
+        #endif
+    #endif
+
+    #if !defined(NO_TLS) && defined(HAVE_NULL_CIPHER)
+        #if !defined(NO_RSA)
+            #if !defined(NO_SHA)
+                #define BUILD_TLS_RSA_WITH_NULL_SHA
+            #endif
+            #ifndef NO_SHA256
+                #define BUILD_TLS_RSA_WITH_NULL_SHA256
+            #endif
+        #endif
+        #if !defined(NO_PSK)
+            #if !defined(NO_SHA)
+                #define BUILD_TLS_PSK_WITH_NULL_SHA
+            #endif
+            #ifndef NO_SHA256
+                #define BUILD_TLS_PSK_WITH_NULL_SHA256
+            #endif
+            #ifdef WOLFSSL_SHA384
+                #define BUILD_TLS_PSK_WITH_NULL_SHA384
+            #endif
+        #endif
+    #endif
+
+    #if !defined(NO_HC128) && !defined(NO_RSA) && !defined(NO_TLS)
+        #define BUILD_TLS_RSA_WITH_HC_128_MD5
+        #if !defined(NO_SHA)
+            #define BUILD_TLS_RSA_WITH_HC_128_SHA
+        #endif
+        #if defined(HAVE_BLAKE2)
+            #define BUILD_TLS_RSA_WITH_HC_128_B2B256
+        #endif
+    #endif
+
+    #if !defined(NO_RABBIT) && !defined(NO_TLS) && !defined(NO_RSA)
+        #if !defined(NO_SHA)
+            #define BUILD_TLS_RSA_WITH_RABBIT_SHA
+        #endif
+    #endif
+
+    #if !defined(NO_DH) && !defined(NO_AES) && !defined(NO_TLS) && \
+        !defined(NO_RSA)
+
+        #if !defined(NO_SHA)
+            #define BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+            #define BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+        #endif
+        #if !defined(NO_SHA256)
+            #define BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
+            #define BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
+        #endif
+    #endif
+
+    #if defined(HAVE_ANON) && !defined(NO_TLS) && !defined(NO_DH) && \
+        !defined(NO_AES) && !defined(NO_SHA)
+        #define BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA
+    #endif
+
+    #if !defined(NO_DH) && !defined(NO_PSK) && !defined(NO_TLS)
+        #ifndef NO_SHA256
+            #define BUILD_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
+            #ifdef HAVE_NULL_CIPHER
+                #define BUILD_TLS_DHE_PSK_WITH_NULL_SHA256
+            #endif
+        #endif
+        #ifdef WOLFSSL_SHA384
+            #define BUILD_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
+            #ifdef HAVE_NULL_CIPHER
+                #define BUILD_TLS_DHE_PSK_WITH_NULL_SHA384
+            #endif
+        #endif
+    #endif
+
+    #if defined(HAVE_ECC) && !defined(NO_TLS)
+        #if !defined(NO_AES)
+            #if !defined(NO_SHA)
+                #if !defined(NO_RSA)
+                    #define BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+                    #define BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+                    #define BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
+                    #define BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
+                #endif
+
+                #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+                #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+
+                #define BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
+                #define BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
+            #endif /* NO_SHA */
+            #ifndef NO_SHA256
+                #if !defined(NO_RSA)
+                    #define BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+                    #define BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
+                #endif
+                #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+                #define BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
+            #endif
+
+            #ifdef WOLFSSL_SHA384
+                #if !defined(NO_RSA)
+                    #define BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+                    #define BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
+                #endif
+                #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+                #define BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
+            #endif
+
+            #if defined (HAVE_AESGCM)
+                #if !defined(NO_RSA)
+                    #define BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+                    #if defined(WOLFSSL_SHA384)
+                        #define BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+                    #endif
+                #endif
+
+                #define BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+
+                #if defined(WOLFSSL_SHA384)
+                    #define BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+                #endif
+            #endif
+        #endif /* NO_AES */
+        #if !defined(NO_RC4)
+            #if !defined(NO_SHA)
+                #if !defined(NO_RSA)
+                    #define BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
+                    #define BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA
+                #endif
+
+                #define BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+                #define BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
+            #endif
+        #endif
+        #if !defined(NO_DES3)
+            #ifndef NO_SHA
+                #if !defined(NO_RSA)
+                    #define BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+                    #define BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+                #endif
+
+                #define BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+                #define BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
+            #endif /* NO_SHA */
+        #endif
+    #endif
+
+#endif /* !WOLFSSL_MAX_STRENGTH */
+
+#if !defined(NO_DH) && !defined(NO_AES) && !defined(NO_TLS) && \
+    !defined(NO_RSA) && defined(HAVE_AESGCM)
+
+    #ifndef NO_SHA256
+        #define BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+    #endif
+
+    #ifdef WOLFSSL_SHA384
+        #define BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+    #endif
+#endif
+
+#if !defined(NO_DH) && !defined(NO_PSK) && !defined(NO_TLS)
+    #ifndef NO_SHA256
+        #ifdef HAVE_AESGCM
+            #define BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
+        #endif
+        #ifdef HAVE_AESCCM
+            #define BUILD_TLS_DHE_PSK_WITH_AES_128_CCM
+            #define BUILD_TLS_DHE_PSK_WITH_AES_256_CCM
+        #endif
+    #endif
+    #if defined(WOLFSSL_SHA384) && defined(HAVE_AESGCM)
+        #define BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
+    #endif
+#endif
+
+#if defined(HAVE_ECC) && !defined(NO_TLS) && !defined(NO_AES)
+    #ifdef HAVE_AESGCM
+        #ifndef NO_SHA256
+            #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+            #ifndef NO_RSA
+                #define BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+            #endif
+        #endif
+        #ifdef WOLFSSL_SHA384
+            #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+            #ifndef NO_RSA
+                #define BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+            #endif
+        #endif
+    #endif
+    #if defined(HAVE_AESCCM) && !defined(NO_SHA256)
+        #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+        #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
+    #endif
+#endif
+
+#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && !defined(NO_SHA256)
+    #ifdef HAVE_ECC
+        #define BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
+        #ifndef NO_RSA
+            #define BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+        #endif
+    #endif
+    #if !defined(NO_DH) && !defined(NO_RSA)
+        #define BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+    #endif
+#endif
+
+
+#if defined(BUILD_SSL_RSA_WITH_RC4_128_SHA) || \
+    defined(BUILD_SSL_RSA_WITH_RC4_128_MD5)
+    #define BUILD_ARC4
+#endif
+
+#if defined(BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA)
+    #define BUILD_DES3
+#endif
+
+#if defined(BUILD_TLS_RSA_WITH_AES_128_CBC_SHA) || \
+    defined(BUILD_TLS_RSA_WITH_AES_256_CBC_SHA) || \
+    defined(BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
+    #undef  BUILD_AES
+    #define BUILD_AES
+#endif
+
+#if defined(BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256) || \
+    defined(BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256) || \
+    defined(BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) || \
+    defined(BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256)
+    #define BUILD_AESGCM
+#endif
+
+#if defined(BUILD_TLS_RSA_WITH_HC_128_SHA) || \
+    defined(BUILD_TLS_RSA_WITH_HC_128_MD5) || \
+    defined(BUILD_TLS_RSA_WITH_HC_128_B2B256)
+    #define BUILD_HC128
+#endif
+
+#if defined(BUILD_TLS_RSA_WITH_RABBIT_SHA)
+    #define BUILD_RABBIT
+#endif
+
+#ifdef NO_DES3
+    #define DES_BLOCK_SIZE 8
+#else
+    #undef  BUILD_DES3
+    #define BUILD_DES3
+#endif
+
+#ifdef NO_AES
+    #define AES_BLOCK_SIZE 16
+#else
+    #undef  BUILD_AES
+    #define BUILD_AES
+#endif
+
+#ifndef NO_RC4
+    #undef  BUILD_ARC4
+    #define BUILD_ARC4
+#endif
+
+#ifdef HAVE_CHACHA
+    #define CHACHA20_BLOCK_SIZE 16
+#endif
+
+#if defined(WOLFSSL_MAX_STRENGTH) || \
+    defined(HAVE_AESGCM) || defined(HAVE_AESCCM) || \
+    (defined(HAVE_CHACHA) && defined(HAVE_POLY1305))
+
+    #define HAVE_AEAD
+#endif
+
+#if defined(WOLFSSL_MAX_STRENGTH) || \
+    defined(HAVE_ECC) || !defined(NO_DH)
+
+    #define HAVE_PFS
+#endif
+
+
+/* actual cipher values, 2nd byte */
+enum {
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA  = 0x39,
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA  = 0x33,
+    TLS_DH_anon_WITH_AES_128_CBC_SHA  = 0x34,
+    TLS_RSA_WITH_AES_256_CBC_SHA      = 0x35,
+    TLS_RSA_WITH_AES_128_CBC_SHA      = 0x2F,
+    TLS_RSA_WITH_NULL_SHA             = 0x02,
+    TLS_PSK_WITH_AES_256_CBC_SHA      = 0x8d,
+    TLS_PSK_WITH_AES_128_CBC_SHA256   = 0xae,
+    TLS_PSK_WITH_AES_256_CBC_SHA384   = 0xaf,
+    TLS_PSK_WITH_AES_128_CBC_SHA      = 0x8c,
+    TLS_PSK_WITH_NULL_SHA256          = 0xb0,
+    TLS_PSK_WITH_NULL_SHA384          = 0xb1,
+    TLS_PSK_WITH_NULL_SHA             = 0x2c,
+    SSL_RSA_WITH_RC4_128_SHA          = 0x05,
+    SSL_RSA_WITH_RC4_128_MD5          = 0x04,
+    SSL_RSA_WITH_3DES_EDE_CBC_SHA     = 0x0A,
+
+    /* ECC suites, first byte is 0xC0 (ECC_BYTE) */
+    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA    = 0x14,
+    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA    = 0x13,
+    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA  = 0x0A,
+    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA  = 0x09,
+    TLS_ECDHE_RSA_WITH_RC4_128_SHA        = 0x11,
+    TLS_ECDHE_ECDSA_WITH_RC4_128_SHA      = 0x07,
+    TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA   = 0x12,
+    TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0x08,
+    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256   = 0x27,
+    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0x23,
+    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384   = 0x28,
+    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0x24,
+
+    /* static ECDH, first byte is 0xC0 (ECC_BYTE) */
+    TLS_ECDH_RSA_WITH_AES_256_CBC_SHA    = 0x0F,
+    TLS_ECDH_RSA_WITH_AES_128_CBC_SHA    = 0x0E,
+    TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA  = 0x05,
+    TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA  = 0x04,
+    TLS_ECDH_RSA_WITH_RC4_128_SHA        = 0x0C,
+    TLS_ECDH_ECDSA_WITH_RC4_128_SHA      = 0x02,
+    TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA   = 0x0D,
+    TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = 0x03,
+    TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256   = 0x29,
+    TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = 0x25,
+    TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384   = 0x2A,
+    TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = 0x26,
+
+    /* wolfSSL extension - eSTREAM */
+    TLS_RSA_WITH_HC_128_MD5       = 0xFB,
+    TLS_RSA_WITH_HC_128_SHA       = 0xFC,
+    TLS_RSA_WITH_RABBIT_SHA       = 0xFD,
+
+    /* wolfSSL extension - Blake2b 256 */
+    TLS_RSA_WITH_AES_128_CBC_B2B256   = 0xF8,
+    TLS_RSA_WITH_AES_256_CBC_B2B256   = 0xF9,
+    TLS_RSA_WITH_HC_128_B2B256        = 0xFA,   /* eSTREAM too */
+
+    /* wolfSSL extension - NTRU */
+    TLS_NTRU_RSA_WITH_RC4_128_SHA      = 0xe5,
+    TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA = 0xe6,
+    TLS_NTRU_RSA_WITH_AES_128_CBC_SHA  = 0xe7,  /* clashes w/official SHA-256 */
+    TLS_NTRU_RSA_WITH_AES_256_CBC_SHA  = 0xe8,
+
+    /* SHA256 */
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x6b,
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x67,
+    TLS_RSA_WITH_AES_256_CBC_SHA256     = 0x3d,
+    TLS_RSA_WITH_AES_128_CBC_SHA256     = 0x3c,
+    TLS_RSA_WITH_NULL_SHA256            = 0x3b,
+    TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = 0xb2,
+    TLS_DHE_PSK_WITH_NULL_SHA256        = 0xb4,
+
+    /* SHA384 */
+    TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = 0xb3,
+    TLS_DHE_PSK_WITH_NULL_SHA384        = 0xb5,
+
+    /* AES-GCM */
+    TLS_RSA_WITH_AES_128_GCM_SHA256          = 0x9c,
+    TLS_RSA_WITH_AES_256_GCM_SHA384          = 0x9d,
+    TLS_DHE_RSA_WITH_AES_128_GCM_SHA256      = 0x9e,
+    TLS_DHE_RSA_WITH_AES_256_GCM_SHA384      = 0x9f,
+    TLS_PSK_WITH_AES_128_GCM_SHA256          = 0xa8,
+    TLS_PSK_WITH_AES_256_GCM_SHA384          = 0xa9,
+    TLS_DHE_PSK_WITH_AES_128_GCM_SHA256      = 0xaa,
+    TLS_DHE_PSK_WITH_AES_256_GCM_SHA384      = 0xab,
+
+    /* ECC AES-GCM, first byte is 0xC0 (ECC_BYTE) */
+    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256  = 0x2b,
+    TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384  = 0x2c,
+    TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256   = 0x2d,
+    TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384   = 0x2e,
+    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256    = 0x2f,
+    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384    = 0x30,
+    TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256     = 0x31,
+    TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384     = 0x32,
+
+    /* AES-CCM, first byte is 0xC0 but isn't ECC,
+     * also, in some of the other AES-CCM suites
+     * there will be second byte number conflicts
+     * with non-ECC AES-GCM */
+    TLS_RSA_WITH_AES_128_CCM_8         = 0xa0,
+    TLS_RSA_WITH_AES_256_CCM_8         = 0xa1,
+    TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = 0xae,
+    TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 = 0xaf,
+    TLS_PSK_WITH_AES_128_CCM           = 0xa4,
+    TLS_PSK_WITH_AES_256_CCM           = 0xa5,
+    TLS_PSK_WITH_AES_128_CCM_8         = 0xa8,
+    TLS_PSK_WITH_AES_256_CCM_8         = 0xa9,
+    TLS_DHE_PSK_WITH_AES_128_CCM       = 0xa6,
+    TLS_DHE_PSK_WITH_AES_256_CCM       = 0xa7,
+
+    /* Camellia */
+    TLS_RSA_WITH_CAMELLIA_128_CBC_SHA        = 0x41,
+    TLS_RSA_WITH_CAMELLIA_256_CBC_SHA        = 0x84,
+    TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256     = 0xba,
+    TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256     = 0xc0,
+    TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA    = 0x45,
+    TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA    = 0x88,
+    TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xbe,
+    TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0xc4,
+
+    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256   = 0x13,
+    TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0x14,
+    TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256     = 0x15,
+
+    /* Renegotiation Indication Extension Special Suite */
+    TLS_EMPTY_RENEGOTIATION_INFO_SCSV        = 0xff
+};
+
+
+#ifndef WOLFSSL_SESSION_TIMEOUT
+    #define WOLFSSL_SESSION_TIMEOUT 500
+    /* default session resumption cache timeout in seconds */
+#endif
+
+
+enum Misc {
+    ECC_BYTE    =  0xC0,           /* ECC first cipher suite byte */
+    CHACHA_BYTE = 0xCC,            /* ChaCha first cipher suite */
+
+    SEND_CERT       = 1,
+    SEND_BLANK_CERT = 2,
+
+    DTLS_MAJOR      = 0xfe,     /* DTLS major version number */
+    DTLS_MINOR      = 0xff,     /* DTLS minor version number */
+    DTLSv1_2_MINOR  = 0xfd,     /* DTLS minor version number */
+    SSLv3_MAJOR     = 3,        /* SSLv3 and TLSv1+  major version number */
+    SSLv3_MINOR     = 0,        /* TLSv1   minor version number */
+    TLSv1_MINOR     = 1,        /* TLSv1   minor version number */
+    TLSv1_1_MINOR   = 2,        /* TLSv1_1 minor version number */
+    TLSv1_2_MINOR   = 3,        /* TLSv1_2 minor version number */
+    OLD_HELLO_ID    = 0x01,     /* SSLv2 Client Hello Indicator */
+    INVALID_BYTE    = 0xff,     /* Used to initialize cipher specs values */
+    NO_COMPRESSION  =  0,
+    ZLIB_COMPRESSION = 221,     /* wolfSSL zlib compression */
+    HELLO_EXT_SIG_ALGO = 13,    /* ID for the sig_algo hello extension */
+    SECRET_LEN      = 48,       /* pre RSA and all master */
+    ENCRYPT_LEN     = 512,      /* allow 4096 bit static buffer */
+    SIZEOF_SENDER   =  4,       /* clnt or srvr           */
+    FINISHED_SZ     = 36,       /* MD5_DIGEST_SIZE + SHA_DIGEST_SIZE */
+    MAX_RECORD_SIZE = 16384,    /* 2^14, max size by standard */
+    MAX_MSG_EXTRA   = 38 + MAX_DIGEST_SIZE,
+                                /* max added to msg, mac + pad  from */
+                                /* RECORD_HEADER_SZ + BLOCK_SZ (pad) + Max
+                                   digest sz + BLOC_SZ (iv) + pad byte (1) */
+    MAX_COMP_EXTRA  = 1024,     /* max compression extra */
+    MAX_MTU         = 1500,     /* 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_STR_VERSION = 8,        /* string rep of protocol version */
+
+    PAD_MD5        = 48,       /* pad length for finished */
+    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 */
+    SEQ_SZ         =  8,       /* 64 bit sequence number  */
+    BYTE3_LEN      =  3,       /* up to 24 bit byte lengths */
+    ALERT_SIZE     =  2,       /* level + description     */
+    VERIFY_HEADER  =  2,       /* always use 2 bytes      */
+    EXT_ID_SZ      =  2,       /* always use 2 bytes      */
+    MAX_DH_SIZE    = 513,      /* 4096 bit plus possible leading 0 */
+    SESSION_HINT_SZ = 4,       /* session timeout hint */
+
+    MAX_SUITE_SZ = 200,        /* 100 suites for now! */
+    RAN_LEN      = 32,         /* random length           */
+    SEED_LEN     = RAN_LEN * 2, /* tls prf seed length    */
+    ID_LEN       = 32,         /* session id length       */
+    MAX_COOKIE_LEN = 32,       /* max dtls cookie size    */
+    COOKIE_SZ    = 20,         /* use a 20 byte cookie    */
+    SUITE_LEN    =  2,         /* cipher suite sz length  */
+    ENUM_LEN     =  1,         /* always a byte           */
+    OPAQUE8_LEN  =  1,         /* 1 byte                  */
+    OPAQUE16_LEN =  2,         /* 2 bytes                 */
+    OPAQUE24_LEN =  3,         /* 3 bytes                 */
+    OPAQUE32_LEN =  4,         /* 4 bytes                 */
+    COMP_LEN     =  1,         /* compression length      */
+    CURVE_LEN    =  2,         /* ecc named curve length  */
+    SERVER_ID_LEN = 20,        /* server session id length  */
+    
+    HANDSHAKE_HEADER_SZ   = 4,  /* type + length(3)        */
+    RECORD_HEADER_SZ      = 5,  /* type + version + len(2) */
+    CERT_HEADER_SZ        = 3,  /* always 3 bytes          */
+    REQ_HEADER_SZ         = 2,  /* cert request header sz  */
+    HINT_LEN_SZ           = 2,  /* length of hint size field */
+    TRUNCATED_HMAC_SZ     = 10, /* length of hmac w/ truncated hmac extension */
+    HELLO_EXT_TYPE_SZ     = 2,  /* length of a hello extension type */
+    HELLO_EXT_SZ          = 8,  /* total length of the lazy hello extensions */
+    HELLO_EXT_LEN         = 6,  /* length of the lazy hello extensions */
+    HELLO_EXT_SIGALGO_SZ  = 2,  /* length of signature algo extension  */
+    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) */
+    DTLS_RECORD_HEADER_SZ    = 13, /* normal + epoch(2) + seq_num(6) */
+    DTLS_HANDSHAKE_EXTRA     = 8,  /* diff from normal */
+    DTLS_RECORD_EXTRA        = 8,  /* diff from normal */
+    DTLS_HANDSHAKE_SEQ_SZ    = 2,  /* handshake header sequence number */
+    DTLS_HANDSHAKE_FRAG_SZ   = 3,  /* fragment offset and length are 24 bit */
+    DTLS_POOL_SZ             = 5,  /* buffers to hold in the retry pool */
+
+    FINISHED_LABEL_SZ   = 15,  /* TLS finished label size */
+    TLS_FINISHED_SZ     = 12,  /* TLS has a shorter size  */
+    MASTER_LABEL_SZ     = 13,  /* TLS master secret label sz */
+    KEY_LABEL_SZ        = 13,  /* TLS key block expansion sz */
+    MAX_PRF_HALF        = 256, /* Maximum half secret len */
+    MAX_PRF_LABSEED     = 128, /* Maximum label + seed len */
+    MAX_PRF_DIG         = 224, /* Maximum digest len      */
+    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             */
+
+    AEAD_SEQ_OFFSET     = 4,        /* Auth Data: Sequence number */
+    AEAD_TYPE_OFFSET    = 8,        /* Auth Data: Type            */
+    AEAD_VMAJ_OFFSET    = 9,        /* Auth Data: Major Version   */
+    AEAD_VMIN_OFFSET    = 10,       /* Auth Data: Minor Version   */
+    AEAD_LEN_OFFSET     = 11,       /* Auth Data: Length          */
+    AEAD_AUTH_DATA_SZ   = 13,       /* Size of the data to authenticate */
+    AEAD_IMP_IV_SZ      = 4,        /* Size of the implicit IV     */
+    AEAD_EXP_IV_SZ      = 8,        /* Size of the explicit IV     */
+    AEAD_NONCE_SZ       = AEAD_EXP_IV_SZ + AEAD_IMP_IV_SZ,
+
+    AES_GCM_AUTH_SZ     = 16, /* AES-GCM Auth Tag length    */
+    AES_CCM_16_AUTH_SZ  = 16, /* AES-CCM-16 Auth Tag length */
+    AES_CCM_8_AUTH_SZ   = 8,  /* AES-CCM-8 Auth Tag Length  */
+
+    CAMELLIA_128_KEY_SIZE = 16, /* for 128 bit */
+    CAMELLIA_192_KEY_SIZE = 24, /* for 192 bit */
+    CAMELLIA_256_KEY_SIZE = 32, /* for 256 bit */
+    CAMELLIA_IV_SIZE      = 16, /* always block size */
+
+    CHACHA20_256_KEY_SIZE = 32,  /* for 256 bit             */
+    CHACHA20_128_KEY_SIZE = 16,  /* for 128 bit             */
+    CHACHA20_IV_SIZE      =  8,  /* 64 bits for iv          */
+
+    POLY1305_AUTH_SZ    = 16,  /* 128 bits                */
+
+    HC_128_KEY_SIZE     = 16,  /* 128 bits                */
+    HC_128_IV_SIZE      = 16,  /* also 128 bits           */
+
+    RABBIT_KEY_SIZE     = 16,  /* 128 bits                */
+    RABBIT_IV_SIZE      =  8,  /* 64 bits for iv          */
+
+    EVP_SALT_SIZE       =  8,  /* evp salt size 64 bits   */
+
+    ECDHE_SIZE          = 32,  /* ECHDE server size defaults to 256 bit */
+    MAX_EXPORT_ECC_SZ   = 256, /* Export ANS X9.62 max future size */
+
+    MAX_HELLO_SZ       = 128,  /* max client or server hello */
+    MAX_CERT_VERIFY_SZ = 1024, /* max   */
+    CLIENT_HELLO_FIRST =  35,  /* Protocol + RAN_LEN + sizeof(id_len) */
+    MAX_SUITE_NAME     =  48,  /* maximum length of cipher suite string */
+
+    DTLS_TIMEOUT_INIT       =  1, /* default timeout init for DTLS receive  */
+    DTLS_TIMEOUT_MAX        = 64, /* default max timeout for DTLS receive */
+    DTLS_TIMEOUT_MULTIPLIER =  2, /* default timeout multiplier for DTLS recv */
+
+    MAX_PSK_ID_LEN     = 128,  /* max psk identity/hint supported */
+    MAX_PSK_KEY_LEN    =  64,  /* max psk key supported */
+
+    MAX_WOLFSSL_FILE_SIZE = 1024 * 1024 * 4,  /* 4 mb file size alloc limit */
+
+#ifdef FORTRESS
+    MAX_EX_DATA        =   3,  /* allow for three items of ex_data */
+#endif
+
+    MAX_X509_SIZE      = 2048, /* max static x509 buffer size */
+    CERT_MIN_SIZE      =  256, /* min PEM cert size with header/footer */
+    MAX_FILENAME_SZ    =  256, /* max file name length */
+    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 */
+    MAX_NTRU_ENCRYPT_SZ = 1027, /* NTRU max for now */
+    MAX_NTRU_BITS       =  256, /* max symmetric bit strength */
+    NO_SNIFF           =   0,  /* not sniffing */
+    SNIFF              =   1,  /* currently sniffing */
+
+    HASH_SIG_SIZE      =   2,  /* default SHA1 RSA */
+
+    NO_CAVIUM_DEVICE   =  -2,  /* invalid cavium device id */
+
+    NO_COPY            =   0,  /* should we copy static buffer for write */
+    COPY               =   1   /* should we copy static buffer for write */
+};
+
+
+#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 */
+#define SESSIDX_ROW_SHIFT 4
+#define SESSIDX_IDX_MASK  0x0F
+#endif
+
+
+/* max cert chain peer depth */
+#ifndef MAX_CHAIN_DEPTH
+    #define MAX_CHAIN_DEPTH 9
+#endif
+
+#ifndef SESSION_TICKET_LEN
+    #define SESSION_TICKET_LEN 256
+#endif
+
+#ifndef SESSION_TICKET_HINT_DEFAULT
+    #define SESSION_TICKET_HINT_DEFAULT 300
+#endif
+
+
+/* don't use extra 3/4k stack space unless need to */
+#ifdef HAVE_NTRU
+    #define MAX_ENCRYPT_SZ MAX_NTRU_ENCRYPT_SZ
+#else
+    #define MAX_ENCRYPT_SZ ENCRYPT_LEN
+#endif
+
+
+/* states */
+enum states {
+    NULL_STATE = 0,
+
+    SERVER_HELLOVERIFYREQUEST_COMPLETE,
+    SERVER_HELLO_COMPLETE,
+    SERVER_CERT_COMPLETE,
+    SERVER_KEYEXCHANGE_COMPLETE,
+    SERVER_HELLODONE_COMPLETE,
+    SERVER_FINISHED_COMPLETE,
+
+    CLIENT_HELLO_COMPLETE,
+    CLIENT_KEYEXCHANGE_COMPLETE,
+    CLIENT_FINISHED_COMPLETE,
+
+    HANDSHAKE_DONE
+};
+
+
+#if defined(__GNUC__)
+    #define WOLFSSL_PACK __attribute__ ((packed))
+#else
+    #define WOLFSSL_PACK
+#endif
+
+/* SSL Version */
+typedef struct ProtocolVersion {
+    byte major;
+    byte minor;
+} WOLFSSL_PACK ProtocolVersion;
+
+
+WOLFSSL_LOCAL ProtocolVersion MakeSSLv3(void);
+WOLFSSL_LOCAL ProtocolVersion MakeTLSv1(void);
+WOLFSSL_LOCAL ProtocolVersion MakeTLSv1_1(void);
+WOLFSSL_LOCAL ProtocolVersion MakeTLSv1_2(void);
+
+#ifdef WOLFSSL_DTLS
+    WOLFSSL_LOCAL ProtocolVersion MakeDTLSv1(void);
+    WOLFSSL_LOCAL ProtocolVersion MakeDTLSv1_2(void);
+#endif
+
+
+enum BIO_TYPE {
+    BIO_BUFFER = 1,
+    BIO_SOCKET = 2,
+    BIO_SSL    = 3,
+    BIO_MEMORY = 4
+};
+
+
+/* wolfSSL BIO_METHOD type */
+struct WOLFSSL_BIO_METHOD {
+    byte type;               /* method type */
+};
+
+
+/* wolfSSL BIO type */
+struct WOLFSSL_BIO {
+    byte        type;          /* method type */
+    byte        close;         /* close flag */
+    byte        eof;           /* eof flag */
+    WOLFSSL*     ssl;           /* possible associated ssl */
+    byte*       mem;           /* memory buffer */
+    int         memLen;        /* memory buffer length */
+    int         fd;            /* possible file descriptor */
+    WOLFSSL_BIO* prev;          /* previous in chain */
+    WOLFSSL_BIO* next;          /* next in chain */
+};
+
+
+/* wolfSSL method type */
+struct WOLFSSL_METHOD {
+    ProtocolVersion version;
+    byte            side;         /* connection side, server or client */
+    byte            downgrade;    /* whether to downgrade version, default no */
+};
+
+
+/* defautls to client */
+WOLFSSL_LOCAL void InitSSL_Method(WOLFSSL_METHOD*, ProtocolVersion);
+
+/* for sniffer */
+WOLFSSL_LOCAL int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
+                            word32 size, word32 totalSz, int sniff);
+WOLFSSL_LOCAL int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx);
+
+
+/* wolfSSL buffer type */
+typedef struct buffer {
+    byte*  buffer;
+    word32 length;
+} buffer;
+
+
+enum {
+    FORCED_FREE = 1,
+    NO_FORCED_FREE = 0
+};
+
+
+/* only use compression extra if using compression */
+#ifdef HAVE_LIBZ
+    #define COMP_EXTRA MAX_COMP_EXTRA
+#else
+    #define COMP_EXTRA 0
+#endif
+
+/* only the sniffer needs space in the buffer for extra MTU record(s) */
+#ifdef WOLFSSL_SNIFFER
+    #define MTU_EXTRA MAX_MTU * 3 
+#else
+    #define MTU_EXTRA 0
+#endif
+
+
+/* embedded callbacks require large static buffers, make sure on */
+#ifdef WOLFSSL_CALLBACKS
+    #undef  LARGE_STATIC_BUFFERS
+    #define LARGE_STATIC_BUFFERS
+#endif
+
+
+/* give user option to use 16K static buffers */
+#if defined(LARGE_STATIC_BUFFERS)
+    #define RECORD_SIZE MAX_RECORD_SIZE
+#else
+    #ifdef WOLFSSL_DTLS
+        #define RECORD_SIZE MAX_MTU 
+    #else
+        #define RECORD_SIZE 128 
+    #endif
+#endif
+
+
+/* user option to turn off 16K output option */
+/* if using small static buffers (default) and SSL_write tries to write data
+   larger than the record we have, dynamically get it, unless user says only
+   write in static buffer chuncks  */
+#ifndef STATIC_CHUNKS_ONLY
+    #define OUTPUT_RECORD_SIZE MAX_RECORD_SIZE
+#else
+    #define OUTPUT_RECORD_SIZE RECORD_SIZE
+#endif
+
+/* wolfSSL input buffer
+
+   RFC 2246:
+
+   length
+       The length (in bytes) of the following TLSPlaintext.fragment.
+       The length should not exceed 2^14.
+*/
+#if defined(LARGE_STATIC_BUFFERS)
+    #define STATIC_BUFFER_LEN RECORD_HEADER_SZ + RECORD_SIZE + COMP_EXTRA + \
+             MTU_EXTRA + MAX_MSG_EXTRA
+#else
+    /* don't fragment memory from the record header */
+    #define STATIC_BUFFER_LEN RECORD_HEADER_SZ
+#endif
+
+typedef struct {
+    ALIGN16 byte staticBuffer[STATIC_BUFFER_LEN];
+    byte*  buffer;       /* place holder for static or dynamic buffer */
+    word32 length;       /* total buffer length used */
+    word32 idx;          /* idx to part of length already consumed */
+    word32 bufferSize;   /* current buffer size */
+    byte   dynamicFlag;  /* dynamic memory currently in use */
+    byte   offset;       /* alignment offset attempt */
+} bufferStatic;
+
+/* Cipher Suites holder */
+typedef struct Suites {
+    word16 suiteSz;                 /* suite length in bytes        */
+    word16 hashSigAlgoSz;           /* SigAlgo extension length in bytes */
+    byte   suites[MAX_SUITE_SZ];
+    byte   hashSigAlgo[HELLO_EXT_SIGALGO_MAX]; /* sig/algo to offer */
+    byte   setSuites;               /* user set suites from default */
+    byte   hashAlgo;                /* selected hash algorithm */
+    byte   sigAlgo;                 /* selected sig algorithm */
+} Suites;
+
+
+WOLFSSL_LOCAL
+void InitSuites(Suites*, ProtocolVersion, word16, word16, word16, word16,
+                word16, word16, int);
+WOLFSSL_LOCAL
+int  SetCipherList(Suites*, const char* list);
+
+#ifndef PSK_TYPES_DEFINED
+    typedef unsigned int (*psk_client_callback)(WOLFSSL*, const char*, char*,
+                          unsigned int, unsigned char*, unsigned int);
+    typedef unsigned int (*psk_server_callback)(WOLFSSL*, const char*,
+                          unsigned char*, unsigned int);
+#endif /* PSK_TYPES_DEFINED */
+
+
+#ifdef HAVE_NETX
+    WOLFSSL_LOCAL int NetX_Receive(WOLFSSL *ssl, char *buf, int sz, void *ctx);
+    WOLFSSL_LOCAL int NetX_Send(WOLFSSL *ssl, char *buf, int sz, void *ctx);
+#endif /* HAVE_NETX */
+
+
+/* wolfSSL Cipher type just points back to SSL */
+struct WOLFSSL_CIPHER {
+    WOLFSSL* ssl;
+};
+
+
+typedef struct OCSP_Entry OCSP_Entry;
+
+#ifdef NO_SHA
+    #define OCSP_DIGEST_SIZE SHA256_DIGEST_SIZE
+#else
+    #define OCSP_DIGEST_SIZE SHA_DIGEST_SIZE
+#endif
+
+#ifdef NO_ASN 
+    /* no_asn won't have */
+    typedef struct CertStatus CertStatus;
+#endif
+
+struct OCSP_Entry {
+    OCSP_Entry* next;                        /* next entry             */
+    byte    issuerHash[OCSP_DIGEST_SIZE];    /* issuer hash            */ 
+    byte    issuerKeyHash[OCSP_DIGEST_SIZE]; /* issuer public key hash */
+    CertStatus* status;                      /* OCSP response list     */
+    int         totalStatus;                 /* number on list         */
+};
+
+
+#ifndef HAVE_OCSP
+    typedef struct WOLFSSL_OCSP WOLFSSL_OCSP;
+#endif
+
+/* wolfSSL OCSP controller */
+struct WOLFSSL_OCSP {
+    WOLFSSL_CERT_MANAGER* cm;            /* pointer back to cert manager */
+    OCSP_Entry*          ocspList;      /* OCSP response list */
+    wolfSSL_Mutex         ocspLock;      /* OCSP list lock */
+};
+
+#ifndef MAX_DATE_SIZE
+#define MAX_DATE_SIZE 32
+#endif
+
+typedef struct CRL_Entry CRL_Entry;
+
+#ifdef NO_SHA
+    #define CRL_DIGEST_SIZE SHA256_DIGEST_SIZE
+#else
+    #define CRL_DIGEST_SIZE SHA_DIGEST_SIZE
+#endif
+
+#ifdef NO_ASN 
+    typedef struct RevokedCert RevokedCert;
+#endif
+
+/* Complete CRL */
+struct CRL_Entry {
+    CRL_Entry* next;                      /* next entry */
+    byte    issuerHash[CRL_DIGEST_SIZE];  /* issuer hash                 */ 
+    /* byte    crlHash[CRL_DIGEST_SIZE];      raw crl data hash           */ 
+    /* restore the hash here if needed for optimized comparisons */
+    byte    lastDate[MAX_DATE_SIZE]; /* last date updated  */
+    byte    nextDate[MAX_DATE_SIZE]; /* next update date   */
+    byte    lastDateFormat;          /* last date format */
+    byte    nextDateFormat;          /* next date format */
+    RevokedCert* certs;              /* revoked cert list  */
+    int          totalCerts;         /* number on list     */
+};
+
+
+typedef struct CRL_Monitor CRL_Monitor;
+
+/* CRL directory monitor */
+struct CRL_Monitor {
+    char* path;      /* full dir path, if valid pointer we're using */
+    int   type;      /* PEM or ASN1 type */
+};
+
+
+#ifndef HAVE_CRL
+    typedef struct WOLFSSL_CRL WOLFSSL_CRL;
+#endif
+
+/* wolfSSL CRL controller */
+struct WOLFSSL_CRL {
+    WOLFSSL_CERT_MANAGER* cm;            /* pointer back to cert manager */
+    CRL_Entry*           crlList;       /* our CRL list */
+    wolfSSL_Mutex         crlLock;       /* CRL list lock */
+    CRL_Monitor          monitors[2];   /* PEM and DER possible */
+#ifdef HAVE_CRL_MONITOR
+    pthread_t            tid;           /* monitoring thread */
+    int                  mfd;           /* monitor fd, -1 if no init yet */
+#endif
+};
+
+
+#ifdef NO_ASN 
+    typedef struct Signer Signer;
+#endif
+
+
+#ifndef CA_TABLE_SIZE
+    #define CA_TABLE_SIZE 11
+#endif
+
+/* wolfSSL Certificate Manager */
+struct WOLFSSL_CERT_MANAGER {
+    Signer*         caTable[CA_TABLE_SIZE]; /* the CA signer table */
+    void*           heap;               /* heap helper */
+    WOLFSSL_CRL*    crl;                /* CRL checker */
+    WOLFSSL_OCSP*   ocsp;               /* OCSP checker */
+    char*           ocspOverrideURL;    /* use this responder */
+    void*           ocspIOCtx;          /* I/O callback CTX */
+    CallbackCACache caCacheCallback;    /* CA cache addition callback */
+    CbMissingCRL    cbMissingCRL;       /* notify through cb of missing crl */
+    CbOCSPIO        ocspIOCb;           /* I/O callback for OCSP lookup */
+    CbOCSPRespFree  ocspRespFreeCb;     /* Frees OCSP Response from IO Cb */
+    wolfSSL_Mutex   caLock;             /* CA list lock */
+    byte            crlEnabled;         /* is CRL on ? */
+    byte            crlCheckAll;        /* always leaf, but all ? */
+    byte            ocspEnabled;        /* is OCSP on ? */
+    byte            ocspCheckAll;       /* always leaf, but all ? */
+    byte            ocspSendNonce;      /* send the OCSP nonce ? */
+    byte            ocspUseOverrideURL; /* ignore cert's responder, override */
+};
+
+WOLFSSL_LOCAL int CM_SaveCertCache(WOLFSSL_CERT_MANAGER*, const char*);
+WOLFSSL_LOCAL int CM_RestoreCertCache(WOLFSSL_CERT_MANAGER*, const char*);
+WOLFSSL_LOCAL int CM_MemSaveCertCache(WOLFSSL_CERT_MANAGER*, void*, int, int*);
+WOLFSSL_LOCAL int CM_MemRestoreCertCache(WOLFSSL_CERT_MANAGER*, const void*, int);
+WOLFSSL_LOCAL int CM_GetCertCacheMemSize(WOLFSSL_CERT_MANAGER*);
+
+/* wolfSSL Sock Addr */
+struct WOLFSSL_SOCKADDR {
+    unsigned int sz; /* sockaddr size */
+    void*        sa; /* pointer to the sockaddr_in or sockaddr_in6 */
+};
+
+typedef struct WOLFSSL_DTLS_CTX {
+    WOLFSSL_SOCKADDR peer;
+    int fd;
+} WOLFSSL_DTLS_CTX;
+
+
+#ifdef WOLFSSL_DTLS
+
+    #ifdef WORD64_AVAILABLE
+        typedef word64 DtlsSeq;
+    #else
+        typedef word32 DtlsSeq;
+    #endif
+    #define DTLS_SEQ_BITS (sizeof(DtlsSeq) * CHAR_BIT)
+
+    typedef struct DtlsState {
+        DtlsSeq window;     /* Sliding window for current epoch    */
+        word16 nextEpoch;   /* Expected epoch in next record       */
+        word32 nextSeq;     /* Expected sequence in next record    */
+
+        word16 curEpoch;    /* Received epoch in current record    */
+        word32 curSeq;      /* Received sequence in current record */
+
+        DtlsSeq prevWindow; /* Sliding window for old epoch        */
+        word32 prevSeq;     /* Next sequence in allowed old epoch  */
+    } DtlsState;
+
+#endif /* WOLFSSL_DTLS */
+
+
+/* keys and secrets */
+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];
+    byte client_write_IV[AES_IV_SIZE];               /* max sizes */
+    byte server_write_IV[AES_IV_SIZE];
+#ifdef HAVE_AEAD
+    byte aead_exp_IV[AEAD_EXP_IV_SZ];
+    byte aead_enc_imp_IV[AEAD_IMP_IV_SZ];
+    byte aead_dec_imp_IV[AEAD_IMP_IV_SZ];
+#endif
+
+    word32 peer_sequence_number;
+    word32 sequence_number;
+
+#ifdef WOLFSSL_DTLS
+    DtlsState dtls_state;                       /* Peer's state */
+    word16 dtls_peer_handshake_number;
+    word16 dtls_expected_peer_handshake_number;
+
+    word16 dtls_epoch;                          /* Current tx epoch    */
+    word32 dtls_sequence_number;                /* Current tx sequence */
+    word16 dtls_handshake_number;               /* Current tx handshake seq */
+#endif
+
+    word32 encryptSz;             /* last size of encrypted data   */
+    word32 padSz;                 /* how much to advance after decrypt part */
+    byte   encryptionOn;          /* true after change cipher spec */
+    byte   decryptedCur;          /* only decrypt current record once */
+} Keys;
+
+
+
+/* RFC 6066 TLS Extensions */
+#ifdef HAVE_TLS_EXTENSIONS
+
+typedef enum {
+    SERVER_NAME_INDICATION = 0x0000,
+    MAX_FRAGMENT_LENGTH    = 0x0001,
+    TRUNCATED_HMAC         = 0x0004,
+    ELLIPTIC_CURVES        = 0x000a,
+    SESSION_TICKET         = 0x0023,
+    SECURE_RENEGOTIATION   = 0xff01
+} TLSX_Type;
+
+typedef struct TLSX {
+    TLSX_Type    type; /* Extension Type  */
+    void*        data; /* Extension Data  */
+    byte         resp; /* IsResponse Flag */
+    struct TLSX* next; /* List Behavior   */
+} TLSX;
+
+WOLFSSL_LOCAL TLSX*  TLSX_Find(TLSX* list, TLSX_Type type);
+WOLFSSL_LOCAL void   TLSX_FreeAll(TLSX* list);
+WOLFSSL_LOCAL int    TLSX_SupportExtensions(WOLFSSL* ssl);
+
+#ifndef NO_WOLFSSL_CLIENT
+WOLFSSL_LOCAL word16 TLSX_GetRequestSize(WOLFSSL* ssl);
+WOLFSSL_LOCAL word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output);
+#endif
+
+#ifndef NO_WOLFSSL_SERVER
+WOLFSSL_LOCAL word16 TLSX_GetResponseSize(WOLFSSL* ssl);
+WOLFSSL_LOCAL word16 TLSX_WriteResponse(WOLFSSL* ssl, byte* output);
+#endif
+
+WOLFSSL_LOCAL int    TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length,
+                                                byte isRequest, Suites *suites);
+                                                
+#elif defined(HAVE_SNI)                  \
+   || defined(HAVE_MAX_FRAGMENT)         \
+   || defined(HAVE_TRUNCATED_HMAC)       \
+   || defined(HAVE_SUPPORTED_CURVES)     \
+   || defined(HAVE_SECURE_RENEGOTIATION) \
+   || defined(HAVE_SESSION_TICKET)
+
+#error Using TLS extensions requires HAVE_TLS_EXTENSIONS to be defined.
+
+#endif /* HAVE_TLS_EXTENSIONS */
+
+/* Server Name Indication */
+#ifdef HAVE_SNI
+
+typedef struct SNI {
+    byte                       type;    /* SNI Type          */
+    union { char* host_name; } data;    /* SNI Data          */
+    struct SNI*                next;    /* List Behavior     */
+#ifndef NO_WOLFSSL_SERVER
+    byte                       options; /* Behaviour options */
+    byte                       status;  /* Matching result   */
+#endif
+} SNI;
+
+WOLFSSL_LOCAL int TLSX_UseSNI(TLSX** extensions, byte type, const void* data,
+                                                                   word16 size);
+
+#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);
+#endif
+
+#endif /* HAVE_SNI */
+
+/* Maximum Fragment Length */
+#ifdef HAVE_MAX_FRAGMENT
+
+WOLFSSL_LOCAL int TLSX_UseMaxFragment(TLSX** extensions, byte mfl);
+
+#endif /* HAVE_MAX_FRAGMENT */
+
+#ifdef HAVE_TRUNCATED_HMAC
+
+WOLFSSL_LOCAL int TLSX_UseTruncatedHMAC(TLSX** extensions);
+
+#endif /* HAVE_TRUNCATED_HMAC */
+
+#ifdef HAVE_SUPPORTED_CURVES
+
+typedef struct EllipticCurve {
+    word16                name; /* CurveNames    */
+    struct EllipticCurve* next; /* List Behavior */
+} EllipticCurve;
+
+WOLFSSL_LOCAL int TLSX_UseSupportedCurve(TLSX** extensions, word16 name);
+
+#ifndef NO_WOLFSSL_SERVER
+WOLFSSL_LOCAL int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first,
+                                                                   byte second);
+#endif
+
+#endif /* HAVE_SUPPORTED_CURVES */
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+
+enum key_cache_state {
+    SCR_CACHE_NULL   = 0,       /* empty / begin state */
+    SCR_CACHE_NEEDED,           /* need to cache keys */
+    SCR_CACHE_COPY,             /* we have a cached copy */
+    SCR_CACHE_PARTIAL,          /* partial restore to real keys */
+    SCR_CACHE_COMPLETE          /* complete restore to real keys */
+};
+
+
+/* Additional Conection State according to rfc5746 section 3.1 */
+typedef struct SecureRenegotiation {
+   byte                 enabled;  /* secure_renegotiation flag in rfc */
+   byte                 startScr; /* server requested client to start scr */
+   enum key_cache_state cache_status;  /* track key cache state */
+   byte                 client_verify_data[TLS_FINISHED_SZ];  /* cached */
+   byte                 server_verify_data[TLS_FINISHED_SZ];  /* cached */
+   byte                 subject_hash[SHA_DIGEST_SIZE];  /* peer cert hash */
+   Keys                 tmp_keys;  /* can't overwrite real keys yet */
+} SecureRenegotiation;
+
+WOLFSSL_LOCAL int TLSX_UseSecureRenegotiation(TLSX** extensions);
+
+#endif /* HAVE_SECURE_RENEGOTIATION */
+
+#ifdef HAVE_SESSION_TICKET
+
+typedef struct SessionTicket {
+    word32 lifetime;
+    byte*  data;
+    word16 size;
+} SessionTicket;
+
+WOLFSSL_LOCAL int  TLSX_UseSessionTicket(TLSX** extensions, 
+                                                         SessionTicket* ticket);
+WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime,
+                                                       byte* data, word16 size);
+WOLFSSL_LOCAL void TLSX_SessionTicket_Free(SessionTicket* ticket);
+#endif /* HAVE_SESSION_TICKET */
+
+/* wolfSSL context type */
+struct WOLFSSL_CTX {
+    WOLFSSL_METHOD* method;
+    wolfSSL_Mutex   countMutex;    /* reference count mutex */
+    int         refCount;         /* reference count */
+#ifndef NO_DH
+    buffer      serverDH_P;
+    buffer      serverDH_G;
+#endif
+#ifndef NO_CERTS
+    buffer      certificate;
+    buffer      certChain;
+                 /* chain after self, in DER, with leading size for each cert */
+    buffer      privateKey;
+    WOLFSSL_CERT_MANAGER* cm;      /* our cert manager, ctx owns SSL will use */
+#endif
+    Suites*     suites;           /* make dynamic, user may not need/set */
+    void*       heap;             /* for user memory overrides */
+    byte        verifyPeer;
+    byte        verifyNone;
+    byte        failNoCert;
+    byte        sessionCacheOff;
+    byte        sessionCacheFlushOff;
+    byte        sendVerify;       /* for client side */
+    byte        haveRSA;          /* RSA 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        minDowngrade;     /* minimum downgrade version */
+#ifndef NO_DH
+    word16      minDhKeySz;       /* minimum DH key size */
+#endif
+    CallbackIORecv CBIORecv;
+    CallbackIOSend CBIOSend;
+#ifdef WOLFSSL_DTLS
+    CallbackGenCookie CBIOCookie;       /* gen cookie callback */
+#endif
+    VerifyCallback  verifyCallback;     /* cert verification callback */
+    word32          timeout;            /* session timeout */
+#ifdef HAVE_ECC
+    word16          eccTempKeySz;       /* in octets 20 - 66 */
+    word32          pkCurveOID;         /* curve Ecc_Sum */
+#endif
+#ifndef NO_PSK
+    byte        havePSK;                /* psk key set by user */
+    psk_client_callback client_psk_cb;  /* client callback */
+    psk_server_callback server_psk_cb;  /* server callback */
+    char        server_hint[MAX_PSK_ID_LEN];
+#endif /* NO_PSK */
+#ifdef HAVE_ANON
+    byte        haveAnon;               /* User wants to allow Anon suites */
+#endif /* HAVE_ANON */
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+    pem_password_cb passwd_cb;
+    void*            userdata;
+#endif /* OPENSSL_EXTRA */
+#ifdef HAVE_OCSP
+    WOLFSSL_OCSP      ocsp;
+#endif
+#ifdef HAVE_CAVIUM
+    int              devId;            /* cavium device id to use */
+#endif
+#ifdef HAVE_TLS_EXTENSIONS
+    TLSX* extensions;                  /* RFC 6066 TLS Extensions data */
+    #if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SEVER)
+        SessionTicketEncCb ticketEncCb;   /* enc/dec session ticket Cb */
+        void*              ticketEncCtx;  /* session encrypt context */
+        int                ticketHint;    /* ticket hint in seconds */
+    #endif
+#endif
+#ifdef ATOMIC_USER
+    CallbackMacEncrypt    MacEncryptCb;    /* Atomic User Mac/Encrypt Cb */
+    CallbackDecryptVerify DecryptVerifyCb; /* Atomic User Decrypt/Verify Cb */
+#endif
+#ifdef HAVE_PK_CALLBACKS
+    #ifdef HAVE_ECC
+        CallbackEccSign   EccSignCb;    /* User EccSign   Callback handler */
+        CallbackEccVerify EccVerifyCb;  /* User EccVerify Callback handler */
+    #endif /* HAVE_ECC */
+    #ifndef NO_RSA 
+        CallbackRsaSign   RsaSignCb;    /* User RsaSign   Callback handler */
+        CallbackRsaVerify RsaVerifyCb;  /* User RsaVerify Callback handler */
+        CallbackRsaEnc    RsaEncCb;     /* User Rsa Public Encrypt  handler */
+        CallbackRsaDec    RsaDecCb;     /* User Rsa Private Decrypt handler */
+    #endif /* NO_RSA */
+#endif /* HAVE_PK_CALLBACKS */
+};
+
+
+WOLFSSL_LOCAL
+int InitSSL_Ctx(WOLFSSL_CTX*, WOLFSSL_METHOD*);
+WOLFSSL_LOCAL
+void FreeSSL_Ctx(WOLFSSL_CTX*);
+WOLFSSL_LOCAL
+void SSL_CtxResourceFree(WOLFSSL_CTX*);
+
+WOLFSSL_LOCAL
+int DeriveTlsKeys(WOLFSSL* ssl);
+WOLFSSL_LOCAL
+int ProcessOldClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
+                          word32 inSz, word16 sz);
+#ifndef NO_CERTS
+    WOLFSSL_LOCAL
+    int AddCA(WOLFSSL_CERT_MANAGER* ctx, buffer der, int type, int verify);
+    WOLFSSL_LOCAL
+    int AlreadySigner(WOLFSSL_CERT_MANAGER* cm, byte* hash);
+#endif
+
+/* All cipher suite related info */
+typedef struct CipherSpecs {
+    word16 key_size;
+    word16 iv_size;
+    word16 block_size;
+    word16 aead_mac_size;
+    byte bulk_cipher_algorithm;
+    byte cipher_type;               /* block, stream, or aead */
+    byte mac_algorithm;
+    byte kea;                       /* key exchange algo */
+    byte sig_algo;
+    byte hash_size;
+    byte pad_size;
+    byte static_ecdh;
+} CipherSpecs;
+
+
+void InitCipherSpecs(CipherSpecs* cs);
+
+
+/* Supported Message Authentication Codes from page 43 */
+enum MACAlgorithm { 
+    no_mac,
+    md5_mac,
+    sha_mac,
+    sha224_mac,
+    sha256_mac,     /* needs to match external KDF_MacAlgorithm */
+    sha384_mac,
+    sha512_mac,
+    rmd_mac,
+    blake2b_mac
+};
+
+
+/* Supported Key Exchange Protocols */
+enum KeyExchangeAlgorithm { 
+    no_kea,
+    rsa_kea, 
+    diffie_hellman_kea, 
+    fortezza_kea,
+    psk_kea,
+    dhe_psk_kea,
+    ntru_kea,
+    ecc_diffie_hellman_kea,
+    ecc_static_diffie_hellman_kea       /* for verify suite only */
+};
+
+
+/* Supported Authentication Schemes */
+enum SignatureAlgorithm {
+    anonymous_sa_algo,
+    rsa_sa_algo,
+    dsa_sa_algo,
+    ecc_dsa_sa_algo
+};
+
+
+/* Supprted ECC Curve Types */
+enum EccCurves {
+    named_curve = 3
+};
+
+
+/* Valid client certificate request types from page 27 */
+enum ClientCertificateType {    
+    rsa_sign            = 1, 
+    dss_sign            = 2,
+    rsa_fixed_dh        = 3,
+    dss_fixed_dh        = 4,
+    rsa_ephemeral_dh    = 5,
+    dss_ephemeral_dh    = 6,
+    fortezza_kea_cert   = 20,
+    ecdsa_sign          = 64,
+    rsa_fixed_ecdh      = 65,
+    ecdsa_fixed_ecdh    = 66
+};
+
+
+enum CipherType { stream, block, aead };
+
+
+
+
+
+
+/* cipher for now */
+typedef struct Ciphers {
+#ifdef BUILD_ARC4
+    Arc4*   arc4;
+#endif
+#ifdef BUILD_DES3
+    Des3*   des3;
+#endif
+#if defined(BUILD_AES) || defined(BUILD_AESGCM)
+    Aes*    aes;
+#endif
+#ifdef HAVE_CAMELLIA
+    Camellia* cam;
+#endif
+#ifdef HAVE_CHACHA
+    ChaCha*   chacha;
+#endif
+#ifdef HAVE_HC128
+    HC128*  hc128;
+#endif
+#ifdef BUILD_RABBIT
+    Rabbit* rabbit;
+#endif
+    byte    setup;       /* have we set it up flag for detection */
+} Ciphers;
+
+
+#ifdef HAVE_ONE_TIME_AUTH
+/* Ciphers for one time authentication such as poly1305 */
+typedef struct OneTimeAuth {
+#ifdef HAVE_POLY1305
+    Poly1305* poly1305;
+#endif
+    byte    setup;      /* flag for if a cipher has been set */
+
+} OneTimeAuth;
+#endif
+
+
+WOLFSSL_LOCAL void InitCiphers(WOLFSSL* ssl);
+WOLFSSL_LOCAL void FreeCiphers(WOLFSSL* ssl);
+
+
+/* hashes type */
+typedef struct Hashes {
+    #ifndef NO_OLD_TLS
+        byte md5[MD5_DIGEST_SIZE];
+    #endif
+    byte sha[SHA_DIGEST_SIZE];
+    #ifndef NO_SHA256
+        byte sha256[SHA256_DIGEST_SIZE];
+    #endif
+    #ifdef WOLFSSL_SHA384
+        byte sha384[SHA384_DIGEST_SIZE];
+    #endif
+    #ifdef WOLFSSL_SHA512
+        byte sha512[SHA512_DIGEST_SIZE];
+    #endif
+} Hashes;
+
+
+/* Static x509 buffer */
+typedef struct x509_buffer {
+    int  length;                  /* actual size */
+    byte buffer[MAX_X509_SIZE];   /* max static cert size */
+} x509_buffer;
+
+
+/* wolfSSL X509_CHAIN, for no dynamic memory SESSION_CACHE */
+struct WOLFSSL_X509_CHAIN {
+    int         count;                    /* total number in chain */
+    x509_buffer certs[MAX_CHAIN_DEPTH];   /* only allow max depth 4 for now */
+};
+
+
+/* wolfSSL session type */
+struct WOLFSSL_SESSION {
+    word32       bornOn;                        /* create time in seconds   */
+    word32       timeout;                       /* timeout in seconds       */
+    byte         sessionID[ID_LEN];             /* id for protocol */
+    byte         sessionIDSz;
+    byte         masterSecret[SECRET_LEN];      /* stored secret */
+#ifdef SESSION_CERTS
+    WOLFSSL_X509_CHAIN chain;                    /* peer cert chain, static  */
+    ProtocolVersion version;                    /* which version was used */
+    byte            cipherSuite0;               /* first byte, normally 0 */
+    byte            cipherSuite;                /* 2nd byte, actual suite */
+#endif
+#ifndef NO_CLIENT_CACHE
+    word16       idLen;                         /* serverID length */
+    byte         serverID[SERVER_ID_LEN];       /* for easier client lookup */
+#endif
+#ifdef HAVE_SESSION_TICKET
+    word16       ticketLen;
+    byte         ticket[SESSION_TICKET_LEN];
+#endif
+};
+
+
+WOLFSSL_LOCAL
+WOLFSSL_SESSION* GetSession(WOLFSSL*, byte*);
+WOLFSSL_LOCAL
+int          SetSession(WOLFSSL*, WOLFSSL_SESSION*);
+
+typedef int (*hmacfp) (WOLFSSL*, byte*, const byte*, word32, int, int);
+
+#ifndef NO_CLIENT_CACHE
+    WOLFSSL_SESSION* GetSessionClient(WOLFSSL*, const byte*, int);
+#endif
+
+/* client connect state for nonblocking restart */
+enum ConnectState {
+    CONNECT_BEGIN = 0,
+    CLIENT_HELLO_SENT,
+    HELLO_AGAIN,               /* HELLO_AGAIN s for DTLS case */
+    HELLO_AGAIN_REPLY,
+    FIRST_REPLY_DONE,
+    FIRST_REPLY_FIRST,
+    FIRST_REPLY_SECOND,
+    FIRST_REPLY_THIRD,
+    FIRST_REPLY_FOURTH,
+    FINISHED_DONE,
+    SECOND_REPLY_DONE
+};
+
+
+/* server accept state for nonblocking restart */
+enum AcceptState {
+    ACCEPT_BEGIN = 0,
+    ACCEPT_CLIENT_HELLO_DONE,
+    HELLO_VERIFY_SENT,
+    ACCEPT_FIRST_REPLY_DONE,
+    SERVER_HELLO_SENT,
+    CERT_SENT,
+    KEY_EXCHANGE_SENT,
+    CERT_REQ_SENT,
+    SERVER_HELLO_DONE,
+    ACCEPT_SECOND_REPLY_DONE,
+    TICKET_SENT,
+    CHANGE_CIPHER_SENT,
+    ACCEPT_FINISHED_DONE,
+    ACCEPT_THIRD_REPLY_DONE
+};
+
+
+typedef struct Buffers {
+    bufferStatic    inputBuffer;
+    bufferStatic    outputBuffer;
+    buffer          domainName;             /* for client check */
+    buffer          clearOutputBuffer;
+    int             prevSent;              /* previous plain text bytes sent
+                                              when got WANT_WRITE            */
+    int             plainSz;               /* plain text bytes in buffer to send
+                                              when got WANT_WRITE            */
+    byte            weOwnCert;             /* SSL own cert flag */
+    byte            weOwnCertChain;        /* SSL own cert chain flag */
+    byte            weOwnKey;              /* SSL own key  flag */
+    byte            weOwnDH;               /* SSL own dh (p,g)  flag */
+#ifndef NO_DH
+    buffer          serverDH_P;            /* WOLFSSL_CTX owns, unless we own */
+    buffer          serverDH_G;            /* WOLFSSL_CTX owns, unless we own */
+    buffer          serverDH_Pub;
+    buffer          serverDH_Priv;
+#endif
+#ifndef NO_CERTS
+    buffer          certificate;           /* WOLFSSL_CTX owns, unless we own */
+    buffer          key;                   /* WOLFSSL_CTX owns, unless we own */
+    buffer          certChain;             /* WOLFSSL_CTX owns, unless we own */
+                 /* chain after self, in DER, with leading size for each cert */
+#endif
+#ifdef WOLFSSL_DTLS
+    WOLFSSL_DTLS_CTX dtlsCtx;               /* DTLS connection context */
+#endif
+#ifdef HAVE_PK_CALLBACKS
+    #ifdef HAVE_ECC
+        buffer peerEccDsaKey;              /* we own for Ecc Verify Callbacks */
+    #endif /* HAVE_ECC */
+    #ifndef NO_RSA
+        buffer peerRsaKey;                 /* we own for Rsa Verify Callbacks */
+    #endif /* NO_RSA */
+#endif /* HAVE_PK_CALLBACKS */
+} Buffers;
+
+typedef struct Options {
+#ifndef NO_PSK
+    psk_client_callback client_psk_cb;
+    psk_server_callback server_psk_cb;
+    word16            havePSK:1;            /* psk key set by user */
+#endif /* NO_PSK */
+
+    /* on/off or small bit flags, optimize layout */
+    word16            sendVerify:2;     /* false = 0, true = 1, sendBlank = 2 */
+    word16            sessionCacheOff:1;
+    word16            sessionCacheFlushOff:1;
+    word16            side:1;             /* client or server end */
+    word16            verifyPeer:1;
+    word16            verifyNone:1;
+    word16            failNoCert:1;
+    word16            downgrade:1;        /* allow downgrade of versions */
+    word16            resuming:1;
+    word16            haveSessionId:1;    /* server may not send */
+    word16            tls:1;              /* using TLS ? */
+    word16            tls1_1:1;           /* using TLSv1.1+ ? */
+    word16            dtls:1;             /* using datagrams ? */
+    word16            connReset:1;        /* has the peer reset */
+    word16            isClosed:1;         /* if we consider conn closed */
+    word16            closeNotify:1;      /* we've recieved a close notify */
+    word16            sentNotify:1;       /* we've sent a close notify */
+    word16            usingCompression:1; /* are we using compression */
+    word16            haveRSA:1;          /* RSA available */
+    word16            haveDH:1;           /* server DH parms set by user */
+    word16            haveNTRU:1;         /* server NTRU  private key loaded */
+    word16            haveECDSAsig:1;     /* server ECDSA signed cert */
+    word16            haveStaticECC:1;    /* static server ECC private key */
+    word16            havePeerCert:1;     /* do we have peer's cert */
+    word16            havePeerVerify:1;   /* and peer's cert verify */
+    word16            usingPSK_cipher:1;  /* are using psk as cipher */
+    word16            usingAnon_cipher:1; /* are we using an anon cipher */
+    word16            sendAlertState:1;   /* nonblocking resume */
+    word16            partialWrite:1;     /* only one msg per write call */
+    word16            quietShutdown:1;    /* don't send close notify */
+    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 */
+#ifdef HAVE_POLY1305
+    word16            oldPoly:1;        /* set when to use old rfc way of poly*/
+#endif
+#ifdef HAVE_ANON
+    word16            haveAnon:1;       /* User wants to allow Anon suites */
+#endif
+#ifdef HAVE_SESSION_TICKET
+    word16            createTicket:1;     /* Server to create new Ticket */
+    word16            useTicket:1;        /* Use Ticket not session cache */
+#endif
+
+    /* need full byte values for this section */
+    byte            processReply;           /* nonblocking resume */
+    byte            cipherSuite0;           /* first byte, normally 0 */
+    byte            cipherSuite;            /* second byte, actual suite */
+    byte            serverState;
+    byte            clientState;
+    byte            handShakeState;
+    byte            handShakeDone;      /* at least one handshake complete */
+    byte            minDowngrade;       /* minimum downgrade version */
+    byte            connectState;       /* nonblocking resume */
+    byte            acceptState;        /* nonblocking resume */
+#ifndef NO_DH
+    word16          minDhKeySz;         /* minimum DH key size */
+    word16          dhKeySz;            /* actual DH key size */
+#endif
+
+} Options;
+
+typedef struct Arrays {
+    word32          preMasterSz;        /* differs for DH, actual size */
+#ifndef NO_PSK
+    word32          psk_keySz;          /* acutal size */
+    char            client_identity[MAX_PSK_ID_LEN];
+    char            server_hint[MAX_PSK_ID_LEN];
+    byte            psk_key[MAX_PSK_KEY_LEN];
+#endif
+    byte            clientRandom[RAN_LEN];
+    byte            serverRandom[RAN_LEN];
+    byte            sessionID[ID_LEN];
+    byte            sessionIDSz;
+    byte            preMasterSecret[ENCRYPT_LEN];
+    byte            masterSecret[SECRET_LEN];
+#ifdef WOLFSSL_DTLS
+    byte            cookie[MAX_COOKIE_LEN];
+    byte            cookieSz;
+#endif
+} Arrays;
+
+#ifndef ASN_NAME_MAX
+#define ASN_NAME_MAX 256
+#endif
+
+#ifndef MAX_DATE_SZ
+#define MAX_DATE_SZ 32
+#endif
+
+struct WOLFSSL_X509_NAME {
+    char  *name;
+    char  staticName[ASN_NAME_MAX];
+    int   dynamicName;
+    int   sz;
+#ifdef OPENSSL_EXTRA
+    DecodedName fullName;
+#endif /* OPENSSL_EXTRA */
+};
+
+#ifndef EXTERNAL_SERIAL_SIZE
+    #define EXTERNAL_SERIAL_SIZE 32
+#endif
+
+#ifdef NO_ASN 
+    typedef struct DNS_entry DNS_entry;
+#endif
+
+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;
+    byte             deviceType[EXTERNAL_SERIAL_SIZE];
+    int              hwTypeSz;
+    byte             hwType[EXTERNAL_SERIAL_SIZE];
+    int              hwSerialNumSz;
+    byte             hwSerialNum[EXTERNAL_SERIAL_SIZE];
+    #ifdef OPENSSL_EXTRA
+        byte             certPolicySet;
+        byte             certPolicyCrit;
+    #endif /* OPENSSL_EXTRA */
+#endif
+    int              notBeforeSz;
+    byte             notBefore[MAX_DATE_SZ];
+    int              notAfterSz;
+    byte             notAfter[MAX_DATE_SZ];
+    int              sigOID;
+    buffer           sig;
+    int              pubKeyOID;
+    buffer           pubKey;
+    #ifdef HAVE_ECC
+        word32       pkCurveOID;
+    #endif /* HAVE_ECC */
+    buffer           derCert;                        /* may need  */
+    DNS_entry*       altNames;                       /* alt names list */
+    DNS_entry*       altNamesNext;                   /* hint for retrieval */
+    byte             dynamicMemory;                  /* dynamic memory flag */
+    byte             isCa;
+#ifdef OPENSSL_EXTRA
+    word32           pathLength;
+    word16           keyUsage;
+    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;
+#endif /* OPENSSL_EXTRA */
+};
+
+
+/* record layer header for PlainText, Compressed, and CipherText */
+typedef struct RecordLayerHeader {
+    byte            type;
+    byte            pvMajor;
+    byte            pvMinor;
+    byte            length[2];
+} RecordLayerHeader;
+
+
+/* record layer header for DTLS PlainText, Compressed, and CipherText */
+typedef struct DtlsRecordLayerHeader {
+    byte            type;
+    byte            pvMajor;
+    byte            pvMinor;
+    byte            epoch[2];             /* increment on cipher state change */
+    byte            sequence_number[6];   /* per record */
+    byte            length[2];
+} DtlsRecordLayerHeader;
+
+
+typedef struct DtlsPool {
+    buffer          buf[DTLS_POOL_SZ];
+    int             used;
+} DtlsPool;
+
+typedef struct DtlsMsg {
+    struct DtlsMsg* next;
+    word32          seq;       /* Handshake sequence number    */
+    word32          sz;        /* Length of whole mesage       */
+    word32          fragSz;    /* Length of fragments received */
+    byte            type;
+    byte*           buf;
+    byte*           msg;
+} DtlsMsg;
+
+
+#ifdef HAVE_NETX
+
+    /* NETX I/O Callback default */
+    typedef struct NetX_Ctx {
+        NX_TCP_SOCKET* nxSocket;    /* send/recv socket handle */
+        NX_PACKET*     nxPacket;    /* incoming packet handle for short reads */
+        ULONG          nxOffset;    /* offset already read from nxPacket */
+        ULONG          nxWait;      /* wait option flag */
+    } NetX_Ctx;
+
+#endif
+
+
+/* Handshake messages recevied from peer (plus change cipher */
+typedef struct MsgsReceived {
+    word16 got_hello_request:1;
+    word16 got_client_hello:1;
+    word16 got_server_hello:1;
+    word16 got_hello_verify_request:1;
+    word16 got_session_ticket:1;
+    word16 got_certificate:1;
+    word16 got_server_key_exchange:1;
+    word16 got_certificate_request:1;
+    word16 got_server_hello_done:1;
+    word16 got_certificate_verify:1;
+    word16 got_client_key_exchange:1;
+    word16 got_finished:1;
+    word16 got_change_cipher:1;
+} MsgsReceived;
+
+
+/* Handshake hashes */
+typedef struct HS_Hashes {
+    Hashes          verifyHashes;
+    Hashes          certHashes;         /* for cert verify */
+#ifndef NO_OLD_TLS
+#ifndef NO_SHA
+    Sha             hashSha;            /* sha hash of handshake msgs */
+#endif
+#ifndef NO_MD5
+    Md5             hashMd5;            /* md5 hash of handshake msgs */
+#endif
+#endif /* NO_OLD_TLS */
+#ifndef NO_SHA256
+    Sha256          hashSha256;         /* sha256 hash of handshake msgs */
+#endif
+#ifdef WOLFSSL_SHA384
+    Sha384          hashSha384;         /* sha384 hash of handshake msgs */
+#endif
+#ifdef WOLFSSL_SHA512
+    Sha512          hashSha512;         /* sha512 hash of handshake msgs */
+#endif
+} HS_Hashes;
+
+
+/* wolfSSL ssl type */
+struct WOLFSSL {
+    WOLFSSL_CTX*    ctx;
+    Suites*         suites;             /* only need during handshake */
+    Arrays*         arrays;
+    HS_Hashes*      hsHashes;
+    void*           IOCB_ReadCtx;
+    void*           IOCB_WriteCtx;
+    RNG*            rng;
+    void*           verifyCbCtx;        /* cert verify callback user ctx*/
+    VerifyCallback  verifyCallback;     /* cert verification callback */
+    void*           heap;               /* for user overrides */
+#ifndef NO_HANDSHAKE_DONE_CB
+    HandShakeDoneCb hsDoneCb;          /*  notify user handshake done */
+    void*           hsDoneCtx;         /*  user handshake cb context  */
+#endif
+    WOLFSSL_CIPHER  cipher;
+    hmacfp          hmac;
+    Ciphers         encrypt;
+    Ciphers         decrypt;
+    Buffers         buffers;
+    WOLFSSL_SESSION session;
+    WOLFSSL_ALERT_HISTORY alert_history;
+    int             error;
+    int             rfd;                /* read  file descriptor */
+    int             wfd;                /* write file descriptor */
+    int             rflags;             /* user read  flags */
+    int             wflags;             /* user write flags */
+    word32          timeout;            /* session timeout */
+    word16          curSize;
+    RecordLayerHeader curRL;
+    MsgsReceived    msgsReceived;       /* peer messages received */
+    ProtocolVersion version;            /* negotiated version */
+    ProtocolVersion chVersion;          /* client hello version */
+    CipherSpecs     specs;
+    Keys            keys;
+    Options         options;
+#ifdef OPENSSL_EXTRA
+    WOLFSSL_BIO*     biord;              /* socket bio read  to free/close */
+    WOLFSSL_BIO*     biowr;              /* socket bio write to free/close */
+#endif
+#ifndef NO_RSA
+    RsaKey*         peerRsaKey;
+    byte            peerRsaKeyPresent;
+#endif
+#ifdef HAVE_NTRU
+    word16          peerNtruKeyLen;
+    byte            peerNtruKey[MAX_NTRU_PUB_KEY_SZ];
+    byte            peerNtruKeyPresent;
+#endif
+#ifdef HAVE_ECC
+    ecc_key*        peerEccKey;              /* peer's  ECDHE key */
+    ecc_key*        peerEccDsaKey;           /* peer's  ECDSA key */
+    ecc_key*        eccTempKey;              /* private ECDHE key */
+    word32          pkCurveOID;              /* curve Ecc_Sum     */
+    word16          eccTempKeySz;            /* in octets 20 - 66 */
+    byte            peerEccKeyPresent;
+    byte            peerEccDsaKeyPresent;
+    byte            eccTempKeyPresent;
+#endif
+#ifdef HAVE_LIBZ
+    z_stream        c_stream;           /* compression   stream */
+    z_stream        d_stream;           /* decompression stream */
+    byte            didStreamInit;      /* for stream init and end */
+#endif
+#ifdef WOLFSSL_DTLS
+    int             dtls_timeout_init;  /* starting timeout vaule */
+    int             dtls_timeout_max;   /* maximum timeout value */
+    int             dtls_timeout;       /* current timeout value, changes */
+    DtlsPool*       dtls_pool;
+    DtlsMsg*        dtls_msg_list;
+    void*           IOCB_CookieCtx;     /* gen cookie ctx */
+    word32          dtls_expected_rx;
+#endif
+#ifdef WOLFSSL_CALLBACKS
+    HandShakeInfo   handShakeInfo;      /* info saved during handshake */
+    TimeoutInfo     timeoutInfo;        /* info saved during handshake */
+    byte            hsInfoOn;           /* track handshake info        */
+    byte            toInfoOn;           /* track timeout   info        */
+#endif
+#ifdef HAVE_FUZZER
+    CallbackFuzzer  fuzzerCb;           /* for testing with using fuzzer */
+    void*           fuzzerCtx;          /* user defined pointer */
+#endif
+#ifdef KEEP_PEER_CERT
+    WOLFSSL_X509     peerCert;           /* X509 peer cert */
+#endif
+#ifdef FORTRESS
+    void*           ex_data[MAX_EX_DATA]; /* external data, for Fortress */
+#endif
+#ifdef HAVE_CAVIUM
+    int              devId;            /* cavium device id to use */
+#endif
+#ifdef HAVE_ONE_TIME_AUTH
+    OneTimeAuth     auth;
+#endif
+#ifdef HAVE_TLS_EXTENSIONS
+    TLSX* extensions;                  /* RFC 6066 TLS Extensions data */
+    #ifdef HAVE_MAX_FRAGMENT
+        word16 max_fragment;
+    #endif
+    #ifdef HAVE_TRUNCATED_HMAC
+        byte truncated_hmac;
+    #endif
+    #ifdef HAVE_SECURE_RENEGOTIATION
+        SecureRenegotiation* secure_renegotiation; /* valid pointer indicates */
+    #endif                                         /* user turned on */
+    #if !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET)
+        CallbackSessionTicket session_ticket_cb;
+        void*                 session_ticket_ctx;
+        byte                  expect_session_ticket;
+    #endif
+#endif /* HAVE_TLS_EXTENSIONS */
+#ifdef HAVE_NETX
+    NetX_Ctx        nxCtx;             /* NetX IO Context */
+#endif
+#ifdef SESSION_INDEX
+    int sessionIndex;                  /* Session's location in the cache. */
+#endif
+#ifdef ATOMIC_USER
+    void*    MacEncryptCtx;    /* Atomic User Mac/Encrypt Callback Context */
+    void*    DecryptVerifyCtx; /* Atomic User Decrypt/Verify Callback Context */
+#endif
+#ifdef HAVE_PK_CALLBACKS
+    #ifdef HAVE_ECC
+        void* EccSignCtx;     /* Ecc Sign   Callback Context */
+        void* EccVerifyCtx;   /* Ecc Verify Callback Context */
+    #endif /* HAVE_ECC */
+    #ifndef NO_RSA
+        void* RsaSignCtx;     /* Rsa Sign   Callback Context */
+        void* RsaVerifyCtx;   /* Rsa Verify Callback Context */
+        void* RsaEncCtx;      /* Rsa Public  Encrypt   Callback Context */
+        void* RsaDecCtx;      /* Rsa Private Decrypt   Callback Context */
+    #endif /* NO_RSA */
+#endif /* HAVE_PK_CALLBACKS */
+#ifdef HAVE_SECRET_CALLBACK
+        SessionSecretCb sessionSecretCb;
+        void*           sessionSecretCtx;
+#endif /* HAVE_SECRET_CALLBACK */
+};
+
+
+WOLFSSL_LOCAL
+int  InitSSL(WOLFSSL*, WOLFSSL_CTX*);
+WOLFSSL_LOCAL
+void FreeSSL(WOLFSSL*);
+WOLFSSL_API void SSL_ResourceFree(WOLFSSL*);   /* Micrium uses */
+
+
+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 PemToDer(const unsigned char* buff, long sz, int type,
+                              buffer* der, void* heap, EncryptedInfo* info,
+                              int* eccKey);
+
+    WOLFSSL_LOCAL int ProcessFile(WOLFSSL_CTX* ctx, const char* fname, int format,
+                                 int type, WOLFSSL* ssl, int userChain,
+                                WOLFSSL_CRL* crl);
+#endif
+
+
+#ifdef WOLFSSL_CALLBACKS
+    WOLFSSL_LOCAL
+    void InitHandShakeInfo(HandShakeInfo*);
+    WOLFSSL_LOCAL 
+    void FinishHandShakeInfo(HandShakeInfo*, const WOLFSSL*);
+    WOLFSSL_LOCAL 
+    void AddPacketName(const char*, HandShakeInfo*);
+
+    WOLFSSL_LOCAL
+    void InitTimeoutInfo(TimeoutInfo*);
+    WOLFSSL_LOCAL 
+    void FreeTimeoutInfo(TimeoutInfo*, void*);
+    WOLFSSL_LOCAL 
+    void AddPacketInfo(const char*, TimeoutInfo*, const byte*, int, void*);
+    WOLFSSL_LOCAL 
+    void AddLateName(const char*, TimeoutInfo*);
+    WOLFSSL_LOCAL 
+    void AddLateRecordHeader(const RecordLayerHeader* rl, TimeoutInfo* info);
+#endif
+
+
+/* Record Layer Header identifier from page 12 */
+enum ContentType {
+    no_type            = 0,
+    change_cipher_spec = 20, 
+    alert              = 21, 
+    handshake          = 22, 
+    application_data   = 23 
+};
+
+
+/* handshake header, same for each message type, pgs 20/21 */
+typedef struct HandShakeHeader {
+    byte            type;
+    word24          length;
+} HandShakeHeader;
+
+
+/* DTLS handshake header, same for each message type */
+typedef struct DtlsHandShakeHeader {
+    byte            type;
+    word24          length;
+    byte            message_seq[2];    /* start at 0, restransmit gets same # */
+    word24          fragment_offset;   /* bytes in previous fragments */
+    word24          fragment_length;   /* length of this fragment */
+} DtlsHandShakeHeader;
+
+
+enum HandShakeType {
+    no_shake            = -1,
+    hello_request       = 0, 
+    client_hello        = 1, 
+    server_hello        = 2,
+    hello_verify_request = 3,       /* DTLS addition */
+    session_ticket      =  4,
+    certificate         = 11, 
+    server_key_exchange = 12,
+    certificate_request = 13, 
+    server_hello_done   = 14,
+    certificate_verify  = 15, 
+    client_key_exchange = 16,
+    finished            = 20,
+    certificate_status  = 22,
+    change_cipher_hs    = 55      /* simulate unique handshake type for sanity
+                                     checks.  record layer change_cipher
+                                     conflicts with handshake finished */
+};
+
+
+static const byte client[SIZEOF_SENDER] = { 0x43, 0x4C, 0x4E, 0x54 };
+static const byte server[SIZEOF_SENDER] = { 0x53, 0x52, 0x56, 0x52 };
+
+static const byte tls_client[FINISHED_LABEL_SZ + 1] = "client finished";
+static const byte tls_server[FINISHED_LABEL_SZ + 1] = "server finished";
+
+
+/* internal functions */
+WOLFSSL_LOCAL int SendChangeCipher(WOLFSSL*);
+WOLFSSL_LOCAL int SendTicket(WOLFSSL*);
+WOLFSSL_LOCAL int DoClientTicket(WOLFSSL*, const byte*, word32);
+WOLFSSL_LOCAL int SendData(WOLFSSL*, const void*, int);
+WOLFSSL_LOCAL int SendCertificate(WOLFSSL*);
+WOLFSSL_LOCAL int SendCertificateRequest(WOLFSSL*);
+WOLFSSL_LOCAL int SendServerKeyExchange(WOLFSSL*);
+WOLFSSL_LOCAL int SendBuffered(WOLFSSL*);
+WOLFSSL_LOCAL int ReceiveData(WOLFSSL*, byte*, int, int);
+WOLFSSL_LOCAL int SendFinished(WOLFSSL*);
+WOLFSSL_LOCAL int SendAlert(WOLFSSL*, int, int);
+WOLFSSL_LOCAL int ProcessReply(WOLFSSL*);
+
+WOLFSSL_LOCAL int SetCipherSpecs(WOLFSSL*);
+WOLFSSL_LOCAL int MakeMasterSecret(WOLFSSL*);
+
+WOLFSSL_LOCAL int  AddSession(WOLFSSL*);
+WOLFSSL_LOCAL int  DeriveKeys(WOLFSSL* ssl);
+WOLFSSL_LOCAL int  StoreKeys(WOLFSSL* ssl, const byte* keyData);
+
+WOLFSSL_LOCAL int IsTLS(const WOLFSSL* ssl);
+WOLFSSL_LOCAL int IsAtLeastTLSv1_2(const WOLFSSL* ssl);
+
+WOLFSSL_LOCAL void FreeHandshakeResources(WOLFSSL* ssl);
+WOLFSSL_LOCAL void ShrinkInputBuffer(WOLFSSL* ssl, int forcedFree);
+WOLFSSL_LOCAL void ShrinkOutputBuffer(WOLFSSL* ssl);
+
+WOLFSSL_LOCAL int VerifyClientSuite(WOLFSSL* ssl);
+#ifndef NO_CERTS
+    WOLFSSL_LOCAL Signer* GetCA(void* cm, byte* hash);
+    #ifndef NO_SKID
+        WOLFSSL_LOCAL Signer* GetCAByName(void* cm, byte* hash);
+    #endif
+#endif
+WOLFSSL_LOCAL int  BuildTlsFinished(WOLFSSL* ssl, Hashes* hashes,
+                                   const byte* sender);
+WOLFSSL_LOCAL void FreeArrays(WOLFSSL* ssl, int keep);
+WOLFSSL_LOCAL  int CheckAvailableSize(WOLFSSL *ssl, int size);
+WOLFSSL_LOCAL  int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength);
+
+#ifndef NO_TLS
+    WOLFSSL_LOCAL int  MakeTlsMasterSecret(WOLFSSL*);
+    WOLFSSL_LOCAL int  TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in,
+                               word32 sz, int content, int verify);
+#endif
+
+#ifndef NO_WOLFSSL_CLIENT
+    WOLFSSL_LOCAL int SendClientHello(WOLFSSL*);
+    WOLFSSL_LOCAL int SendClientKeyExchange(WOLFSSL*);
+    WOLFSSL_LOCAL int SendCertificateVerify(WOLFSSL*);
+#endif /* NO_WOLFSSL_CLIENT */
+
+#ifndef NO_WOLFSSL_SERVER
+    WOLFSSL_LOCAL int SendServerHello(WOLFSSL*);
+    WOLFSSL_LOCAL int SendServerHelloDone(WOLFSSL*);
+    #ifdef WOLFSSL_DTLS
+        WOLFSSL_LOCAL int SendHelloVerifyRequest(WOLFSSL*);
+    #endif
+#endif /* NO_WOLFSSL_SERVER */
+
+#ifdef WOLFSSL_DTLS
+    WOLFSSL_LOCAL int  DtlsPoolInit(WOLFSSL*);
+    WOLFSSL_LOCAL int  DtlsPoolSave(WOLFSSL*, const byte*, int);
+    WOLFSSL_LOCAL int  DtlsPoolTimeout(WOLFSSL*);
+    WOLFSSL_LOCAL int  DtlsPoolSend(WOLFSSL*);
+    WOLFSSL_LOCAL void DtlsPoolReset(WOLFSSL*);
+
+    WOLFSSL_LOCAL DtlsMsg* DtlsMsgNew(word32, void*);
+    WOLFSSL_LOCAL void DtlsMsgDelete(DtlsMsg*, void*);
+    WOLFSSL_LOCAL void DtlsMsgListDelete(DtlsMsg*, void*);
+    WOLFSSL_LOCAL void DtlsMsgSet(DtlsMsg*, word32, const byte*, byte,
+                                                             word32, word32);
+    WOLFSSL_LOCAL DtlsMsg* DtlsMsgFind(DtlsMsg*, word32);
+    WOLFSSL_LOCAL DtlsMsg* DtlsMsgStore(DtlsMsg*, word32, const byte*, word32,
+                                                byte, word32, word32, void*);
+    WOLFSSL_LOCAL DtlsMsg* DtlsMsgInsert(DtlsMsg*, DtlsMsg*);
+#endif /* WOLFSSL_DTLS */
+
+#ifndef NO_TLS
+    
+
+#endif /* NO_TLS */
+
+
+WOLFSSL_LOCAL word32  LowResTimer(void);
+
+WOLFSSL_LOCAL void InitX509Name(WOLFSSL_X509_NAME*, int);
+WOLFSSL_LOCAL void FreeX509Name(WOLFSSL_X509_NAME* name);
+WOLFSSL_LOCAL void InitX509(WOLFSSL_X509*, int);
+WOLFSSL_LOCAL void FreeX509(WOLFSSL_X509*);
+#ifndef NO_CERTS
+    WOLFSSL_LOCAL int  CopyDecodedToX509(WOLFSSL_X509*, DecodedCert*);
+#endif
+
+/* used by ssl.c and wolfssl_int.c */
+WOLFSSL_LOCAL void c32to24(word32 in, word24 out);
+
+WOLFSSL_LOCAL const char* const* GetCipherNames(void);
+WOLFSSL_LOCAL int GetCipherNamesSize(void);
+
+
+enum encrypt_side {
+    ENCRYPT_SIDE_ONLY = 1,
+    DECRYPT_SIDE_ONLY,
+    ENCRYPT_AND_DECRYPT_SIDE
+};
+
+WOLFSSL_LOCAL int SetKeysSide(WOLFSSL*, enum encrypt_side);
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+#endif /* wolfSSL_INT_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/ocsp.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,53 @@
+/* ocsp.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+/* wolfSSL OCSP API */
+
+#ifndef WOLFSSL_OCSP_H
+#define WOLFSSL_OCSP_H
+
+#ifdef HAVE_OCSP
+
+#include <wolfssl/ssl.h>
+#include <wolfssl/wolfcrypt/asn.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+typedef struct WOLFSSL_OCSP WOLFSSL_OCSP;
+
+WOLFSSL_LOCAL int  InitOCSP(WOLFSSL_OCSP*, WOLFSSL_CERT_MANAGER*);
+WOLFSSL_LOCAL void FreeOCSP(WOLFSSL_OCSP*, int dynamic);
+
+WOLFSSL_LOCAL int  CheckCertOCSP(WOLFSSL_OCSP*, DecodedCert*);
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+
+#endif /* HAVE_OCSP */
+#endif /* WOLFSSL_OCSP_H */
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/options.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,91 @@
+/* wolfssl options.h
+ * generated from configure options
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef WOLFSSL_OPTIONS_IGNORE_SYS
+#undef  _POSIX_THREADS
+#define _POSIX_THREADS
+#endif
+
+#undef  HAVE_THREAD_LS
+#define HAVE_THREAD_LS
+
+#ifndef WOLFSSL_OPTIONS_IGNORE_SYS
+#undef  _THREAD_SAFE
+#define _THREAD_SAFE
+#endif
+
+#undef  HAVE_AESGCM
+#define HAVE_AESGCM
+
+#undef  WOLFSSL_SHA512
+#define WOLFSSL_SHA512
+
+#undef  WOLFSSL_SHA384
+#define WOLFSSL_SHA384
+
+#undef  NO_DSA
+#define NO_DSA
+
+#undef  HAVE_ECC
+#define HAVE_ECC
+
+#undef  TFM_ECC256
+#define TFM_ECC256
+
+#undef  ECC_SHAMIR
+#define ECC_SHAMIR
+
+#undef  NO_PSK
+#define NO_PSK
+
+#undef  NO_RC4
+#define NO_RC4
+
+#undef  NO_MD4
+#define NO_MD4
+
+#undef  NO_HC128
+#define NO_HC128
+
+#undef  NO_RABBIT
+#define NO_RABBIT
+
+#undef  HAVE_POLY1305
+#define HAVE_POLY1305
+
+#undef  HAVE_ONE_TIME_AUTH
+#define HAVE_ONE_TIME_AUTH
+
+#undef  HAVE_CHACHA
+#define HAVE_CHACHA
+
+#undef  HAVE_HASHDRBG
+#define HAVE_HASHDRBG
+
+#undef  NO_PWDBASED
+#define NO_PWDBASED
+
+#undef  USE_FAST_MATH
+#define USE_FAST_MATH
+
+#undef  WOLFSSL_X86_64_BUILD
+#define WOLFSSL_X86_64_BUILD
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/sniffer.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,83 @@
+/* sniffer.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef WOLFSSL_SNIFFER_H
+#define WOLFSSL_SNIFFER_H
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef _WIN32
+    #ifdef SSL_SNIFFER_EXPORTS
+        #define SSL_SNIFFER_API __declspec(dllexport)
+    #else
+        #define SSL_SNIFFER_API __declspec(dllimport)
+    #endif
+#else
+    #define SSL_SNIFFER_API
+#endif /* _WIN32 */
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* @param typeK: (formerly keyType) was shadowing a global declaration in 
+ *                wolfssl/wolfcrypt/asn.h line 175
+ */
+WOLFSSL_API 
+SSL_SNIFFER_API int ssl_SetPrivateKey(const char* address, int port,
+                                      const char* keyFile, int typeK,
+                                      const char* password, char* error);
+
+WOLFSSL_API
+SSL_SNIFFER_API int ssl_SetNamedPrivateKey(const char* name,
+                                           const char* address, int port,
+                                           const char* keyFile, int typeK,
+                                           const char* password, char* error);
+
+WOLFSSL_API 
+SSL_SNIFFER_API int ssl_DecodePacket(const unsigned char* packet, int length,
+                                     unsigned char* data, char* error);
+
+WOLFSSL_API 
+SSL_SNIFFER_API int ssl_Trace(const char* traceFile, char* error);
+        
+        
+WOLFSSL_API void ssl_InitSniffer(void);
+        
+WOLFSSL_API void ssl_FreeSniffer(void);
+
+        
+/* ssl_SetPrivateKey typeKs */
+enum {
+    FILETYPE_PEM = 1,
+    FILETYPE_DER = 2,
+};
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+#endif /* wolfSSL_SNIFFER_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/sniffer_error.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,115 @@
+/* sniffer_error.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef WOLFSSL_SNIFFER_ERROR_H
+#define WOLFSSL_SNIFFER_ERROR_H
+
+/* need to have errors as #defines since .rc files can't handle enums */
+/* need to start at 1 and go in order for same reason */
+
+#define MEMORY_STR 1
+#define NEW_SERVER_STR 2
+#define IP_CHECK_STR 3
+#define SERVER_NOT_REG_STR 4
+#define TCP_CHECK_STR 5
+#define SERVER_PORT_NOT_REG_STR 6
+#define RSA_DECRYPT_STR 7
+#define RSA_DECODE_STR 8
+#define BAD_CIPHER_SPEC_STR 9
+#define SERVER_HELLO_INPUT_STR 10
+
+#define BAD_SESSION_RESUME_STR 11
+#define SERVER_DID_RESUMPTION_STR 12
+#define CLIENT_HELLO_INPUT_STR 13
+#define CLIENT_RESUME_TRY_STR 14
+#define HANDSHAKE_INPUT_STR 15
+#define GOT_HELLO_VERIFY_STR 16
+#define GOT_SERVER_HELLO_STR 17
+#define GOT_CERT_REQ_STR 18
+#define GOT_SERVER_KEY_EX_STR 19
+#define GOT_CERT_STR 20
+
+#define GOT_SERVER_HELLO_DONE_STR 21
+#define GOT_FINISHED_STR 22
+#define GOT_CLIENT_HELLO_STR 23
+#define GOT_CLIENT_KEY_EX_STR 24
+#define GOT_CERT_VER_STR 25
+#define GOT_UNKNOWN_HANDSHAKE_STR 26
+#define NEW_SESSION_STR 27
+#define BAD_NEW_SSL_STR 28
+#define GOT_PACKET_STR 29
+#define NO_DATA_STR 30
+
+#define BAD_SESSION_STR 31
+#define GOT_OLD_CLIENT_HELLO_STR 32
+#define OLD_CLIENT_INPUT_STR 33
+#define OLD_CLIENT_OK_STR 34
+#define BAD_OLD_CLIENT_STR 35
+#define BAD_RECORD_HDR_STR 36
+#define RECORD_INPUT_STR 37
+#define GOT_HANDSHAKE_STR 38
+#define BAD_HANDSHAKE_STR 39
+#define GOT_CHANGE_CIPHER_STR 40
+
+#define GOT_APP_DATA_STR 41
+#define BAD_APP_DATA_STR 42
+#define GOT_ALERT_STR 43
+#define ANOTHER_MSG_STR 44
+#define REMOVE_SESSION_STR 45
+#define KEY_FILE_STR 46
+#define BAD_IPVER_STR 47
+#define BAD_PROTO_STR 48
+#define PACKET_HDR_SHORT_STR 49
+#define GOT_UNKNOWN_RECORD_STR 50
+
+#define BAD_TRACE_FILE_STR 51
+#define FATAL_ERROR_STR 52
+#define PARTIAL_INPUT_STR 53
+#define BUFFER_ERROR_STR 54
+#define PARTIAL_ADD_STR 55
+#define DUPLICATE_STR 56
+#define OUT_OF_ORDER_STR 57
+#define OVERLAP_DUPLICATE_STR 58
+#define OVERLAP_REASSEMBLY_BEGIN_STR 59
+#define OVERLAP_REASSEMBLY_END_STR 60
+
+#define MISSED_CLIENT_HELLO_STR 61
+#define GOT_HELLO_REQUEST_STR 62
+#define GOT_SESSION_TICKET_STR 63
+#define BAD_INPUT_STR 64
+#define BAD_DECRYPT_TYPE 65
+#define BAD_FINISHED_MSG 66
+#define BAD_COMPRESSION_STR 67
+#define BAD_DERIVE_STR 68
+#define ACK_MISSED_STR 69
+#define BAD_DECRYPT    70 
+
+#define DECRYPT_KEYS_NOT_SETUP 71
+#define CLIENT_HELLO_LATE_KEY_STR 72
+#define GOT_CERT_STATUS_STR 73
+#define RSA_KEY_MISSING_STR 74
+/* !!!! also add to msgTable in sniffer.c and .rc file !!!! */
+
+
+#endif /* wolfSSL_SNIFFER_ERROR_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/ssl.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,1465 @@
+/* ssl.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+/* wolfSSL API */
+
+#ifndef WOLFSSL_SSL_H
+#define WOLFSSL_SSL_H
+
+
+/* for users not using preprocessor flags*/
+#include <wolfssl/wolfcrypt/settings.h>
+#include <wolfssl/version.h>
+
+#ifndef NO_FILESYSTEM
+    #ifdef FREESCALE_MQX
+        #include <fio.h>
+    #else
+        #include <stdio.h>   /* ERR_printf */
+    #endif
+#endif
+
+#ifdef WOLFSSL_PREFIX
+    #include "prefix_ssl.h"
+#endif
+
+#ifdef LIBWOLFSSL_VERSION_STRING
+    #define WOLFSSL_VERSION LIBWOLFSSL_VERSION_STRING
+#endif
+
+#ifdef _WIN32
+    /* wincrypt.h clashes */
+    #undef OCSP_REQUEST
+    #undef OCSP_RESPONSE
+#endif
+
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+typedef struct WOLFSSL          WOLFSSL;
+typedef struct WOLFSSL_SESSION  WOLFSSL_SESSION;
+typedef struct WOLFSSL_METHOD   WOLFSSL_METHOD;
+typedef struct WOLFSSL_CTX      WOLFSSL_CTX;
+
+typedef struct WOLFSSL_X509       WOLFSSL_X509;
+typedef struct WOLFSSL_X509_NAME  WOLFSSL_X509_NAME;
+typedef struct WOLFSSL_X509_CHAIN WOLFSSL_X509_CHAIN;
+
+typedef struct WOLFSSL_CERT_MANAGER WOLFSSL_CERT_MANAGER;
+typedef struct WOLFSSL_SOCKADDR     WOLFSSL_SOCKADDR;
+
+/* redeclare guard */
+#define WOLFSSL_TYPES_DEFINED
+
+
+typedef struct WOLFSSL_RSA            WOLFSSL_RSA;
+typedef struct WOLFSSL_DSA            WOLFSSL_DSA;
+typedef struct WOLFSSL_CIPHER         WOLFSSL_CIPHER;
+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_BIO            WOLFSSL_BIO;
+typedef struct WOLFSSL_BIO_METHOD     WOLFSSL_BIO_METHOD;
+typedef struct WOLFSSL_X509_EXTENSION WOLFSSL_X509_EXTENSION;
+typedef struct WOLFSSL_ASN1_TIME      WOLFSSL_ASN1_TIME;
+typedef struct WOLFSSL_ASN1_INTEGER   WOLFSSL_ASN1_INTEGER;
+typedef struct WOLFSSL_ASN1_OBJECT    WOLFSSL_ASN1_OBJECT;
+typedef struct WOLFSSL_ASN1_STRING    WOLFSSL_ASN1_STRING;
+typedef struct WOLFSSL_dynlock_value  WOLFSSL_dynlock_value;
+
+#define WOLFSSL_ASN1_UTCTIME WOLFSSL_ASN1_TIME
+
+typedef struct WOLFSSL_EVP_PKEY {
+    int type;         /* openssh dereference */
+    int save_type;    /* openssh dereference */
+    int pkey_sz;
+    union {
+        char* ptr;
+    } pkey;
+    #ifdef HAVE_ECC
+        int pkey_curve;
+    #endif
+} WOLFSSL_EVP_PKEY;
+
+typedef struct WOLFSSL_MD4_CTX {
+    int buffer[32];      /* big enough to hold, check size in Init */
+} WOLFSSL_MD4_CTX;
+
+
+typedef struct WOLFSSL_COMP_METHOD {
+    int type;            /* stunnel dereference */
+} WOLFSSL_COMP_METHOD;
+
+
+typedef struct WOLFSSL_X509_STORE {
+    int                  cache;          /* stunnel dereference */
+    WOLFSSL_CERT_MANAGER* cm;
+} WOLFSSL_X509_STORE;
+
+typedef struct WOLFSSL_ALERT {
+    int code;
+    int level;
+} WOLFSSL_ALERT;
+
+typedef struct WOLFSSL_ALERT_HISTORY {
+    WOLFSSL_ALERT last_rx;
+    WOLFSSL_ALERT last_tx;
+} WOLFSSL_ALERT_HISTORY;
+
+typedef struct WOLFSSL_X509_REVOKED {
+    WOLFSSL_ASN1_INTEGER* serialNumber;          /* stunnel dereference */
+} WOLFSSL_X509_REVOKED;
+
+
+typedef struct WOLFSSL_X509_OBJECT {
+    union {
+        char* ptr;
+        WOLFSSL_X509_CRL* crl;           /* stunnel dereference */
+    } data;
+} WOLFSSL_X509_OBJECT;
+
+
+typedef struct WOLFSSL_X509_STORE_CTX {
+    WOLFSSL_X509_STORE* store;    /* Store full of a CA cert chain */
+    WOLFSSL_X509* current_cert;   /* stunnel dereference */
+    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   discardSessionCerts;   /* so verify callback can flag for discard */
+} WOLFSSL_X509_STORE_CTX;
+
+
+/* Valid Alert types from page 16/17 */
+enum AlertDescription {
+    close_notify            = 0,
+    unexpected_message      = 10,
+    bad_record_mac          = 20,
+    record_overflow         = 22,
+    decompression_failure   = 30,
+    handshake_failure       = 40,
+    no_certificate          = 41,
+    bad_certificate         = 42,
+    unsupported_certificate = 43,
+    certificate_revoked     = 44,
+    certificate_expired     = 45,
+    certificate_unknown     = 46,
+    illegal_parameter       = 47,
+    decrypt_error           = 51,
+    #ifdef WOLFSSL_MYSQL_COMPATIBLE
+    /* catch name conflict for enum protocol with MYSQL build */
+    wc_protocol_version     = 70,
+    #else
+    protocol_version        = 70,
+    #endif
+    no_renegotiation        = 100,
+    unrecognized_name       = 112
+};
+
+
+enum AlertLevel {
+    alert_warning = 1,
+    alert_fatal = 2
+};
+
+
+WOLFSSL_API WOLFSSL_METHOD *wolfSSLv3_server_method(void);
+WOLFSSL_API WOLFSSL_METHOD *wolfSSLv3_client_method(void);
+WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_server_method(void);
+WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_client_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_server_method(void);
+WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_client_method(void);
+
+#ifdef WOLFSSL_DTLS
+    WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_client_method(void);
+    WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_server_method(void);
+    WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_2_client_method(void);
+    WOLFSSL_API WOLFSSL_METHOD *wolfDTLSv1_2_server_method(void);
+#endif
+
+#ifdef HAVE_POLY1305
+    WOLFSSL_API int wolfSSL_use_old_poly(WOLFSSL*, int);
+#endif
+
+#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
+
+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);
+WOLFSSL_API int wolfSSL_CTX_load_verify_locations(WOLFSSL_CTX*, const char*,
+                                                const char*);
+WOLFSSL_API int wolfSSL_CTX_use_certificate_chain_file(WOLFSSL_CTX *,
+                                                     const char *file);
+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 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_RSAPrivateKey_file(WOLFSSL*, const char*, int);
+
+#ifdef WOLFSSL_DER_LOAD
+    WOLFSSL_API int wolfSSL_CTX_der_load_verify_locations(WOLFSSL_CTX*,
+                                                    const char*, int);
+#endif
+
+#ifdef HAVE_NTRU
+    WOLFSSL_API int wolfSSL_CTX_use_NTRUPrivateKey_file(WOLFSSL_CTX*, const char*);
+    /* load NTRU private key blob */
+#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 int  wolfSSL_set_fd (WOLFSSL*, int);
+WOLFSSL_API char* wolfSSL_get_cipher_list(int priority);
+WOLFSSL_API int  wolfSSL_get_ciphers(char*, int);
+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*);
+WOLFSSL_API int  wolfSSL_connect(WOLFSSL*);     /* please see note at top of README
+                                             if you get an error from connect */
+WOLFSSL_API int  wolfSSL_write(WOLFSSL*, const void*, int);
+WOLFSSL_API int  wolfSSL_read(WOLFSSL*, void*, int);
+WOLFSSL_API int  wolfSSL_peek(WOLFSSL*, void*, int);
+WOLFSSL_API int  wolfSSL_accept(WOLFSSL*);
+WOLFSSL_API void wolfSSL_CTX_free(WOLFSSL_CTX*);
+WOLFSSL_API void wolfSSL_free(WOLFSSL*);
+WOLFSSL_API int  wolfSSL_shutdown(WOLFSSL*);
+WOLFSSL_API int  wolfSSL_send(WOLFSSL*, const void*, int sz, int flags);
+WOLFSSL_API int  wolfSSL_recv(WOLFSSL*, void*, int sz, int flags);
+
+WOLFSSL_API void wolfSSL_CTX_set_quiet_shutdown(WOLFSSL_CTX*, int);
+WOLFSSL_API void wolfSSL_set_quiet_shutdown(WOLFSSL*, int);
+
+WOLFSSL_API int  wolfSSL_get_error(WOLFSSL*, int);
+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);
+
+#ifdef SESSION_INDEX
+WOLFSSL_API int wolfSSL_GetSessionIndex(WOLFSSL* ssl);
+WOLFSSL_API int wolfSSL_GetSessionAtIndex(int index, WOLFSSL_SESSION* session);
+#endif /* SESSION_INDEX */
+
+#if defined(SESSION_INDEX) && defined(SESSION_CERTS)
+WOLFSSL_API
+    WOLFSSL_X509_CHAIN* wolfSSL_SESSION_get_peer_chain(WOLFSSL_SESSION* session);
+#endif /* SESSION_INDEX && SESSION_CERTS */
+
+typedef int (*VerifyCallback)(int, WOLFSSL_X509_STORE_CTX*);
+typedef int (*pem_password_cb)(char*, int, int, void*);
+
+WOLFSSL_API void wolfSSL_CTX_set_verify(WOLFSSL_CTX*, int,
+                                      VerifyCallback verify_callback);
+WOLFSSL_API void wolfSSL_set_verify(WOLFSSL*, int, VerifyCallback verify_callback);
+WOLFSSL_API void wolfSSL_SetCertCbCtx(WOLFSSL*, void*);
+
+WOLFSSL_API int  wolfSSL_pending(WOLFSSL*);
+
+WOLFSSL_API void wolfSSL_load_error_strings(void);
+WOLFSSL_API int  wolfSSL_library_init(void);
+WOLFSSL_API long wolfSSL_CTX_set_session_cache_mode(WOLFSSL_CTX*, long);
+
+#ifdef HAVE_SECRET_CALLBACK
+typedef int (*SessionSecretCb)(WOLFSSL* ssl,
+                                        void* secret, int* secretSz, void* ctx);
+WOLFSSL_API int  wolfSSL_set_session_secret_cb(WOLFSSL*, SessionSecretCb, void*);
+#endif /* HAVE_SECRET_CALLBACK */
+
+/* session cache persistence */
+WOLFSSL_API int  wolfSSL_save_session_cache(const char*);
+WOLFSSL_API int  wolfSSL_restore_session_cache(const char*);
+WOLFSSL_API int  wolfSSL_memsave_session_cache(void*, int);
+WOLFSSL_API int  wolfSSL_memrestore_session_cache(const void*, int);
+WOLFSSL_API int  wolfSSL_get_session_cache_memsize(void);
+
+/* certificate cache persistence, uses ctx since certs are per ctx */
+WOLFSSL_API int  wolfSSL_CTX_save_cert_cache(WOLFSSL_CTX*, const char*);
+WOLFSSL_API int  wolfSSL_CTX_restore_cert_cache(WOLFSSL_CTX*, const char*);
+WOLFSSL_API int  wolfSSL_CTX_memsave_cert_cache(WOLFSSL_CTX*, void*, int, int*);
+WOLFSSL_API int  wolfSSL_CTX_memrestore_cert_cache(WOLFSSL_CTX*, const void*, int);
+WOLFSSL_API int  wolfSSL_CTX_get_cert_cache_memsize(WOLFSSL_CTX*);
+
+/* only supports full name from cipher_name[] delimited by : */
+WOLFSSL_API int  wolfSSL_CTX_set_cipher_list(WOLFSSL_CTX*, const char*);
+WOLFSSL_API int  wolfSSL_set_cipher_list(WOLFSSL*, const char*);
+
+/* Nonblocking DTLS helper functions */
+WOLFSSL_API int  wolfSSL_dtls_get_current_timeout(WOLFSSL* ssl);
+WOLFSSL_API int  wolfSSL_dtls_set_timeout_init(WOLFSSL* ssl, int);
+WOLFSSL_API int  wolfSSL_dtls_set_timeout_max(WOLFSSL* ssl, int);
+WOLFSSL_API int  wolfSSL_dtls_got_timeout(WOLFSSL* ssl);
+WOLFSSL_API int  wolfSSL_dtls(WOLFSSL* ssl);
+
+WOLFSSL_API int  wolfSSL_dtls_set_peer(WOLFSSL*, void*, unsigned int);
+WOLFSSL_API int  wolfSSL_dtls_get_peer(WOLFSSL*, void*, unsigned int*);
+
+WOLFSSL_API int   wolfSSL_ERR_GET_REASON(int err);
+WOLFSSL_API char* wolfSSL_ERR_error_string(unsigned long,char*);
+WOLFSSL_API void  wolfSSL_ERR_error_string_n(unsigned long e, char* buf,
+                                           unsigned long sz);
+WOLFSSL_API const char* wolfSSL_ERR_reason_error_string(unsigned long);
+
+/* extras */
+
+#define STACK_OF(x) x
+
+WOLFSSL_API int  wolfSSL_set_ex_data(WOLFSSL*, int, void*);
+WOLFSSL_API int  wolfSSL_get_shutdown(const WOLFSSL*);
+WOLFSSL_API int  wolfSSL_set_rfd(WOLFSSL*, int);
+WOLFSSL_API int  wolfSSL_set_wfd(WOLFSSL*, int);
+WOLFSSL_API void wolfSSL_set_shutdown(WOLFSSL*, int);
+WOLFSSL_API int  wolfSSL_set_session_id_context(WOLFSSL*, const unsigned char*,
+                                           unsigned int);
+WOLFSSL_API void wolfSSL_set_connect_state(WOLFSSL*);
+WOLFSSL_API void wolfSSL_set_accept_state(WOLFSSL*);
+WOLFSSL_API int  wolfSSL_session_reused(WOLFSSL*);
+WOLFSSL_API void wolfSSL_SESSION_free(WOLFSSL_SESSION* session);
+WOLFSSL_API int  wolfSSL_is_init_finished(WOLFSSL*);
+
+WOLFSSL_API const char*  wolfSSL_get_version(WOLFSSL*);
+WOLFSSL_API int  wolfSSL_get_current_cipher_suite(WOLFSSL* ssl);
+WOLFSSL_API WOLFSSL_CIPHER*  wolfSSL_get_current_cipher(WOLFSSL*);
+WOLFSSL_API char*        wolfSSL_CIPHER_description(WOLFSSL_CIPHER*, char*, int);
+WOLFSSL_API const char*  wolfSSL_CIPHER_get_name(const WOLFSSL_CIPHER* cipher);
+WOLFSSL_API const char*  wolfSSL_get_cipher(WOLFSSL*);
+WOLFSSL_API WOLFSSL_SESSION* wolfSSL_get1_session(WOLFSSL* ssl);
+                           /* what's ref count */
+
+WOLFSSL_API void wolfSSL_X509_free(WOLFSSL_X509*);
+WOLFSSL_API void wolfSSL_OPENSSL_free(void*);
+
+WOLFSSL_API int wolfSSL_OCSP_parse_url(char* url, char** host, char** port,
+                                     char** path, int* ssl);
+
+WOLFSSL_API WOLFSSL_METHOD* wolfSSLv23_client_method(void);
+WOLFSSL_API WOLFSSL_METHOD* wolfSSLv2_client_method(void);
+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_read(WOLFSSL_BIO*, void*, int);
+WOLFSSL_API int  wolfSSL_BIO_write(WOLFSSL_BIO*, const void*, int);
+WOLFSSL_API WOLFSSL_BIO* wolfSSL_BIO_push(WOLFSSL_BIO*, WOLFSSL_BIO* append);
+WOLFSSL_API WOLFSSL_BIO* wolfSSL_BIO_pop(WOLFSSL_BIO*);
+WOLFSSL_API int  wolfSSL_BIO_flush(WOLFSSL_BIO*);
+WOLFSSL_API int  wolfSSL_BIO_pending(WOLFSSL_BIO*);
+
+WOLFSSL_API WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_buffer(void);
+WOLFSSL_API long wolfSSL_BIO_set_write_buffer_size(WOLFSSL_BIO*, long size);
+WOLFSSL_API WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_ssl(void);
+WOLFSSL_API WOLFSSL_BIO*        wolfSSL_BIO_new_socket(int sfd, int flag);
+WOLFSSL_API int         wolfSSL_BIO_eof(WOLFSSL_BIO*);
+
+WOLFSSL_API WOLFSSL_BIO_METHOD* wolfSSL_BIO_s_mem(void);
+WOLFSSL_API WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_base64(void);
+WOLFSSL_API void wolfSSL_BIO_set_flags(WOLFSSL_BIO*, int);
+
+WOLFSSL_API int wolfSSL_BIO_get_mem_data(WOLFSSL_BIO* bio,const unsigned char** p);
+WOLFSSL_API WOLFSSL_BIO* wolfSSL_BIO_new_mem_buf(void* buf, int len);
+
+
+WOLFSSL_API long        wolfSSL_BIO_set_ssl(WOLFSSL_BIO*, WOLFSSL*, int flag);
+WOLFSSL_API void        wolfSSL_set_bio(WOLFSSL*, WOLFSSL_BIO* rd, WOLFSSL_BIO* wr);
+
+WOLFSSL_API int  wolfSSL_add_all_algorithms(void);
+
+WOLFSSL_API void        wolfSSL_RAND_screen(void);
+WOLFSSL_API const char* wolfSSL_RAND_file_name(char*, unsigned long);
+WOLFSSL_API int         wolfSSL_RAND_write_file(const char*);
+WOLFSSL_API int         wolfSSL_RAND_load_file(const char*, long);
+WOLFSSL_API int         wolfSSL_RAND_egd(const char*);
+WOLFSSL_API int         wolfSSL_RAND_seed(const void*, int);
+WOLFSSL_API void        wolfSSL_RAND_add(const void*, int, double);
+
+WOLFSSL_API WOLFSSL_COMP_METHOD* wolfSSL_COMP_zlib(void);
+WOLFSSL_API WOLFSSL_COMP_METHOD* wolfSSL_COMP_rle(void);
+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 void wolfSSL_set_id_callback(unsigned long (*f)(void));
+WOLFSSL_API void wolfSSL_set_locking_callback(void (*f)(int, int, const char*,
+                                                      int));
+WOLFSSL_API void wolfSSL_set_dynlock_create_callback(WOLFSSL_dynlock_value* (*f)
+                                                   (const char*, int));
+WOLFSSL_API void wolfSSL_set_dynlock_lock_callback(void (*f)(int,
+                                      WOLFSSL_dynlock_value*, const char*, int));
+WOLFSSL_API void wolfSSL_set_dynlock_destroy_callback(void (*f)
+                                     (WOLFSSL_dynlock_value*, const char*, int));
+WOLFSSL_API int  wolfSSL_num_locks(void);
+
+WOLFSSL_API WOLFSSL_X509* wolfSSL_X509_STORE_CTX_get_current_cert(
+                                                        WOLFSSL_X509_STORE_CTX*);
+WOLFSSL_API int   wolfSSL_X509_STORE_CTX_get_error(WOLFSSL_X509_STORE_CTX*);
+WOLFSSL_API int   wolfSSL_X509_STORE_CTX_get_error_depth(WOLFSSL_X509_STORE_CTX*);
+
+WOLFSSL_API char*       wolfSSL_X509_NAME_oneline(WOLFSSL_X509_NAME*, char*, int);
+WOLFSSL_API WOLFSSL_X509_NAME*  wolfSSL_X509_get_issuer_name(WOLFSSL_X509*);
+WOLFSSL_API WOLFSSL_X509_NAME*  wolfSSL_X509_get_subject_name(WOLFSSL_X509*);
+WOLFSSL_API int  wolfSSL_X509_ext_isSet_by_NID(WOLFSSL_X509*, int);
+WOLFSSL_API int  wolfSSL_X509_ext_get_critical_by_NID(WOLFSSL_X509*, int);
+WOLFSSL_API int  wolfSSL_X509_get_isCA(WOLFSSL_X509*);
+WOLFSSL_API int  wolfSSL_X509_get_isSet_pathLength(WOLFSSL_X509*);
+WOLFSSL_API unsigned int wolfSSL_X509_get_pathLength(WOLFSSL_X509*);
+WOLFSSL_API unsigned int wolfSSL_X509_get_keyUsage(WOLFSSL_X509*);
+WOLFSSL_API unsigned char* wolfSSL_X509_get_authorityKeyID(
+                                            WOLFSSL_X509*, unsigned char*, int*);
+WOLFSSL_API unsigned char* wolfSSL_X509_get_subjectKeyID(
+                                            WOLFSSL_X509*, unsigned char*, int*);
+WOLFSSL_API int wolfSSL_X509_NAME_entry_count(WOLFSSL_X509_NAME*);
+WOLFSSL_API int wolfSSL_X509_NAME_get_text_by_NID(
+                                            WOLFSSL_X509_NAME*, int, char*, int);
+WOLFSSL_API int         wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX*);
+WOLFSSL_API const char* wolfSSL_X509_verify_cert_error_string(long);
+WOLFSSL_API int wolfSSL_X509_get_signature_type(WOLFSSL_X509*);
+WOLFSSL_API int wolfSSL_X509_get_signature(WOLFSSL_X509*, unsigned char*, int*);
+
+WOLFSSL_API int wolfSSL_X509_LOOKUP_add_dir(WOLFSSL_X509_LOOKUP*,const char*,long);
+WOLFSSL_API int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP*, const char*,
+                                            long);
+WOLFSSL_API WOLFSSL_X509_LOOKUP_METHOD* wolfSSL_X509_LOOKUP_hash_dir(void);
+WOLFSSL_API WOLFSSL_X509_LOOKUP_METHOD* wolfSSL_X509_LOOKUP_file(void);
+
+WOLFSSL_API WOLFSSL_X509_LOOKUP* wolfSSL_X509_STORE_add_lookup(WOLFSSL_X509_STORE*,
+                                                    WOLFSSL_X509_LOOKUP_METHOD*);
+WOLFSSL_API WOLFSSL_X509_STORE*  wolfSSL_X509_STORE_new(void);
+WOLFSSL_API void         wolfSSL_X509_STORE_free(WOLFSSL_X509_STORE*);
+WOLFSSL_API int          wolfSSL_X509_STORE_add_cert(
+                                              WOLFSSL_X509_STORE*, WOLFSSL_X509*);
+WOLFSSL_API int          wolfSSL_X509_STORE_set_default_paths(WOLFSSL_X509_STORE*);
+WOLFSSL_API int          wolfSSL_X509_STORE_get_by_subject(WOLFSSL_X509_STORE_CTX*,
+                                   int, WOLFSSL_X509_NAME*, WOLFSSL_X509_OBJECT*);
+WOLFSSL_API WOLFSSL_X509_STORE_CTX* wolfSSL_X509_STORE_CTX_new(void);
+WOLFSSL_API int  wolfSSL_X509_STORE_CTX_init(WOLFSSL_X509_STORE_CTX*,
+                      WOLFSSL_X509_STORE*, WOLFSSL_X509*, STACK_OF(WOLFSSL_X509)*);
+WOLFSSL_API void wolfSSL_X509_STORE_CTX_free(WOLFSSL_X509_STORE_CTX*);
+WOLFSSL_API void wolfSSL_X509_STORE_CTX_cleanup(WOLFSSL_X509_STORE_CTX*);
+
+WOLFSSL_API WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_lastUpdate(WOLFSSL_X509_CRL*);
+WOLFSSL_API WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_nextUpdate(WOLFSSL_X509_CRL*);
+
+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 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*);
+
+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 int wolfSSL_ASN1_TIME_print(WOLFSSL_BIO*, const WOLFSSL_ASN1_TIME*);
+
+WOLFSSL_API int  wolfSSL_ASN1_INTEGER_cmp(const WOLFSSL_ASN1_INTEGER*,
+                                       const WOLFSSL_ASN1_INTEGER*);
+WOLFSSL_API long wolfSSL_ASN1_INTEGER_get(const WOLFSSL_ASN1_INTEGER*);
+
+WOLFSSL_API STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_load_client_CA_file(const char*);
+
+WOLFSSL_API void  wolfSSL_CTX_set_client_CA_list(WOLFSSL_CTX*,
+                                               STACK_OF(WOLFSSL_X509_NAME)*);
+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_get_ex_data(const WOLFSSL*, int);
+
+WOLFSSL_API void wolfSSL_CTX_set_default_passwd_cb_userdata(WOLFSSL_CTX*,
+                                                          void* userdata);
+WOLFSSL_API void wolfSSL_CTX_set_default_passwd_cb(WOLFSSL_CTX*, pem_password_cb);
+
+
+WOLFSSL_API void wolfSSL_CTX_set_info_callback(WOLFSSL_CTX*, void (*)(void));
+
+WOLFSSL_API unsigned long wolfSSL_ERR_peek_error(void);
+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(WOLFSSL*);
+
+WOLFSSL_API WOLFSSL_RSA* wolfSSL_RSA_generate_key(int, unsigned long,
+                                               void(*)(int, int, void*), void*);
+WOLFSSL_API void wolfSSL_CTX_set_tmp_rsa_callback(WOLFSSL_CTX*,
+                                             WOLFSSL_RSA*(*)(WOLFSSL*, int, int));
+
+WOLFSSL_API int wolfSSL_PEM_def_callback(char*, int num, int w, void* key);
+
+WOLFSSL_API long wolfSSL_CTX_sess_accept(WOLFSSL_CTX*);
+WOLFSSL_API long wolfSSL_CTX_sess_connect(WOLFSSL_CTX*);
+WOLFSSL_API long wolfSSL_CTX_sess_accept_good(WOLFSSL_CTX*);
+WOLFSSL_API long wolfSSL_CTX_sess_connect_good(WOLFSSL_CTX*);
+WOLFSSL_API long wolfSSL_CTX_sess_accept_renegotiate(WOLFSSL_CTX*);
+WOLFSSL_API long wolfSSL_CTX_sess_connect_renegotiate(WOLFSSL_CTX*);
+WOLFSSL_API long wolfSSL_CTX_sess_hits(WOLFSSL_CTX*);
+WOLFSSL_API long wolfSSL_CTX_sess_cb_hits(WOLFSSL_CTX*);
+WOLFSSL_API long wolfSSL_CTX_sess_cache_full(WOLFSSL_CTX*);
+WOLFSSL_API long wolfSSL_CTX_sess_misses(WOLFSSL_CTX*);
+WOLFSSL_API long wolfSSL_CTX_sess_timeouts(WOLFSSL_CTX*);
+WOLFSSL_API long wolfSSL_CTX_sess_number(WOLFSSL_CTX*);
+WOLFSSL_API long wolfSSL_CTX_sess_get_cache_size(WOLFSSL_CTX*);
+
+#define WOLFSSL_DEFAULT_CIPHER_LIST ""   /* default all */
+#define WOLFSSL_RSA_F4 0x10001L
+
+enum {
+    OCSP_NOCERTS     = 1,
+    OCSP_NOINTERN    = 2,
+    OCSP_NOSIGS      = 4,
+    OCSP_NOCHAIN     = 8,
+    OCSP_NOVERIFY    = 16,
+    OCSP_NOEXPLICIT  = 32,
+    OCSP_NOCASIGN    = 64,
+    OCSP_NODELEGATED = 128,
+    OCSP_NOCHECKS    = 256,
+    OCSP_TRUSTOTHER  = 512,
+    OCSP_RESPID_KEY  = 1024,
+    OCSP_NOTIME      = 2048,
+
+    OCSP_CERTID   = 2,
+    OCSP_REQUEST  = 4,
+    OCSP_RESPONSE = 8,
+    OCSP_BASICRESP = 16,
+
+    WOLFSSL_OCSP_URL_OVERRIDE = 1,
+    WOLFSSL_OCSP_NO_NONCE     = 2,
+    WOLFSSL_OCSP_CHECKALL     = 4,
+
+    WOLFSSL_CRL_CHECKALL = 1,
+
+    ASN1_GENERALIZEDTIME = 4,
+
+    SSL_OP_MICROSOFT_SESS_ID_BUG = 1,
+    SSL_OP_NETSCAPE_CHALLENGE_BUG = 2,
+    SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = 3,
+    SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG = 4,
+    SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = 5,
+    SSL_OP_MSIE_SSLV2_RSA_PADDING = 6,
+    SSL_OP_SSLEAY_080_CLIENT_DH_BUG = 7,
+    SSL_OP_TLS_D5_BUG = 8,
+    SSL_OP_TLS_BLOCK_PADDING_BUG = 9,
+    SSL_OP_TLS_ROLLBACK_BUG = 10,
+    SSL_OP_ALL = 11,
+    SSL_OP_EPHEMERAL_RSA = 12,
+    SSL_OP_NO_SSLv3 = 13,
+    SSL_OP_NO_TLSv1 = 14,
+    SSL_OP_PKCS1_CHECK_1 = 15,
+    SSL_OP_PKCS1_CHECK_2 = 16,
+    SSL_OP_NETSCAPE_CA_DN_BUG = 17,
+    SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG = 18,
+    SSL_OP_SINGLE_DH_USE = 19,
+    SSL_OP_NO_TICKET = 20,
+    SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 21,
+    SSL_OP_NO_QUERY_MTU = 22,
+    SSL_OP_COOKIE_EXCHANGE = 23,
+    SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 24,
+    SSL_OP_SINGLE_ECDH_USE = 25,
+    SSL_OP_CIPHER_SERVER_PREFERENCE = 26,
+
+    SSL_MAX_SSL_SESSION_ID_LENGTH = 32,
+
+    EVP_R_BAD_DECRYPT = 2,
+
+    SSL_CB_LOOP = 4,
+    SSL_ST_CONNECT = 5,
+    SSL_ST_ACCEPT  = 6,
+    SSL_CB_ALERT   = 7,
+    SSL_CB_READ    = 8,
+    SSL_CB_HANDSHAKE_DONE = 9,
+
+    SSL_MODE_ENABLE_PARTIAL_WRITE = 2,
+
+    BIO_FLAGS_BASE64_NO_NL = 1,
+    BIO_CLOSE   = 1,
+    BIO_NOCLOSE = 0,
+
+    NID_undef = 0,
+
+    X509_FILETYPE_PEM = 8,
+    X509_LU_X509      = 9,
+    X509_LU_CRL       = 12,
+
+    X509_V_ERR_CRL_SIGNATURE_FAILURE = 13,
+    X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD = 14,
+    X509_V_ERR_CRL_HAS_EXPIRED                = 15,
+    X509_V_ERR_CERT_REVOKED                   = 16,
+    X509_V_ERR_CERT_CHAIN_TOO_LONG            = 17,
+    X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT      = 18,
+    X509_V_ERR_CERT_NOT_YET_VALID             = 19,
+    X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD = 20,
+    X509_V_ERR_CERT_HAS_EXPIRED               = 21,
+    X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD  = 22,
+
+    X509_V_OK = 0,
+
+    CRYPTO_LOCK = 1,
+    CRYPTO_NUM_LOCKS = 10
+};
+
+/* extras end */
+
+#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)
+/* wolfSSL extension, provide last error from SSL_get_error
+   since not using thread storage error queue */
+WOLFSSL_API void  wolfSSL_ERR_print_errors_fp(FILE*, int err);
+#endif
+
+enum { /* ssl Constants */
+    SSL_ERROR_NONE      =  0,   /* for most functions */
+    SSL_FAILURE         =  0,   /* for some functions */
+    SSL_SUCCESS         =  1,
+    SSL_SHUTDOWN_NOT_DONE =  2,  /* call wolfSSL_shutdown again to complete */
+
+    SSL_BAD_CERTTYPE    = -8,
+    SSL_BAD_STAT        = -7,
+    SSL_BAD_PATH        = -6,
+    SSL_BAD_FILETYPE    = -5,
+    SSL_BAD_FILE        = -4,
+    SSL_NOT_IMPLEMENTED = -3,
+    SSL_UNKNOWN         = -2,
+    SSL_FATAL_ERROR     = -1,
+
+    SSL_FILETYPE_ASN1    = 2,
+    SSL_FILETYPE_PEM     = 1,
+    SSL_FILETYPE_DEFAULT = 2, /* ASN1 */
+    SSL_FILETYPE_RAW     = 3, /* NTRU raw key blob */
+
+    SSL_VERIFY_NONE                 = 0,
+    SSL_VERIFY_PEER                 = 1,
+    SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 2,
+    SSL_VERIFY_CLIENT_ONCE          = 4,
+
+    SSL_SESS_CACHE_OFF                = 30,
+    SSL_SESS_CACHE_CLIENT             = 31,
+    SSL_SESS_CACHE_SERVER             = 32,
+    SSL_SESS_CACHE_BOTH               = 33,
+    SSL_SESS_CACHE_NO_AUTO_CLEAR      = 34,
+    SSL_SESS_CACHE_NO_INTERNAL_LOOKUP = 35,
+
+    SSL_ERROR_WANT_READ        =  2,
+    SSL_ERROR_WANT_WRITE       =  3,
+    SSL_ERROR_WANT_CONNECT     =  7,
+    SSL_ERROR_WANT_ACCEPT      =  8,
+    SSL_ERROR_SYSCALL          =  5,
+    SSL_ERROR_WANT_X509_LOOKUP = 83,
+    SSL_ERROR_ZERO_RETURN      =  6,
+    SSL_ERROR_SSL              = 85,
+
+    SSL_SENT_SHUTDOWN     = 1,
+    SSL_RECEIVED_SHUTDOWN = 2,
+    SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER = 4,
+    SSL_OP_NO_SSLv2       = 8,
+
+    SSL_R_SSL_HANDSHAKE_FAILURE           = 101,
+    SSL_R_TLSV1_ALERT_UNKNOWN_CA          = 102,
+    SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN = 103,
+    SSL_R_SSLV3_ALERT_BAD_CERTIFICATE     = 104,
+
+    PEM_BUFSIZE = 1024
+};
+
+
+#ifndef NO_PSK
+    typedef unsigned int (*psk_client_callback)(WOLFSSL*, const char*, char*,
+                                    unsigned int, unsigned char*, unsigned int);
+    WOLFSSL_API void wolfSSL_CTX_set_psk_client_callback(WOLFSSL_CTX*,
+                                                    psk_client_callback);
+    WOLFSSL_API void wolfSSL_set_psk_client_callback(WOLFSSL*,psk_client_callback);
+
+    WOLFSSL_API const char* wolfSSL_get_psk_identity_hint(const WOLFSSL*);
+    WOLFSSL_API const char* wolfSSL_get_psk_identity(const WOLFSSL*);
+
+    WOLFSSL_API int wolfSSL_CTX_use_psk_identity_hint(WOLFSSL_CTX*, const char*);
+    WOLFSSL_API int wolfSSL_use_psk_identity_hint(WOLFSSL*, const char*);
+
+    typedef unsigned int (*psk_server_callback)(WOLFSSL*, const char*,
+                          unsigned char*, unsigned int);
+    WOLFSSL_API void wolfSSL_CTX_set_psk_server_callback(WOLFSSL_CTX*,
+                                                    psk_server_callback);
+    WOLFSSL_API void wolfSSL_set_psk_server_callback(WOLFSSL*,psk_server_callback);
+
+    #define PSK_TYPES_DEFINED
+#endif /* NO_PSK */
+
+
+#ifdef HAVE_ANON
+    WOLFSSL_API int wolfSSL_CTX_allow_anon_cipher(WOLFSSL_CTX*);
+#endif /* HAVE_ANON */
+
+
+/* extra begins */
+
+enum {  /* ERR Constants */
+    ERR_TXT_STRING = 1
+};
+
+WOLFSSL_API unsigned long wolfSSL_ERR_get_error_line_data(const char**, int*,
+                                                 const char**, int *);
+
+WOLFSSL_API unsigned long wolfSSL_ERR_get_error(void);
+WOLFSSL_API void          wolfSSL_ERR_clear_error(void);
+
+
+WOLFSSL_API int  wolfSSL_RAND_status(void);
+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);
+#ifndef NO_CERTS
+  WOLFSSL_API int  wolfSSL_CTX_check_private_key(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 void wolfSSL_cleanup_all_ex_data(void);
+WOLFSSL_API long wolfSSL_CTX_set_mode(WOLFSSL_CTX* ctx, long mode);
+WOLFSSL_API long wolfSSL_CTX_get_mode(WOLFSSL_CTX* ctx);
+WOLFSSL_API void wolfSSL_CTX_set_default_read_ahead(WOLFSSL_CTX* ctx, int m);
+WOLFSSL_API long wolfSSL_SSL_get_mode(WOLFSSL* ssl);
+
+WOLFSSL_API long wolfSSL_CTX_sess_set_cache_size(WOLFSSL_CTX*, long);
+
+WOLFSSL_API int  wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX*);
+WOLFSSL_API int  wolfSSL_CTX_set_session_id_context(WOLFSSL_CTX*,
+                                            const unsigned char*, unsigned int);
+WOLFSSL_API WOLFSSL_X509* wolfSSL_get_peer_certificate(WOLFSSL* ssl);
+
+WOLFSSL_API int wolfSSL_want_read(WOLFSSL*);
+WOLFSSL_API int wolfSSL_want_write(WOLFSSL*);
+
+WOLFSSL_API int wolfSSL_BIO_printf(WOLFSSL_BIO*, const char*, ...);
+WOLFSSL_API int wolfSSL_ASN1_UTCTIME_print(WOLFSSL_BIO*,
+                                         const WOLFSSL_ASN1_UTCTIME*);
+WOLFSSL_API int   wolfSSL_sk_num(WOLFSSL_X509_REVOKED*);
+WOLFSSL_API void* wolfSSL_sk_value(WOLFSSL_X509_REVOKED*, int);
+
+/* stunnel 4.28 needs */
+WOLFSSL_API void* wolfSSL_CTX_get_ex_data(const WOLFSSL_CTX*, int);
+WOLFSSL_API int   wolfSSL_CTX_set_ex_data(WOLFSSL_CTX*, int, void*);
+WOLFSSL_API void  wolfSSL_CTX_sess_set_get_cb(WOLFSSL_CTX*,
+                       WOLFSSL_SESSION*(*f)(WOLFSSL*, unsigned char*, int, int*));
+WOLFSSL_API void  wolfSSL_CTX_sess_set_new_cb(WOLFSSL_CTX*,
+                                            int (*f)(WOLFSSL*, WOLFSSL_SESSION*));
+WOLFSSL_API void  wolfSSL_CTX_sess_set_remove_cb(WOLFSSL_CTX*,
+                                       void (*f)(WOLFSSL_CTX*, WOLFSSL_SESSION*));
+
+WOLFSSL_API int          wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION*,unsigned char**);
+WOLFSSL_API WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION**,
+                                                   const unsigned char**, long);
+
+WOLFSSL_API long wolfSSL_SESSION_get_timeout(const WOLFSSL_SESSION*);
+WOLFSSL_API long wolfSSL_SESSION_get_time(const WOLFSSL_SESSION*);
+WOLFSSL_API int  wolfSSL_CTX_get_ex_new_index(long, void*, void*, void*, void*);
+
+/* extra ends */
+
+
+/* wolfSSL extensions */
+
+/* call before SSL_connect, if verifying will add name check to
+   date check and signature check */
+WOLFSSL_API int wolfSSL_check_domain_name(WOLFSSL* ssl, const char* dn);
+
+/* need to call once to load library (session cache) */
+WOLFSSL_API int wolfSSL_Init(void);
+/* call when done to cleanup/free session cache mutex / resources  */
+WOLFSSL_API int wolfSSL_Cleanup(void);
+
+/* which library version do we have */
+WOLFSSL_API const char* wolfSSL_lib_version(void);
+/* which library version do we have in hex */
+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);
+/* turn on wolfSSL data compression */
+WOLFSSL_API int wolfSSL_set_compression(WOLFSSL* ssl);
+
+WOLFSSL_API int wolfSSL_set_timeout(WOLFSSL*, unsigned int);
+WOLFSSL_API int wolfSSL_CTX_set_timeout(WOLFSSL_CTX*, unsigned int);
+
+/* get wolfSSL peer X509_CHAIN */
+WOLFSSL_API WOLFSSL_X509_CHAIN* wolfSSL_get_peer_chain(WOLFSSL* ssl);
+/* peer chain count */
+WOLFSSL_API int  wolfSSL_get_chain_count(WOLFSSL_X509_CHAIN* chain);
+/* index cert length */
+WOLFSSL_API int  wolfSSL_get_chain_length(WOLFSSL_X509_CHAIN*, int idx);
+/* index cert */
+WOLFSSL_API unsigned char* wolfSSL_get_chain_cert(WOLFSSL_X509_CHAIN*, int idx);
+/* index cert in X509 */
+WOLFSSL_API WOLFSSL_X509* wolfSSL_get_chain_X509(WOLFSSL_X509_CHAIN*, int idx);
+/* free X509 */
+WOLFSSL_API void wolfSSL_FreeX509(WOLFSSL_X509*);
+/* get index cert in PEM */
+WOLFSSL_API int  wolfSSL_get_chain_cert_pem(WOLFSSL_X509_CHAIN*, int idx,
+                                unsigned char* buffer, int inLen, int* outLen);
+WOLFSSL_API const unsigned char* wolfSSL_get_sessionID(const WOLFSSL_SESSION* s);
+WOLFSSL_API int  wolfSSL_X509_get_serial_number(WOLFSSL_X509*,unsigned char*,int*);
+WOLFSSL_API char*  wolfSSL_X509_get_subjectCN(WOLFSSL_X509*);
+WOLFSSL_API const unsigned char* wolfSSL_X509_get_der(WOLFSSL_X509*, int*);
+WOLFSSL_API const unsigned char* wolfSSL_X509_notBefore(WOLFSSL_X509*);
+WOLFSSL_API const unsigned char* wolfSSL_X509_notAfter(WOLFSSL_X509*);
+WOLFSSL_API int wolfSSL_X509_version(WOLFSSL_X509*);
+
+WOLFSSL_API int wolfSSL_cmp_peer_cert_to_file(WOLFSSL*, const char*);
+
+WOLFSSL_API char* wolfSSL_X509_get_next_altname(WOLFSSL_X509*);
+
+WOLFSSL_API WOLFSSL_X509*
+    wolfSSL_X509_d2i(WOLFSSL_X509** x509, const unsigned char* in, int len);
+#ifndef NO_FILESYSTEM
+    #ifndef NO_STDIO_FILESYSTEM
+    WOLFSSL_API WOLFSSL_X509*
+        wolfSSL_X509_d2i_fp(WOLFSSL_X509** x509, FILE* file);
+    #endif
+WOLFSSL_API WOLFSSL_X509*
+    wolfSSL_X509_load_certificate_file(const char* fname, int format);
+#endif
+
+#ifdef WOLFSSL_SEP
+    WOLFSSL_API unsigned char*
+           wolfSSL_X509_get_device_type(WOLFSSL_X509*, unsigned char*, int*);
+    WOLFSSL_API unsigned char*
+           wolfSSL_X509_get_hw_type(WOLFSSL_X509*, unsigned char*, int*);
+    WOLFSSL_API unsigned char*
+           wolfSSL_X509_get_hw_serial_number(WOLFSSL_X509*, unsigned char*, int*);
+#endif
+
+/* connect enough to get peer cert */
+WOLFSSL_API int  wolfSSL_connect_cert(WOLFSSL* ssl);
+
+#ifndef NO_DH
+/* server Diffie-Hellman parameters */
+WOLFSSL_API int  wolfSSL_SetTmpDH(WOLFSSL*, const unsigned char* p, int pSz,
+                                const unsigned char* g, int gSz);
+WOLFSSL_API int  wolfSSL_SetTmpDH_buffer(WOLFSSL*, const unsigned char* b, long sz,
+                                       int format);
+#ifndef NO_FILESYSTEM
+    WOLFSSL_API int  wolfSSL_SetTmpDH_file(WOLFSSL*, const char* f, int format);
+#endif
+
+/* server ctx Diffie-Hellman parameters */
+WOLFSSL_API int  wolfSSL_CTX_SetTmpDH(WOLFSSL_CTX*, const unsigned char* p,
+                                    int pSz, const unsigned char* g, int gSz);
+WOLFSSL_API int  wolfSSL_CTX_SetTmpDH_buffer(WOLFSSL_CTX*, const unsigned char* b,
+                                           long sz, int format);
+
+#ifndef NO_FILESYSTEM
+    WOLFSSL_API int  wolfSSL_CTX_SetTmpDH_file(WOLFSSL_CTX*, const char* f,
+                                             int format);
+#endif
+
+WOLFSSL_API int wolfSSL_CTX_SetMinDhKey_Sz(WOLFSSL_CTX*, unsigned short);
+WOLFSSL_API int wolfSSL_SetMinDhKey_Sz(WOLFSSL*, unsigned short);
+WOLFSSL_API int wolfSSL_GetDhKey_Sz(WOLFSSL*);
+#endif /* NO_DH */
+
+WOLFSSL_API int  wolfSSL_SetTmpEC_DHE_Sz(WOLFSSL*, unsigned short);
+WOLFSSL_API int  wolfSSL_CTX_SetTmpEC_DHE_Sz(WOLFSSL_CTX*, unsigned short);
+
+/* keyblock size in bytes or -1 */
+/* need to call wolfSSL_KeepArrays before handshake to save keys */
+WOLFSSL_API int wolfSSL_get_keyblock_size(WOLFSSL*);
+WOLFSSL_API int wolfSSL_get_keys(WOLFSSL*,unsigned char** ms, unsigned int* msLen,
+                                       unsigned char** sr, unsigned int* srLen,
+                                       unsigned char** cr, unsigned int* crLen);
+
+/* Computes EAP-TLS and EAP-TTLS keying material from the master_secret. */
+WOLFSSL_API int wolfSSL_make_eap_keys(WOLFSSL*, void* key, unsigned int len,
+                                                             const char* label);
+
+
+#ifndef _WIN32
+    #ifndef NO_WRITEV
+        #ifdef __PPU
+            #include <sys/types.h>
+            #include <sys/socket.h>
+        #elif !defined(WOLFSSL_MDK_ARM) && !defined(WOLFSSL_IAR_ARM) && !defined(WOLFSSL_PICOTCP)
+            #include <sys/uio.h>
+        #endif
+        /* allow writev style writing */
+        WOLFSSL_API int wolfSSL_writev(WOLFSSL* ssl, const struct iovec* iov,
+                                     int iovcnt);
+    #endif
+#endif
+
+
+#ifndef NO_CERTS
+    /* SSL_CTX versions */
+    WOLFSSL_API int wolfSSL_CTX_UnloadCAs(WOLFSSL_CTX*);
+    WOLFSSL_API int wolfSSL_CTX_load_verify_buffer(WOLFSSL_CTX*,
+                                               const unsigned char*, long, int);
+    WOLFSSL_API int wolfSSL_CTX_use_certificate_buffer(WOLFSSL_CTX*,
+                                               const unsigned char*, long, int);
+    WOLFSSL_API int wolfSSL_CTX_use_PrivateKey_buffer(WOLFSSL_CTX*,
+                                               const unsigned char*, long, int);
+    WOLFSSL_API int wolfSSL_CTX_use_certificate_chain_buffer(WOLFSSL_CTX*,
+                                                    const unsigned char*, long);
+
+    /* SSL versions */
+    WOLFSSL_API int wolfSSL_use_certificate_buffer(WOLFSSL*, const unsigned char*,
+                                               long, int);
+    WOLFSSL_API int wolfSSL_use_PrivateKey_buffer(WOLFSSL*, const unsigned char*,
+                                               long, int);
+    WOLFSSL_API int wolfSSL_use_certificate_chain_buffer(WOLFSSL*,
+                                               const unsigned char*, long);
+    WOLFSSL_API int wolfSSL_UnloadCertsKeys(WOLFSSL*);
+#endif
+
+WOLFSSL_API int wolfSSL_CTX_set_group_messages(WOLFSSL_CTX*);
+WOLFSSL_API int wolfSSL_set_group_messages(WOLFSSL*);
+
+/* I/O callbacks */
+typedef int (*CallbackIORecv)(WOLFSSL *ssl, char *buf, int sz, void *ctx);
+typedef int (*CallbackIOSend)(WOLFSSL *ssl, char *buf, int sz, void *ctx);
+
+#ifdef HAVE_FUZZER
+enum fuzzer_type {
+    FUZZ_HMAC      = 0,
+    FUZZ_ENCRYPT   = 1,
+    FUZZ_SIGNATURE = 2,
+    FUZZ_HASH      = 3,
+    FUZZ_HEAD      = 4
+};
+
+typedef int (*CallbackFuzzer)(WOLFSSL* ssl, const unsigned char* buf, int sz,
+        int type, void* fuzzCtx);
+
+WOLFSSL_API void wolfSSL_SetFuzzerCb(WOLFSSL* ssl, CallbackFuzzer cbf, void* fCtx);
+#endif
+
+WOLFSSL_API void wolfSSL_SetIORecv(WOLFSSL_CTX*, CallbackIORecv);
+WOLFSSL_API void wolfSSL_SetIOSend(WOLFSSL_CTX*, CallbackIOSend);
+
+WOLFSSL_API void wolfSSL_SetIOReadCtx( WOLFSSL* ssl, void *ctx);
+WOLFSSL_API void wolfSSL_SetIOWriteCtx(WOLFSSL* ssl, void *ctx);
+
+WOLFSSL_API void* wolfSSL_GetIOReadCtx( WOLFSSL* ssl);
+WOLFSSL_API void* wolfSSL_GetIOWriteCtx(WOLFSSL* ssl);
+
+WOLFSSL_API void wolfSSL_SetIOReadFlags( WOLFSSL* ssl, int flags);
+WOLFSSL_API void wolfSSL_SetIOWriteFlags(WOLFSSL* ssl, int flags);
+
+
+#ifndef WOLFSSL_USER_IO
+    /* default IO callbacks */
+    WOLFSSL_API int EmbedReceive(WOLFSSL* ssl, char* buf, int sz, void* ctx);
+    WOLFSSL_API int EmbedSend(WOLFSSL* ssl, char* buf, int sz, void* ctx);
+
+    #ifdef HAVE_OCSP
+        WOLFSSL_API int EmbedOcspLookup(void*, const char*, int, unsigned char*,
+                                       int, unsigned char**);
+        WOLFSSL_API void EmbedOcspRespFree(void*, unsigned char*);
+    #endif
+
+    #ifdef WOLFSSL_DTLS
+        WOLFSSL_API int EmbedReceiveFrom(WOLFSSL* ssl, char* buf, int sz, void*);
+        WOLFSSL_API int EmbedSendTo(WOLFSSL* ssl, char* buf, int sz, void* ctx);
+        WOLFSSL_API int EmbedGenerateCookie(WOLFSSL* ssl, unsigned char* buf,
+                                           int sz, void*);
+    #endif /* WOLFSSL_DTLS */
+#endif /* WOLFSSL_USER_IO */
+
+
+#ifdef HAVE_NETX
+    WOLFSSL_API void wolfSSL_SetIO_NetX(WOLFSSL* ssl, NX_TCP_SOCKET* nxsocket,
+                                      ULONG waitoption);
+#endif
+
+typedef int (*CallbackGenCookie)(WOLFSSL* ssl, unsigned char* buf, int sz,
+                                 void* ctx);
+WOLFSSL_API void  wolfSSL_CTX_SetGenCookie(WOLFSSL_CTX*, CallbackGenCookie);
+WOLFSSL_API void  wolfSSL_SetCookieCtx(WOLFSSL* ssl, void *ctx);
+WOLFSSL_API void* wolfSSL_GetCookieCtx(WOLFSSL* ssl);
+
+
+/* I/O Callback default errors */
+enum IOerrors {
+    WOLFSSL_CBIO_ERR_GENERAL    = -1,     /* general unexpected err */
+    WOLFSSL_CBIO_ERR_WANT_READ  = -2,     /* need to call read  again */
+    WOLFSSL_CBIO_ERR_WANT_WRITE = -2,     /* need to call write again */
+    WOLFSSL_CBIO_ERR_CONN_RST   = -3,     /* connection reset */
+    WOLFSSL_CBIO_ERR_ISR        = -4,     /* interrupt */
+    WOLFSSL_CBIO_ERR_CONN_CLOSE = -5,     /* connection closed or epipe */
+    WOLFSSL_CBIO_ERR_TIMEOUT    = -6      /* socket timeout */
+};
+
+
+/* CA cache callbacks */
+enum {
+    WOLFSSL_SSLV3    = 0,
+    WOLFSSL_TLSV1    = 1,
+    WOLFSSL_TLSV1_1  = 2,
+    WOLFSSL_TLSV1_2  = 3,
+    WOLFSSL_USER_CA  = 1,          /* user added as trusted */
+    WOLFSSL_CHAIN_CA = 2           /* added to cache from trusted chain */
+};
+
+WOLFSSL_API int wolfSSL_CTX_SetMinVersion(WOLFSSL_CTX* ctx, int version);
+WOLFSSL_API int wolfSSL_SetMinVersion(WOLFSSL* ssl, int version);
+WOLFSSL_API int wolfSSL_GetObjectSize(void);  /* object size based on build */
+WOLFSSL_API int wolfSSL_SetVersion(WOLFSSL* ssl, int version);
+WOLFSSL_API int wolfSSL_KeyPemToDer(const unsigned char*, int sz, unsigned char*,
+                                  int, const char*);
+WOLFSSL_API int wolfSSL_CertPemToDer(const unsigned char*, int sz, unsigned char*,
+                                   int, int);
+
+typedef void (*CallbackCACache)(unsigned char* der, int sz, int type);
+typedef void (*CbMissingCRL)(const char* url);
+typedef int  (*CbOCSPIO)(void*, const char*, int,
+                                         unsigned char*, int, unsigned char**);
+typedef void (*CbOCSPRespFree)(void*,unsigned char*);
+
+/* User Atomic Record Layer CallBacks */
+typedef int (*CallbackMacEncrypt)(WOLFSSL* ssl, unsigned char* macOut,
+       const unsigned char* macIn, unsigned int macInSz, int macContent,
+       int macVerify, unsigned char* encOut, const unsigned char* encIn,
+       unsigned int encSz, void* ctx);
+WOLFSSL_API void  wolfSSL_CTX_SetMacEncryptCb(WOLFSSL_CTX*, CallbackMacEncrypt);
+WOLFSSL_API void  wolfSSL_SetMacEncryptCtx(WOLFSSL* ssl, void *ctx);
+WOLFSSL_API void* wolfSSL_GetMacEncryptCtx(WOLFSSL* ssl);
+
+typedef int (*CallbackDecryptVerify)(WOLFSSL* ssl,
+       unsigned char* decOut, const unsigned char* decIn,
+       unsigned int decSz, int content, int verify, unsigned int* padSz,
+       void* ctx);
+WOLFSSL_API void  wolfSSL_CTX_SetDecryptVerifyCb(WOLFSSL_CTX*,
+                                               CallbackDecryptVerify);
+WOLFSSL_API void  wolfSSL_SetDecryptVerifyCtx(WOLFSSL* ssl, void *ctx);
+WOLFSSL_API void* wolfSSL_GetDecryptVerifyCtx(WOLFSSL* ssl);
+
+WOLFSSL_API const unsigned char* wolfSSL_GetMacSecret(WOLFSSL*, int);
+WOLFSSL_API const unsigned char* wolfSSL_GetClientWriteKey(WOLFSSL*);
+WOLFSSL_API const unsigned char* wolfSSL_GetClientWriteIV(WOLFSSL*);
+WOLFSSL_API const unsigned char* wolfSSL_GetServerWriteKey(WOLFSSL*);
+WOLFSSL_API const unsigned char* wolfSSL_GetServerWriteIV(WOLFSSL*);
+WOLFSSL_API int                  wolfSSL_GetKeySize(WOLFSSL*);
+WOLFSSL_API int                  wolfSSL_GetIVSize(WOLFSSL*);
+WOLFSSL_API int                  wolfSSL_GetSide(WOLFSSL*);
+WOLFSSL_API int                  wolfSSL_IsTLSv1_1(WOLFSSL*);
+WOLFSSL_API int                  wolfSSL_GetBulkCipher(WOLFSSL*);
+WOLFSSL_API int                  wolfSSL_GetCipherBlockSize(WOLFSSL*);
+WOLFSSL_API int                  wolfSSL_GetAeadMacSize(WOLFSSL*);
+WOLFSSL_API int                  wolfSSL_GetHmacSize(WOLFSSL*);
+WOLFSSL_API int                  wolfSSL_GetHmacType(WOLFSSL*);
+WOLFSSL_API int                  wolfSSL_GetCipherType(WOLFSSL*);
+WOLFSSL_API int                  wolfSSL_SetTlsHmacInner(WOLFSSL*, unsigned char*,
+                                                       unsigned int, int, int);
+
+/* Atomic User Needs */
+enum {
+    WOLFSSL_SERVER_END = 0,
+    WOLFSSL_CLIENT_END = 1,
+    WOLFSSL_BLOCK_TYPE = 2,
+    WOLFSSL_STREAM_TYPE = 3,
+    WOLFSSL_AEAD_TYPE = 4,
+    WOLFSSL_TLS_HMAC_INNER_SZ = 13      /* SEQ_SZ + ENUM + VERSION_SZ + LEN_SZ */
+};
+
+/* for GetBulkCipher and internal use */
+enum BulkCipherAlgorithm {
+    wolfssl_cipher_null,
+    wolfssl_rc4,
+    wolfssl_rc2,
+    wolfssl_des,
+    wolfssl_triple_des,             /* leading 3 (3des) not valid identifier */
+    wolfssl_des40,
+    wolfssl_idea,
+    wolfssl_aes,
+    wolfssl_aes_gcm,
+    wolfssl_aes_ccm,
+    wolfssl_chacha,
+    wolfssl_camellia,
+    wolfssl_hc128,                  /* wolfSSL extensions */
+    wolfssl_rabbit
+};
+
+
+/* for KDF TLS 1.2 mac types */
+enum KDF_MacAlgorithm {
+    wolfssl_sha256 = 4,     /* needs to match internal MACAlgorithm */
+    wolfssl_sha384,
+    wolfssl_sha512
+};
+
+
+/* Public Key Callback support */
+typedef int (*CallbackEccSign)(WOLFSSL* ssl,
+       const unsigned char* in, unsigned int inSz,
+       unsigned char* out, unsigned int* outSz,
+       const unsigned char* keyDer, unsigned int keySz,
+       void* ctx);
+WOLFSSL_API void  wolfSSL_CTX_SetEccSignCb(WOLFSSL_CTX*, CallbackEccSign);
+WOLFSSL_API void  wolfSSL_SetEccSignCtx(WOLFSSL* ssl, void *ctx);
+WOLFSSL_API void* wolfSSL_GetEccSignCtx(WOLFSSL* ssl);
+
+typedef int (*CallbackEccVerify)(WOLFSSL* ssl,
+       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);
+WOLFSSL_API void  wolfSSL_CTX_SetEccVerifyCb(WOLFSSL_CTX*, CallbackEccVerify);
+WOLFSSL_API void  wolfSSL_SetEccVerifyCtx(WOLFSSL* ssl, void *ctx);
+WOLFSSL_API void* wolfSSL_GetEccVerifyCtx(WOLFSSL* ssl);
+
+typedef int (*CallbackRsaSign)(WOLFSSL* ssl,
+       const unsigned char* in, unsigned int inSz,
+       unsigned char* out, unsigned int* outSz,
+       const unsigned char* keyDer, unsigned int keySz,
+       void* ctx);
+WOLFSSL_API void  wolfSSL_CTX_SetRsaSignCb(WOLFSSL_CTX*, CallbackRsaSign);
+WOLFSSL_API void  wolfSSL_SetRsaSignCtx(WOLFSSL* ssl, void *ctx);
+WOLFSSL_API void* wolfSSL_GetRsaSignCtx(WOLFSSL* ssl);
+
+typedef int (*CallbackRsaVerify)(WOLFSSL* ssl,
+       unsigned char* sig, unsigned int sigSz,
+       unsigned char** out,
+       const unsigned char* keyDer, unsigned int keySz,
+       void* ctx);
+WOLFSSL_API void  wolfSSL_CTX_SetRsaVerifyCb(WOLFSSL_CTX*, CallbackRsaVerify);
+WOLFSSL_API void  wolfSSL_SetRsaVerifyCtx(WOLFSSL* ssl, void *ctx);
+WOLFSSL_API void* wolfSSL_GetRsaVerifyCtx(WOLFSSL* ssl);
+
+/* RSA Public Encrypt cb */
+typedef int (*CallbackRsaEnc)(WOLFSSL* ssl,
+       const unsigned char* in, unsigned int inSz,
+       unsigned char* out, unsigned int* outSz,
+       const unsigned char* keyDer, unsigned int keySz,
+       void* ctx);
+WOLFSSL_API void  wolfSSL_CTX_SetRsaEncCb(WOLFSSL_CTX*, CallbackRsaEnc);
+WOLFSSL_API void  wolfSSL_SetRsaEncCtx(WOLFSSL* ssl, void *ctx);
+WOLFSSL_API void* wolfSSL_GetRsaEncCtx(WOLFSSL* ssl);
+
+/* RSA Private Decrypt cb */
+typedef int (*CallbackRsaDec)(WOLFSSL* ssl,
+       unsigned char* in, unsigned int inSz,
+       unsigned char** out,
+       const unsigned char* keyDer, unsigned int keySz,
+       void* ctx);
+WOLFSSL_API void  wolfSSL_CTX_SetRsaDecCb(WOLFSSL_CTX*, CallbackRsaDec);
+WOLFSSL_API void  wolfSSL_SetRsaDecCtx(WOLFSSL* ssl, void *ctx);
+WOLFSSL_API void* wolfSSL_GetRsaDecCtx(WOLFSSL* ssl);
+
+
+#ifndef NO_CERTS
+	WOLFSSL_API void wolfSSL_CTX_SetCACb(WOLFSSL_CTX*, CallbackCACache);
+
+    WOLFSSL_API WOLFSSL_CERT_MANAGER* wolfSSL_CertManagerNew(void);
+    WOLFSSL_API void wolfSSL_CertManagerFree(WOLFSSL_CERT_MANAGER*);
+
+    WOLFSSL_API int wolfSSL_CertManagerLoadCA(WOLFSSL_CERT_MANAGER*, const char* f,
+                                                                 const char* d);
+    WOLFSSL_API int wolfSSL_CertManagerUnloadCAs(WOLFSSL_CERT_MANAGER* cm);
+    WOLFSSL_API int wolfSSL_CertManagerVerify(WOLFSSL_CERT_MANAGER*, const char* f,
+                                                                    int format);
+    WOLFSSL_API int wolfSSL_CertManagerVerifyBuffer(WOLFSSL_CERT_MANAGER* cm,
+                                const unsigned char* buff, long sz, int format);
+    WOLFSSL_API int wolfSSL_CertManagerCheckCRL(WOLFSSL_CERT_MANAGER*,
+                                                        unsigned char*, int sz);
+    WOLFSSL_API int wolfSSL_CertManagerEnableCRL(WOLFSSL_CERT_MANAGER*,
+                                                                   int options);
+    WOLFSSL_API int wolfSSL_CertManagerDisableCRL(WOLFSSL_CERT_MANAGER*);
+    WOLFSSL_API int wolfSSL_CertManagerLoadCRL(WOLFSSL_CERT_MANAGER*, const char*,
+                                                                      int, int);
+    WOLFSSL_API int wolfSSL_CertManagerSetCRL_Cb(WOLFSSL_CERT_MANAGER*,
+                                                                  CbMissingCRL);
+    WOLFSSL_API int wolfSSL_CertManagerCheckOCSP(WOLFSSL_CERT_MANAGER*,
+                                                        unsigned char*, int sz);
+    WOLFSSL_API int wolfSSL_CertManagerEnableOCSP(WOLFSSL_CERT_MANAGER*,
+                                                                   int options);
+    WOLFSSL_API int wolfSSL_CertManagerDisableOCSP(WOLFSSL_CERT_MANAGER*);
+    WOLFSSL_API int wolfSSL_CertManagerSetOCSPOverrideURL(WOLFSSL_CERT_MANAGER*,
+                                                                   const char*);
+    WOLFSSL_API int wolfSSL_CertManagerSetOCSP_Cb(WOLFSSL_CERT_MANAGER*,
+                                               CbOCSPIO, CbOCSPRespFree, void*);
+
+    WOLFSSL_API int wolfSSL_EnableCRL(WOLFSSL* ssl, int options);
+    WOLFSSL_API int wolfSSL_DisableCRL(WOLFSSL* ssl);
+    WOLFSSL_API int wolfSSL_LoadCRL(WOLFSSL*, const char*, int, int);
+    WOLFSSL_API int wolfSSL_SetCRL_Cb(WOLFSSL*, CbMissingCRL);
+    WOLFSSL_API int wolfSSL_EnableOCSP(WOLFSSL*, int options);
+    WOLFSSL_API int wolfSSL_DisableOCSP(WOLFSSL*);
+    WOLFSSL_API int wolfSSL_SetOCSP_OverrideURL(WOLFSSL*, const char*);
+    WOLFSSL_API int wolfSSL_SetOCSP_Cb(WOLFSSL*, CbOCSPIO, CbOCSPRespFree, void*);
+
+    WOLFSSL_API int wolfSSL_CTX_EnableCRL(WOLFSSL_CTX* ctx, int options);
+    WOLFSSL_API int wolfSSL_CTX_DisableCRL(WOLFSSL_CTX* ctx);
+    WOLFSSL_API int wolfSSL_CTX_LoadCRL(WOLFSSL_CTX*, const char*, int, int);
+    WOLFSSL_API int wolfSSL_CTX_SetCRL_Cb(WOLFSSL_CTX*, CbMissingCRL);
+    WOLFSSL_API int wolfSSL_CTX_EnableOCSP(WOLFSSL_CTX*, int options);
+    WOLFSSL_API int wolfSSL_CTX_DisableOCSP(WOLFSSL_CTX*);
+    WOLFSSL_API int wolfSSL_CTX_SetOCSP_OverrideURL(WOLFSSL_CTX*, const char*);
+    WOLFSSL_API int wolfSSL_CTX_SetOCSP_Cb(WOLFSSL_CTX*,
+                                               CbOCSPIO, CbOCSPRespFree, void*);
+#endif /* !NO_CERTS */
+
+/* end of handshake frees temporary arrays, if user needs for get_keys or
+   psk hints, call KeepArrays before handshake and then FreeArrays when done
+   if don't want to wait for object free */
+WOLFSSL_API void wolfSSL_KeepArrays(WOLFSSL*);
+WOLFSSL_API void wolfSSL_FreeArrays(WOLFSSL*);
+
+
+/* cavium additions */
+WOLFSSL_API int wolfSSL_UseCavium(WOLFSSL*, int devId);
+WOLFSSL_API int wolfSSL_CTX_UseCavium(WOLFSSL_CTX*, int devId);
+
+/* TLS Extensions */
+
+/* Server Name Indication */
+#ifdef HAVE_SNI
+
+/* SNI types */
+enum {
+    WOLFSSL_SNI_HOST_NAME = 0
+};
+
+WOLFSSL_API int wolfSSL_UseSNI(WOLFSSL* ssl, unsigned char type, const void* data,
+                                                           unsigned short size);
+WOLFSSL_API int wolfSSL_CTX_UseSNI(WOLFSSL_CTX* ctx, unsigned char type,
+                                         const void* data, unsigned short size);
+
+#ifndef NO_WOLFSSL_SERVER
+
+/* SNI options */
+enum {
+    WOLFSSL_SNI_CONTINUE_ON_MISMATCH = 0x01, /* do not abort on mismatch flag */
+    WOLFSSL_SNI_ANSWER_ON_MISMATCH   = 0x02  /* fake match on mismatch flag */
+};
+
+WOLFSSL_API void wolfSSL_SNI_SetOptions(WOLFSSL* ssl, unsigned char type,
+                                                         unsigned char options);
+WOLFSSL_API void wolfSSL_CTX_SNI_SetOptions(WOLFSSL_CTX* ctx, unsigned char type,
+                                                         unsigned char options);
+
+/* SNI status */
+enum {
+    WOLFSSL_SNI_NO_MATCH   = 0,
+    WOLFSSL_SNI_FAKE_MATCH = 1, /* if WOLFSSL_SNI_ANSWER_ON_MISMATCH is enabled */
+    WOLFSSL_SNI_REAL_MATCH = 2
+};
+
+WOLFSSL_API unsigned char wolfSSL_SNI_Status(WOLFSSL* ssl, unsigned char type);
+
+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
+
+/* Maximum Fragment Length */
+#ifdef HAVE_MAX_FRAGMENT
+
+/* Fragment lengths */
+enum {
+    WOLFSSL_MFL_2_9  = 1, /*  512 bytes */
+    WOLFSSL_MFL_2_10 = 2, /* 1024 bytes */
+    WOLFSSL_MFL_2_11 = 3, /* 2048 bytes */
+    WOLFSSL_MFL_2_12 = 4, /* 4096 bytes */
+    WOLFSSL_MFL_2_13 = 5  /* 8192 bytes *//* wolfSSL ONLY!!! */
+};
+
+#ifndef NO_WOLFSSL_CLIENT
+
+WOLFSSL_API int wolfSSL_UseMaxFragment(WOLFSSL* ssl, unsigned char mfl);
+WOLFSSL_API int wolfSSL_CTX_UseMaxFragment(WOLFSSL_CTX* ctx, unsigned char mfl);
+
+#endif
+#endif
+
+/* Truncated HMAC */
+#ifdef HAVE_TRUNCATED_HMAC
+#ifndef NO_WOLFSSL_CLIENT
+
+WOLFSSL_API int wolfSSL_UseTruncatedHMAC(WOLFSSL* ssl);
+WOLFSSL_API int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx);
+
+#endif
+#endif
+
+/* Elliptic Curves */
+enum {
+    WOLFSSL_ECC_SECP160R1 = 0x10,
+    WOLFSSL_ECC_SECP192R1 = 0x13,
+    WOLFSSL_ECC_SECP224R1 = 0x15,
+    WOLFSSL_ECC_SECP256R1 = 0x17,
+    WOLFSSL_ECC_SECP384R1 = 0x18,
+    WOLFSSL_ECC_SECP521R1 = 0x19
+};
+
+#ifdef HAVE_SUPPORTED_CURVES
+#ifndef NO_WOLFSSL_CLIENT
+
+WOLFSSL_API int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, unsigned short name);
+WOLFSSL_API int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx,
+                                                           unsigned short name);
+
+#endif
+#endif
+
+/* Secure Renegotiation */
+#ifdef HAVE_SECURE_RENEGOTIATION
+
+WOLFSSL_API int wolfSSL_UseSecureRenegotiation(WOLFSSL* ssl);
+WOLFSSL_API int wolfSSL_Rehandshake(WOLFSSL* ssl);
+
+#endif
+
+/* Session Ticket */
+#ifdef HAVE_SESSION_TICKET
+
+#ifndef NO_WOLFSSL_CLIENT
+WOLFSSL_API int wolfSSL_UseSessionTicket(WOLFSSL* ssl);
+WOLFSSL_API int wolfSSL_CTX_UseSessionTicket(WOLFSSL_CTX* ctx);
+WOLFSSL_API int wolfSSL_get_SessionTicket(WOLFSSL*, unsigned char*, unsigned int*);
+WOLFSSL_API int wolfSSL_set_SessionTicket(WOLFSSL*, unsigned char*, unsigned int);
+typedef int (*CallbackSessionTicket)(WOLFSSL*, const unsigned char*, int, void*);
+WOLFSSL_API int wolfSSL_set_SessionTicket_cb(WOLFSSL*,
+                                                  CallbackSessionTicket, void*);
+#endif /* NO_WOLFSSL_CLIENT */
+
+#ifndef NO_WOLFSSL_SERVER
+
+#define WOLFSSL_TICKET_NAME_SZ 16
+#define WOLFSSL_TICKET_IV_SZ   16
+#define WOLFSSL_TICKET_MAC_SZ  32
+
+enum TicketEncRet {
+    WOLFSSL_TICKET_RET_FATAL  = -1,  /* fatal error, don't use ticket */
+    WOLFSSL_TICKET_RET_OK     =  0,  /* ok, use ticket */
+    WOLFSSL_TICKET_RET_REJECT,       /* don't use ticket, but not fatal */
+    WOLFSSL_TICKET_RET_CREATE        /* existing ticket ok and create new one */
+};
+
+typedef int (*SessionTicketEncCb)(WOLFSSL*,
+                                 unsigned char key_name[WOLFSSL_TICKET_NAME_SZ],
+                                 unsigned char iv[WOLFSSL_TICKET_IV_SZ],
+                                 unsigned char mac[WOLFSSL_TICKET_MAC_SZ],
+                                 int enc, unsigned char*, int, int*, void*);
+WOLFSSL_API int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx,
+                                            SessionTicketEncCb);
+WOLFSSL_API int wolfSSL_CTX_set_TicketHint(WOLFSSL_CTX* ctx, int);
+WOLFSSL_API int wolfSSL_CTX_set_TicketEncCtx(WOLFSSL_CTX* ctx, void*);
+
+#endif /* NO_WOLFSSL_SERVER */
+
+#endif /* HAVE_SESSION_TICKET */
+
+#define WOLFSSL_CRL_MONITOR   0x01   /* monitor this dir flag */
+#define WOLFSSL_CRL_START_MON 0x02   /* start monitoring flag */
+
+
+/* notify user the hanshake is done */
+typedef int (*HandShakeDoneCb)(WOLFSSL*, void*);
+WOLFSSL_API int wolfSSL_SetHsDoneCb(WOLFSSL*, HandShakeDoneCb, void*);
+
+
+WOLFSSL_API int wolfSSL_PrintSessionStats(void);
+WOLFSSL_API int wolfSSL_get_session_stats(unsigned int* active,
+                                          unsigned int* total,
+                                          unsigned int* peak,
+                                          unsigned int* maxSessions);
+/* External facing KDF */
+WOLFSSL_API
+int wolfSSL_MakeTlsMasterSecret(unsigned char* ms, unsigned int msLen,
+                               const unsigned char* pms, unsigned int pmsLen,
+                               const unsigned char* cr, const unsigned char* sr,
+                               int tls1_2, int hash_type);
+
+WOLFSSL_API
+int wolfSSL_DeriveTlsKeys(unsigned char* key_data, unsigned int keyLen,
+                               const unsigned char* ms, unsigned int msLen,
+                               const unsigned char* sr, const unsigned char* cr,
+                               int tls1_2, int hash_type);
+
+#ifdef WOLFSSL_CALLBACKS
+
+/* used internally by wolfSSL while OpenSSL types aren't */
+#include <wolfssl/callbacks.h>
+
+typedef int (*HandShakeCallBack)(HandShakeInfo*);
+typedef int (*TimeoutCallBack)(TimeoutInfo*);
+
+/* wolfSSL connect extension allowing HandShakeCallBack and/or TimeoutCallBack
+   for diagnostics */
+WOLFSSL_API int wolfSSL_connect_ex(WOLFSSL*, HandShakeCallBack, TimeoutCallBack,
+                                 Timeval);
+WOLFSSL_API int wolfSSL_accept_ex(WOLFSSL*, HandShakeCallBack, TimeoutCallBack,
+                                Timeval);
+
+#endif /* WOLFSSL_CALLBACKS */
+
+
+#ifdef WOLFSSL_HAVE_WOLFSCEP
+    WOLFSSL_API void wolfSSL_wolfSCEP(void);
+#endif /* WOLFSSL_HAVE_WOLFSCEP */
+
+#ifdef WOLFSSL_HAVE_CERT_SERVICE
+    WOLFSSL_API void wolfSSL_cert_service(void);
+#endif
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+
+#endif /* WOLFSSL_SSL_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/test.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,1953 @@
+/* test.h */
+
+#ifndef wolfSSL_TEST_H
+#define wolfSSL_TEST_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <ctype.h>
+#include <wolfssl/wolfcrypt/types.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/random.h>
+
+#ifdef ATOMIC_USER
+    #include <wolfssl/wolfcrypt/aes.h>
+    #include <wolfssl/wolfcrypt/arc4.h>
+    #include <wolfssl/wolfcrypt/hmac.h>
+#endif
+#ifdef HAVE_PK_CALLBACKS
+    #include <wolfssl/wolfcrypt/asn.h>
+    #ifdef HAVE_ECC
+        #include <wolfssl/wolfcrypt/ecc.h>
+    #endif /* HAVE_ECC */
+#endif /*HAVE_PK_CALLBACKS */
+
+#ifdef USE_WINDOWS_API 
+    #include <winsock2.h>
+    #include <process.h>
+    #ifdef TEST_IPV6            /* don't require newer SDK for IPV4 */
+        #include <ws2tcpip.h>
+        #include <wspiapi.h>
+    #endif
+    #define SOCKET_T SOCKET
+    #define SNPRINTF _snprintf
+#elif defined(WOLFSSL_MDK_ARM)
+    #include <string.h>
+#elif defined(WOLFSSL_TIRTOS)
+    #include <string.h>
+    #include <netdb.h>
+    #include <sys/types.h>
+    #include <arpa/inet.h>
+    #include <sys/socket.h>
+    #include <ti/sysbios/knl/Task.h>
+    struct hostent {
+    	char *h_name; /* official name of host */
+    	char **h_aliases; /* alias list */
+    	int h_addrtype; /* host address type */
+    	int h_length; /* length of address */
+    	char **h_addr_list; /* list of addresses from name server */
+    };
+    #define SOCKET_T int
+#else
+    #include <string.h>
+    #include <sys/types.h>
+#ifndef WOLFSSL_LEANPSK
+    #include <unistd.h>
+    #include <netdb.h>
+    #include <netinet/in.h>
+    #include <netinet/tcp.h>
+    #include <arpa/inet.h>
+    #include <sys/ioctl.h>
+    #include <sys/time.h>
+    #include <sys/socket.h>
+    #include <pthread.h>
+    #include <fcntl.h>
+    #ifdef TEST_IPV6
+        #include <netdb.h>
+    #endif
+#endif
+    #define SOCKET_T int
+    #ifndef SO_NOSIGPIPE
+        #include <signal.h>  /* ignore SIGPIPE */
+    #endif
+    #define SNPRINTF snprintf
+#endif /* USE_WINDOWS_API */
+
+#ifdef HAVE_CAVIUM
+    #include "cavium_sysdep.h"
+    #include "cavium_common.h"
+    #include "cavium_ioctl.h"
+#endif
+
+#ifdef _MSC_VER
+    /* disable conversion warning */
+    /* 4996 warning to use MS extensions e.g., strcpy_s instead of strncpy */
+    #pragma warning(disable:4244 4996)
+#endif
+
+
+#if defined(__MACH__) || defined(USE_WINDOWS_API)
+    #ifndef _SOCKLEN_T
+        typedef int socklen_t;
+    #endif
+#endif
+
+
+/* HPUX doesn't use socklent_t for third parameter to accept, unless
+   _XOPEN_SOURCE_EXTENDED is defined */
+#if !defined(__hpux__) && !defined(WOLFSSL_MDK_ARM) && !defined(WOLFSSL_IAR_ARM)
+    typedef socklen_t* ACCEPT_THIRD_T;
+#else
+    #if defined _XOPEN_SOURCE_EXTENDED
+        typedef socklen_t* ACCEPT_THIRD_T;
+    #else
+        typedef int*       ACCEPT_THIRD_T;
+    #endif
+#endif
+
+
+#ifdef USE_WINDOWS_API 
+    #define CloseSocket(s) closesocket(s)
+    #define StartTCP() { WSADATA wsd; WSAStartup(0x0002, &wsd); }
+#elif defined(WOLFSSL_MDK_ARM)
+    #define CloseSocket(s) closesocket(s)
+    #define StartTCP() 
+#else
+    #define CloseSocket(s) close(s)
+    #define StartTCP() 
+#endif
+
+
+#ifdef SINGLE_THREADED
+    typedef unsigned int  THREAD_RETURN;
+    typedef void*         THREAD_TYPE;
+    #define WOLFSSL_THREAD
+#else
+    #if defined(_POSIX_THREADS) && !defined(__MINGW32__)
+        typedef void*         THREAD_RETURN;
+        typedef pthread_t     THREAD_TYPE;
+        #define WOLFSSL_THREAD
+        #define INFINITE -1
+        #define WAIT_OBJECT_0 0L
+    #elif defined(WOLFSSL_MDK_ARM)
+        typedef unsigned int  THREAD_RETURN;
+        typedef int           THREAD_TYPE;
+        #define WOLFSSL_THREAD
+    #elif defined(WOLFSSL_TIRTOS)
+        typedef void          THREAD_RETURN;
+        typedef Task_Handle   THREAD_TYPE;
+        #define WOLFSSL_THREAD
+    #else
+        typedef unsigned int  THREAD_RETURN;
+        typedef intptr_t      THREAD_TYPE;
+        #define WOLFSSL_THREAD __stdcall
+    #endif
+#endif
+
+
+#ifdef TEST_IPV6
+    typedef struct sockaddr_in6 SOCKADDR_IN_T;
+    #define AF_INET_V    AF_INET6
+#else
+    typedef struct sockaddr_in  SOCKADDR_IN_T;
+    #define AF_INET_V    AF_INET
+#endif
+   
+
+#define SERVER_DEFAULT_VERSION 3
+#define SERVER_DTLS_DEFAULT_VERSION (-2)
+#define SERVER_INVALID_VERSION (-99)
+#define CLIENT_DEFAULT_VERSION 3
+#define CLIENT_DTLS_DEFAULT_VERSION (-2)
+#define CLIENT_INVALID_VERSION (-99)
+#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_MAX_STRENGTH)
+    #define DEFAULT_MIN_DHKEY_BITS 2048
+#else
+    #define DEFAULT_MIN_DHKEY_BITS 1024
+#endif
+
+/* all certs relative to wolfSSL home directory now */
+#define caCert     "./certs/ca-cert.pem"
+#define eccCert    "./certs/server-ecc.pem"
+#define eccKey     "./certs/ecc-key.pem"
+#define svrCert    "./certs/server-cert.pem"
+#define svrKey     "./certs/server-key.pem"
+#define cliCert    "./certs/client-cert.pem"
+#define cliKey     "./certs/client-key.pem"
+#define ntruCert   "./certs/ntru-cert.pem"
+#define ntruKey    "./certs/ntru-key.raw"
+#define dhParam    "./certs/dh2048.pem"
+#define cliEccKey  "./certs/ecc-client-key.pem"
+#define cliEccCert "./certs/client-ecc-cert.pem"
+#define crlPemDir  "./certs/crl"
+
+typedef struct tcp_ready {
+    word16 ready;              /* predicate */
+    word16 port;
+#if defined(_POSIX_THREADS) && !defined(__MINGW32__)
+    pthread_mutex_t mutex;
+    pthread_cond_t  cond;
+#endif
+} tcp_ready;    
+
+
+void InitTcpReady(tcp_ready*);
+void FreeTcpReady(tcp_ready*);
+
+typedef WOLFSSL_METHOD* (*method_provider)(void);
+typedef void (*ctx_callback)(WOLFSSL_CTX* ctx);
+typedef void (*ssl_callback)(WOLFSSL* ssl);
+
+typedef struct callback_functions {
+    method_provider method;
+    ctx_callback ctx_ready;
+    ssl_callback ssl_ready;
+    ssl_callback on_result;
+} callback_functions;
+
+typedef struct func_args {
+    int    argc;
+    char** argv;
+    int    return_code;
+    tcp_ready* signal;
+    callback_functions *callbacks;
+} func_args;
+
+void wait_tcp_ready(func_args*);
+
+typedef THREAD_RETURN WOLFSSL_THREAD THREAD_FUNC(void*);
+
+void start_thread(THREAD_FUNC, func_args*, THREAD_TYPE*);
+void join_thread(THREAD_TYPE);
+
+/* wolfSSL */
+#ifndef TEST_IPV6
+    static const char* const wolfSSLIP   = "127.0.0.1";
+#else
+    static const char* const wolfSSLIP   = "::1";
+#endif
+static const word16      wolfSSLPort = 11111;
+
+static INLINE void err_sys(const char* msg)
+{
+    printf("wolfSSL error: %s\n", msg);
+    if (msg)
+        exit(EXIT_FAILURE);
+}
+
+
+#define MY_EX_USAGE 2
+
+extern int   myoptind;
+extern char* myoptarg;
+
+static INLINE int mygetopt(int argc, char** argv, const char* optstring)
+{
+    static char* next = NULL;
+
+    char  c;
+    char* cp;
+
+    if (myoptind == 0)
+        next = NULL;   /* we're starting new/over */
+
+    if (next == NULL || *next == '\0') {
+        if (myoptind == 0)
+            myoptind++;
+
+        if (myoptind >= argc || argv[myoptind][0] != '-' ||
+                                argv[myoptind][1] == '\0') {
+            myoptarg = NULL;
+            if (myoptind < argc)
+                myoptarg = argv[myoptind];
+
+            return -1;
+        }
+
+        if (strcmp(argv[myoptind], "--") == 0) {
+            myoptind++;
+            myoptarg = NULL;
+
+            if (myoptind < argc)
+                myoptarg = argv[myoptind];
+
+            return -1;
+        }
+
+        next = argv[myoptind];
+        next++;                  /* skip - */
+        myoptind++;
+    }
+
+    c  = *next++;
+    /* The C++ strchr can return a different value */
+    cp = (char*)strchr(optstring, c);
+
+    if (cp == NULL || c == ':') 
+        return '?';
+
+    cp++;
+
+    if (*cp == ':') {
+        if (*next != '\0') {
+            myoptarg = next;
+            next     = NULL;
+        }
+        else if (myoptind < argc) {
+            myoptarg = argv[myoptind];
+            myoptind++;
+        }
+        else 
+            return '?';
+    }
+
+    return c;
+}
+
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+
+static INLINE int PasswordCallBack(char* passwd, int sz, int rw, void* userdata)
+{
+    (void)rw;
+    (void)userdata;
+    strncpy(passwd, "yassl123", sz);
+    return 8;
+}
+
+#endif
+
+
+#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
+
+static INLINE void ShowX509(WOLFSSL_X509* x509, const char* hdr)
+{
+    char* altName;
+    char* issuer  = wolfSSL_X509_NAME_oneline(
+                                       wolfSSL_X509_get_issuer_name(x509), 0, 0);
+    char* subject = wolfSSL_X509_NAME_oneline(
+                                      wolfSSL_X509_get_subject_name(x509), 0, 0);
+    byte  serial[32];
+    int   ret;
+    int   sz = sizeof(serial);
+        
+    printf("%s\n issuer : %s\n subject: %s\n", hdr, issuer, subject);
+
+    while ( (altName = wolfSSL_X509_get_next_altname(x509)) != NULL)
+        printf(" altname = %s\n", altName);
+
+    ret = wolfSSL_X509_get_serial_number(x509, serial, &sz);
+    if (ret == SSL_SUCCESS) {
+        int  i;
+        int  strLen;
+        char serialMsg[80];
+
+        /* testsuite has multiple threads writing to stdout, get output
+           message ready to write once */
+        strLen = sprintf(serialMsg, " serial number");
+        for (i = 0; i < sz; i++)
+            sprintf(serialMsg + strLen + (i*3), ":%02x ", serial[i]);
+        printf("%s\n", serialMsg);
+    }
+
+    XFREE(subject, 0, DYNAMIC_TYPE_OPENSSL);
+    XFREE(issuer,  0, DYNAMIC_TYPE_OPENSSL);
+}
+
+#endif /* KEEP_PEER_CERT || SESSION_CERTS */
+
+
+static INLINE void showPeer(WOLFSSL* ssl)
+{
+
+    WOLFSSL_CIPHER* cipher;
+#ifdef KEEP_PEER_CERT
+    WOLFSSL_X509* peer = wolfSSL_get_peer_certificate(ssl);
+    if (peer)
+        ShowX509(peer, "peer's cert info:");
+    else
+        printf("peer has no cert!\n");
+#endif
+    printf("SSL version is %s\n", wolfSSL_get_version(ssl));
+
+    cipher = wolfSSL_get_current_cipher(ssl);
+    printf("SSL cipher suite is %s\n", wolfSSL_CIPHER_get_name(cipher));
+
+#if defined(SESSION_CERTS) && defined(SHOW_CERTS)
+    {
+        WOLFSSL_X509_CHAIN* chain = wolfSSL_get_peer_chain(ssl);
+        int                count = wolfSSL_get_chain_count(chain);
+        int i;
+
+        for (i = 0; i < count; i++) {
+            int length;
+            unsigned char buffer[3072];
+            WOLFSSL_X509* chainX509;
+
+            wolfSSL_get_chain_cert_pem(chain,i,buffer, sizeof(buffer), &length);
+            buffer[length] = 0;
+            printf("cert %d has length %d data = \n%s\n", i, length, buffer);
+
+            chainX509 = wolfSSL_get_chain_X509(chain, i);
+            if (chainX509)
+                ShowX509(chainX509, "session cert info:");
+            else
+                printf("get_chain_X509 failed\n");
+            wolfSSL_FreeX509(chainX509);
+        }
+    }
+#endif
+  (void)ssl;
+}
+
+
+static INLINE void build_addr(SOCKADDR_IN_T* addr, const char* peer,
+                              word16 port, int udp)
+{
+    int useLookup = 0;
+    (void)useLookup;
+    (void)udp;
+
+    memset(addr, 0, sizeof(SOCKADDR_IN_T));
+
+#ifndef TEST_IPV6
+    /* peer could be in human readable form */
+    if ( (peer != INADDR_ANY) && isalpha((int)peer[0])) {
+        #ifdef WOLFSSL_MDK_ARM
+            int err;
+            struct hostent* entry = gethostbyname(peer, &err);
+        #elif defined(WOLFSSL_TIRTOS)
+            struct hostent* entry = DNSGetHostByName(peer);
+        #else
+            struct hostent* entry = gethostbyname(peer);
+        #endif
+
+        if (entry) {
+            memcpy(&addr->sin_addr.s_addr, entry->h_addr_list[0],
+                   entry->h_length);
+            useLookup = 1;
+        }
+        else
+            err_sys("no entry for host");
+    }
+#endif
+
+
+#ifndef TEST_IPV6
+    #if defined(WOLFSSL_MDK_ARM)
+        addr->sin_family = PF_INET;
+    #else
+        addr->sin_family = AF_INET_V;
+    #endif
+    addr->sin_port = htons(port);
+    if (peer == INADDR_ANY)
+        addr->sin_addr.s_addr = INADDR_ANY;
+    else {
+        if (!useLookup)
+            addr->sin_addr.s_addr = inet_addr(peer);
+    }
+#else
+    addr->sin6_family = AF_INET_V;
+    addr->sin6_port = htons(port);
+    if (peer == INADDR_ANY)
+        addr->sin6_addr = in6addr_any;
+    else {
+        #ifdef HAVE_GETADDRINFO
+            struct addrinfo  hints;
+            struct addrinfo* answer = NULL;
+            int    ret;
+            char   strPort[80];
+
+            memset(&hints, 0, sizeof(hints));
+
+            hints.ai_family   = AF_INET_V;
+            hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
+            hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP;
+
+            SNPRINTF(strPort, sizeof(strPort), "%d", port);
+            strPort[79] = '\0';
+
+            ret = getaddrinfo(peer, strPort, &hints, &answer);
+            if (ret < 0 || answer == NULL)
+                err_sys("getaddrinfo failed");
+
+            memcpy(addr, answer->ai_addr, answer->ai_addrlen);
+            freeaddrinfo(answer);
+        #else
+            printf("no ipv6 getaddrinfo, loopback only tests/examples\n");
+            addr->sin6_addr = in6addr_loopback;
+        #endif
+    }
+#endif
+}
+
+
+static INLINE void tcp_socket(SOCKET_T* sockfd, int udp)
+{
+    if (udp)
+        *sockfd = socket(AF_INET_V, SOCK_DGRAM, 0);
+    else
+        *sockfd = socket(AF_INET_V, SOCK_STREAM, 0);
+
+#ifdef USE_WINDOWS_API
+    if (*sockfd == INVALID_SOCKET)
+        err_sys("socket failed\n");
+#elif defined(WOLFSSL_TIRTOS)
+    if (*sockfd == -1)
+        err_sys("socket failed\n");
+#else
+    if (*sockfd < 0)
+        err_sys("socket failed\n");
+#endif
+
+#ifndef USE_WINDOWS_API 
+#ifdef SO_NOSIGPIPE
+    {
+        int       on = 1;
+        socklen_t len = sizeof(on);
+        int       res = setsockopt(*sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, len);
+        if (res < 0)
+            err_sys("setsockopt SO_NOSIGPIPE failed\n");
+    }
+#elif defined(WOLFSSL_MDK_ARM) || defined (WOLFSSL_TIRTOS)
+    /* nothing to define */
+#else  /* no S_NOSIGPIPE */
+    signal(SIGPIPE, SIG_IGN);
+#endif /* S_NOSIGPIPE */
+
+#if defined(TCP_NODELAY)
+    if (!udp)
+    {
+        int       on = 1;
+        socklen_t len = sizeof(on);
+        int       res = setsockopt(*sockfd, IPPROTO_TCP, TCP_NODELAY, &on, len);
+        if (res < 0)
+            err_sys("setsockopt TCP_NODELAY failed\n");
+    }
+#endif
+#endif  /* USE_WINDOWS_API */
+}
+
+static INLINE void tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port,
+                               int udp)
+{
+    SOCKADDR_IN_T addr;
+    build_addr(&addr, ip, port, udp);
+    tcp_socket(sockfd, udp);
+
+    if (!udp) {
+        if (connect(*sockfd, (const struct sockaddr*)&addr, sizeof(addr)) != 0)
+            err_sys("tcp connect failed");
+    }
+}
+
+
+static INLINE void udp_connect(SOCKET_T* sockfd, void* addr, int addrSz)
+{
+    if (connect(*sockfd, (const struct sockaddr*)addr, addrSz) != 0)
+        err_sys("tcp connect failed");
+}
+
+
+enum {
+    TEST_SELECT_FAIL,
+    TEST_TIMEOUT,
+    TEST_RECV_READY,
+    TEST_ERROR_READY
+};
+
+
+#if !defined(WOLFSSL_MDK_ARM) && !defined(WOLFSSL_TIRTOS)
+static INLINE int tcp_select(SOCKET_T socketfd, int to_sec)
+{
+    fd_set recvfds, errfds;
+    SOCKET_T nfds = socketfd + 1;
+    struct timeval timeout = { (to_sec > 0) ? to_sec : 0, 0};
+    int result;
+
+    FD_ZERO(&recvfds);
+    FD_SET(socketfd, &recvfds);
+    FD_ZERO(&errfds);
+    FD_SET(socketfd, &errfds);
+
+    result = select(nfds, &recvfds, NULL, &errfds, &timeout);
+
+    if (result == 0)
+        return TEST_TIMEOUT;
+    else if (result > 0) {
+        if (FD_ISSET(socketfd, &recvfds))
+            return TEST_RECV_READY;
+        else if(FD_ISSET(socketfd, &errfds))
+            return TEST_ERROR_READY;
+    }
+
+    return TEST_SELECT_FAIL;
+}
+#elif defined(WOLFSSL_TIRTOS)
+static INLINE int tcp_select(SOCKET_T socketfd, int to_sec)
+{
+    return TEST_RECV_READY;
+}
+#endif /* !WOLFSSL_MDK_ARM */
+
+
+static INLINE void tcp_listen(SOCKET_T* sockfd, word16* port, int useAnyAddr,
+                              int udp)
+{
+    SOCKADDR_IN_T addr;
+
+    /* don't use INADDR_ANY by default, firewall may block, make user switch
+       on */
+    build_addr(&addr, (useAnyAddr ? INADDR_ANY : wolfSSLIP), *port, udp);
+    tcp_socket(sockfd, udp);
+
+#if !defined(USE_WINDOWS_API) && !defined(WOLFSSL_MDK_ARM)
+    {
+        int       res, on  = 1;
+        socklen_t len = sizeof(on);
+        res = setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, &on, len);
+        if (res < 0)
+            err_sys("setsockopt SO_REUSEADDR failed\n");
+    }
+#endif
+
+    if (bind(*sockfd, (const struct sockaddr*)&addr, sizeof(addr)) != 0)
+        err_sys("tcp bind failed");
+    if (!udp) {
+        if (listen(*sockfd, 5) != 0)
+            err_sys("tcp listen failed");
+    }
+    #if (defined(NO_MAIN_DRIVER) && !defined(USE_WINDOWS_API)) && !defined(WOLFSSL_TIRTOS)
+        if (*port == 0) {
+            socklen_t len = sizeof(addr);
+            if (getsockname(*sockfd, (struct sockaddr*)&addr, &len) == 0) {
+                #ifndef TEST_IPV6
+                    *port = ntohs(addr.sin_port);
+                #else
+                    *port = ntohs(addr.sin6_port);
+                #endif
+            }
+        }
+    #endif
+}
+
+
+static INLINE int udp_read_connect(SOCKET_T sockfd)
+{
+    SOCKADDR_IN_T cliaddr;
+    byte          b[1500];
+    int           n;
+    socklen_t     len = sizeof(cliaddr);
+
+    n = (int)recvfrom(sockfd, (char*)b, sizeof(b), MSG_PEEK,
+                      (struct sockaddr*)&cliaddr, &len);
+    if (n > 0) {
+        if (connect(sockfd, (const struct sockaddr*)&cliaddr,
+                    sizeof(cliaddr)) != 0)
+            err_sys("udp connect failed");
+    }
+    else
+        err_sys("recvfrom failed");
+
+    return sockfd;
+}
+
+static INLINE void udp_accept(SOCKET_T* sockfd, SOCKET_T* clientfd,
+                              int useAnyAddr, word16 port, func_args* args)
+{
+    SOCKADDR_IN_T addr;
+
+    (void)args;
+    build_addr(&addr, (useAnyAddr ? INADDR_ANY : wolfSSLIP), port, 1);
+    tcp_socket(sockfd, 1);
+
+
+#if !defined(USE_WINDOWS_API) && !defined(WOLFSSL_MDK_ARM)
+    {
+        int       res, on  = 1;
+        socklen_t len = sizeof(on);
+        res = setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, &on, len);
+        if (res < 0)
+            err_sys("setsockopt SO_REUSEADDR failed\n");
+    }
+#endif
+
+    if (bind(*sockfd, (const struct sockaddr*)&addr, sizeof(addr)) != 0)
+        err_sys("tcp bind failed");
+
+    #if (defined(NO_MAIN_DRIVER) && !defined(USE_WINDOWS_API)) && !defined(WOLFSSL_TIRTOS)
+        if (port == 0) {
+            socklen_t len = sizeof(addr);
+            if (getsockname(*sockfd, (struct sockaddr*)&addr, &len) == 0) {
+                #ifndef TEST_IPV6
+                    port = ntohs(addr.sin_port);
+                #else
+                    port = ntohs(addr.sin6_port);
+                #endif
+            }
+        }
+    #endif
+
+#if defined(_POSIX_THREADS) && defined(NO_MAIN_DRIVER) && !defined(__MINGW32__)
+    /* signal ready to accept data */
+    {
+    tcp_ready* ready = args->signal;
+    pthread_mutex_lock(&ready->mutex);
+    ready->ready = 1;
+    ready->port = port;
+    pthread_cond_signal(&ready->cond);
+    pthread_mutex_unlock(&ready->mutex);
+    }
+#elif defined (WOLFSSL_TIRTOS)
+    /* Need mutex? */
+    tcp_ready* ready = args->signal;
+    ready->ready = 1;
+    ready->port = port;
+#endif
+
+    *clientfd = udp_read_connect(*sockfd);
+}
+
+static INLINE void tcp_accept(SOCKET_T* sockfd, SOCKET_T* clientfd,
+                              func_args* args, word16 port, int useAnyAddr,
+                              int udp, int ready_file)
+{
+    SOCKADDR_IN_T client;
+    socklen_t client_len = sizeof(client);
+
+    if (udp) {
+        udp_accept(sockfd, clientfd, useAnyAddr, port, args);
+        return;
+    }
+
+    tcp_listen(sockfd, &port, useAnyAddr, udp);
+
+#if defined(_POSIX_THREADS) && defined(NO_MAIN_DRIVER) && !defined(__MINGW32__)
+    /* signal ready to tcp_accept */
+    {
+    tcp_ready* ready = args->signal;
+    pthread_mutex_lock(&ready->mutex);
+    ready->ready = 1;
+    ready->port = port;
+    pthread_cond_signal(&ready->cond);
+    pthread_mutex_unlock(&ready->mutex);
+    }
+#elif defined (WOLFSSL_TIRTOS)
+    /* Need mutex? */
+    tcp_ready* ready = args->signal;
+    ready->ready = 1;
+    ready->port = port;
+#endif
+
+    if (ready_file) {
+#ifndef NO_FILESYSTEM
+    #ifndef USE_WINDOWS_API
+        FILE* srf = fopen("/tmp/wolfssl_server_ready", "w");
+    #else
+        FILE* srf = fopen("wolfssl_server_ready", "w");
+    #endif
+
+        if (srf) {
+            fputs("ready", srf);
+            fclose(srf);
+        }
+#endif
+    }
+
+    *clientfd = accept(*sockfd, (struct sockaddr*)&client,
+                      (ACCEPT_THIRD_T)&client_len);
+#ifdef USE_WINDOWS_API
+    if (*clientfd == INVALID_SOCKET)
+        err_sys("tcp accept failed");
+#else
+    if (*clientfd == -1)
+        err_sys("tcp accept failed");
+#endif
+}
+
+
+static INLINE void tcp_set_nonblocking(SOCKET_T* sockfd)
+{
+    #ifdef USE_WINDOWS_API 
+        unsigned long blocking = 1;
+        int ret = ioctlsocket(*sockfd, FIONBIO, &blocking);
+        if (ret == SOCKET_ERROR)
+            err_sys("ioctlsocket failed");
+    #elif defined(WOLFSSL_MDK_ARM) || defined (WOLFSSL_TIRTOS)
+         /* non blocking not suppported, for now */ 
+    #else
+        int flags = fcntl(*sockfd, F_GETFL, 0);
+        if (flags < 0)
+            err_sys("fcntl get failed");
+        flags = fcntl(*sockfd, F_SETFL, flags | O_NONBLOCK);
+        if (flags < 0)
+            err_sys("fcntl set failed");
+    #endif
+}
+
+
+#ifndef NO_PSK
+
+static 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)
+{
+    (void)ssl;
+    (void)hint;
+    (void)key_max_len;
+
+    /* identity is OpenSSL testing default for openssl s_client, keep same */
+    strncpy(identity, "Client_identity", id_max_len);
+
+
+    /* 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;
+
+    return 4;   /* length of key in octets or 0 for error */
+}
+
+
+static INLINE unsigned int my_psk_server_cb(WOLFSSL* ssl, const char* identity,
+        unsigned char* key, unsigned int key_max_len)
+{
+    (void)ssl;
+    (void)key_max_len;
+
+    /* identity is OpenSSL testing default for openssl s_client, keep same */
+    if (strncmp(identity, "Client_identity", 15) != 0)
+        return 0;
+
+    /* 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;
+
+    return 4;   /* length of key in octets or 0 for error */
+}
+
+#endif /* NO_PSK */
+
+
+#ifdef USE_WINDOWS_API 
+
+    #define WIN32_LEAN_AND_MEAN
+    #include <windows.h>
+
+    static INLINE double current_time()
+    {
+        static int init = 0;
+        static LARGE_INTEGER freq;
+    
+        LARGE_INTEGER count;
+
+        if (!init) {
+            QueryPerformanceFrequency(&freq);
+            init = 1;
+        }
+
+        QueryPerformanceCounter(&count);
+
+        return (double)count.QuadPart / freq.QuadPart;
+    }
+
+#elif defined(WOLFSSL_TIRTOS)
+    extern double current_time();
+#else
+
+#if !defined(WOLFSSL_MDK_ARM)
+    #include <sys/time.h>
+
+    static INLINE double current_time(void)
+    {
+        struct timeval tv;
+        gettimeofday(&tv, 0);
+
+        return (double)tv.tv_sec + (double)tv.tv_usec / 1000000;
+    }
+        
+#endif
+#endif /* USE_WINDOWS_API */
+
+
+#if defined(NO_FILESYSTEM) && !defined(NO_CERTS)
+
+    enum {
+        WOLFSSL_CA   = 1,
+        WOLFSSL_CERT = 2,
+        WOLFSSL_KEY  = 3
+    };
+
+    static INLINE void load_buffer(WOLFSSL_CTX* ctx, const char* fname, int type)
+    {
+        /* test buffer load */
+        long  sz = 0;
+        byte  buff[10000];
+        FILE* file = fopen(fname, "rb");
+
+        if (!file)
+            err_sys("can't open file for buffer load "
+                    "Please run from wolfSSL home directory if not");
+        fseek(file, 0, SEEK_END);
+        sz = ftell(file);
+        rewind(file);
+        fread(buff, sizeof(buff), 1, file);
+  
+        if (type == WOLFSSL_CA) {
+            if (wolfSSL_CTX_load_verify_buffer(ctx, buff, sz, SSL_FILETYPE_PEM)
+                                              != SSL_SUCCESS)
+                err_sys("can't load buffer ca file");
+        }
+        else if (type == WOLFSSL_CERT) {
+            if (wolfSSL_CTX_use_certificate_buffer(ctx, buff, sz,
+                        SSL_FILETYPE_PEM) != SSL_SUCCESS)
+                err_sys("can't load buffer cert file");
+        }
+        else if (type == WOLFSSL_KEY) {
+            if (wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, sz,
+                        SSL_FILETYPE_PEM) != SSL_SUCCESS)
+                err_sys("can't load buffer key file");
+        }
+    }
+
+#endif /* NO_FILESYSTEM */
+
+#ifdef VERIFY_CALLBACK
+
+static INLINE int myVerify(int preverify, WOLFSSL_X509_STORE_CTX* store)
+{
+    (void)preverify;
+    char buffer[WOLFSSL_MAX_ERROR_SZ];
+
+#ifdef OPENSSL_EXTRA
+    WOLFSSL_X509* peer;
+#endif
+
+    printf("In verification callback, error = %d, %s\n", store->error,
+                                 wolfSSL_ERR_error_string(store->error, buffer));
+#ifdef OPENSSL_EXTRA
+    peer = store->current_cert;
+    if (peer) {
+        char* issuer  = wolfSSL_X509_NAME_oneline(
+                                       wolfSSL_X509_get_issuer_name(peer), 0, 0);
+        char* subject = wolfSSL_X509_NAME_oneline(
+                                      wolfSSL_X509_get_subject_name(peer), 0, 0);
+        printf("peer's cert info:\n issuer : %s\n subject: %s\n", issuer,
+                                                                  subject);
+        XFREE(subject, 0, DYNAMIC_TYPE_OPENSSL);
+        XFREE(issuer,  0, DYNAMIC_TYPE_OPENSSL);
+    }
+    else
+        printf("peer has no cert!\n");
+#endif
+    printf("Subject's domain name is %s\n", store->domain);
+
+    printf("Allowing to continue anyway (shouldn't do this, EVER!!!)\n");
+    return 1;
+}
+
+#endif /* VERIFY_CALLBACK */
+
+
+static INLINE int myDateCb(int preverify, WOLFSSL_X509_STORE_CTX* store)
+{
+    char buffer[WOLFSSL_MAX_ERROR_SZ];
+    (void)preverify;
+
+    printf("In verification callback, error = %d, %s\n", store->error,
+                                 wolfSSL_ERR_error_string(store->error, buffer));
+    printf("Subject's domain name is %s\n", store->domain);
+
+    if (store->error == ASN_BEFORE_DATE_E || store->error == ASN_AFTER_DATE_E) {
+        printf("Overriding cert date error as example for bad clock testing\n");
+        return 1;
+    }
+    printf("Cert error is not date error, not overriding\n");
+
+    return 0;
+}
+
+
+#ifdef HAVE_CRL
+
+static INLINE void CRL_CallBack(const char* url)
+{
+    printf("CRL callback url = %s\n", url);
+}
+
+#endif
+
+#ifndef NO_DH
+static INLINE void SetDH(WOLFSSL* ssl)
+{
+    /* dh1024 p */
+    static unsigned char p[] =
+    {
+        0xE6, 0x96, 0x9D, 0x3D, 0x49, 0x5B, 0xE3, 0x2C, 0x7C, 0xF1, 0x80, 0xC3,
+        0xBD, 0xD4, 0x79, 0x8E, 0x91, 0xB7, 0x81, 0x82, 0x51, 0xBB, 0x05, 0x5E,
+        0x2A, 0x20, 0x64, 0x90, 0x4A, 0x79, 0xA7, 0x70, 0xFA, 0x15, 0xA2, 0x59,
+        0xCB, 0xD5, 0x23, 0xA6, 0xA6, 0xEF, 0x09, 0xC4, 0x30, 0x48, 0xD5, 0xA2,
+        0x2F, 0x97, 0x1F, 0x3C, 0x20, 0x12, 0x9B, 0x48, 0x00, 0x0E, 0x6E, 0xDD,
+        0x06, 0x1C, 0xBC, 0x05, 0x3E, 0x37, 0x1D, 0x79, 0x4E, 0x53, 0x27, 0xDF,
+        0x61, 0x1E, 0xBB, 0xBE, 0x1B, 0xAC, 0x9B, 0x5C, 0x60, 0x44, 0xCF, 0x02,
+        0x3D, 0x76, 0xE0, 0x5E, 0xEA, 0x9B, 0xAD, 0x99, 0x1B, 0x13, 0xA6, 0x3C,
+        0x97, 0x4E, 0x9E, 0xF1, 0x83, 0x9E, 0xB5, 0xDB, 0x12, 0x51, 0x36, 0xF7,
+        0x26, 0x2E, 0x56, 0xA8, 0x87, 0x15, 0x38, 0xDF, 0xD8, 0x23, 0xC6, 0x50,
+        0x50, 0x85, 0xE2, 0x1F, 0x0D, 0xD5, 0xC8, 0x6B,
+    };
+
+    /* dh1024 g */
+    static unsigned char g[] =
+    {
+      0x02,
+    };
+
+    wolfSSL_SetTmpDH(ssl, p, sizeof(p), g, sizeof(g));
+}
+
+static INLINE void SetDHCtx(WOLFSSL_CTX* ctx)
+{
+    /* dh1024 p */
+    static unsigned char p[] =
+    {
+        0xE6, 0x96, 0x9D, 0x3D, 0x49, 0x5B, 0xE3, 0x2C, 0x7C, 0xF1, 0x80, 0xC3,
+        0xBD, 0xD4, 0x79, 0x8E, 0x91, 0xB7, 0x81, 0x82, 0x51, 0xBB, 0x05, 0x5E,
+        0x2A, 0x20, 0x64, 0x90, 0x4A, 0x79, 0xA7, 0x70, 0xFA, 0x15, 0xA2, 0x59,
+        0xCB, 0xD5, 0x23, 0xA6, 0xA6, 0xEF, 0x09, 0xC4, 0x30, 0x48, 0xD5, 0xA2,
+        0x2F, 0x97, 0x1F, 0x3C, 0x20, 0x12, 0x9B, 0x48, 0x00, 0x0E, 0x6E, 0xDD,
+        0x06, 0x1C, 0xBC, 0x05, 0x3E, 0x37, 0x1D, 0x79, 0x4E, 0x53, 0x27, 0xDF,
+        0x61, 0x1E, 0xBB, 0xBE, 0x1B, 0xAC, 0x9B, 0x5C, 0x60, 0x44, 0xCF, 0x02,
+        0x3D, 0x76, 0xE0, 0x5E, 0xEA, 0x9B, 0xAD, 0x99, 0x1B, 0x13, 0xA6, 0x3C,
+        0x97, 0x4E, 0x9E, 0xF1, 0x83, 0x9E, 0xB5, 0xDB, 0x12, 0x51, 0x36, 0xF7,
+        0x26, 0x2E, 0x56, 0xA8, 0x87, 0x15, 0x38, 0xDF, 0xD8, 0x23, 0xC6, 0x50,
+        0x50, 0x85, 0xE2, 0x1F, 0x0D, 0xD5, 0xC8, 0x6B,
+    };
+
+    /* dh1024 g */
+    static unsigned char g[] =
+    {
+      0x02,
+    };
+
+    wolfSSL_CTX_SetTmpDH(ctx, p, sizeof(p), g, sizeof(g));
+}
+#endif /* NO_DH */
+
+#ifndef NO_CERTS
+
+static INLINE void CaCb(unsigned char* der, int sz, int type)
+{
+    (void)der;
+    printf("Got CA cache add callback, derSz = %d, type = %d\n", sz, type);
+}
+
+#endif /* !NO_CERTS */
+
+#ifdef HAVE_CAVIUM
+
+static INLINE int OpenNitroxDevice(int dma_mode,int dev_id)
+{
+   Csp1CoreAssignment core_assign;
+   Uint32             device;
+
+   if (CspInitialize(CAVIUM_DIRECT,CAVIUM_DEV_ID))
+      return -1;
+   if (Csp1GetDevType(&device))
+      return -1;
+   if (device != NPX_DEVICE) {
+      if (ioctl(gpkpdev_hdlr[CAVIUM_DEV_ID], IOCTL_CSP1_GET_CORE_ASSIGNMENT,
+                (Uint32 *)&core_assign)!= 0)
+         return -1;
+   }
+   CspShutdown(CAVIUM_DEV_ID);
+
+   return CspInitialize(dma_mode, dev_id);
+}
+
+#endif /* HAVE_CAVIUM */
+
+
+#ifdef USE_WINDOWS_API 
+
+/* do back x number of directories */
+static INLINE void ChangeDirBack(int x)
+{
+    char path[MAX_PATH];
+
+    if (x == 1)
+        strncpy(path, "..\\", MAX_PATH);
+    else if (x == 2)
+        strncpy(path, "..\\..\\", MAX_PATH);
+    else if (x == 3)
+        strncpy(path, "..\\..\\..\\", MAX_PATH);
+    else if (x == 4)
+        strncpy(path, "..\\..\\..\\..\\", MAX_PATH);
+    else
+        strncpy(path, ".\\", MAX_PATH);
+    
+    SetCurrentDirectoryA(path);
+}
+
+/* does current dir contain str */
+static INLINE int CurrentDir(const char* str)
+{
+    char  path[MAX_PATH];
+    char* baseName;
+
+    GetCurrentDirectoryA(sizeof(path), path);
+
+    baseName = strrchr(path, '\\');
+    if (baseName)
+        baseName++;
+    else
+        baseName = path;
+
+    if (strstr(baseName, str))
+        return 1;
+
+    return 0;
+}
+
+#elif defined(WOLFSSL_MDK_ARM)
+    /* KEIL-RL File System does not support relative directry */
+#elif defined(WOLFSSL_TIRTOS)
+#else
+
+#ifndef MAX_PATH
+    #define MAX_PATH 256
+#endif
+
+/* do back x number of directories */
+static INLINE void ChangeDirBack(int x)
+{
+    char path[MAX_PATH];
+
+    if (x == 1)
+        strncpy(path, "../", MAX_PATH);
+    else if (x == 2)
+        strncpy(path, "../../", MAX_PATH);
+    else if (x == 3)
+        strncpy(path, "../../../", MAX_PATH);
+    else if (x == 4)
+        strncpy(path, "../../../../", MAX_PATH);
+    else
+        strncpy(path, "./", MAX_PATH);
+    
+    if (chdir(path) < 0)
+        printf("chdir to %s failed\n", path);
+}
+
+/* does current dir contain str */
+static INLINE int CurrentDir(const char* str)
+{
+    char  path[MAX_PATH];
+    char* baseName;
+
+    if (getcwd(path, sizeof(path)) == NULL) {
+        printf("no current dir?\n");
+        return 0;
+    }
+
+    baseName = strrchr(path, '/');
+    if (baseName)
+        baseName++;
+    else
+        baseName = path;
+
+    if (strstr(baseName, str))
+        return 1;
+
+    return 0;
+}
+
+#endif /* USE_WINDOWS_API */
+
+
+#ifdef USE_WOLFSSL_MEMORY
+
+    typedef struct memoryStats {
+        size_t totalAllocs;     /* number of allocations */
+        size_t totalBytes;      /* total number of bytes allocated */
+        size_t peakBytes;       /* concurrent max bytes */
+        size_t currentBytes;    /* total current bytes in use */
+    } memoryStats;
+
+    typedef struct memHint {
+        size_t thisSize;      /* size of this memory */
+        void*  thisMemory;    /* actual memory for user */
+    } memHint;
+
+    typedef struct memoryTrack {
+        union {
+            memHint hint;
+            byte    alignit[16];   /* make sure we have strong alignment */
+        } u;
+    } memoryTrack;
+
+    #if defined(WOLFSSL_TRACK_MEMORY)
+        #define DO_MEM_STATS
+        static memoryStats ourMemStats;
+    #endif
+
+    static INLINE void* TrackMalloc(size_t sz)
+    {
+        memoryTrack* mt;
+
+        if (sz == 0)
+            return NULL;
+
+        mt = (memoryTrack*)malloc(sizeof(memoryTrack) + sz);
+        if (mt == NULL)
+            return NULL;
+
+        mt->u.hint.thisSize   = sz;
+        mt->u.hint.thisMemory = (byte*)mt + sizeof(memoryTrack);
+
+#ifdef DO_MEM_STATS
+        ourMemStats.totalAllocs++;
+        ourMemStats.totalBytes   += sz;
+        ourMemStats.currentBytes += sz;
+        if (ourMemStats.currentBytes > ourMemStats.peakBytes)
+            ourMemStats.peakBytes = ourMemStats.currentBytes;
+#endif
+
+        return mt->u.hint.thisMemory;
+    }
+
+
+    static INLINE void TrackFree(void* ptr)
+    {
+        memoryTrack* mt;
+
+        if (ptr == NULL)
+            return;
+
+        mt = (memoryTrack*)ptr;
+        --mt;   /* same as minus sizeof(memoryTrack), removes header */
+
+#ifdef DO_MEM_STATS 
+        ourMemStats.currentBytes -= mt->u.hint.thisSize; 
+#endif
+
+        free(mt);
+    }
+
+
+    static INLINE void* TrackRealloc(void* ptr, size_t sz)
+    {
+        void* ret = TrackMalloc(sz);
+
+        if (ptr) {
+            /* if realloc is bigger, don't overread old ptr */
+            memoryTrack* mt = (memoryTrack*)ptr;
+            --mt;  /* same as minus sizeof(memoryTrack), removes header */
+
+            if (mt->u.hint.thisSize < sz)
+                sz = mt->u.hint.thisSize;
+        }
+
+        if (ret && ptr)
+            memcpy(ret, ptr, sz);
+
+        if (ret)
+            TrackFree(ptr);
+
+        return ret;
+    }
+
+    static INLINE void InitMemoryTracker(void) 
+    {
+        if (wolfSSL_SetAllocators(TrackMalloc, TrackFree, TrackRealloc) != 0)
+            err_sys("wolfSSL SetAllocators failed for track memory");
+
+    #ifdef DO_MEM_STATS
+        ourMemStats.totalAllocs  = 0;
+        ourMemStats.totalBytes   = 0;
+        ourMemStats.peakBytes    = 0;
+        ourMemStats.currentBytes = 0;
+    #endif
+    }
+
+    static INLINE void ShowMemoryTracker(void) 
+    {
+    #ifdef DO_MEM_STATS 
+        printf("total   Allocs = %9lu\n",
+                                       (unsigned long)ourMemStats.totalAllocs);
+        printf("total   Bytes  = %9lu\n",
+                                       (unsigned long)ourMemStats.totalBytes);
+        printf("peak    Bytes  = %9lu\n",
+                                       (unsigned long)ourMemStats.peakBytes);
+        printf("current Bytes  = %9lu\n",
+                                       (unsigned long)ourMemStats.currentBytes);
+    #endif
+    }
+
+#endif /* USE_WOLFSSL_MEMORY */
+
+
+#ifdef HAVE_STACK_SIZE
+
+typedef THREAD_RETURN WOLFSSL_THREAD (*thread_func)(void* args);
+
+
+static INLINE void StackSizeCheck(func_args* args, thread_func tf)
+{
+    int            ret, i, used;
+    unsigned char* myStack;
+    int            stackSize = 1024*128;
+    pthread_attr_t myAttr;
+    pthread_t      threadId;
+
+#ifdef PTHREAD_STACK_MIN
+    if (stackSize < PTHREAD_STACK_MIN)
+        stackSize = PTHREAD_STACK_MIN;
+#endif
+
+    ret = posix_memalign((void**)&myStack, sysconf(_SC_PAGESIZE), stackSize);
+    if (ret != 0) 
+        err_sys("posix_memalign failed\n");        
+
+    memset(myStack, 0x01, stackSize);
+
+    ret = pthread_attr_init(&myAttr);
+    if (ret != 0)
+        err_sys("attr_init failed");
+
+    ret = pthread_attr_setstack(&myAttr, myStack, stackSize);
+    if (ret != 0)
+        err_sys("attr_setstackaddr failed");
+
+    ret = pthread_create(&threadId, &myAttr, tf, args);
+    if (ret != 0) {
+        perror("pthread_create failed");
+        exit(EXIT_FAILURE);
+    }
+
+    ret = pthread_join(threadId, NULL);
+    if (ret != 0)
+        err_sys("pthread_join failed");
+
+    for (i = 0; i < stackSize; i++) {
+        if (myStack[i] != 0x01) {
+            break;
+        }
+    }
+
+    used = stackSize - i;
+    printf("stack used = %d\n", used);
+}
+
+
+#endif /* HAVE_STACK_SIZE */
+
+
+#ifdef STACK_TRAP
+
+/* good settings
+   --enable-debug --disable-shared C_EXTRA_FLAGS="-DUSER_TIME -DTFM_TIMING_RESISTANT -DPOSITIVE_EXP_ONLY -DSTACK_TRAP"
+
+*/
+
+#ifdef HAVE_STACK_SIZE
+    /* client only for now, setrlimit will fail if pthread_create() called */
+    /* STACK_SIZE does pthread_create() on client */
+    #error "can't use STACK_TRAP with STACK_SIZE, setrlimit will fail"
+#endif /* HAVE_STACK_SIZE */
+
+static INLINE void StackTrap(void)
+{
+    struct rlimit  rl;
+    if (getrlimit(RLIMIT_STACK, &rl) != 0)
+        err_sys("getrlimit failed");
+    printf("rlim_cur = %llu\n", rl.rlim_cur);
+    rl.rlim_cur = 1024*21;  /* adjust trap size here */
+    if (setrlimit(RLIMIT_STACK, &rl) != 0) {
+        perror("setrlimit");
+        err_sys("setrlimit failed");
+    }
+}
+
+#else /* STACK_TRAP */
+
+static INLINE void StackTrap(void)
+{
+}
+
+#endif /* STACK_TRAP */
+
+
+#ifdef ATOMIC_USER
+
+/* Atomic Encrypt Context example */
+typedef struct AtomicEncCtx {
+    int  keySetup;           /* have we done key setup yet */
+    Aes  aes;                /* for aes example */
+} AtomicEncCtx;
+
+
+/* Atomic Decrypt Context example */
+typedef struct AtomicDecCtx {
+    int  keySetup;           /* have we done key setup yet */
+    Aes  aes;                /* for aes example */
+} AtomicDecCtx;
+
+
+static 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,
+       unsigned int encSz, void* ctx)
+{
+    int  ret;
+    Hmac hmac;
+    byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ];
+    AtomicEncCtx* encCtx = (AtomicEncCtx*)ctx;
+    const char* tlsStr = "TLS";
+
+    /* example supports (d)tls aes */
+    if (wolfSSL_GetBulkCipher(ssl) != wolfssl_aes) {
+        printf("myMacEncryptCb not using AES\n");
+        return -1;
+    }
+
+    if (strstr(wolfSSL_get_version(ssl), tlsStr) == NULL) {
+        printf("myMacEncryptCb not using (D)TLS\n");
+        return -1;
+    }
+
+    /* hmac, not needed if aead mode */
+    wolfSSL_SetTlsHmacInner(ssl, myInner, macInSz, macContent, macVerify);
+
+    ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl),
+               wolfSSL_GetMacSecret(ssl, macVerify), wolfSSL_GetHmacSize(ssl));
+    if (ret != 0)
+        return ret;
+    ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner));
+    if (ret != 0)
+        return ret;
+    ret = wc_HmacUpdate(&hmac, macIn, macInSz);
+    if (ret != 0)
+        return ret;
+    ret = wc_HmacFinal(&hmac, macOut);
+    if (ret != 0)
+        return ret;
+
+
+    /* encrypt setup on first time */
+    if (encCtx->keySetup == 0) {
+        int   keyLen = wolfSSL_GetKeySize(ssl);
+        const byte* key;
+        const byte* iv;
+
+        if (wolfSSL_GetSide(ssl) == WOLFSSL_CLIENT_END) {
+            key = wolfSSL_GetClientWriteKey(ssl);
+            iv  = wolfSSL_GetClientWriteIV(ssl);
+        }
+        else {
+            key = wolfSSL_GetServerWriteKey(ssl);
+            iv  = wolfSSL_GetServerWriteIV(ssl);
+        }
+
+        ret = wc_AesSetKey(&encCtx->aes, key, keyLen, iv, AES_ENCRYPTION);
+        if (ret != 0) {
+            printf("AesSetKey failed in myMacEncryptCb\n");
+            return ret;
+        }
+        encCtx->keySetup = 1;
+    }
+
+    /* encrypt */
+    return wc_AesCbcEncrypt(&encCtx->aes, encOut, encIn, encSz);
+}
+
+
+static INLINE int myDecryptVerifyCb(WOLFSSL* ssl, 
+       unsigned char* decOut, const unsigned char* decIn,
+       unsigned int decSz, int macContent, int macVerify,
+       unsigned int* padSz, void* ctx)
+{
+    AtomicDecCtx* decCtx = (AtomicDecCtx*)ctx;
+    int ret      = 0;
+    int macInSz  = 0;
+    int ivExtra  = 0;
+    int digestSz = wolfSSL_GetHmacSize(ssl);
+    unsigned int pad     = 0;
+    unsigned int padByte = 0;
+    Hmac hmac;
+    byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ];
+    byte verify[MAX_DIGEST_SIZE];
+    const char* tlsStr = "TLS";
+
+    /* example supports (d)tls aes */
+    if (wolfSSL_GetBulkCipher(ssl) != wolfssl_aes) {
+        printf("myMacEncryptCb not using AES\n");
+        return -1;
+    }
+
+    if (strstr(wolfSSL_get_version(ssl), tlsStr) == NULL) {
+        printf("myMacEncryptCb not using (D)TLS\n");
+        return -1;
+    }
+
+    /*decrypt */
+    if (decCtx->keySetup == 0) {
+        int   keyLen = wolfSSL_GetKeySize(ssl);
+        const byte* key;
+        const byte* iv;
+
+        /* decrypt is from other side (peer) */
+        if (wolfSSL_GetSide(ssl) == WOLFSSL_SERVER_END) {
+            key = wolfSSL_GetClientWriteKey(ssl);
+            iv  = wolfSSL_GetClientWriteIV(ssl);
+        }
+        else {
+            key = wolfSSL_GetServerWriteKey(ssl);
+            iv  = wolfSSL_GetServerWriteIV(ssl);
+        }
+
+        ret = wc_AesSetKey(&decCtx->aes, key, keyLen, iv, AES_DECRYPTION);
+        if (ret != 0) {
+            printf("AesSetKey failed in myDecryptVerifyCb\n");
+            return ret;
+        }
+        decCtx->keySetup = 1;
+    }
+
+    /* decrypt */
+    ret = wc_AesCbcDecrypt(&decCtx->aes, decOut, decIn, decSz);
+
+    if (wolfSSL_GetCipherType(ssl) == WOLFSSL_AEAD_TYPE) {
+        *padSz = wolfSSL_GetAeadMacSize(ssl);
+        return 0; /* hmac, not needed if aead mode */
+    }
+
+    if (wolfSSL_GetCipherType(ssl) == WOLFSSL_BLOCK_TYPE) {
+        pad     = *(decOut + decSz - 1);
+        padByte = 1;
+        if (wolfSSL_IsTLSv1_1(ssl))
+            ivExtra = wolfSSL_GetCipherBlockSize(ssl);
+    }
+
+    *padSz  = wolfSSL_GetHmacSize(ssl) + pad + padByte;
+    macInSz = decSz - ivExtra - digestSz - pad - padByte;
+
+    wolfSSL_SetTlsHmacInner(ssl, myInner, macInSz, macContent, macVerify);
+
+    ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl),
+               wolfSSL_GetMacSecret(ssl, macVerify), digestSz);
+    if (ret != 0)
+        return ret;
+    ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner));
+    if (ret != 0)
+        return ret;
+    ret = wc_HmacUpdate(&hmac, decOut + ivExtra, macInSz);
+    if (ret != 0)
+        return ret;
+    ret = wc_HmacFinal(&hmac, verify);
+    if (ret != 0)
+        return ret;
+
+    if (memcmp(verify, decOut + decSz - digestSz - pad - padByte,
+               digestSz) != 0) {
+        printf("myDecryptVerify verify failed\n");
+        return -1;
+    }
+
+    return ret;
+}
+
+
+static INLINE void SetupAtomicUser(WOLFSSL_CTX* ctx, WOLFSSL* ssl)
+{
+    AtomicEncCtx* encCtx;
+    AtomicDecCtx* decCtx;
+
+    encCtx = (AtomicEncCtx*)malloc(sizeof(AtomicEncCtx));
+    if (encCtx == NULL)
+        err_sys("AtomicEncCtx malloc failed");
+    memset(encCtx, 0, sizeof(AtomicEncCtx));
+
+    decCtx = (AtomicDecCtx*)malloc(sizeof(AtomicDecCtx));
+    if (decCtx == NULL) {
+        free(encCtx);
+        err_sys("AtomicDecCtx malloc failed");
+    }
+    memset(decCtx, 0, sizeof(AtomicDecCtx));
+
+    wolfSSL_CTX_SetMacEncryptCb(ctx, myMacEncryptCb);
+    wolfSSL_SetMacEncryptCtx(ssl, encCtx);
+
+    wolfSSL_CTX_SetDecryptVerifyCb(ctx, myDecryptVerifyCb);
+    wolfSSL_SetDecryptVerifyCtx(ssl, decCtx);
+}
+
+
+static INLINE void FreeAtomicUser(WOLFSSL* ssl)
+{
+    AtomicEncCtx* encCtx = (AtomicEncCtx*)wolfSSL_GetMacEncryptCtx(ssl);
+    AtomicDecCtx* decCtx = (AtomicDecCtx*)wolfSSL_GetDecryptVerifyCtx(ssl);
+
+    free(decCtx);
+    free(encCtx);
+}
+
+#endif /* ATOMIC_USER */
+
+
+#ifdef HAVE_PK_CALLBACKS
+
+#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)
+{
+    RNG     rng;
+    int     ret;
+    word32  idx = 0;
+    ecc_key myKey;
+
+    (void)ssl;
+    (void)ctx;
+
+    ret = wc_InitRng(&rng);
+    if (ret != 0)
+        return ret;
+
+    wc_ecc_init(&myKey);
+    
+    ret = wc_EccPrivateKeyDecode(key, &idx, &myKey, keySz);    
+    if (ret == 0)
+        ret = wc_ecc_sign_hash(in, inSz, out, outSz, &rng, &myKey);
+    wc_ecc_free(&myKey);
+    wc_FreeRng(&rng);
+
+    return ret;
+}
+
+
+static 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;
+    ecc_key myKey;
+
+    (void)ssl;
+    (void)ctx;
+
+    wc_ecc_init(&myKey);
+    
+    ret = wc_ecc_import_x963(key, keySz, &myKey);
+    if (ret == 0)
+        ret = wc_ecc_verify_hash(sig, sigSz, hash, hashSz, result, &myKey);
+    wc_ecc_free(&myKey);
+
+    return ret;
+}
+
+#endif /* HAVE_ECC */
+
+#ifndef NO_RSA
+
+static INLINE int myRsaSign(WOLFSSL* ssl, const byte* in, word32 inSz,
+        byte* out, word32* outSz, const byte* key, word32 keySz, void* ctx)
+{
+    RNG     rng;
+    int     ret;
+    word32  idx = 0;
+    RsaKey  myKey;
+
+    (void)ssl;
+    (void)ctx;
+
+    ret = wc_InitRng(&rng);
+    if (ret != 0)
+        return ret;
+
+    wc_InitRsaKey(&myKey, NULL);
+    
+    ret = wc_RsaPrivateKeyDecode(key, &idx, &myKey, keySz);    
+    if (ret == 0)
+        ret = wc_RsaSSL_Sign(in, inSz, out, *outSz, &myKey, &rng);
+    if (ret > 0) {  /* save and convert to 0 success */
+        *outSz = ret;
+        ret = 0;
+    }
+    wc_FreeRsaKey(&myKey);
+    wc_FreeRng(&rng);
+
+    return ret;
+}
+
+
+static 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;
+
+    (void)ssl;
+    (void)ctx;
+
+    wc_InitRsaKey(&myKey, NULL);
+
+    ret = wc_RsaPublicKeyDecode(key, &idx, &myKey, keySz);
+    if (ret == 0)
+        ret = wc_RsaSSL_VerifyInline(sig, sigSz, out, &myKey);
+    wc_FreeRsaKey(&myKey);
+
+    return ret;
+}
+
+
+static INLINE int myRsaEnc(WOLFSSL* ssl, const byte* in, word32 inSz,
+                           byte* out, word32* outSz, const byte* key,
+                           word32 keySz, void* ctx)
+{
+    int     ret;
+    word32  idx = 0;
+    RsaKey  myKey;
+    RNG     rng;
+
+    (void)ssl;
+    (void)ctx;
+
+    ret = wc_InitRng(&rng);
+    if (ret != 0)
+        return ret;
+
+    wc_InitRsaKey(&myKey, NULL);
+    
+    ret = wc_RsaPublicKeyDecode(key, &idx, &myKey, keySz);
+    if (ret == 0) {
+        ret = wc_RsaPublicEncrypt(in, inSz, out, *outSz, &myKey, &rng);
+        if (ret > 0) {
+            *outSz = ret;
+            ret = 0;  /* reset to success */
+        }
+    }
+    wc_FreeRsaKey(&myKey);
+    wc_FreeRng(&rng);
+
+    return ret;
+}
+
+static INLINE int myRsaDec(WOLFSSL* ssl, byte* in, word32 inSz,
+                           byte** out,
+                           const byte* key, word32 keySz, void* ctx)
+{
+    int     ret;
+    word32  idx = 0;
+    RsaKey  myKey;
+
+    (void)ssl;
+    (void)ctx;
+
+    wc_InitRsaKey(&myKey, NULL);
+
+    ret = wc_RsaPrivateKeyDecode(key, &idx, &myKey, keySz);
+    if (ret == 0) {
+        ret = wc_RsaPrivateDecryptInline(in, inSz, out, &myKey);
+    }
+    wc_FreeRsaKey(&myKey);
+
+    return ret;
+}
+
+#endif /* NO_RSA */
+
+static INLINE void SetupPkCallbacks(WOLFSSL_CTX* ctx, WOLFSSL* ssl)
+{
+    (void)ctx;
+    (void)ssl;
+
+    #ifdef HAVE_ECC
+        wolfSSL_CTX_SetEccSignCb(ctx, myEccSign);
+        wolfSSL_CTX_SetEccVerifyCb(ctx, myEccVerify);
+    #endif /* HAVE_ECC */
+    #ifndef NO_RSA 
+        wolfSSL_CTX_SetRsaSignCb(ctx, myRsaSign);
+        wolfSSL_CTX_SetRsaVerifyCb(ctx, myRsaVerify);
+        wolfSSL_CTX_SetRsaEncCb(ctx, myRsaEnc);
+        wolfSSL_CTX_SetRsaDecCb(ctx, myRsaDec);
+    #endif /* NO_RSA */
+}
+
+#endif /* HAVE_PK_CALLBACKS */
+
+
+
+
+
+#if defined(__hpux__) || defined(__MINGW32__) || defined (WOLFSSL_TIRTOS) \
+                      || defined(_MSC_VER)
+
+/* HP/UX doesn't have strsep, needed by test/suites.c */
+static INLINE char* strsep(char **stringp, const char *delim)
+{
+    char* start;
+    char* end;
+
+    start = *stringp;
+    if (start == NULL)
+        return NULL;
+
+    if ((end = strpbrk(start, delim))) {
+        *end++ = '\0';
+        *stringp = end;
+    } else {
+        *stringp = NULL;
+    }
+
+    return start;
+}
+
+#endif /* __hpux__ and others */
+
+/* Create unique filename, len is length of tempfn name, assuming
+   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)
+{
+    int x, size;
+    static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                   "abcdefghijklmnopqrstuvwxyz";
+    RNG rng;
+    byte out;
+
+    if (tempfn == NULL || len < 1 || num < 1 || len <= num) {
+        printf("Bad input\n");
+        return NULL;
+    }
+
+    size = len - 1;
+
+    if (wc_InitRng(&rng) != 0) {
+        printf("InitRng failed\n");
+        return NULL;
+    }
+
+    for (x = size; x > size - num; x--) {
+        if (wc_RNG_GenerateBlock(&rng,(byte*)&out, sizeof(out)) != 0) {
+            printf("RNG_GenerateBlock failed\n");
+            return NULL;
+        }
+        tempfn[x] = alphanum[out % (sizeof(alphanum) - 1)];
+    }
+    tempfn[len] = '\0';
+
+    wc_FreeRng(&rng);
+
+    return tempfn;
+}
+
+
+
+#if defined(HAVE_SESSION_TICKET) && defined(HAVE_CHACHA) && \
+                                    defined(HAVE_POLY1305)
+
+    #include <wolfssl/wolfcrypt/chacha20_poly1305.h>
+
+    typedef struct key_ctx {
+        byte name[WOLFSSL_TICKET_NAME_SZ];     /* name for this context */
+        byte key[16];                          /* cipher key */
+    } key_ctx;
+
+    static key_ctx myKey_ctx;
+    static RNG rng;
+
+    static INLINE int TicketInit(void)
+    {
+        int ret = wc_InitRng(&rng);
+        if (ret != 0) return ret;
+
+        ret = wc_RNG_GenerateBlock(&rng, myKey_ctx.key, sizeof(myKey_ctx.key));
+        if (ret != 0) return ret;
+
+        ret = wc_RNG_GenerateBlock(&rng, myKey_ctx.name,sizeof(myKey_ctx.name));
+        if (ret != 0) return ret;
+
+        return 0;
+    }
+
+    static INLINE void TicketCleanup(void)
+    {
+        wc_FreeRng(&rng);
+    }
+
+    static INLINE int myTicketEncCb(WOLFSSL* ssl,
+                             byte key_name[WOLFSSL_TICKET_NAME_SZ],
+                             byte iv[WOLFSSL_TICKET_IV_SZ],
+                             byte mac[WOLFSSL_TICKET_MAC_SZ],
+                             int enc, byte* ticket, int inLen, int* outLen,
+                             void* userCtx)
+    {
+        (void)ssl;
+        (void)userCtx;
+
+        int ret;
+        word16 sLen = htons(inLen);
+        byte aad[WOLFSSL_TICKET_NAME_SZ + WOLFSSL_TICKET_IV_SZ + 2];
+        int  aadSz = WOLFSSL_TICKET_NAME_SZ + WOLFSSL_TICKET_IV_SZ + 2;
+        byte* tmp = aad;
+
+        if (enc) {
+            XMEMCPY(key_name, myKey_ctx.name, WOLFSSL_TICKET_NAME_SZ);
+
+            ret = wc_RNG_GenerateBlock(&rng, iv, WOLFSSL_TICKET_IV_SZ);
+            if (ret != 0) return WOLFSSL_TICKET_RET_REJECT;
+
+            /* build aad from key name, iv, and length */
+            XMEMCPY(tmp, key_name, WOLFSSL_TICKET_NAME_SZ);
+            tmp += WOLFSSL_TICKET_NAME_SZ;
+            XMEMCPY(tmp, iv, WOLFSSL_TICKET_IV_SZ);
+            tmp += WOLFSSL_TICKET_IV_SZ;
+            XMEMCPY(tmp, &sLen, 2);
+
+            ret = wc_ChaCha20Poly1305_Encrypt(myKey_ctx.key, iv,
+                                              aad, aadSz,
+                                              ticket, inLen,
+                                              ticket,
+                                              mac);
+            if (ret != 0) return WOLFSSL_TICKET_RET_REJECT;
+            *outLen = inLen;  /* no padding in this mode */
+        } else {
+            /* decrypt */
+
+            /* see if we know this key */
+            if (XMEMCMP(key_name, myKey_ctx.name, WOLFSSL_TICKET_NAME_SZ) != 0){
+                printf("client presented unknown ticket key name ");
+                return WOLFSSL_TICKET_RET_FATAL;
+            }
+
+            /* build aad from key name, iv, and length */
+            XMEMCPY(tmp, key_name, WOLFSSL_TICKET_NAME_SZ);
+            tmp += WOLFSSL_TICKET_NAME_SZ;
+            XMEMCPY(tmp, iv, WOLFSSL_TICKET_IV_SZ);
+            tmp += WOLFSSL_TICKET_IV_SZ;
+            XMEMCPY(tmp, &sLen, 2);
+
+            ret = wc_ChaCha20Poly1305_Decrypt(myKey_ctx.key, iv,
+                                              aad, aadSz,
+                                              ticket, inLen,
+                                              mac,
+                                              ticket);
+            if (ret != 0) return WOLFSSL_TICKET_RET_REJECT;
+            *outLen = inLen;  /* no padding in this mode */
+        }
+
+        return WOLFSSL_TICKET_RET_OK;
+    }
+
+#endif  /* HAVE_SESSION_TICKET && CHACHA20 && POLY1305 */
+
+#endif /* wolfSSL_TEST_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/version.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,36 @@
+/* wolfssl_version.h.in
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LIBWOLFSSL_VERSION_STRING "3.6.0"
+#define LIBWOLFSSL_VERSION_HEX 0x03006000
+
+#ifdef __cplusplus
+}
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/version.h.in	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,36 @@
+/* wolfssl_version.h.in
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LIBWOLFSSL_VERSION_STRING "@VERSION@"
+#define LIBWOLFSSL_VERSION_HEX @HEX_VERSION@
+
+#ifdef __cplusplus
+}
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/aes.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,189 @@
+/* aes.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_AES_H
+#define WOLF_CRYPT_AES_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifndef NO_AES
+
+/* included for fips @wc_fips */
+#ifdef HAVE_FIPS
+#include <cyassl/ctaocrypt/aes.h>
+#if defined(CYASSL_AES_COUNTER) && !defined(WOLFSSL_AES_COUNTER)
+    #define WOLFSSL_AES_COUNTER
+#endif
+#if !defined(WOLFSSL_AES_DIRECT) && defined(CYASSL_AES_DIRECT)
+    #define WOLFSSL_AES_DIRECT
+#endif
+#endif
+
+#ifndef HAVE_FIPS /* to avoid redefinition of macros */
+#ifdef HAVE_CAVIUM
+    #include <wolfssl/ctaocrypt/logging.h>
+    #include "cavium_common.h"
+#endif
+
+#ifdef WOLFSSL_AESNI
+
+#include <wmmintrin.h>
+
+#if !defined (ALIGN16)
+    #if defined (__GNUC__)
+        #define ALIGN16 __attribute__ ( (aligned (16)))
+    #elif defined(_MSC_VER)
+        /* disable align warning, we want alignment ! */
+        #pragma warning(disable: 4324)
+        #define ALIGN16 __declspec (align (16))
+    #else
+        #define ALIGN16
+    #endif
+#endif
+
+#endif /* WOLFSSL_AESNI */
+
+#if !defined (ALIGN16)
+    #define ALIGN16
+#endif
+#endif /* HAVE_FIPS */
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#ifndef HAVE_FIPS /* to avoid redefinition of structures */
+#define WOLFSSL_AES_CAVIUM_MAGIC 0xBEEF0002
+
+enum {
+    AES_ENC_TYPE   = 1,   /* cipher unique type */
+    AES_ENCRYPTION = 0,
+    AES_DECRYPTION = 1,
+    AES_BLOCK_SIZE = 16
+};
+
+
+typedef struct Aes {
+    /* AESNI needs key first, rounds 2nd, not sure why yet */
+    ALIGN16 word32 key[60];
+    word32  rounds;
+
+    ALIGN16 word32 reg[AES_BLOCK_SIZE / sizeof(word32)];      /* for CBC mode */
+    ALIGN16 word32 tmp[AES_BLOCK_SIZE / sizeof(word32)];      /* same         */
+
+#ifdef HAVE_AESGCM
+    ALIGN16 byte H[AES_BLOCK_SIZE];
+#ifdef GCM_TABLE
+    /* key-based fast multiplication table. */
+    ALIGN16 byte M0[256][AES_BLOCK_SIZE];
+#endif /* GCM_TABLE */
+#endif /* HAVE_AESGCM */
+#ifdef WOLFSSL_AESNI
+    byte use_aesni;
+#endif /* WOLFSSL_AESNI */
+#ifdef HAVE_CAVIUM
+    AesType type;            /* aes key type */
+    int     devId;           /* nitrox device id */
+    word32  magic;           /* using cavium magic */
+    word64  contextHandle;   /* nitrox context memory handle */
+#endif
+#ifdef WOLFSSL_AES_COUNTER
+    word32  left;            /* unsued bytes left from last call */
+#endif
+#ifdef WOLFSSL_PIC32MZ_CRYPT
+    word32 key_ce[AES_BLOCK_SIZE*2/sizeof(word32)] ;
+    word32 iv_ce [AES_BLOCK_SIZE  /sizeof(word32)] ;
+    int    keylen ;
+#endif
+#ifdef WOLFSSL_TI_CRYPT
+    int    keylen ;
+#endif
+} Aes;
+
+
+#ifdef HAVE_AESGCM
+typedef struct Gmac {
+    Aes aes;
+} Gmac;
+#endif /* HAVE_AESGCM */
+#endif /* HAVE_FIPS */
+
+ WOLFSSL_API int  wc_AesSetKey(Aes* aes, const byte* key, word32 len, const byte* iv,
+                          int dir);
+ WOLFSSL_API int  wc_AesSetIV(Aes* aes, const byte* iv);
+ 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);
+ WOLFSSL_API int  wc_AesCbcDecryptWithKey(byte* out, const byte* in, word32 inSz,
+                                 const byte* key, word32 keySz, const byte* iv);
+
+/* AES-CTR */
+#ifdef WOLFSSL_AES_COUNTER
+ WOLFSSL_API void wc_AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz);
+#endif
+/* AES-DIRECT */
+#if defined(WOLFSSL_AES_DIRECT)
+ WOLFSSL_API void wc_AesEncryptDirect(Aes* aes, byte* out, const byte* in);
+ WOLFSSL_API void wc_AesDecryptDirect(Aes* aes, byte* out, const byte* in);
+ WOLFSSL_API int  wc_AesSetKeyDirect(Aes* aes, const byte* key, word32 len,
+                                const byte* iv, int dir);
+#endif
+#ifdef HAVE_AESGCM
+ WOLFSSL_API int  wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len);
+ WOLFSSL_API 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);
+ WOLFSSL_API 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);
+
+ 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);
+#endif /* HAVE_AESGCM */
+#ifdef HAVE_AESCCM
+ WOLFSSL_API void wc_AesCcmSetKey(Aes* aes, const byte* key, word32 keySz);
+ WOLFSSL_API void wc_AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
+                              const byte* nonce, word32 nonceSz,
+                              byte* authTag, word32 authTagSz,
+                              const byte* authIn, word32 authInSz);
+ WOLFSSL_API int  wc_AesCcmDecrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
+                              const byte* nonce, word32 nonceSz,
+                              const byte* authTag, word32 authTagSz,
+                              const byte* authIn, word32 authInSz);
+#endif /* HAVE_AESCCM */
+
+#ifdef HAVE_CAVIUM
+     WOLFSSL_API int  wc_AesInitCavium(Aes*, int);
+     WOLFSSL_API void wc_AesFreeCavium(Aes*);
+#endif
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* NO_AES */
+#endif /* WOLF_CRYPT_AES_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/arc4.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,66 @@
+/* arc4.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef WOLF_CRYPT_ARC4_H
+#define WOLF_CRYPT_ARC4_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#define WOLFSSL_ARC4_CAVIUM_MAGIC 0xBEEF0001
+
+enum {
+	ARC4_ENC_TYPE   = 4,    /* cipher unique type */
+    ARC4_STATE_SIZE = 256
+};
+
+/* ARC4 encryption and decryption */
+typedef struct Arc4 {
+    byte x;
+    byte y;
+    byte state[ARC4_STATE_SIZE];
+#ifdef HAVE_CAVIUM
+    int    devId;           /* nitrox device id */
+    word32 magic;           /* using cavium magic */
+    word64 contextHandle;   /* nitrox context memory handle */
+#endif
+} Arc4;
+
+WOLFSSL_API void wc_Arc4Process(Arc4*, byte*, const byte*, word32);
+WOLFSSL_API void wc_Arc4SetKey(Arc4*, const byte*, word32);
+
+#ifdef HAVE_CAVIUM
+    WOLFSSL_API int  wc_Arc4InitCavium(Arc4*, int);
+    WOLFSSL_API void wc_Arc4FreeCavium(Arc4*);
+#endif
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* WOLF_CRYPT_ARC4_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/asn.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,743 @@
+/* asn.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_ASN_H
+#define WOLF_CRYPT_ASN_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifndef NO_ASN
+
+#include <wolfssl/wolfcrypt/integer.h>
+#ifndef NO_RSA
+    #include <wolfssl/wolfcrypt/rsa.h>
+#endif
+
+/* fips declare of RsaPrivateKeyDecode @wc_fips */
+#if defined(HAVE_FIPS) && !defined(NO_RSA)
+    #include <cyassl/ctaocrypt/rsa.h>
+#endif
+
+#ifndef NO_DH
+    #include <wolfssl/wolfcrypt/dh.h>
+#endif
+#ifndef NO_DSA
+    #include <wolfssl/wolfcrypt/dsa.h>
+#endif
+#ifndef NO_SHA
+    #include <wolfssl/wolfcrypt/sha.h>
+#endif
+#ifndef NO_MD5
+    #include <wolfssl/wolfcrypt/md5.h>
+#endif
+#include <wolfssl/wolfcrypt/sha256.h>
+#include <wolfssl/wolfcrypt/asn_public.h>   /* public interface */
+#ifdef HAVE_ECC
+    #include <wolfssl/wolfcrypt/ecc.h>
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+enum {
+    ISSUER  = 0,
+    SUBJECT = 1,
+
+    EXTERNAL_SERIAL_SIZE = 32,
+
+    BEFORE  = 0,
+    AFTER   = 1
+};
+
+/* ASN Tags   */
+enum ASN_Tags {
+    ASN_BOOLEAN           = 0x01,
+    ASN_INTEGER           = 0x02,
+    ASN_BIT_STRING        = 0x03,
+    ASN_OCTET_STRING      = 0x04,
+    ASN_TAG_NULL          = 0x05,
+    ASN_OBJECT_ID         = 0x06,
+    ASN_ENUMERATED        = 0x0a,
+    ASN_UTF8STRING        = 0x0c,
+    ASN_SEQUENCE          = 0x10,
+    ASN_SET               = 0x11,
+    ASN_UTC_TIME          = 0x17,
+    ASN_OTHER_TYPE        = 0x00,
+    ASN_RFC822_TYPE       = 0x01,
+    ASN_DNS_TYPE          = 0x02,
+    ASN_DIR_TYPE          = 0x04,
+    ASN_GENERALIZED_TIME  = 0x18,
+    CRL_EXTENSIONS        = 0xa0,
+    ASN_EXTENSIONS        = 0xa3,
+    ASN_LONG_LENGTH       = 0x80
+};
+
+enum  ASN_Flags{
+    ASN_CONSTRUCTED       = 0x20,
+    ASN_CONTEXT_SPECIFIC  = 0x80
+};
+
+enum DN_Tags {
+    ASN_COMMON_NAME   = 0x03,   /* CN */
+    ASN_SUR_NAME      = 0x04,   /* SN */
+    ASN_SERIAL_NUMBER = 0x05,   /* serialNumber */
+    ASN_COUNTRY_NAME  = 0x06,   /* C  */
+    ASN_LOCALITY_NAME = 0x07,   /* L  */
+    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 {
+    ECC_PREFIX_0 = 160,
+    ECC_PREFIX_1 = 161
+};
+
+enum Misc_ASN {
+    ASN_NAME_MAX        = 256,
+    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 */
+    PKCS12              =  12,     /* PKCS #12 */
+    MAX_UNICODE_SZ      = 256,
+    ASN_BOOL_SIZE       =   2,     /* including type */
+    ASN_ECC_HEADER_SZ   =   2,     /* String type + 1 byte len */
+    ASN_ECC_CONTEXT_SZ  =   2,     /* Content specific type + 1 byte len */
+#ifdef NO_SHA
+    KEYID_SIZE          = SHA256_DIGEST_SIZE,
+#else
+    KEYID_SIZE          = SHA_DIGEST_SIZE,
+#endif
+    RSA_INTS            =   8,     /* RSA ints in private key */
+    MIN_DATE_SIZE       =  13,
+    MAX_DATE_SIZE       =  32,
+    ASN_GEN_TIME_SZ     =  15,     /* 7 numbers * 2 + Zulu tag */
+    MAX_ENCODED_SIG_SZ  = 512,
+    MAX_SIG_SZ          = 256,
+    MAX_ALGO_SZ         =  20,
+    MAX_SEQ_SZ          =   5,     /* enum(seq | con) + length(4) */
+    MAX_SET_SZ          =   5,     /* enum(set | con) + length(4) */
+    MAX_OCTET_STR_SZ    =   5,     /* enum(set | con) + length(4) */
+    MAX_EXP_SZ          =   5,     /* enum(contextspec|con|exp) + length(4) */
+    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) + legnth(4) */
+    MAX_RSA_INT_SZ      = 517,     /* RSA raw sz 4096 for bits + tag + len(4) */
+    MAX_NTRU_KEY_SZ     = 610,     /* NTRU 112 bit public key */
+    MAX_NTRU_ENC_SZ     = 628,     /* NTRU 112 bit DER public encoding */
+    MAX_LENGTH_SZ       =   4,     /* Max length size for DER encoding */
+    MAX_RSA_E_SZ        =  16,     /* Max RSA public e size */
+    MAX_CA_SZ           =  32,     /* Max encoded CA basic constraint length */
+    MAX_SN_SZ           =  35,     /* Max encoded serial number (INT) length */
+#ifdef WOLFSSL_CERT_GEN
+    #ifdef WOLFSSL_CERT_REQ
+                          /* Max encoded cert req attributes length */
+        MAX_ATTRIB_SZ   = MAX_SEQ_SZ * 3 + (11 + MAX_SEQ_SZ) * 2 +
+                          MAX_PRSTR_SZ + CTC_NAME_SIZE, /* 11 is the OID size */
+    #endif
+    #ifdef WOLFSSL_ALT_NAMES
+        MAX_EXTENSIONS_SZ   = 1 + MAX_LENGTH_SZ + CTC_MAX_ALT_SIZE,
+    #else
+        MAX_EXTENSIONS_SZ   = 1 + MAX_LENGTH_SZ + MAX_CA_SZ,
+    #endif
+                                   /* Max total extensions, id + len + others */
+#endif
+    MAX_OCSP_EXT_SZ     = 58,      /* Max OCSP Extension length */
+    MAX_OCSP_NONCE_SZ   = 18,      /* OCSP Nonce size           */
+    EIGHTK_BUF          = 8192,    /* Tmp buffer size           */
+    MAX_PUBLIC_KEY_SZ   = MAX_NTRU_ENC_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ * 2
+                                   /* use bigger NTRU size */
+};
+
+
+enum Oid_Types {
+    hashType  = 0,
+    sigType   = 1,
+    keyType   = 2,
+    curveType = 3,
+    blkType   = 4
+};
+
+
+enum Hash_Sum  {
+    MD2h    = 646,
+    MD5h    = 649,
+    SHAh    =  88,
+    SHA256h = 414,
+    SHA384h = 415,
+    SHA512h = 416
+};
+
+
+enum Block_Sum {
+    DESb  = 69,
+    DES3b = 652
+};
+
+
+enum Key_Sum {
+    DSAk   = 515,
+    RSAk   = 645,
+    NTRUk  = 274,
+    ECDSAk = 518
+};
+
+
+enum Ecc_Sum {
+    ECC_256R1 = 526,
+    ECC_384R1 = 210,
+    ECC_521R1 = 211,
+    ECC_160R1 = 184,
+    ECC_192R1 = 520,
+    ECC_224R1 = 209
+};
+
+
+enum KDF_Sum {
+    PBKDF2_OID = 660
+};
+
+
+enum Extensions_Sum {
+    BASIC_CA_OID    = 133,
+    ALT_NAMES_OID   = 131,
+    CRL_DIST_OID    = 145,
+    AUTH_INFO_OID   = 69,
+    CA_ISSUER_OID   = 117,
+    AUTH_KEY_OID    = 149,
+    SUBJ_KEY_OID    = 128,
+    CERT_POLICY_OID = 146,
+    KEY_USAGE_OID   = 129,  /* 2.5.29.15 */
+    INHIBIT_ANY_OID = 168,  /* 2.5.29.54 */
+    EXT_KEY_USAGE_OID = 151, /* 2.5.29.37 */
+    NAME_CONS_OID   = 144   /* 2.5.29.30 */
+};
+
+enum CertificatePolicy_Sum {
+    CP_ANY_OID      = 146  /* id-ce 32 0 */
+};
+
+enum SepHardwareName_Sum {
+    HW_NAME_OID     = 79   /* 1.3.6.1.5.5.7.8.4 from RFC 4108*/
+};
+
+enum AuthInfo_Sum {
+    AIA_OCSP_OID      = 116, /* 1.3.6.1.5.5.7.48.1 */
+    AIA_CA_ISSUER_OID = 117  /* 1.3.6.1.5.5.7.48.2 */
+};
+
+enum ExtKeyUsage_Sum { /* From RFC 5280 */
+    EKU_ANY_OID         = 151, /* 2.5.29.37.0, anyExtendedKeyUsage         */
+    EKU_SERVER_AUTH_OID = 71,  /* 1.3.6.1.5.5.7.3.1, id-kp-serverAuth      */
+    EKU_CLIENT_AUTH_OID = 72,  /* 1.3.6.1.5.5.7.3.2, id-kp-clientAuth      */
+    EKU_OCSP_SIGN_OID   = 79   /* 1.3.6.1.5.5.7.3.9, OCSPSigning           */
+};
+
+
+enum VerifyType {
+    NO_VERIFY = 0,
+    VERIFY    = 1
+};
+
+
+/* Key usage extension bits */
+#define KEYUSE_DIGITAL_SIG    0x0100
+#define KEYUSE_CONTENT_COMMIT 0x0080
+#define KEYUSE_KEY_ENCIPHER   0x0040
+#define KEYUSE_DATA_ENCIPHER  0x0020
+#define KEYUSE_KEY_AGREE      0x0010
+#define KEYUSE_KEY_CERT_SIGN  0x0008
+#define KEYUSE_CRL_SIGN       0x0004
+#define KEYUSE_ENCIPHER_ONLY  0x0002
+#define KEYUSE_DECIPHER_ONLY  0x0001
+
+#define EXTKEYUSE_ANY         0x08
+#define EXTKEYUSE_OCSP_SIGN   0x04
+#define EXTKEYUSE_CLIENT_AUTH 0x02
+#define EXTKEYUSE_SERVER_AUTH 0x01
+
+typedef struct DNS_entry   DNS_entry;
+
+struct DNS_entry {
+    DNS_entry* next;   /* next on DNS list */
+    char*      name;   /* actual DNS name */
+};
+
+
+typedef struct Base_entry  Base_entry;
+
+struct Base_entry {
+    Base_entry* next;   /* next on name base list */
+    char*       name;   /* actual name base */
+    int         nameSz; /* name length */
+    byte        type;   /* Name base type (DNS or RFC822) */
+};
+
+
+struct DecodedName {
+    char*   fullName;
+    int     fullNameLen;
+    int     entryCount;
+    int     cnIdx;
+    int     cnLen;
+    int     snIdx;
+    int     snLen;
+    int     cIdx;
+    int     cLen;
+    int     lIdx;
+    int     lLen;
+    int     stIdx;
+    int     stLen;
+    int     oIdx;
+    int     oLen;
+    int     ouIdx;
+    int     ouLen;
+    int     emailIdx;
+    int     emailLen;
+    int     uidIdx;
+    int     uidLen;
+    int     serialIdx;
+    int     serialLen;
+};
+
+
+typedef struct DecodedCert DecodedCert;
+typedef struct DecodedName DecodedName;
+typedef struct Signer      Signer;
+
+
+struct DecodedCert {
+    byte*   publicKey;
+    word32  pubKeySize;
+    int     pubKeyStored;
+    word32  certBegin;               /* offset to start of cert          */
+    word32  sigIndex;                /* offset to start of signature     */
+    word32  sigLength;               /* length of signature              */
+    word32  signatureOID;            /* sum of algorithm object id       */
+    word32  keyOID;                  /* sum of key algo  object id       */
+    int     version;                 /* cert version, 1 or 3             */
+    DNS_entry* altNames;             /* alt names list of dns entries    */
+#ifndef IGNORE_NAME_CONSTRAINTS
+    DNS_entry* altEmailNames;        /* alt names list of RFC822 entries */
+    Base_entry* permittedNames;      /* Permitted name bases             */
+    Base_entry* excludedNames;       /* Excluded name bases              */
+#endif /* IGNORE_NAME_CONSTRAINTS */
+    byte    subjectHash[KEYID_SIZE]; /* hash of all Names                */
+    byte    issuerHash[KEYID_SIZE];  /* hash of all Names                */
+#ifdef HAVE_OCSP
+    byte    issuerKeyHash[KEYID_SIZE]; /* hash of the public Key         */
+#endif /* HAVE_OCSP */
+    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 */
+    word32  srcIdx;                  /* current offset into buffer       */
+    word32  maxIdx;                  /* max offset based on init size    */
+    void*   heap;                    /* for user memory overrides        */
+    byte    serial[EXTERNAL_SERIAL_SIZE];  /* raw serial number          */
+    int     serialSz;                /* raw serial bytes stored */
+    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 */
+    int     extAuthInfoSz;           /* length of the URI                */
+    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    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    extBasicConstSet;
+    byte    extBasicConstCrit;
+    byte    extBasicConstPlSet;
+    word32  pathLength;              /* CA basic constraint path length, opt */
+    byte    extSubjAltNameSet;
+    byte    extSubjAltNameCrit;
+    byte    extAuthKeyIdCrit;
+#ifndef IGNORE_NAME_CONSTRAINTS
+    byte    extNameConstraintCrit;
+#endif /* IGNORE_NAME_CONSTRAINTS */
+    byte    extSubjKeyIdCrit;
+    byte    extKeyUsageCrit;
+    byte    extExtKeyUsageCrit;
+    byte*   extExtKeyUsageSrc;
+    word32  extExtKeyUsageSz;
+    word32  extExtKeyUsageCount;
+    byte*   extAuthKeyIdSrc;
+    word32  extAuthKeyIdSz;
+    byte*   extSubjKeyIdSrc;
+    word32  extSubjKeyIdSz;
+#endif
+#ifdef HAVE_ECC
+    word32  pkCurveOID;           /* Public Key's curve OID */
+#endif /* HAVE_ECC */
+    byte*   beforeDate;
+    int     beforeDateLen;
+    byte*   afterDate;
+    int     afterDateLen;
+#ifdef HAVE_PKCS7
+    byte*   issuerRaw;               /* pointer to issuer inside source */
+    int     issuerRawLen;
+#endif
+#ifndef IGNORE_NAME_CONSTRAINT
+    byte*   subjectRaw;               /* pointer to subject inside source */
+    int     subjectRawLen;
+#endif
+#if defined(WOLFSSL_CERT_GEN)
+    /* easy access to subject info for other sign */
+    char*   subjectSN;
+    int     subjectSNLen;
+    char    subjectSNEnc;
+    char*   subjectC;
+    int     subjectCLen;
+    char    subjectCEnc;
+    char*   subjectL;
+    int     subjectLLen;
+    char    subjectLEnc;
+    char*   subjectST;
+    int     subjectSTLen;
+    char    subjectSTEnc;
+    char*   subjectO;
+    int     subjectOLen;
+    char    subjectOEnc;
+    char*   subjectOU;
+    int     subjectOULen;
+    char    subjectOUEnc;
+    char*   subjectEmail;
+    int     subjectEmailLen;
+#endif /* WOLFSSL_CERT_GEN */
+#ifdef OPENSSL_EXTRA
+    DecodedName issuerName;
+    DecodedName subjectName;
+#endif /* OPENSSL_EXTRA */
+#ifdef WOLFSSL_SEP
+    int     deviceTypeSz;
+    byte*   deviceType;
+    int     hwTypeSz;
+    byte*   hwType;
+    int     hwSerialNumSz;
+    byte*   hwSerialNum;
+    #ifdef OPENSSL_EXTRA
+        byte    extCertPolicySet;
+        byte    extCertPolicyCrit;
+    #endif /* OPENSSL_EXTRA */
+#endif /* WOLFSSL_SEP */
+};
+
+
+#ifdef NO_SHA
+    #define SIGNER_DIGEST_SIZE SHA256_DIGEST_SIZE
+#else
+    #define SIGNER_DIGEST_SIZE SHA_DIGEST_SIZE
+#endif
+
+/* CA Signers */
+/* if change layout change PERSIST_CERT_CACHE functions too */
+struct Signer {
+    word32  pubKeySize;
+    word32  keyOID;                  /* key type */
+    word16  keyUsage;
+    byte*   publicKey;
+    int     nameLen;
+    char*   name;                    /* common name */
+#ifndef IGNORE_NAME_CONSTRAINTS
+        Base_entry* permittedNames;
+        Base_entry* excludedNames;
+#endif /* IGNORE_NAME_CONSTRAINTS */
+    byte    subjectNameHash[SIGNER_DIGEST_SIZE];
+                                     /* sha hash of names in certificate */
+    #ifndef NO_SKID
+        byte    subjectKeyIdHash[SIGNER_DIGEST_SIZE];
+                                     /* sha hash of names in certificate */
+    #endif
+    Signer* next;
+};
+
+
+/* not for public consumption but may use for testing sometimes */
+#ifdef WOLFSSL_TEST_CERT
+    #define WOLFSSL_TEST_API WOLFSSL_API
+#else
+    #define WOLFSSL_TEST_API WOLFSSL_LOCAL
+#endif
+
+WOLFSSL_TEST_API void FreeAltNames(DNS_entry*, void*);
+#ifndef IGNORE_NAME_CONSTRAINTS
+    WOLFSSL_TEST_API void FreeNameSubtrees(Base_entry*, void*);
+#endif /* IGNORE_NAME_CONSTRAINTS */
+WOLFSSL_TEST_API void InitDecodedCert(DecodedCert*, byte*, word32, void*);
+WOLFSSL_TEST_API void FreeDecodedCert(DecodedCert*);
+WOLFSSL_TEST_API int  ParseCert(DecodedCert*, int type, int verify, void* cm);
+
+WOLFSSL_LOCAL int ParseCertRelative(DecodedCert*, int type, int verify,void* cm);
+WOLFSSL_LOCAL int DecodeToKey(DecodedCert*, int verify);
+
+WOLFSSL_LOCAL Signer* MakeSigner(void*);
+WOLFSSL_LOCAL void    FreeSigner(Signer*, void*);
+WOLFSSL_LOCAL void    FreeSignerTable(Signer**, int, void*);
+
+
+WOLFSSL_LOCAL int ToTraditional(byte* buffer, word32 length);
+WOLFSSL_LOCAL int ToTraditionalEnc(byte* buffer, word32 length,const char*, int);
+
+WOLFSSL_LOCAL int ValidateDate(const byte* date, byte format, int dateType);
+
+/* ASN.1 helper functions */
+WOLFSSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len,
+                           word32 maxIdx);
+WOLFSSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len,
+                             word32 maxIdx);
+WOLFSSL_LOCAL int GetSet(const byte* input, word32* inOutIdx, int* len,
+                        word32 maxIdx);
+WOLFSSL_LOCAL int GetMyVersion(const byte* input, word32* inOutIdx,
+                              int* version);
+WOLFSSL_LOCAL int GetInt(mp_int* mpi, const byte* input, word32* inOutIdx,
+                        word32 maxIdx);
+WOLFSSL_LOCAL int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid,
+                           word32 maxIdx);
+WOLFSSL_LOCAL word32 SetLength(word32 length, byte* output);
+WOLFSSL_LOCAL word32 SetSequence(word32 len, byte* output);
+WOLFSSL_LOCAL word32 SetOctetString(word32 len, byte* output);
+WOLFSSL_LOCAL word32 SetImplicit(byte tag, byte number, word32 len,byte* output);
+WOLFSSL_LOCAL word32 SetExplicit(byte number, word32 len, byte* output);
+WOLFSSL_LOCAL word32 SetSet(word32 len, byte* output);
+WOLFSSL_LOCAL word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz);
+WOLFSSL_LOCAL int SetMyVersion(word32 version, byte* output, int header);
+WOLFSSL_LOCAL int SetSerialNumber(const byte* sn, word32 snSz, byte* output);
+WOLFSSL_LOCAL int GetNameHash(const byte* source, word32* idx, byte* hash,
+                             int maxIdx);
+
+#ifdef HAVE_ECC
+    /* ASN sig helpers */
+    WOLFSSL_LOCAL int StoreECC_DSA_Sig(byte* out, word32* outLen, mp_int* r,
+                                      mp_int* s);
+    WOLFSSL_LOCAL int DecodeECC_DSA_Sig(const byte* sig, word32 sigLen,
+                                       mp_int* r, mp_int* s);
+#endif
+
+#ifdef WOLFSSL_CERT_GEN
+
+enum cert_enums {
+    NAME_ENTRIES    =  8,
+    JOINT_LEN       =  2,
+    EMAIL_JOINT_LEN =  9,
+    RSA_KEY         = 10,
+    NTRU_KEY        = 11,
+    ECC_KEY         = 12
+};
+
+#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 */
+
+
+
+/* for pointer use */
+typedef struct CertStatus CertStatus;
+
+#ifdef HAVE_OCSP
+
+enum Ocsp_Response_Status {
+    OCSP_SUCCESSFUL        = 0, /* Response has valid confirmations */
+    OCSP_MALFORMED_REQUEST = 1, /* Illegal confirmation request */
+    OCSP_INTERNAL_ERROR    = 2, /* Internal error in issuer */
+    OCSP_TRY_LATER         = 3, /* Try again later */
+    OCSP_SIG_REQUIRED      = 5, /* Must sign the request (4 is skipped) */
+    OCSP_UNAUTHROIZED      = 6  /* Request unauthorized */
+};
+
+
+enum Ocsp_Cert_Status {
+    CERT_GOOD    = 0,
+    CERT_REVOKED = 1,
+    CERT_UNKNOWN = 2
+};
+
+
+enum Ocsp_Sums {
+    OCSP_BASIC_OID = 117,
+    OCSP_NONCE_OID = 118
+};
+
+
+typedef struct OcspRequest  OcspRequest;
+typedef struct OcspResponse OcspResponse;
+
+
+struct CertStatus {
+    CertStatus* next;
+
+    byte serial[EXTERNAL_SERIAL_SIZE];
+    int serialSz;
+
+    int status;
+
+    byte thisDate[MAX_DATE_SIZE];
+    byte nextDate[MAX_DATE_SIZE];
+    byte thisDateFormat;
+    byte nextDateFormat;
+};
+
+
+struct OcspResponse {
+    int     responseStatus;  /* return code from Responder */
+
+    byte*   response;        /* Pointer to beginning of OCSP Response */
+    word32  responseSz;      /* length of the OCSP Response */
+
+    byte    producedDate[MAX_DATE_SIZE];
+							 /* Date at which this response was signed */
+    byte    producedDateFormat; /* format of the producedDate */
+    byte*   issuerHash;
+    byte*   issuerKeyHash;
+
+    byte*   cert;
+    word32  certSz;
+
+    byte*   sig;             /* Pointer to sig in source */
+    word32  sigSz;           /* Length in octets for the sig */
+    word32  sigOID;          /* OID for hash used for sig */
+
+    CertStatus* status;      /* certificate status to fill out */
+
+    byte*   nonce;           /* pointer to nonce inside ASN.1 response */
+    int     nonceSz;         /* length of the nonce string */
+
+    byte*   source;          /* pointer to source buffer, not owned */
+    word32  maxIdx;          /* max offset based on init size */
+};
+
+
+struct OcspRequest {
+    DecodedCert* cert;
+
+    byte    useNonce;
+    byte    nonce[MAX_OCSP_NONCE_SZ];
+    int     nonceSz;
+
+    byte*   issuerHash;      /* pointer to issuerHash in source cert */
+    byte*   issuerKeyHash;   /* pointer to issuerKeyHash in source cert */
+    byte*   serial;          /* pointer to serial number in source cert */
+    int     serialSz;        /* length of the serial number */
+
+    byte*   dest;            /* pointer to the destination ASN.1 buffer */
+    word32  destSz;          /* length of the destination buffer */
+};
+
+
+WOLFSSL_LOCAL void InitOcspResponse(OcspResponse*, CertStatus*, byte*, word32);
+WOLFSSL_LOCAL int  OcspResponseDecode(OcspResponse*);
+
+WOLFSSL_LOCAL void InitOcspRequest(OcspRequest*, DecodedCert*,
+                                                          byte, byte*, word32);
+WOLFSSL_LOCAL int  EncodeOcspRequest(OcspRequest*);
+
+WOLFSSL_LOCAL int  CompareOcspReqResp(OcspRequest*, OcspResponse*);
+
+
+#endif /* HAVE_OCSP */
+
+
+/* for pointer use */
+typedef struct RevokedCert RevokedCert;
+
+#ifdef HAVE_CRL
+
+struct RevokedCert {
+    byte         serialNumber[EXTERNAL_SERIAL_SIZE];
+    int          serialSz;
+    RevokedCert* next;
+};
+
+typedef struct DecodedCRL DecodedCRL;
+
+struct DecodedCRL {
+    word32  certBegin;               /* offset to start of cert          */
+    word32  sigIndex;                /* offset to start of signature     */
+    word32  sigLength;               /* length of signature              */
+    word32  signatureOID;            /* sum of algorithm object id       */
+    byte*   signature;               /* pointer into raw source, not owned */
+    byte    issuerHash[SIGNER_DIGEST_SIZE]; /* issuer hash               */
+    byte    crlHash[SIGNER_DIGEST_SIZE]; /* raw crl data hash            */
+    byte    lastDate[MAX_DATE_SIZE]; /* last date updated  */
+    byte    nextDate[MAX_DATE_SIZE]; /* next update date   */
+    byte    lastDateFormat;          /* format of last date */
+    byte    nextDateFormat;          /* format of next date */
+    RevokedCert* certs;              /* revoked cert list  */
+    int          totalCerts;         /* number on list     */
+};
+
+WOLFSSL_LOCAL void InitDecodedCRL(DecodedCRL*);
+WOLFSSL_LOCAL int  ParseCRL(DecodedCRL*, const byte* buff, word32 sz, void* cm);
+WOLFSSL_LOCAL void FreeDecodedCRL(DecodedCRL*);
+
+
+#endif /* HAVE_CRL */
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* !NO_ASN */
+#endif /* WOLF_CRYPT_ASN_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/asn_public.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,198 @@
+/* asn_public.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef WOLF_CRYPT_ASN_PUBLIC_H
+#define WOLF_CRYPT_ASN_PUBLIC_H
+
+#include <wolfssl/wolfcrypt/types.h>
+#ifdef HAVE_ECC
+    #include <wolfssl/wolfcrypt/ecc.h>
+#endif
+#if defined(WOLFSSL_CERT_GEN) && !defined(NO_RSA)
+    #include <wolfssl/wolfcrypt/rsa.h>
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* Certificate file Type */
+enum CertType {
+    CERT_TYPE       = 0,
+    PRIVATEKEY_TYPE,
+    DH_PARAM_TYPE,
+    CRL_TYPE,
+    CA_TYPE,
+    ECC_PRIVATEKEY_TYPE,
+    CERTREQ_TYPE
+};
+
+
+/* Signature type, by OID sum */
+enum Ctc_SigType {
+    CTC_SHAwDSA      = 517,
+    CTC_MD2wRSA      = 646,
+    CTC_MD5wRSA      = 648,
+    CTC_SHAwRSA      = 649,
+    CTC_SHAwECDSA    = 520,
+    CTC_SHA256wRSA   = 655,
+    CTC_SHA256wECDSA = 524,
+    CTC_SHA384wRSA   = 656,
+    CTC_SHA384wECDSA = 525,
+    CTC_SHA512wRSA   = 657,
+    CTC_SHA512wECDSA = 526
+};
+
+enum Ctc_Encoding {
+    CTC_UTF8       = 0x0c, /* utf8      */
+    CTC_PRINTABLE  = 0x13  /* printable */
+};
+
+
+#ifdef WOLFSSL_CERT_GEN
+
+#ifndef HAVE_ECC
+    typedef struct ecc_key ecc_key;
+#endif
+
+enum Ctc_Misc {
+    CTC_NAME_SIZE    =    64,
+    CTC_DATE_SIZE    =    32,
+    CTC_MAX_ALT_SIZE = 16384,   /* may be huge */
+    CTC_SERIAL_SIZE  =     8
+};
+
+typedef struct CertName {
+    char country[CTC_NAME_SIZE];
+    char countryEnc;
+    char state[CTC_NAME_SIZE];
+    char stateEnc;
+    char locality[CTC_NAME_SIZE];
+    char localityEnc;
+    char sur[CTC_NAME_SIZE];
+    char surEnc;
+    char org[CTC_NAME_SIZE];
+    char orgEnc;
+    char unit[CTC_NAME_SIZE];
+    char unitEnc;
+    char commonName[CTC_NAME_SIZE];
+    char commonNameEnc;
+    char email[CTC_NAME_SIZE];  /* !!!! email has to be last !!!! */
+} CertName;
+
+
+/* for user to fill for certificate generation */
+typedef struct Cert {
+    int      version;                   /* x509 version  */
+    byte     serial[CTC_SERIAL_SIZE];   /* serial number */
+    int      sigType;                   /* signature algo type */
+    CertName issuer;                    /* issuer info */
+    int      daysValid;                 /* validity days */
+    int      selfSigned;                /* self signed flag */
+    CertName subject;                   /* subject info */
+    int      isCA;                      /* is this going to be a CA */
+    /* internal use only */
+    int      bodySz;                    /* pre sign total size */
+    int      keyType;                   /* public key type of subject */
+#ifdef WOLFSSL_ALT_NAMES
+    byte     altNames[CTC_MAX_ALT_SIZE]; /* altNames copy */
+    int      altNamesSz;                 /* altNames size in bytes */
+    byte     beforeDate[CTC_DATE_SIZE];  /* before date copy */
+    int      beforeDateSz;               /* size of copy */
+    byte     afterDate[CTC_DATE_SIZE];   /* after date copy */
+    int      afterDateSz;                /* size of copy */
+#endif
+#ifdef WOLFSSL_CERT_REQ
+    char     challengePw[CTC_NAME_SIZE];
+#endif
+} Cert;
+#endif /* WOLFSSL_CERT_GEN */
+
+
+#ifdef WOLFSSL_CERT_GEN
+
+
+
+/* Initialize and Set Certficate defaults:
+   version    = 3 (0x2)
+   serial     = 0 (Will be randomly generated)
+   sigType    = SHA_WITH_RSA
+   issuer     = blank
+   daysValid  = 500
+   selfSigned = 1 (true) use subject as issuer
+   subject    = blank
+   isCA       = 0 (false)
+   keyType    = RSA_KEY (default)
+*/
+WOLFSSL_API void wc_InitCert(Cert*);
+WOLFSSL_API int  wc_MakeCert(Cert*, byte* derBuffer, word32 derSz, RsaKey*,
+                         ecc_key*, RNG*);
+#ifdef WOLFSSL_CERT_REQ
+    WOLFSSL_API int  wc_MakeCertReq(Cert*, byte* derBuffer, word32 derSz, RsaKey*,
+                                ecc_key*);
+#endif
+WOLFSSL_API int  wc_SignCert(int requestSz, int sigType, byte* derBuffer,
+                         word32 derSz, RsaKey*, ecc_key*, RNG*);
+WOLFSSL_API int  wc_MakeSelfCert(Cert*, byte* derBuffer, word32 derSz, RsaKey*,
+                             RNG*);
+WOLFSSL_API int  wc_SetIssuer(Cert*, const char*);
+WOLFSSL_API int  wc_SetSubject(Cert*, const char*);
+#ifdef WOLFSSL_ALT_NAMES
+    WOLFSSL_API int  wc_SetAltNames(Cert*, const char*);
+#endif
+WOLFSSL_API int  wc_SetIssuerBuffer(Cert*, const byte*, int);
+WOLFSSL_API int  wc_SetSubjectBuffer(Cert*, const byte*, int);
+WOLFSSL_API int  wc_SetAltNamesBuffer(Cert*, const byte*, int);
+WOLFSSL_API int  wc_SetDatesBuffer(Cert*, const byte*, int);
+
+    #ifdef HAVE_NTRU
+        WOLFSSL_API int  wc_MakeNtruCert(Cert*, byte* derBuffer, word32 derSz,
+                                     const byte* ntruKey, word16 keySz, RNG*);
+    #endif
+
+#endif /* WOLFSSL_CERT_GEN */
+
+
+#if defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN)
+    WOLFSSL_API int wc_DerToPem(const byte* der, word32 derSz, byte* output,
+                            word32 outputSz, int type);
+#endif
+
+#ifdef HAVE_ECC
+    /* private key helpers */
+    WOLFSSL_API int wc_EccPrivateKeyDecode(const byte* input,word32* inOutIdx,
+                                         ecc_key*,word32);
+    WOLFSSL_API int wc_EccKeyToDer(ecc_key*, byte* output, word32 inLen);
+#endif
+
+/* DER encode signature */
+WOLFSSL_API word32 wc_EncodeSignature(byte* out, const byte* digest, word32 digSz,
+                                  int hashOID);
+WOLFSSL_API int wc_GetCTC_HashOID(int type);
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* WOLF_CRYPT_ASN_PUBLIC_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/blake2-impl.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,155 @@
+/*
+   BLAKE2 reference source code package - reference C implementations
+
+   Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
+
+   To the extent possible under law, the author(s) have dedicated all copyright
+   and related and neighboring rights to this software to the public domain
+   worldwide. This software is distributed without any warranty.
+
+   You should have received a copy of the CC0 Public Domain Dedication along with
+   this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
+*/
+/* blake2-impl.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef WOLFCRYPT_BLAKE2_IMPL_H
+#define WOLFCRYPT_BLAKE2_IMPL_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+static inline word32 load32( const void *src )
+{
+#if defined(LITTLE_ENDIAN_ORDER)
+  return *( word32 * )( src );
+#else
+  const byte *p = ( byte * )src;
+  word32 w = *p++;
+  w |= ( word32 )( *p++ ) <<  8;
+  w |= ( word32 )( *p++ ) << 16;
+  w |= ( word32 )( *p++ ) << 24;
+  return w;
+#endif
+}
+
+static inline word64 load64( const void *src )
+{
+#if defined(LITTLE_ENDIAN_ORDER)
+  return *( word64 * )( src );
+#else
+  const byte *p = ( byte * )src;
+  word64 w = *p++;
+  w |= ( word64 )( *p++ ) <<  8;
+  w |= ( word64 )( *p++ ) << 16;
+  w |= ( word64 )( *p++ ) << 24;
+  w |= ( word64 )( *p++ ) << 32;
+  w |= ( word64 )( *p++ ) << 40;
+  w |= ( word64 )( *p++ ) << 48;
+  w |= ( word64 )( *p++ ) << 56;
+  return w;
+#endif
+}
+
+static inline void store32( void *dst, word32 w )
+{
+#if defined(LITTLE_ENDIAN_ORDER)
+  *( word32 * )( dst ) = w;
+#else
+  byte *p = ( byte * )dst;
+  *p++ = ( byte )w; w >>= 8;
+  *p++ = ( byte )w; w >>= 8;
+  *p++ = ( byte )w; w >>= 8;
+  *p++ = ( byte )w;
+#endif
+}
+
+static inline void store64( void *dst, word64 w )
+{
+#if defined(LITTLE_ENDIAN_ORDER)
+  *( word64 * )( dst ) = w;
+#else
+  byte *p = ( byte * )dst;
+  *p++ = ( byte )w; w >>= 8;
+  *p++ = ( byte )w; w >>= 8;
+  *p++ = ( byte )w; w >>= 8;
+  *p++ = ( byte )w; w >>= 8;
+  *p++ = ( byte )w; w >>= 8;
+  *p++ = ( byte )w; w >>= 8;
+  *p++ = ( byte )w; w >>= 8;
+  *p++ = ( byte )w;
+#endif
+}
+
+static inline word64 load48( const void *src )
+{
+  const byte *p = ( const byte * )src;
+  word64 w = *p++;
+  w |= ( word64 )( *p++ ) <<  8;
+  w |= ( word64 )( *p++ ) << 16;
+  w |= ( word64 )( *p++ ) << 24;
+  w |= ( word64 )( *p++ ) << 32;
+  w |= ( word64 )( *p++ ) << 40;
+  return w;
+}
+
+static inline void store48( void *dst, word64 w )
+{
+  byte *p = ( byte * )dst;
+  *p++ = ( byte )w; w >>= 8;
+  *p++ = ( byte )w; w >>= 8;
+  *p++ = ( byte )w; w >>= 8;
+  *p++ = ( byte )w; w >>= 8;
+  *p++ = ( byte )w; w >>= 8;
+  *p++ = ( byte )w;
+}
+
+static inline word32 rotl32( const word32 w, const unsigned c )
+{
+  return ( w << c ) | ( w >> ( 32 - c ) );
+}
+
+static inline word64 rotl64( const word64 w, const unsigned c )
+{
+  return ( w << c ) | ( w >> ( 64 - c ) );
+}
+
+static inline word32 rotr32( const word32 w, const unsigned c )
+{
+  return ( w >> c ) | ( w << ( 32 - c ) );
+}
+
+static inline word64 rotr64( const word64 w, const unsigned c )
+{
+  return ( w >> c ) | ( w << ( 64 - c ) );
+}
+
+/* prevents compiler optimizing out memset() */
+static inline void secure_zero_memory( void *v, word64 n )
+{
+  volatile byte *p = ( volatile byte * )v;
+
+  while( n-- ) *p++ = 0;
+}
+
+#endif  /* WOLFCRYPT_BLAKE2_IMPL_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/blake2-int.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,184 @@
+/*
+   BLAKE2 reference source code package - reference C implementations
+
+   Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
+
+   To the extent possible under law, the author(s) have dedicated all copyright
+   and related and neighboring rights to this software to the public domain
+   worldwide. This software is distributed without any warranty.
+
+   You should have received a copy of the CC0 Public Domain Dedication along with
+   this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
+*/
+/* blake2-int.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+
+#ifndef WOLFCRYPT_BLAKE2_INT_H
+#define WOLFCRYPT_BLAKE2_INT_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+
+#if defined(_MSC_VER)
+    #define ALIGN(x) __declspec(align(x))
+#elif defined(__GNUC__)
+    #define ALIGN(x) __attribute__((aligned(x)))
+#else
+    #define ALIGN(x)
+#endif
+
+
+#if defined(__cplusplus)
+    extern "C" {
+#endif
+
+  enum blake2s_constant
+  {
+    BLAKE2S_BLOCKBYTES = 64,
+    BLAKE2S_OUTBYTES   = 32,
+    BLAKE2S_KEYBYTES   = 32,
+    BLAKE2S_SALTBYTES  = 8,
+    BLAKE2S_PERSONALBYTES = 8
+  };
+
+  enum blake2b_constant
+  {
+    BLAKE2B_BLOCKBYTES = 128,
+    BLAKE2B_OUTBYTES   = 64,
+    BLAKE2B_KEYBYTES   = 64,
+    BLAKE2B_SALTBYTES  = 16,
+    BLAKE2B_PERSONALBYTES = 16
+  };
+
+#pragma pack(push, 1)
+  typedef struct __blake2s_param
+  {
+    byte  digest_length; /* 1 */
+    byte  key_length;    /* 2 */
+    byte  fanout;        /* 3 */
+    byte  depth;         /* 4 */
+    word32 leaf_length;   /* 8 */
+    byte  node_offset[6];/* 14 */
+    byte  node_depth;    /* 15 */
+    byte  inner_length;  /* 16 */
+    /* byte  reserved[0]; */
+    byte  salt[BLAKE2B_SALTBYTES]; /* 24 */
+    byte  personal[BLAKE2S_PERSONALBYTES];  /* 32 */
+  } blake2s_param;
+
+  ALIGN( 64 ) typedef struct __blake2s_state
+  {
+    word32 h[8];
+    word32 t[2];
+    word32 f[2];
+    byte  buf[2 * BLAKE2S_BLOCKBYTES];
+    word64 buflen;
+    byte  last_node;
+  } blake2s_state ;
+
+  typedef struct __blake2b_param
+  {
+    byte  digest_length; /* 1 */
+    byte  key_length;    /* 2 */
+    byte  fanout;        /* 3 */
+    byte  depth;         /* 4 */
+    word32 leaf_length;   /* 8 */
+    word64 node_offset;   /* 16 */
+    byte  node_depth;    /* 17 */
+    byte  inner_length;  /* 18 */
+    byte  reserved[14];  /* 32 */
+    byte  salt[BLAKE2B_SALTBYTES]; /* 48 */
+    byte  personal[BLAKE2B_PERSONALBYTES];  /* 64 */
+  } blake2b_param;
+
+  ALIGN( 64 ) typedef struct __blake2b_state
+  {
+    word64 h[8];
+    word64 t[2];
+    word64 f[2];
+    byte  buf[2 * BLAKE2B_BLOCKBYTES];
+    word64 buflen;
+    byte  last_node;
+  } blake2b_state;
+
+  typedef struct __blake2sp_state
+  {
+    blake2s_state S[8][1];
+    blake2s_state R[1];
+    byte buf[8 * BLAKE2S_BLOCKBYTES];
+    word64 buflen;
+  } blake2sp_state;
+
+  typedef struct __blake2bp_state
+  {
+    blake2b_state S[4][1];
+    blake2b_state R[1];
+    byte buf[4 * BLAKE2B_BLOCKBYTES];
+    word64 buflen;
+  } blake2bp_state;
+#pragma pack(pop)
+
+  /* Streaming API */
+  int blake2s_init( blake2s_state *S, const byte outlen );
+  int blake2s_init_key( blake2s_state *S, const byte outlen, const void *key, const byte keylen );
+  int blake2s_init_param( blake2s_state *S, const blake2s_param *P );
+  int blake2s_update( blake2s_state *S, const byte *in, word64 inlen );
+  int blake2s_final( blake2s_state *S, byte *out, byte outlen );
+
+  int blake2b_init( blake2b_state *S, const byte outlen );
+  int blake2b_init_key( blake2b_state *S, const byte outlen, const void *key, const byte keylen );
+  int blake2b_init_param( blake2b_state *S, const blake2b_param *P );
+  int blake2b_update( blake2b_state *S, const byte *in, word64 inlen );
+  int blake2b_final( blake2b_state *S, byte *out, byte outlen );
+
+  int blake2sp_init( blake2sp_state *S, const byte outlen );
+  int blake2sp_init_key( blake2sp_state *S, const byte outlen, const void *key, const byte keylen );
+  int blake2sp_update( blake2sp_state *S, const byte *in, word64 inlen );
+  int blake2sp_final( blake2sp_state *S, byte *out, byte outlen );
+
+  int blake2bp_init( blake2bp_state *S, const byte outlen );
+  int blake2bp_init_key( blake2bp_state *S, const byte outlen, const void *key, const byte keylen );
+  int blake2bp_update( blake2bp_state *S, const byte *in, word64 inlen );
+  int blake2bp_final( blake2bp_state *S, byte *out, byte outlen );
+
+  /* Simple API */
+  int blake2s( byte *out, const void *in, const void *key, const byte outlen, const word64 inlen, byte keylen );
+  int blake2b( byte *out, const void *in, const void *key, const byte outlen, const word64 inlen, byte keylen );
+
+  int blake2sp( byte *out, const void *in, const void *key, const byte outlen, const word64 inlen, byte keylen );
+  int blake2bp( byte *out, const void *in, const void *key, const byte outlen, const word64 inlen, byte keylen );
+
+  static inline int blake2( byte *out, const void *in, const void *key, const byte outlen, const word64 inlen, byte keylen )
+  {
+    return blake2b( out, in, key, outlen, inlen, keylen );
+  }
+
+
+
+#if defined(__cplusplus)
+    }
+#endif
+
+#endif  /* WOLFCRYPT_BLAKE2_INT_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/blake2.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,72 @@
+/* blake2.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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
+ * a with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+
+
+#ifndef WOLF_CRYPT_BLAKE2_H
+#define WOLF_CRYPT_BLAKE2_H
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_BLAKE2
+
+#include <wolfssl/wolfcrypt/blake2-int.h>
+
+/* call old functions if using fips for the sake of hmac @wc_fips */
+#ifdef HAVE_FIPS
+    /* Since hmac can call blake functions provide original calls */
+    #define wc_InitBlake2b   InitBlake2b
+    #define wc_Blake2bUpdate Blake2bUpdate
+    #define wc_Blake2bFinal  Blake2bFinal
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* in bytes, variable digest size up to 512 bits (64 bytes) */
+enum {
+    BLAKE2B_ID  = 7,   /* hash type unique */
+    BLAKE2B_256 = 32   /* 256 bit type, SSL default */
+};
+
+
+/* BLAKE2b digest */
+typedef struct Blake2b {
+    blake2b_state S[1];         /* our state */
+    word32        digestSz;     /* digest size used on init */
+} Blake2b;
+
+
+WOLFSSL_API int wc_InitBlake2b(Blake2b*, word32);
+WOLFSSL_API int wc_Blake2bUpdate(Blake2b*, const byte*, word32);
+WOLFSSL_API int wc_Blake2bFinal(Blake2b*, byte*, word32);
+
+
+
+#ifdef __cplusplus
+    }
+#endif
+
+#endif  /* HAVE_BLAKE2 */
+#endif  /* WOLF_CRYPT_BLAKE2_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/camellia.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,97 @@
+/* camellia.h ver 1.2.0
+ *
+ * Copyright (c) 2006,2007
+ * NTT (Nippon Telegraph and Telephone Corporation) . All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer as
+ *   the first lines of this file unmodified.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NTT ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL NTT BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* camellia.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_CAMELLIA_H
+#define WOLF_CRYPT_CAMELLIA_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef HAVE_CAMELLIA
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+enum {
+    CAMELLIA_BLOCK_SIZE = 16
+};
+
+#define CAMELLIA_TABLE_BYTE_LEN 272
+#define CAMELLIA_TABLE_WORD_LEN (CAMELLIA_TABLE_BYTE_LEN / sizeof(word32))
+
+typedef word32 KEY_TABLE_TYPE[CAMELLIA_TABLE_WORD_LEN];
+
+typedef struct Camellia {
+    word32 keySz;
+    KEY_TABLE_TYPE key;
+    word32 reg[CAMELLIA_BLOCK_SIZE / sizeof(word32)]; /* for CBC mode */
+    word32 tmp[CAMELLIA_BLOCK_SIZE / sizeof(word32)]; /* for CBC mode */
+} Camellia;
+
+
+WOLFSSL_API int  wc_CamelliaSetKey(Camellia* cam,
+                                   const byte* key, word32 len, const byte* iv);
+WOLFSSL_API int  wc_CamelliaSetIV(Camellia* cam, const byte* iv);
+WOLFSSL_API void wc_CamelliaEncryptDirect(Camellia* cam, byte* out,
+                                                                const byte* in);
+WOLFSSL_API void wc_CamelliaDecryptDirect(Camellia* cam, byte* out,
+                                                                const byte* in);
+WOLFSSL_API void wc_CamelliaCbcEncrypt(Camellia* cam,
+                                          byte* out, const byte* in, word32 sz);
+WOLFSSL_API void wc_CamelliaCbcDecrypt(Camellia* cam,
+                                          byte* out, const byte* in, word32 sz);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* HAVE_CAMELLIA */
+#endif /* WOLF_CRYPT_CAMELLIA_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/chacha.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,58 @@
+/* chacha.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_CHACHA_H
+#define WOLF_CRYPT_CHACHA_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef HAVE_CHACHA
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+enum {
+	CHACHA_ENC_TYPE = 7     /* cipher unique type */
+};
+
+typedef struct ChaCha {
+    word32 X[16];           /* state of cipher */
+} 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 */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/chacha20_poly1305.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,80 @@
+/* chacha20_poly1305.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+/* This implementation of the ChaCha20-Poly1305 AEAD is based on "ChaCha20
+ * and Poly1305 for IETF protocols" (draft-irtf-cfrg-chacha20-poly1305-10):
+ * https://tools.ietf.org/html/draft-irtf-cfrg-chacha20-poly1305-10
+ */
+
+#ifndef WOLF_CRYPT_CHACHA20_POLY1305_H
+#define WOLF_CRYPT_CHACHA20_POLY1305_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#define CHACHA20_POLY1305_AEAD_KEYSIZE      32
+#define CHACHA20_POLY1305_AEAD_IV_SIZE      12
+#define CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE 16
+
+enum {
+    CHACHA20_POLY_1305_ENC_TYPE = 8    /* cipher unique type */
+};
+
+    /*
+     * The IV for this implementation is 96 bits to give the most flexibility.
+     *
+     * Some protocols may have unique per-invocation inputs that are not
+     * 96-bit in length. For example, IPsec may specify a 64-bit nonce. In
+     * such a case, it is up to the protocol document to define how to
+     * transform the protocol nonce into a 96-bit nonce, for example by
+     * concatenating a constant value.
+     */
+
+WOLFSSL_API
+int wc_ChaCha20Poly1305_Encrypt(
+                const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
+                const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE],
+                const byte* inAAD, const word32 inAADLen,
+                const byte* inPlaintext, const word32 inPlaintextLen,
+                byte* outCiphertext,
+                byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]);
+
+WOLFSSL_API
+int wc_ChaCha20Poly1305_Decrypt(
+                const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
+                const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE],
+                const byte* inAAD, const word32 inAADLen,
+                const byte* inCiphertext, const word32 inCiphertextLen,
+                const byte inAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE],
+                byte* outPlaintext);
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* HAVE_CHACHA && HAVE_POLY1305 */
+#endif /* WOLF_CRYPT_CHACHA20_POLY1305_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/coding.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,65 @@
+/* coding.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef WOLF_CRYPT_CODING_H
+#define WOLF_CRYPT_CODING_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+WOLFSSL_API int Base64_Decode(const byte* in, word32 inLen, byte* out,
+                               word32* outLen);
+
+#if defined(OPENSSL_EXTRA) || defined(SESSION_CERTS) || defined(WOLFSSL_KEY_GEN)                         || defined(WOLFSSL_CERT_GEN) || defined(HAVE_WEBSERVER)
+    #ifndef WOLFSSL_BASE64_ENCODE
+        #define WOLFSSL_BASE64_ENCODE
+    #endif
+#endif
+
+
+#ifdef WOLFSSL_BASE64_ENCODE
+    /* encode isn't */
+    WOLFSSL_API
+    int Base64_Encode(const byte* in, word32 inLen, byte* out,
+                                  word32* outLen);
+    WOLFSSL_API
+    int Base64_EncodeEsc(const byte* in, word32 inLen, byte* out,
+                                  word32* outLen);
+#endif
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || defined(HAVE_FIPS)
+    WOLFSSL_API
+    int Base16_Decode(const byte* in, word32 inLen, byte* out, word32* outLen);
+#endif
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* WOLF_CRYPT_CODING_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/compress.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,49 @@
+/* compress.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_COMPRESS_H
+#define WOLF_CRYPT_COMPRESS_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef HAVE_LIBZ
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#define COMPRESS_FIXED 1
+
+
+WOLFSSL_API int wc_Compress(byte*, word32, const byte*, word32, word32);
+WOLFSSL_API int wc_DeCompress(byte*, word32, const byte*, word32);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* HAVE_LIBZ */
+#endif /* WOLF_CRYPT_COMPRESS_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/curve25519.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,103 @@
+/* curve25519.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_CURVE25519_H
+#define WOLF_CRYPT_CURVE25519_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef HAVE_CURVE25519
+
+#include <wolfssl/wolfcrypt/fe_operations.h>
+#include <wolfssl/wolfcrypt/random.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#define CURVE25519_KEYSIZE 32
+
+/* curve25519 set type */
+typedef struct {
+    int size;       /* The size of the curve in octets */
+    const char* name;     /* name of this curve */
+} curve25519_set_type;
+
+
+/* ECC point */
+typedef struct {
+    byte point[CURVE25519_KEYSIZE];
+}ECPoint;
+
+/* A CURVE25519 Key */
+typedef struct {
+    int idx;            /* Index into the ecc_sets[] for the parameters of
+                           this curve if -1, this key is using user supplied
+                           curve in dp */
+    const curve25519_set_type* dp;   /* domain parameters, either points to
+                                   curves (idx >= 0) or user supplied */
+    ECPoint   p;        /* public key  */
+    ECPoint   k;        /* private key */
+} curve25519_key;
+
+WOLFSSL_API
+int wc_curve25519_make_key(RNG* rng, int keysize, curve25519_key* key);
+
+WOLFSSL_API
+int wc_curve25519_shared_secret(curve25519_key* private_key,
+                                curve25519_key* public_key,
+                                byte* out, word32* outlen);
+
+WOLFSSL_API
+int wc_curve25519_init(curve25519_key* key);
+
+WOLFSSL_API
+void wc_curve25519_free(curve25519_key* key);
+
+
+/* raw key helpers */
+WOLFSSL_API
+int wc_curve25519_import_private_raw(const byte* priv, word32 privSz,
+                            const byte* pub, word32 pubSz, curve25519_key* key);
+WOLFSSL_API
+int wc_curve25519_export_private_raw(curve25519_key* key, byte* out,
+                                     word32* outLen);
+
+WOLFSSL_API
+int wc_curve25519_import_public(const byte* in, word32 inLen,
+                                curve25519_key* key);
+
+WOLFSSL_API
+int wc_curve25519_export_public(curve25519_key* key, byte* out, word32* outLen);
+
+
+/* size helper */
+WOLFSSL_API
+int wc_curve25519_size(curve25519_key* key);
+
+#ifdef __cplusplus
+    }    /* extern "C" */
+#endif
+
+#endif /* HAVE_CURVE25519 */
+#endif /* WOLF_CRYPT_CURVE25519_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/des3.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,114 @@
+/* des3.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_DES3_H
+#define WOLF_CRYPT_DES3_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifndef NO_DES3
+
+#ifdef HAVE_FIPS
+/* included for fips @wc_fips */
+#include <cyassl/ctaocrypt/des3.h>
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#ifndef HAVE_FIPS /* to avoid redifinition of macros */
+#define WOLFSSL_3DES_CAVIUM_MAGIC 0xBEEF0003
+
+enum {
+    DES_ENC_TYPE    = 2,     /* cipher unique type */
+    DES3_ENC_TYPE   = 3,     /* cipher unique type */
+    DES_BLOCK_SIZE  = 8,
+    DES_KS_SIZE     = 32,
+
+    DES_ENCRYPTION  = 0,
+    DES_DECRYPTION  = 1
+};
+
+#define DES_IVLEN 8
+#define DES_KEYLEN 8
+#define DES3_IVLEN 8
+#define DES3_KEYLEN 24
+
+
+#ifdef STM32F2_CRYPTO
+enum {
+    DES_CBC = 0,
+    DES_ECB = 1
+};
+#endif
+
+
+/* DES encryption and decryption */
+typedef struct Des {
+    word32 reg[DES_BLOCK_SIZE / sizeof(word32)];      /* for CBC mode */
+    word32 tmp[DES_BLOCK_SIZE / sizeof(word32)];      /* same         */
+    word32 key[DES_KS_SIZE];
+} Des;
+
+
+/* DES3 encryption and decryption */
+typedef struct Des3 {
+    word32 key[3][DES_KS_SIZE];
+    word32 reg[DES_BLOCK_SIZE / sizeof(word32)];      /* for CBC mode */
+    word32 tmp[DES_BLOCK_SIZE / sizeof(word32)];      /* same         */
+#ifdef HAVE_CAVIUM
+    int     devId;           /* nitrox device id */
+    word32  magic;           /* using cavium magic */
+    word64  contextHandle;   /* nitrox context memory handle */
+#endif
+} Des3;
+#endif /* HAVE_FIPS */
+
+WOLFSSL_API int  wc_Des_SetKey(Des* des, const byte* key, const byte* iv, int dir);
+WOLFSSL_API void wc_Des_SetIV(Des* des, const byte* iv);
+WOLFSSL_API int  wc_Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz);
+WOLFSSL_API int  wc_Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz);
+WOLFSSL_API int  wc_Des_EcbEncrypt(Des* des, byte* out, const byte* in, word32 sz);
+WOLFSSL_API int  wc_Des_CbcDecryptWithKey(byte* out, const byte* in, word32 sz,
+                                               const byte* key, const byte* iv);
+
+WOLFSSL_API int  wc_Des3_SetKey(Des3* des, const byte* key, const byte* iv,int dir);
+WOLFSSL_API int  wc_Des3_SetIV(Des3* des, const byte* iv);
+WOLFSSL_API int  wc_Des3_CbcEncrypt(Des3* des, byte* out, const byte* in,word32 sz);
+WOLFSSL_API int  wc_Des3_CbcDecrypt(Des3* des, byte* out, const byte* in,word32 sz);
+WOLFSSL_API int  wc_Des3_CbcDecryptWithKey(byte* out, const byte* in, word32 sz,
+                                               const byte* key, const byte* iv);
+
+
+#ifdef HAVE_CAVIUM
+    WOLFSSL_API int  wc_Des3_InitCavium(Des3*, int);
+    WOLFSSL_API void wc_Des3_FreeCavium(Des3*);
+#endif
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* NO_DES3 */
+#endif /* WOLF_CRYPT_DES3_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/dh.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,67 @@
+/* dh.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_DH_H
+#define WOLF_CRYPT_DH_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifndef NO_DH
+
+#include <wolfssl/wolfcrypt/integer.h>
+#include <wolfssl/wolfcrypt/random.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+/* Diffie-Hellman Key */
+typedef struct DhKey {
+    mp_int p, g;                            /* group parameters  */
+} DhKey;
+
+
+WOLFSSL_API void wc_InitDhKey(DhKey* key);
+WOLFSSL_API void wc_FreeDhKey(DhKey* key);
+
+WOLFSSL_API int wc_DhGenerateKeyPair(DhKey* key, RNG* rng, byte* priv,
+                                 word32* privSz, byte* pub, word32* pubSz);
+WOLFSSL_API int wc_DhAgree(DhKey* key, byte* agree, word32* agreeSz,
+                       const byte* priv, word32 privSz, const byte* otherPub,
+                       word32 pubSz);
+
+WOLFSSL_API int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key,
+                           word32);
+WOLFSSL_API int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
+                        word32 gSz);
+WOLFSSL_API int wc_DhParamsLoad(const byte* input, word32 inSz, byte* p,
+                            word32* pInOutSz, byte* g, word32* gInOutSz);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* NO_DH */
+#endif /* WOLF_CRYPT_DH_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/dsa.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,76 @@
+/* dsa.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_DSA_H
+#define WOLF_CRYPT_DSA_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifndef NO_DSA
+
+#include <wolfssl/wolfcrypt/integer.h>
+#include <wolfssl/wolfcrypt/random.h>
+
+/* for DSA reverse compatibility */
+#define InitDsaKey wc_InitDsaKey
+#define FreeDsaKey wc_FreeDsaKey
+#define DsaSign wc_DsaSign
+#define DsaVerify wc_DsaVerify
+#define DsaPublicKeyDecode wc_DsaPublicKeyDecode
+#define DsaPrivateKeyDecode wc_DsaPrivateKeyDecode
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+enum {
+    DSA_PUBLIC   = 0,
+    DSA_PRIVATE  = 1
+};
+
+/* DSA */
+typedef struct DsaKey {
+    mp_int p, q, g, y, x;
+    int type;                               /* public or private */
+} DsaKey;
+
+
+WOLFSSL_API void wc_InitDsaKey(DsaKey* key);
+WOLFSSL_API void wc_FreeDsaKey(DsaKey* key);
+
+WOLFSSL_API int wc_DsaSign(const byte* digest, byte* out, DsaKey* key, RNG* rng);
+WOLFSSL_API int wc_DsaVerify(const byte* digest, const byte* sig, DsaKey* key,
+                         int* answer);
+
+WOLFSSL_API int wc_DsaPublicKeyDecode(const byte* input, word32* inOutIdx, DsaKey*,
+                                  word32);
+WOLFSSL_API int wc_DsaPrivateKeyDecode(const byte* input, word32* inOutIdx, DsaKey*,
+                                   word32);
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* NO_DSA */
+#endif /* WOLF_CRYPT_DSA_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/ecc.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,246 @@
+/* ecc.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_ECC_H
+#define WOLF_CRYPT_ECC_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef HAVE_ECC
+
+#include <wolfssl/wolfcrypt/integer.h>
+#include <wolfssl/wolfcrypt/random.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+enum {
+    ECC_PUBLICKEY  = 1,
+    ECC_PRIVATEKEY = 2,
+    ECC_MAXNAME    = 16,     /* MAX CURVE NAME LENGTH */
+    SIG_HEADER_SZ  =  6,     /* ECC signature header size */
+    ECC_BUFSIZE    = 256,    /* for exported keys temp buffer */
+    ECC_MINSIZE    = 20,     /* MIN Private Key size */
+    ECC_MAXSIZE    = 66      /* MAX Private Key size */
+};
+
+
+/* ECC set type defined a NIST GF(p) curve */
+typedef struct {
+    int size;       /* The size of the curve in octets */
+    const char* name;     /* name of this curve */
+    const char* prime;    /* prime that defines the field, curve is in (hex) */
+    const char* Af;       /* fields A param (hex) */
+    const char* Bf;       /* fields B param (hex) */
+    const char* order;    /* order of the curve (hex) */
+    const char* Gx;       /* x coordinate of the base point on curve (hex) */
+    const char* Gy;       /* y coordinate of the base point on curve (hex) */
+} ecc_set_type;
+
+
+#ifdef ALT_ECC_SIZE
+
+/* Note on ALT_ECC_SIZE:
+ * The fast math code uses an array of a fixed size to store the big integers.
+ * By default, the array is big enough for RSA keys. There is a size,
+ * FP_MAX_BITS which can be used to make the array smaller when one wants ECC
+ * but not RSA. Some people want fast math sized for both RSA and ECC, where
+ * ECC won't use as much as RSA. The flag ALT_ECC_SIZE switches in an alternate
+ * ecc_point structure that uses an alternate fp_int that has a shorter array
+ * of fp_digits.
+ *
+ * Now, without ALT_ECC_SIZE, the ecc_point has three single item arrays of
+ * mp_ints for the components of the point. With ALT_ECC_SIZE, the components
+ * of the point are pointers that are set to each of a three item array of
+ * alt_fp_ints. While an mp_int will have 4096 bits of digit inside the
+ * structure, the alt_fp_int will only have 512 bits. A size value was added
+ * in the ALT case, as well, and is set by mp_init() and alt_fp_init(). The
+ * functions fp_zero() and fp_copy() use the size parameter. An int needs to
+ * be initialized before using it instead of just fp_zeroing it, the init will
+ * call zero. FP_MAX_BITS_ECC defaults to 512, but can be set to change the
+ * number of bits used in the alternate FP_INT.
+ *
+ * Do not enable ALT_ECC_SIZE and disable fast math in the configuration.
+ */
+
+#ifndef FP_MAX_BITS_ECC
+    #define FP_MAX_BITS_ECC           512
+#endif
+#define FP_MAX_SIZE_ECC           (FP_MAX_BITS_ECC+(8*DIGIT_BIT))
+#if FP_MAX_BITS_ECC % CHAR_BIT
+   #error FP_MAX_BITS_ECC must be a multiple of CHAR_BIT
+#endif
+#define FP_SIZE_ECC    (FP_MAX_SIZE_ECC/DIGIT_BIT)
+
+/* This needs to match the size of the fp_int struct, except the
+ * fp_digit array will be shorter. */
+typedef struct alt_fp_int {
+    int used, sign, size;
+    fp_digit dp[FP_SIZE_ECC];
+} alt_fp_int;
+#endif
+
+/* A point on an ECC curve, stored in Jacbobian format such that (x,y,z) =>
+   (x/z^2, y/z^3, 1) when interpreted as affine */
+typedef struct {
+#ifndef ALT_ECC_SIZE
+    mp_int x[1];        /* The x coordinate */
+    mp_int y[1];        /* The y coordinate */
+    mp_int z[1];        /* The z coordinate */
+#else
+    mp_int* x;        /* The x coordinate */
+    mp_int* y;        /* The y coordinate */
+    mp_int* z;        /* The z coordinate */
+    alt_fp_int xyz[3];
+#endif
+} ecc_point;
+
+
+/* An ECC Key */
+typedef struct {
+    int type;           /* Public or Private */
+    int idx;            /* Index into the ecc_sets[] for the parameters of
+                           this curve if -1, this key is using user supplied
+                           curve in dp */
+    const ecc_set_type* dp;     /* domain parameters, either points to NIST
+                                   curves (idx >= 0) or user supplied */
+    ecc_point pubkey;   /* public key */
+    mp_int    k;        /* private key */
+} ecc_key;
+
+
+/* ECC predefined curve sets  */
+extern const ecc_set_type ecc_sets[];
+
+
+WOLFSSL_API
+int wc_ecc_make_key(RNG* rng, int keysize, ecc_key* key);
+WOLFSSL_API
+int wc_ecc_check_key(ecc_key* key);
+WOLFSSL_API
+int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out,
+                      word32* outlen);
+WOLFSSL_API
+int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, 
+                  RNG* rng, ecc_key* key);
+WOLFSSL_API
+int wc_ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash,
+                    word32 hashlen, int* stat, ecc_key* key);
+WOLFSSL_API
+int wc_ecc_init(ecc_key* key);
+WOLFSSL_API
+void wc_ecc_free(ecc_key* key);
+WOLFSSL_API
+void wc_ecc_fp_free(void);
+
+
+/* ASN key helpers */
+WOLFSSL_API
+int wc_ecc_export_x963(ecc_key*, byte* out, word32* outLen);
+WOLFSSL_API
+int wc_ecc_export_x963_ex(ecc_key*, byte* out, word32* outLen, int compressed);
+    /* extended functionality with compressed option */
+WOLFSSL_API
+int wc_ecc_import_x963(const byte* in, word32 inLen, ecc_key* key);
+WOLFSSL_API
+int wc_ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub,
+                           word32 pubSz, ecc_key* key);
+WOLFSSL_API
+int wc_ecc_rs_to_sig(const char* r, const char* s, byte* out, word32* outlen);
+WOLFSSL_API
+int wc_ecc_import_raw(ecc_key* key, const char* qx, const char* qy,
+                   const char* d, const char* curveName);
+
+WOLFSSL_API
+int wc_ecc_export_private_only(ecc_key* key, byte* out, word32* outLen);
+
+/* size helper */
+WOLFSSL_API
+int wc_ecc_size(ecc_key* key);
+WOLFSSL_API
+int wc_ecc_sig_size(ecc_key* key);
+
+
+#ifdef HAVE_ECC_ENCRYPT
+/* ecc encrypt */
+
+enum ecEncAlgo {
+    ecAES_128_CBC = 1,  /* default */
+    ecAES_256_CBC = 2
+};
+
+enum ecKdfAlgo {
+    ecHKDF_SHA256 = 1,  /* default */
+    ecHKDF_SHA1   = 2
+};
+
+enum ecMacAlgo {
+    ecHMAC_SHA256 = 1,  /* default */
+    ecHMAC_SHA1   = 2
+};
+
+enum {
+    KEY_SIZE_128     = 16,
+    KEY_SIZE_256     = 32,
+    IV_SIZE_64       =  8,
+    EXCHANGE_SALT_SZ = 16,
+    EXCHANGE_INFO_SZ = 23
+};
+
+enum ecFlags {
+    REQ_RESP_CLIENT = 1,
+    REQ_RESP_SERVER = 2
+};
+
+
+typedef struct ecEncCtx ecEncCtx;
+
+WOLFSSL_API
+ecEncCtx* wc_ecc_ctx_new(int flags, RNG* rng);
+WOLFSSL_API
+void wc_ecc_ctx_free(ecEncCtx*);
+WOLFSSL_API
+int wc_ecc_ctx_reset(ecEncCtx*, RNG*);   /* reset for use again w/o alloc/free */
+
+WOLFSSL_API
+const byte* wc_ecc_ctx_get_own_salt(ecEncCtx*);
+WOLFSSL_API
+int wc_ecc_ctx_set_peer_salt(ecEncCtx*, const byte* salt);
+WOLFSSL_API
+int wc_ecc_ctx_set_info(ecEncCtx*, const byte* info, int sz);
+
+WOLFSSL_API
+int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
+                word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx);
+WOLFSSL_API
+int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
+                word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx);
+
+#endif /* HAVE_ECC_ENCRYPT */
+
+#ifdef __cplusplus
+    }    /* extern "C" */
+#endif
+
+#endif /* HAVE_ECC */
+#endif /* WOLF_CRYPT_ECC_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/ed25519.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,95 @@
+/* ed25519.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_ED25519_H
+#define WOLF_CRYPT_ED25519_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef HAVE_ED25519
+
+#include <wolfssl/wolfcrypt/fe_operations.h>
+#include <wolfssl/wolfcrypt/ge_operations.h>
+#include <wolfssl/wolfcrypt/random.h>
+#include <wolfssl/wolfcrypt/sha512.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+/* info about EdDSA curve specifically ed25519, defined as an elliptic curve
+   over GF(p) */
+/*
+    32,                key size
+    "ED25519",         curve name
+    "2^255-19",        prime number
+    "SHA512",          hash function
+    "-121665/121666",  value of d
+*/
+
+#define ED25519_KEY_SIZE 32
+#define ED25519_SIG_SIZE 64
+
+
+/* An ED25519 Key */
+typedef struct {
+    byte    p[32];        /* compressed public key */
+    byte    k[64];        /* private key : 32 secret -- 32 public */
+} ed25519_key;
+
+
+WOLFSSL_API
+int wc_ed25519_make_key(RNG* rng, int keysize, ed25519_key* key);
+WOLFSSL_API
+int wc_ed25519_sign_msg(const byte* in, word32 inlen, byte* out,
+                        word32 *outlen, ed25519_key* key);
+WOLFSSL_API
+int wc_ed25519_verify_msg(byte* sig, word32 siglen, const byte* msg,
+                          word32 msglen, int* stat, ed25519_key* key);
+WOLFSSL_API
+int wc_ed25519_init(ed25519_key* key);
+WOLFSSL_API
+void wc_ed25519_free(ed25519_key* key);
+WOLFSSL_API
+int wc_ed25519_import_public(const byte* in, word32 inLen, ed25519_key* key);
+WOLFSSL_API
+int wc_ed25519_import_private_key(const byte* priv, word32 privSz,
+                               const byte* pub, word32 pubSz, ed25519_key* key);
+WOLFSSL_API
+int wc_ed25519_export_public(ed25519_key*, byte* out, word32* outLen);
+WOLFSSL_API
+int wc_ed25519_export_private_only(ed25519_key* key, byte* out, word32* outLen);
+
+/* size helper */
+WOLFSSL_API
+int wc_ed25519_size(ed25519_key* key);
+WOLFSSL_API
+int wc_ed25519_sig_size(ed25519_key* key);
+
+#ifdef __cplusplus
+    }    /* extern "C" */
+#endif
+
+#endif /* HAVE_ED25519 */
+#endif /* WOLF_CRYPT_ED25519_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/error-crypt.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,168 @@
+/* error-crypt.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef WOLF_CRYPT_ERROR_H
+#define WOLF_CRYPT_ERROR_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef HAVE_FIPS
+	#include <cyassl/ctaocrypt/error-crypt.h>
+	#define wc_ErrorString    CTaoCryptErrorString
+	#define wc_GetErrorString CTaoCryptGetErrorString
+#endif /* HAVE_FIPS */
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+/* error codes */
+enum {
+    MAX_CODE_E         = -100,  /* errors -101 - -299 */
+    OPEN_RAN_E         = -101,  /* opening random device error */
+    READ_RAN_E         = -102,  /* reading random device error */
+    WINCRYPT_E         = -103,  /* windows crypt init error */
+    CRYPTGEN_E         = -104,  /* windows crypt generation error */
+    RAN_BLOCK_E        = -105,  /* reading random device would block */
+    BAD_MUTEX_E        = -106,  /* Bad mutex operation */
+
+    MP_INIT_E          = -110,  /* mp_init error state */
+    MP_READ_E          = -111,  /* mp_read error state */
+    MP_EXPTMOD_E       = -112,  /* mp_exptmod error state */
+    MP_TO_E            = -113,  /* mp_to_xxx error state, can't convert */
+    MP_SUB_E           = -114,  /* mp_sub error state, can't subtract */
+    MP_ADD_E           = -115,  /* mp_add error state, can't add */
+    MP_MUL_E           = -116,  /* mp_mul error state, can't multiply */
+    MP_MULMOD_E        = -117,  /* mp_mulmod error state, can't multiply mod */
+    MP_MOD_E           = -118,  /* mp_mod error state, can't mod */
+    MP_INVMOD_E        = -119,  /* mp_invmod error state, can't inv mod */
+    MP_CMP_E           = -120,  /* mp_cmp error state */
+    MP_ZERO_E          = -121,  /* got a mp zero result, not expected */
+
+    MEMORY_E           = -125,  /* out of memory error */
+
+    RSA_WRONG_TYPE_E   = -130,  /* RSA wrong block type for RSA function */
+    RSA_BUFFER_E       = -131,  /* RSA buffer error, output too small or
+                                   input too large */
+    BUFFER_E           = -132,  /* output buffer too small or input too large */
+    ALGO_ID_E          = -133,  /* setting algo id error */
+    PUBLIC_KEY_E       = -134,  /* setting public key error */
+    DATE_E             = -135,  /* setting date validity error */
+    SUBJECT_E          = -136,  /* setting subject name error */
+    ISSUER_E           = -137,  /* setting issuer  name error */
+    CA_TRUE_E          = -138,  /* setting CA basic constraint true error */
+    EXTENSIONS_E       = -139,  /* setting extensions error */
+
+    ASN_PARSE_E        = -140,  /* ASN parsing error, invalid input */
+    ASN_VERSION_E      = -141,  /* ASN version error, invalid number */
+    ASN_GETINT_E       = -142,  /* ASN get big int error, invalid data */
+    ASN_RSA_KEY_E      = -143,  /* ASN key init error, invalid input */
+    ASN_OBJECT_ID_E    = -144,  /* ASN object id error, invalid id */
+    ASN_TAG_NULL_E     = -145,  /* ASN tag error, not null */
+    ASN_EXPECT_0_E     = -146,  /* ASN expect error, not zero */
+    ASN_BITSTR_E       = -147,  /* ASN bit string error, wrong id */
+    ASN_UNKNOWN_OID_E  = -148,  /* ASN oid error, unknown sum id */
+    ASN_DATE_SZ_E      = -149,  /* ASN date error, bad size */
+    ASN_BEFORE_DATE_E  = -150,  /* ASN date error, current date before */
+    ASN_AFTER_DATE_E   = -151,  /* ASN date error, current date after */
+    ASN_SIG_OID_E      = -152,  /* ASN signature error, mismatched oid */
+    ASN_TIME_E         = -153,  /* ASN time error, unknown time type */
+    ASN_INPUT_E        = -154,  /* ASN input error, not enough data */
+    ASN_SIG_CONFIRM_E  = -155,  /* ASN sig error, confirm failure */
+    ASN_SIG_HASH_E     = -156,  /* ASN sig error, unsupported hash type */
+    ASN_SIG_KEY_E      = -157,  /* ASN sig error, unsupported key type */
+    ASN_DH_KEY_E       = -158,  /* ASN key init error, invalid input */
+    ASN_NTRU_KEY_E     = -159,  /* ASN ntru key decode error, invalid input */
+    ASN_CRIT_EXT_E     = -160,  /* ASN unsupported critical extension */
+
+    ECC_BAD_ARG_E      = -170,  /* ECC input argument of wrong type */
+    ASN_ECC_KEY_E      = -171,  /* ASN ECC bad input */
+    ECC_CURVE_OID_E    = -172,  /* Unsupported ECC OID curve type */
+    BAD_FUNC_ARG       = -173,  /* Bad function argument provided */
+    NOT_COMPILED_IN    = -174,  /* Feature not compiled in */
+    UNICODE_SIZE_E     = -175,  /* Unicode password too big */
+    NO_PASSWORD        = -176,  /* no password provided by user */
+    ALT_NAME_E         = -177,  /* alt name size problem, too big */
+
+    AES_GCM_AUTH_E     = -180,  /* AES-GCM Authentication check failure */
+    AES_CCM_AUTH_E     = -181,  /* AES-CCM Authentication check failure */
+
+    CAVIUM_INIT_E      = -182,  /* Cavium Init type error */
+
+    COMPRESS_INIT_E    = -183,  /* Compress init error */
+    COMPRESS_E         = -184,  /* Compress error */
+    DECOMPRESS_INIT_E  = -185,  /* DeCompress init error */
+    DECOMPRESS_E       = -186,  /* DeCompress error */
+
+    BAD_ALIGN_E         = -187,  /* Bad alignment for operation, no alloc */
+    ASN_NO_SIGNER_E     = -188,  /* ASN no signer to confirm failure */
+    ASN_CRL_CONFIRM_E   = -189,  /* ASN CRL signature confirm failure */
+    ASN_CRL_NO_SIGNER_E = -190,  /* ASN CRL no signer to confirm failure */
+    ASN_OCSP_CONFIRM_E  = -191,  /* ASN OCSP signature confirm failure */
+
+    BAD_ENC_STATE_E     = -192,  /* Bad ecc enc state operation */
+    BAD_PADDING_E       = -193,  /* Bad padding, msg not correct length  */
+
+    REQ_ATTRIBUTE_E     = -194,  /* setting cert request attributes error */
+
+    PKCS7_OID_E         = -195,  /* PKCS#7, mismatched OID error */
+    PKCS7_RECIP_E       = -196,  /* PKCS#7, recipient error */
+    FIPS_NOT_ALLOWED_E  = -197,  /* FIPS not allowed error */
+    ASN_NAME_INVALID_E  = -198,  /* ASN name constraint error */
+
+    RNG_FAILURE_E       = -199,  /* RNG Failed, Reinitialize */
+    HMAC_MIN_KEYLEN_E   = -200,  /* FIPS Mode HMAC Minimum Key Length error */
+    RSA_PAD_E           = -201,  /* RSA Padding Error */
+    LENGTH_ONLY_E       = -202,  /* Returning output length only */
+
+    IN_CORE_FIPS_E      = -203,  /* In Core Integrity check failure */
+    AES_KAT_FIPS_E      = -204,  /* AES KAT failure */
+    DES3_KAT_FIPS_E     = -205,  /* DES3 KAT failure */
+    HMAC_KAT_FIPS_E     = -206,  /* HMAC KAT failure */
+    RSA_KAT_FIPS_E      = -207,  /* RSA KAT failure */
+    DRBG_KAT_FIPS_E     = -208,  /* HASH DRBG KAT failure */
+    DRBG_CONT_FIPS_E    = -209,  /* HASH DRBG Continious test failure */
+    AESGCM_KAT_FIPS_E   = -210,  /* AESGCM KAT failure */
+    THREAD_STORE_KEY_E  = -211,  /* Thread local storage key create failure */
+    THREAD_STORE_SET_E  = -212,  /* Thread local storage key set failure */
+
+    MAC_CMP_FAILED_E    = -213,  /* MAC comparison failed */
+    IS_POINT_E          = -214,  /* ECC is point on curve failed */
+    ECC_INF_E           = -215,  /* ECC point infinity error */
+    ECC_PRIV_KEY_E      = -216,  /* ECC private key not valid error */
+
+    MIN_CODE_E          = -300   /* errors -101 - -299 */
+};
+
+
+WOLFSSL_API void wc_ErrorString(int err, char* buff);
+WOLFSSL_API const char* wc_GetErrorString(int error);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+#endif /* WOLF_CRYPT_ERROR_H */
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/fe_operations.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,133 @@
+/* fe_operations.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_FE_OPERATIONS_H
+#define WOLF_CRYPT_FE_OPERATIONS_H
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#if defined(HAVE_CURVE25519) || defined(HAVE_ED25519)
+
+#ifndef CURVED25519_SMALL
+    #include <stdint.h>
+#endif
+#include <wolfssl/wolfcrypt/types.h>
+
+/*
+fe means field element.
+Here the field is \Z/(2^255-19).
+An element t, entries t[0]...t[9], represents the integer
+t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
+Bounds on each t[i] vary depending on context.
+*/
+
+#ifdef CURVED25519_SMALL
+    #define F25519_SIZE	32
+    typedef byte     fe[32];
+#else
+    typedef int32_t  fe[10];
+#endif
+
+WOLFSSL_LOCAL int  curve25519(byte * q, byte * n, byte * p);
+WOLFSSL_LOCAL void fe_copy(fe, const fe);
+WOLFSSL_LOCAL void fe_add(fe, const fe, const fe);
+WOLFSSL_LOCAL void fe_neg(fe,const fe);
+WOLFSSL_LOCAL void fe_sub(fe, const fe, const fe);
+WOLFSSL_LOCAL void fe_invert(fe, const fe);
+WOLFSSL_LOCAL void fe_mul(fe,const fe,const fe);
+
+/* default to be faster but take more memory */
+#ifndef CURVED25519_SMALL
+
+/* Based On Daniel J Bernstein's curve25519 and ed25519 Public Domain ref10
+   work. */
+
+WOLFSSL_LOCAL void fe_0(fe);
+WOLFSSL_LOCAL void fe_1(fe);
+WOLFSSL_LOCAL int  fe_isnonzero(const fe);
+WOLFSSL_LOCAL int  fe_isnegative(const fe);
+WOLFSSL_LOCAL void fe_tobytes(unsigned char *, const fe);
+WOLFSSL_LOCAL void fe_sq(fe, const fe);
+WOLFSSL_LOCAL void fe_sq2(fe,const fe);
+WOLFSSL_LOCAL void fe_frombytes(fe,const unsigned char *);
+WOLFSSL_LOCAL void fe_cswap(fe,fe,unsigned int);
+WOLFSSL_LOCAL void fe_mul121666(fe,fe);
+WOLFSSL_LOCAL void fe_cmov(fe,const fe,unsigned int);
+WOLFSSL_LOCAL void fe_pow22523(fe,const fe);
+
+/* 64 type needed for SHA512 */
+WOLFSSL_LOCAL uint64_t load_3(const unsigned char *in);
+WOLFSSL_LOCAL uint64_t load_4(const unsigned char *in);
+#endif /* not defined CURVED25519_SMALL */
+
+/* Use less memory and only 32bit types or less, but is slower
+   Based on Daniel Beer's public domain work. */
+#ifdef CURVED25519_SMALL
+static const byte c25519_base_x[F25519_SIZE] = {9};
+static const byte f25519_zero[F25519_SIZE]   = {0};
+static const byte f25519_one[F25519_SIZE]    = {1};
+static const byte fprime_zero[F25519_SIZE]   = {0};
+static const byte fprime_one[F25519_SIZE]    = {1};
+
+WOLFSSL_LOCAL void fe_load(byte *x, word32 c);
+WOLFSSL_LOCAL void fe_normalize(byte *x);
+WOLFSSL_LOCAL void fe_inv__distinct(byte *r, const byte *x);
+
+/* Conditional copy. If condition == 0, then zero is copied to dst. If
+ * condition == 1, then one is copied to dst. Any other value results in
+ * undefined behaviour.
+ */
+WOLFSSL_LOCAL void fe_select(byte *dst, const byte *zero, const byte *one,
+		   byte condition);
+
+/* Multiply a point by a small constant. The two pointers are not
+ * required to be distinct.
+ *
+ * The constant must be less than 2^24.
+ */
+WOLFSSL_LOCAL void fe_mul_c(byte *r, const byte *a, word32 b);
+WOLFSSL_LOCAL void fe_mul__distinct(byte *r, const byte *a, const byte *b);
+
+/* Compute one of the square roots of the field element, if the element
+ * is square. The other square is -r.
+ *
+ * If the input is not square, the returned value is a valid field
+ * element, but not the correct answer. If you don't already know that
+ * your element is square, you should square the return value and test.
+ */
+WOLFSSL_LOCAL void fe_sqrt(byte *r, const byte *x);
+
+/* Conditional copy. If condition == 0, then zero is copied to dst. If
+ * condition == 1, then one is copied to dst. Any other value results in
+ * undefined behaviour.
+ */
+WOLFSSL_LOCAL void fprime_select(byte *dst, const byte *zero, const byte *one,
+		                         byte condition);
+WOLFSSL_LOCAL void fprime_add(byte *r, const byte *a, const byte *modulus);
+WOLFSSL_LOCAL void fprime_sub(byte *r, const byte *a, const byte *modulus);
+WOLFSSL_LOCAL void fprime_mul(byte *r, const byte *a, const byte *b,
+		                      const byte *modulus);
+WOLFSSL_LOCAL void fprime_copy(byte *x, const byte *a);
+#endif /* CURVED25519_SMALL */
+#endif /* HAVE_CURVE25519 or HAVE_ED25519 */
+#endif /* WOLF_CRYPT_FE_OPERATIONS_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/fips_test.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,59 @@
+/* fips_test.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef WOLF_CRYPT_FIPS_TEST_H
+#define WOLF_CRYPT_FIPS_TEST_H
+
+#include <cyassl/ctaocrypt/types.h>
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* Known Answer Test string inputs are hex, internal */
+CYASSL_LOCAL int DoKnownAnswerTests(char*, int);
+
+
+/* FIPS failure callback */
+typedef void(*wolfCrypt_fips_cb)(int ok, int err, const char* hash);
+
+/* Public set function */
+CYASSL_API int wolfCrypt_SetCb_fips(wolfCrypt_fips_cb cbf);
+
+/* Public get status functions */
+CYASSL_API int wolfCrypt_GetStatus_fips(void);
+CYASSL_API const char* wolfCrypt_GetCoreHash_fips(void);
+
+#ifdef HAVE_FORCE_FIPS_FAILURE
+    /* Public function to force failure mode for operational testing */
+    CYASSL_API int wolfCrypt_SetStatus_fips(int);
+#endif
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* WOLF_CRYPT_FIPS_TEST_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/ge_operations.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,116 @@
+/* ge_operations.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+ /* Based On Daniel J Bernstein's ed25519 Public Domain ref10 work. */
+
+#ifndef WOLF_CRYPT_GE_OPERATIONS_H
+#define WOLF_CRYPT_GE_OPERATIONS_H
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_ED25519
+
+#ifndef CURVED25519_SMALL
+    #include <stdint.h>
+#endif
+#include <wolfssl/wolfcrypt/fe_operations.h>
+
+/*
+ge means group element.
+
+Here the group is the set of pairs (x,y) of field elements (see fe.h)
+satisfying -x^2 + y^2 = 1 + d x^2y^2
+where d = -121665/121666.
+
+Representations:
+  ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
+  ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
+  ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
+  ge_precomp (Duif): (y+x,y-x,2dxy)
+*/
+
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+} ge_p2;
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+  fe T;
+} ge_p3;
+
+WOLFSSL_LOCAL int  ge_compress_key(byte* out, const byte* xIn, const byte* yIn,
+                                                                word32 keySz);
+WOLFSSL_LOCAL int  ge_frombytes_negate_vartime(ge_p3 *,const unsigned char *);
+
+WOLFSSL_LOCAL int  ge_double_scalarmult_vartime(ge_p2 *,const unsigned char *,
+                                         const ge_p3 *,const unsigned char *);
+WOLFSSL_LOCAL void ge_scalarmult_base(ge_p3 *,const unsigned char *);
+WOLFSSL_LOCAL void sc_reduce(byte* s);
+WOLFSSL_LOCAL void sc_muladd(byte* s, const byte* a, const byte* b,
+                             const byte* c);
+WOLFSSL_LOCAL void ge_tobytes(unsigned char *,const ge_p2 *);
+WOLFSSL_LOCAL void ge_p3_tobytes(unsigned char *,const ge_p3 *);
+
+#ifndef CURVED25519_SMALL
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+  fe T;
+} ge_p1p1;
+
+typedef struct {
+  fe yplusx;
+  fe yminusx;
+  fe xy2d;
+} ge_precomp;
+
+typedef struct {
+  fe YplusX;
+  fe YminusX;
+  fe Z;
+  fe T2d;
+} ge_cached;
+
+WOLFSSL_LOCAL void ge_p2_0(ge_p2 *);
+WOLFSSL_LOCAL void ge_p3_0(ge_p3 *);
+WOLFSSL_LOCAL void ge_precomp_0(ge_precomp *);
+WOLFSSL_LOCAL void ge_p3_to_p2(ge_p2 *,const ge_p3 *);
+WOLFSSL_LOCAL void ge_p3_to_cached(ge_cached *,const ge_p3 *);
+WOLFSSL_LOCAL void ge_p1p1_to_p2(ge_p2 *,const ge_p1p1 *);
+WOLFSSL_LOCAL void ge_p1p1_to_p3(ge_p3 *,const ge_p1p1 *);
+WOLFSSL_LOCAL void ge_p2_dbl(ge_p1p1 *,const ge_p2 *);
+WOLFSSL_LOCAL void ge_p3_dbl(ge_p1p1 *,const ge_p3 *);
+
+WOLFSSL_LOCAL void ge_madd(ge_p1p1 *,const ge_p3 *,const ge_precomp *);
+WOLFSSL_LOCAL void ge_msub(ge_p1p1 *,const ge_p3 *,const ge_precomp *);
+WOLFSSL_LOCAL void ge_add(ge_p1p1 *,const ge_p3 *,const ge_cached *);
+WOLFSSL_LOCAL void ge_sub(ge_p1p1 *,const ge_p3 *,const ge_cached *);
+#endif /* no CURVED25519_SMALL */
+#endif /* HAVE_ED25519 */
+#endif /* WOLF_CRYPT_GE_OPERATIONS_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/hash.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,42 @@
+/* hash.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_HASH_H
+#define WOLF_CRYPT_HASH_H
+
+#ifndef NO_MD5
+#include <wolfssl/wolfcrypt/md5.h>
+WOLFSSL_API void wc_Md5GetHash(Md5*, byte*);
+WOLFSSL_API void wc_Md5RestorePos(Md5*, Md5*) ;
+#endif
+#ifndef NO_SHA
+#include <wolfssl/wolfcrypt/sha.h>
+WOLFSSL_API int wc_ShaGetHash(Sha*, byte*);
+WOLFSSL_API void wc_ShaRestorePos(Sha*, Sha*) ;
+#endif
+#ifndef NO_SHA256
+#include <wolfssl/wolfcrypt/sha256.h>
+WOLFSSL_API int wc_Sha256GetHash(Sha256*, byte*);
+WOLFSSL_API void wc_Sha256RestorePos(Sha256*, Sha256*) ;
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/hc128.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,59 @@
+/* hc128.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_HC128_H
+#define WOLF_CRYPT_HC128_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifndef NO_HC128
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+enum {
+	HC128_ENC_TYPE    =  6    /* cipher unique type */
+};
+
+/* HC-128 stream cipher */
+typedef struct HC128 {
+    word32 T[1024];             /* P[i] = T[i];  Q[i] = T[1024 + i ]; */
+    word32 X[16];
+    word32 Y[16];
+    word32 counter1024;         /* counter1024 = i mod 1024 at the ith step */
+    word32 key[8];
+    word32 iv[8];
+} HC128;
+
+
+WOLFSSL_API int wc_Hc128_Process(HC128*, byte*, const byte*, word32);
+WOLFSSL_API int wc_Hc128_SetKey(HC128*, const byte* key, const byte* iv);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* HAVE_HC128 */
+#endif /* WOLF_CRYPT_HC128_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/hmac.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,191 @@
+/* hmac.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef NO_HMAC
+
+#ifndef WOLF_CRYPT_HMAC_H
+#define WOLF_CRYPT_HMAC_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifndef NO_MD5
+    #include <wolfssl/wolfcrypt/md5.h>
+#endif
+
+#ifndef NO_SHA
+    #include <wolfssl/wolfcrypt/sha.h>
+#endif
+
+#ifndef NO_SHA256
+    #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 HAVE_CAVIUM
+    #include <wolfssl/wolfcrypt/logging.h>
+    #include "cavium_common.h"
+#endif
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+#ifndef HAVE_FIPS
+#define WOLFSSL_HMAC_CAVIUM_MAGIC 0xBEEF0005
+
+enum {
+    HMAC_FIPS_MIN_KEY = 14,   /* 112 bit key length minimum */
+
+    IPAD    = 0x36,
+    OPAD    = 0x5C,
+
+/* If any hash is not enabled, add the ID here. */
+#ifdef NO_MD5
+    MD5     = 0,
+#endif
+#ifdef NO_SHA
+    SHA     = 1,
+#endif
+#ifdef NO_SHA256
+    SHA256  = 2,
+#endif
+#ifndef WOLFSSL_SHA512
+    SHA512  = 4,
+#endif
+#ifndef WOLFSSL_SHA384
+    SHA384  = 5,
+#endif
+#ifndef HAVE_BLAKE2
+    BLAKE2B_ID = 7,
+#endif
+
+/* Select the largest available hash for the buffer size. */
+#if defined(WOLFSSL_SHA512)
+    MAX_DIGEST_SIZE = SHA512_DIGEST_SIZE,
+    HMAC_BLOCK_SIZE = SHA512_BLOCK_SIZE
+#elif defined(HAVE_BLAKE2)
+    MAX_DIGEST_SIZE = BLAKE2B_OUTBYTES,
+    HMAC_BLOCK_SIZE = BLAKE2B_BLOCKBYTES,
+#elif defined(WOLFSSL_SHA384)
+    MAX_DIGEST_SIZE = SHA384_DIGEST_SIZE,
+    HMAC_BLOCK_SIZE = SHA384_BLOCK_SIZE
+#elif !defined(NO_SHA256)
+    MAX_DIGEST_SIZE = SHA256_DIGEST_SIZE,
+    HMAC_BLOCK_SIZE = SHA256_BLOCK_SIZE
+#elif !defined(NO_SHA)
+    MAX_DIGEST_SIZE = SHA_DIGEST_SIZE,
+    HMAC_BLOCK_SIZE = SHA_BLOCK_SIZE
+#elif !defined(NO_MD5)
+    MAX_DIGEST_SIZE = MD5_DIGEST_SIZE,
+    HMAC_BLOCK_SIZE = MD5_BLOCK_SIZE
+#else
+    #error "You have to have some kind of hash if you want to use HMAC."
+#endif
+};
+
+
+/* hash union */
+typedef union {
+    #ifndef NO_MD5
+        Md5 md5;
+    #endif
+    #ifndef NO_SHA
+        Sha sha;
+    #endif
+    #ifndef NO_SHA256
+        Sha256 sha256;
+    #endif
+    #ifdef WOLFSSL_SHA384
+        Sha384 sha384;
+    #endif
+    #ifdef WOLFSSL_SHA512
+        Sha512 sha512;
+    #endif
+    #ifdef HAVE_BLAKE2
+        Blake2b blake2b;
+    #endif
+} Hash;
+
+/* Hmac digest */
+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)];
+    byte    macType;                                     /* md5 sha or sha256 */
+    byte    innerHashKeyed;                              /* keyed flag */
+#ifdef HAVE_CAVIUM
+    word16   keyLen;          /* hmac key length */
+    word16   dataLen;
+    HashType type;            /* hmac key type */
+    int      devId;           /* nitrox device id */
+    word32   magic;           /* using cavium magic */
+    word64   contextHandle;   /* nitrox context memory handle */
+    byte*    data;            /* buffered input data for one call */
+#endif
+} Hmac;
+
+#endif /* HAVE_FIPS */
+
+/* does init */
+WOLFSSL_API int wc_HmacSetKey(Hmac*, int type, const byte* key, word32 keySz);
+WOLFSSL_API int wc_HmacUpdate(Hmac*, const byte*, word32);
+WOLFSSL_API int wc_HmacFinal(Hmac*, byte*);
+
+#ifdef HAVE_CAVIUM
+    WOLFSSL_API int  wc_HmacInitCavium(Hmac*, int);
+    WOLFSSL_API void wc_HmacFreeCavium(Hmac*);
+#endif
+
+WOLFSSL_API int wolfSSL_GetHmacMaxSize(void);
+
+
+#ifdef HAVE_HKDF
+
+WOLFSSL_API int wc_HKDF(int type, const byte* inKey, word32 inKeySz,
+                    const byte* salt, word32 saltSz,
+                    const byte* info, word32 infoSz,
+                    byte* out, word32 outSz);
+
+#endif /* HAVE_HKDF */
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* WOLF_CRYPT_HMAC_H */
+
+#endif /* NO_HMAC */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/integer.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,325 @@
+/* integer.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+/*
+ * Based on public domain LibTomMath 0.38 by Tom St Denis, tomstdenis@iahu.ca,
+ * http://math.libtomcrypt.com
+ */
+
+
+#ifndef WOLF_CRYPT_INTEGER_H
+#define WOLF_CRYPT_INTEGER_H
+
+/* may optionally use fast math instead, not yet supported on all platforms and
+   may not be faster on all
+*/
+#include <wolfssl/wolfcrypt/types.h>       /* will set MP_xxBIT if not default */
+#ifdef USE_FAST_MATH
+    #include <wolfssl/wolfcrypt/tfm.h>
+#else
+
+#ifndef CHAR_BIT
+    #include <limits.h>
+#endif
+
+#include <wolfssl/wolfcrypt/mpi_class.h>
+
+#ifndef MIN
+   #define MIN(x,y) ((x)<(y)?(x):(y))
+#endif
+
+#ifndef MAX
+   #define MAX(x,y) ((x)>(y)?(x):(y))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+
+/* C++ compilers don't like assigning void * to mp_digit * */
+#define  OPT_CAST(x)  (x *)
+
+#else
+
+/* C on the other hand doesn't care */
+#define  OPT_CAST(x)
+
+#endif
+
+
+/* detect 64-bit mode if possible */
+#if defined(__x86_64__)
+   #if !(defined(MP_64BIT) && defined(MP_16BIT) && defined(MP_8BIT))
+      #define MP_64BIT
+   #endif
+#endif
+/* if intel compiler doesn't provide 128 bit type don't turn on 64bit */
+#if defined(MP_64BIT) && defined(__INTEL_COMPILER) && !defined(HAVE___UINT128_T)
+    #undef MP_64BIT
+#endif
+
+/* some default configurations.
+ *
+ * A "mp_digit" must be able to hold DIGIT_BIT + 1 bits
+ * A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits
+ *
+ * At the very least a mp_digit must be able to hold 7 bits
+ * [any size beyond that is ok provided it doesn't overflow the data type]
+ */
+#ifdef MP_8BIT
+   typedef unsigned char      mp_digit;
+   typedef unsigned short     mp_word;
+#elif defined(MP_16BIT) || defined(NO_64BIT)
+   typedef unsigned short     mp_digit;
+   typedef unsigned int       mp_word;
+#elif defined(MP_64BIT)
+   /* for GCC only on supported platforms */
+   typedef unsigned long long mp_digit;  /* 64 bit type, 128 uses mode(TI) */
+   typedef unsigned long      mp_word __attribute__ ((mode(TI)));
+
+   #define DIGIT_BIT          60
+#else
+   /* this is the default case, 28-bit digits */
+
+   #if defined(_MSC_VER) || defined(__BORLANDC__)
+      typedef unsigned __int64   ulong64;
+   #else
+      typedef unsigned long long ulong64;
+   #endif
+
+   typedef unsigned int       mp_digit;  /* long could be 64 now, changed TAO */
+   typedef ulong64            mp_word;
+
+#ifdef MP_31BIT
+   /* this is an extension that uses 31-bit digits */
+   #define DIGIT_BIT          31
+#else
+   /* default case is 28-bit digits, defines MP_28BIT as a handy test macro */
+   #define DIGIT_BIT          28
+   #define MP_28BIT
+#endif
+#endif
+
+
+/* otherwise the bits per digit is calculated automatically from the size of
+   a mp_digit */
+#ifndef DIGIT_BIT
+   #define DIGIT_BIT ((int)((CHAR_BIT * sizeof(mp_digit) - 1)))
+      /* bits per digit */
+#endif
+
+#define MP_DIGIT_BIT     DIGIT_BIT
+#define MP_MASK          ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
+#define MP_DIGIT_MAX     MP_MASK
+
+/* equalities */
+#define MP_LT        -1   /* less than */
+#define MP_EQ         0   /* equal to */
+#define MP_GT         1   /* greater than */
+
+#define MP_ZPOS       0   /* positive integer */
+#define MP_NEG        1   /* negative */
+
+#define MP_OKAY       0   /* ok result */
+#define MP_MEM        -2  /* out of mem */
+#define MP_VAL        -3  /* invalid input */
+#define MP_RANGE      MP_VAL
+
+#define MP_YES        1   /* yes response */
+#define MP_NO         0   /* no response */
+
+/* Primality generation flags */
+#define LTM_PRIME_BBS      0x0001 /* BBS style prime */
+#define LTM_PRIME_SAFE     0x0002 /* Safe prime (p-1)/2 == prime */
+#define LTM_PRIME_2MSB_ON  0x0008 /* force 2nd MSB to 1 */
+
+typedef int           mp_err;
+
+/* define this to use lower memory usage routines (exptmods mostly) */
+#define MP_LOW_MEM
+
+/* default precision */
+#ifndef MP_PREC
+   #ifndef MP_LOW_MEM
+      #define MP_PREC                 32     /* default digits of precision */
+   #else
+      #define MP_PREC                 1      /* default digits of precision */
+   #endif
+#endif
+
+/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD -
+   BITS_PER_DIGIT*2) */
+#define MP_WARRAY  (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
+
+/* the infamous mp_int structure */
+typedef struct  {
+    int used, alloc, sign;
+    mp_digit *dp;
+} mp_int;
+
+/* callback for mp_prime_random, should fill dst with random bytes and return
+   how many read [upto len] */
+typedef int ltm_prime_callback(unsigned char *dst, int len, void *dat);
+
+
+#define USED(m)    ((m)->used)
+#define DIGIT(m,k) ((m)->dp[(k)])
+#define SIGN(m)    ((m)->sign)
+
+
+/* ---> Basic Manipulations <--- */
+#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
+#define mp_iseven(a) \
+    (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
+#define mp_isodd(a) \
+    (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
+
+
+/* number of primes */
+#ifdef MP_8BIT
+   #define PRIME_SIZE      31
+#else
+   #define PRIME_SIZE      256
+#endif
+
+#define mp_prime_random(a, t, size, bbs, cb, dat) \
+   mp_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?LTM_PRIME_BBS:0, cb, dat)
+
+#define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len))
+#define mp_raw_size(mp)           mp_signed_bin_size(mp)
+#define mp_toraw(mp, str)         mp_to_signed_bin((mp), (str))
+#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len))
+#define mp_mag_size(mp)           mp_unsigned_bin_size(mp)
+#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 s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
+
+extern const char *mp_s_rmap;
+
+/* 6 functions needed by Rsa */
+int  mp_init (mp_int * a);
+void mp_clear (mp_int * a);
+int  mp_unsigned_bin_size(mp_int * a);
+int  mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c);
+int  mp_to_unsigned_bin (mp_int * a, unsigned char *b);
+int  mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y);
+/* end functions needed by Rsa */
+
+/* functions added to support above needed, removed TOOM and KARATSUBA */
+int  mp_count_bits (mp_int * a);
+int  mp_leading_bit (mp_int * a);
+int  mp_init_copy (mp_int * a, mp_int * b);
+int  mp_copy (mp_int * a, mp_int * b);
+int  mp_grow (mp_int * a, int size);
+int  mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d);
+void mp_zero (mp_int * a);
+void mp_clamp (mp_int * a);
+void mp_exch (mp_int * a, mp_int * b);
+void mp_rshd (mp_int * a, int b);
+void mp_rshb (mp_int * a, int b);
+int  mp_mod_2d (mp_int * a, int b, mp_int * c);
+int  mp_mul_2d (mp_int * a, int b, mp_int * c);
+int  mp_lshd (mp_int * a, int b);
+int  mp_abs (mp_int * a, mp_int * b);
+int  mp_invmod (mp_int * a, mp_int * b, mp_int * c);
+int  fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c);
+int  mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c);
+int  mp_cmp_mag (mp_int * a, mp_int * b);
+int  mp_cmp (mp_int * a, mp_int * b);
+int  mp_cmp_d(mp_int * a, mp_digit b);
+void mp_set (mp_int * a, mp_digit b);
+int  mp_mod (mp_int * a, mp_int * b, mp_int * c);
+int  mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d);
+int  mp_div_2(mp_int * a, mp_int * b);
+int  mp_add (mp_int * a, mp_int * b, mp_int * c);
+int  s_mp_add (mp_int * a, mp_int * b, mp_int * c);
+int  s_mp_sub (mp_int * a, mp_int * b, mp_int * c);
+int  mp_sub (mp_int * a, mp_int * b, mp_int * c);
+int  mp_reduce_is_2k_l(mp_int *a);
+int  mp_reduce_is_2k(mp_int *a);
+int  mp_dr_is_modulus(mp_int *a);
+int  mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int);
+int  mp_montgomery_setup (mp_int * n, mp_digit * rho);
+int  fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho);
+int  mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho);
+void mp_dr_setup(mp_int *a, mp_digit *d);
+int  mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k);
+int  mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d);
+int  fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+int  s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+int  mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
+int  mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
+int  mp_reduce (mp_int * x, mp_int * m, mp_int * mu);
+int  mp_reduce_setup (mp_int * a, mp_int * b);
+int  s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
+int  mp_montgomery_calc_normalization (mp_int * a, mp_int * b);
+int  s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+int  s_mp_sqr (mp_int * a, mp_int * b);
+int  fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+int  fast_s_mp_sqr (mp_int * a, mp_int * b);
+int  mp_init_size (mp_int * a, int size);
+int  mp_div_3 (mp_int * a, mp_int *c, mp_digit * d);
+int  mp_mul_2(mp_int * a, mp_int * b);
+int  mp_mul (mp_int * a, mp_int * b, mp_int * c);
+int  mp_sqr (mp_int * a, mp_int * b);
+int  mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d);
+int  mp_mul_d (mp_int * a, mp_digit b, mp_int * c);
+int  mp_2expt (mp_int * a, int b);
+int  mp_reduce_2k_setup(mp_int *a, mp_digit *d);
+int  mp_add_d (mp_int* a, mp_digit b, mp_int* c);
+int mp_set_int (mp_int * a, unsigned long b);
+int mp_sub_d (mp_int * a, mp_digit b, mp_int * c);
+/* end support added functions */
+
+/* added */
+int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e,
+                  mp_int* f);
+
+#if defined(HAVE_ECC) || defined(WOLFSSL_KEY_GEN)
+    int mp_sqrmod(mp_int* a, mp_int* b, mp_int* c);
+#endif
+#ifdef HAVE_ECC
+    int mp_read_radix(mp_int* a, const char* str, int radix);
+#endif
+
+#ifdef WOLFSSL_KEY_GEN
+    int mp_prime_is_prime (mp_int * a, int t, int *result);
+    int mp_gcd (mp_int * a, mp_int * b, mp_int * c);
+    int mp_lcm (mp_int * a, mp_int * b, mp_int * c);
+#endif
+
+int mp_cnt_lsb(mp_int *a);
+int mp_mod_d(mp_int* a, mp_digit b, mp_digit* c);
+
+#ifdef __cplusplus
+   }
+#endif
+
+
+#endif /* USE_FAST_MATH */
+
+#endif  /* WOLF_CRYPT_INTEGER_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/logging.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,71 @@
+/* logging.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+/* submitted by eof */
+
+
+#ifndef WOLFSSL_LOGGING_H
+#define WOLFSSL_LOGGING_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+enum  CYA_Log_Levels {
+    ERROR_LOG = 0,
+    INFO_LOG,
+    ENTER_LOG,
+    LEAVE_LOG,
+    OTHER_LOG
+};
+
+typedef void (*wolfSSL_Logging_cb)(const int logLevel,
+                                  const char *const logMessage);
+
+WOLFSSL_API int wolfSSL_SetLoggingCb(wolfSSL_Logging_cb log_function);
+
+#ifdef DEBUG_WOLFSSL
+
+    void WOLFSSL_ENTER(const char* msg);
+    void WOLFSSL_LEAVE(const char* msg, int ret);
+
+    void WOLFSSL_ERROR(int);
+    void WOLFSSL_MSG(const char* msg);
+
+#else /* DEBUG_WOLFSSL   */
+
+    #define WOLFSSL_ENTER(m)
+    #define WOLFSSL_LEAVE(m, r)
+
+    #define WOLFSSL_ERROR(e)
+    #define WOLFSSL_MSG(m)
+
+#endif /* DEBUG_WOLFSSL  */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* WOLFSSL_LOGGING_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/md2.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,65 @@
+/* md2.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_MD2_H
+#define WOLF_CRYPT_MD2_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef WOLFSSL_MD2
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* in bytes */
+enum {
+    MD2             =  6,    /* hash type unique */
+    MD2_BLOCK_SIZE  = 16,
+    MD2_DIGEST_SIZE = 16,
+    MD2_PAD_SIZE    = 16,
+    MD2_X_SIZE      = 48
+};
+
+
+/* Md2 digest */
+typedef struct Md2 {
+    word32  count;   /* bytes % PAD_SIZE  */
+    byte    X[MD2_X_SIZE];
+    byte    C[MD2_BLOCK_SIZE];
+    byte    buffer[MD2_BLOCK_SIZE];
+} Md2;
+
+
+WOLFSSL_API void wc_InitMd2(Md2*);
+WOLFSSL_API void wc_Md2Update(Md2*, const byte*, word32);
+WOLFSSL_API void wc_Md2Final(Md2*, byte*);
+WOLFSSL_API int  wc_Md2Hash(const byte*, word32, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* WOLFSSL_MD2 */
+#endif /* WOLF_CRYPT_MD2_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/md4.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,63 @@
+/* md4.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_MD4_H
+#define WOLF_CRYPT_MD4_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifndef NO_MD4
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* in bytes */
+enum {
+    MD4_BLOCK_SIZE  = 64,
+    MD4_DIGEST_SIZE = 16,
+    MD4_PAD_SIZE    = 56
+};
+
+
+/* MD4 digest */
+typedef struct Md4 {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word32  digest[MD4_DIGEST_SIZE / sizeof(word32)];
+    word32  buffer[MD4_BLOCK_SIZE  / sizeof(word32)];
+} Md4;
+
+
+WOLFSSL_API void wc_InitMd4(Md4*);
+WOLFSSL_API void wc_Md4Update(Md4*, const byte*, word32);
+WOLFSSL_API void wc_Md4Final(Md4*, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* NO_MD4 */
+#endif /* WOLF_CRYPT_MD4_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/md5.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,86 @@
+/* md5.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_MD5_H
+#define WOLF_CRYPT_MD5_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifndef NO_MD5
+
+#ifdef HAVE_FIPS
+    #define wc_InitMd5   InitMd5
+    #define wc_Md5Update Md5Update
+    #define wc_Md5Final  Md5Final
+    #define wc_Md5Hash   Md5Hash
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* in bytes */
+enum {
+#ifdef STM32F2_HASH
+    MD5_REG_SIZE    =  4,      /* STM32 register size, bytes */
+#endif
+    MD5             =  0,      /* hash type unique */
+    MD5_BLOCK_SIZE  = 64,
+    MD5_DIGEST_SIZE = 16,
+    MD5_PAD_SIZE    = 56
+};
+
+#if defined(WOLFSSL_PIC32MZ_HASH)
+#include "port/pic32/pic32mz-crypt.h"
+#endif
+
+#ifndef WOLFSSL_TI_HASH
+
+/* MD5 digest */
+typedef struct Md5 {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word32  buffer[MD5_BLOCK_SIZE  / sizeof(word32)];
+    #if !defined(WOLFSSL_PIC32MZ_HASH)
+    word32  digest[MD5_DIGEST_SIZE / sizeof(word32)];
+    #else
+    word32  digest[PIC32_HASH_SIZE / sizeof(word32)];
+    pic32mz_desc desc ; /* Crypt Engine descripter */
+    #endif
+} Md5;
+
+#else /* WOLFSSL_TI_HASH */
+    #include "wolfssl/wolfcrypt/port/ti/ti-hash.h"
+#endif
+
+WOLFSSL_API void wc_InitMd5(Md5*);
+WOLFSSL_API void wc_Md5Update(Md5*, const byte*, word32);
+WOLFSSL_API void wc_Md5Final(Md5*, byte*);
+WOLFSSL_API int  wc_Md5Hash(const byte*, word32, byte*);
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* NO_MD5 */
+#endif /* WOLF_CRYPT_MD5_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/memory.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,57 @@
+/* memory.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+/* submitted by eof */
+
+
+#ifndef WOLFSSL_MEMORY_H
+#define WOLFSSL_MEMORY_H
+
+#include <stdlib.h>
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+typedef void *(*wolfSSL_Malloc_cb)(size_t size);
+typedef void (*wolfSSL_Free_cb)(void *ptr);
+typedef void *(*wolfSSL_Realloc_cb)(void *ptr, size_t size);
+
+
+/* Public set function */
+WOLFSSL_API int wolfSSL_SetAllocators(wolfSSL_Malloc_cb  malloc_function,
+                                    wolfSSL_Free_cb    free_function,
+                                    wolfSSL_Realloc_cb realloc_function);
+
+/* Public in case user app wants to use XMALLOC/XFREE */
+WOLFSSL_API void* wolfSSL_Malloc(size_t size);
+WOLFSSL_API void  wolfSSL_Free(void *ptr);
+WOLFSSL_API void* wolfSSL_Realloc(void *ptr, size_t size);
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+#endif /* WOLFSSL_MEMORY_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/misc.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,79 @@
+/* misc.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef WOLF_CRYPT_MISC_H
+#define WOLF_CRYPT_MISC_H
+
+
+#include <wolfssl/wolfcrypt/types.h>
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#ifdef NO_INLINE
+WOLFSSL_LOCAL
+word32 rotlFixed(word32, word32);
+WOLFSSL_LOCAL
+word32 rotrFixed(word32, word32);
+
+WOLFSSL_LOCAL
+word32 ByteReverseWord32(word32);
+WOLFSSL_LOCAL
+void   ByteReverseWords(word32*, const word32*, word32);
+
+WOLFSSL_LOCAL
+void XorWords(wolfssl_word*, const wolfssl_word*, word32);
+WOLFSSL_LOCAL
+void xorbuf(void*, const void*, word32);
+
+WOLFSSL_LOCAL
+void ForceZero(const void*, word32);
+
+WOLFSSL_LOCAL
+int ConstantCompare(const byte*, const byte*, int);
+
+#ifdef WORD64_AVAILABLE
+WOLFSSL_LOCAL
+word64 rotlFixed64(word64, word64);
+WOLFSSL_LOCAL
+word64 rotrFixed64(word64, word64);
+
+WOLFSSL_LOCAL
+word64 ByteReverseWord64(word64);
+WOLFSSL_LOCAL
+void   ByteReverseWords64(word64*, const word64*, word32);
+#endif /* WORD64_AVAILABLE */
+
+#endif /* NO_INLINE */
+
+
+#ifdef __cplusplus
+    }   /* extern "C" */
+#endif
+
+
+#endif /* WOLF_CRYPT_MISC_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/mpi_class.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,1019 @@
+/* mpi_class.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#if !(defined(LTM1) && defined(LTM2) && defined(LTM3))
+#if defined(LTM2)
+#define LTM3
+#endif
+#if defined(LTM1)
+#define LTM2
+#endif
+#define LTM1
+
+#if defined(LTM_ALL)
+#define BN_ERROR_C
+#define BN_FAST_MP_INVMOD_C
+#define BN_FAST_MP_MONTGOMERY_REDUCE_C
+#define BN_FAST_S_MP_MUL_DIGS_C
+#define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+#define BN_FAST_S_MP_SQR_C
+#define BN_MP_2EXPT_C
+#define BN_MP_ABS_C
+#define BN_MP_ADD_C
+#define BN_MP_ADD_D_C
+#define BN_MP_ADDMOD_C
+#define BN_MP_AND_C
+#define BN_MP_CLAMP_C
+#define BN_MP_CLEAR_C
+#define BN_MP_CLEAR_MULTI_C
+#define BN_MP_CMP_C
+#define BN_MP_CMP_D_C
+#define BN_MP_CMP_MAG_C
+#define BN_MP_CNT_LSB_C
+#define BN_MP_COPY_C
+#define BN_MP_COUNT_BITS_C
+#define BN_MP_DIV_C
+#define BN_MP_DIV_2_C
+#define BN_MP_DIV_2D_C
+#define BN_MP_DIV_3_C
+#define BN_MP_DIV_D_C
+#define BN_MP_DR_IS_MODULUS_C
+#define BN_MP_DR_REDUCE_C
+#define BN_MP_DR_SETUP_C
+#define BN_MP_EXCH_C
+#define BN_MP_EXPT_D_C
+#define BN_MP_EXPTMOD_C
+#define BN_MP_EXPTMOD_FAST_C
+#define BN_MP_EXTEUCLID_C
+#define BN_MP_FREAD_C
+#define BN_MP_FWRITE_C
+#define BN_MP_GCD_C
+#define BN_MP_GET_INT_C
+#define BN_MP_GROW_C
+#define BN_MP_INIT_C
+#define BN_MP_INIT_COPY_C
+#define BN_MP_INIT_MULTI_C
+#define BN_MP_INIT_SET_C
+#define BN_MP_INIT_SET_INT_C
+#define BN_MP_INIT_SIZE_C
+#define BN_MP_INVMOD_C
+#define BN_MP_INVMOD_SLOW_C
+#define BN_MP_IS_SQUARE_C
+#define BN_MP_JACOBI_C
+#define BN_MP_KARATSUBA_MUL_C
+#define BN_MP_KARATSUBA_SQR_C
+#define BN_MP_LCM_C
+#define BN_MP_LSHD_C
+#define BN_MP_MOD_C
+#define BN_MP_MOD_2D_C
+#define BN_MP_MOD_D_C
+#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+#define BN_MP_MONTGOMERY_REDUCE_C
+#define BN_MP_MONTGOMERY_SETUP_C
+#define BN_MP_MUL_C
+#define BN_MP_MUL_2_C
+#define BN_MP_MUL_2D_C
+#define BN_MP_MUL_D_C
+#define BN_MP_MULMOD_C
+#define BN_MP_N_ROOT_C
+#define BN_MP_NEG_C
+#define BN_MP_OR_C
+#define BN_MP_PRIME_FERMAT_C
+#define BN_MP_PRIME_IS_DIVISIBLE_C
+#define BN_MP_PRIME_IS_PRIME_C
+#define BN_MP_PRIME_MILLER_RABIN_C
+#define BN_MP_PRIME_NEXT_PRIME_C
+#define BN_MP_PRIME_RABIN_MILLER_TRIALS_C
+#define BN_MP_PRIME_RANDOM_EX_C
+#define BN_MP_RADIX_SIZE_C
+#define BN_MP_RADIX_SMAP_C
+#define BN_MP_RAND_C
+#define BN_MP_READ_RADIX_C
+#define BN_MP_READ_SIGNED_BIN_C
+#define BN_MP_READ_UNSIGNED_BIN_C
+#define BN_MP_REDUCE_C
+#define BN_MP_REDUCE_2K_C
+#define BN_MP_REDUCE_2K_L_C
+#define BN_MP_REDUCE_2K_SETUP_C
+#define BN_MP_REDUCE_2K_SETUP_L_C
+#define BN_MP_REDUCE_IS_2K_C
+#define BN_MP_REDUCE_IS_2K_L_C
+#define BN_MP_REDUCE_SETUP_C
+#define BN_MP_RSHD_C
+#define BN_MP_SET_C
+#define BN_MP_SET_INT_C
+#define BN_MP_SHRINK_C
+#define BN_MP_SIGNED_BIN_SIZE_C
+#define BN_MP_SQR_C
+#define BN_MP_SQRMOD_C
+#define BN_MP_SQRT_C
+#define BN_MP_SUB_C
+#define BN_MP_SUB_D_C
+#define BN_MP_SUBMOD_C
+#define BN_MP_TO_SIGNED_BIN_C
+#define BN_MP_TO_SIGNED_BIN_N_C
+#define BN_MP_TO_UNSIGNED_BIN_C
+#define BN_MP_TO_UNSIGNED_BIN_N_C
+#define BN_MP_TOOM_MUL_C
+#define BN_MP_TOOM_SQR_C
+#define BN_MP_TORADIX_C
+#define BN_MP_TORADIX_N_C
+#define BN_MP_UNSIGNED_BIN_SIZE_C
+#define BN_MP_XOR_C
+#define BN_MP_ZERO_C
+#define BN_PRIME_TAB_C
+#define BN_REVERSE_C
+#define BN_S_MP_ADD_C
+#define BN_S_MP_EXPTMOD_C
+#define BN_S_MP_MUL_DIGS_C
+#define BN_S_MP_MUL_HIGH_DIGS_C
+#define BN_S_MP_SQR_C
+#define BN_S_MP_SUB_C
+#define BNCORE_C
+#endif
+
+#if defined(BN_ERROR_C)
+   #define BN_MP_ERROR_TO_STRING_C
+#endif
+
+#if defined(BN_FAST_MP_INVMOD_C)
+   #define BN_MP_ISEVEN_C
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_COPY_C
+   #define BN_MP_MOD_C
+   #define BN_MP_SET_C
+   #define BN_MP_DIV_2_C
+   #define BN_MP_ISODD_C
+   #define BN_MP_SUB_C
+   #define BN_MP_CMP_C
+   #define BN_MP_ISZERO_C
+   #define BN_MP_CMP_D_C
+   #define BN_MP_ADD_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_FAST_MP_MONTGOMERY_REDUCE_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_FAST_S_MP_MUL_DIGS_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_FAST_S_MP_SQR_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_2EXPT_C)
+   #define BN_MP_ZERO_C
+   #define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_ABS_C)
+   #define BN_MP_COPY_C
+#endif
+
+#if defined(BN_MP_ADD_C)
+   #define BN_S_MP_ADD_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_ADD_D_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_SUB_D_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_ADDMOD_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_ADD_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_AND_C)
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_CLAMP_C)
+#endif
+
+#if defined(BN_MP_CLEAR_C)
+#endif
+
+#if defined(BN_MP_CLEAR_MULTI_C)
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_CMP_C)
+   #define BN_MP_CMP_MAG_C
+#endif
+
+#if defined(BN_MP_CMP_D_C)
+#endif
+
+#if defined(BN_MP_CMP_MAG_C)
+#endif
+
+#if defined(BN_MP_CNT_LSB_C)
+   #define BN_MP_ISZERO_C
+#endif
+
+#if defined(BN_MP_COPY_C)
+   #define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_COUNT_BITS_C)
+#endif
+
+#if defined(BN_MP_DIV_C)
+   #define BN_MP_ISZERO_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_MP_COPY_C
+   #define BN_MP_ZERO_C
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_SET_C
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_ABS_C
+   #define BN_MP_MUL_2D_C
+   #define BN_MP_CMP_C
+   #define BN_MP_SUB_C
+   #define BN_MP_ADD_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_MULTI_C
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_INIT_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_LSHD_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_MUL_D_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_DIV_2_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_DIV_2D_C)
+   #define BN_MP_COPY_C
+   #define BN_MP_ZERO_C
+   #define BN_MP_INIT_C
+   #define BN_MP_MOD_2D_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_DIV_3_C)
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_DIV_D_C)
+   #define BN_MP_ISZERO_C
+   #define BN_MP_COPY_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_DIV_3_C
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_DR_IS_MODULUS_C)
+#endif
+
+#if defined(BN_MP_DR_REDUCE_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_DR_SETUP_C)
+#endif
+
+#if defined(BN_MP_EXCH_C)
+#endif
+
+#if defined(BN_MP_EXPT_D_C)
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_SET_C
+   #define BN_MP_SQR_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_MUL_C
+#endif
+
+#if defined(BN_MP_EXPTMOD_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_INVMOD_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_ABS_C
+   #define BN_MP_CLEAR_MULTI_C
+   #define BN_MP_REDUCE_IS_2K_L_C
+   #define BN_S_MP_EXPTMOD_C
+   #define BN_MP_DR_IS_MODULUS_C
+   #define BN_MP_REDUCE_IS_2K_C
+   #define BN_MP_ISODD_C
+   #define BN_MP_EXPTMOD_FAST_C
+#endif
+
+#if defined(BN_MP_EXPTMOD_FAST_C)
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_INIT_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_MONTGOMERY_SETUP_C
+   #define BN_FAST_MP_MONTGOMERY_REDUCE_C
+   #define BN_MP_MONTGOMERY_REDUCE_C
+   #define BN_MP_DR_SETUP_C
+   #define BN_MP_DR_REDUCE_C
+   #define BN_MP_REDUCE_2K_SETUP_C
+   #define BN_MP_REDUCE_2K_C
+   #define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+   #define BN_MP_MULMOD_C
+   #define BN_MP_SET_C
+   #define BN_MP_MOD_C
+   #define BN_MP_COPY_C
+   #define BN_MP_SQR_C
+   #define BN_MP_MUL_C
+   #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_EXTEUCLID_C)
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_SET_C
+   #define BN_MP_COPY_C
+   #define BN_MP_ISZERO_C
+   #define BN_MP_DIV_C
+   #define BN_MP_MUL_C
+   #define BN_MP_SUB_C
+   #define BN_MP_NEG_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_FREAD_C)
+   #define BN_MP_ZERO_C
+   #define BN_MP_S_RMAP_C
+   #define BN_MP_MUL_D_C
+   #define BN_MP_ADD_D_C
+   #define BN_MP_CMP_D_C
+#endif
+
+#if defined(BN_MP_FWRITE_C)
+   #define BN_MP_RADIX_SIZE_C
+   #define BN_MP_TORADIX_C
+#endif
+
+#if defined(BN_MP_GCD_C)
+   #define BN_MP_ISZERO_C
+   #define BN_MP_ABS_C
+   #define BN_MP_ZERO_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_CNT_LSB_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_MP_EXCH_C
+   #define BN_S_MP_SUB_C
+   #define BN_MP_MUL_2D_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_GET_INT_C)
+#endif
+
+#if defined(BN_MP_GROW_C)
+#endif
+
+#if defined(BN_MP_INIT_C)
+#endif
+
+#if defined(BN_MP_INIT_COPY_C)
+   #define BN_MP_COPY_C
+#endif
+
+#if defined(BN_MP_INIT_MULTI_C)
+   #define BN_MP_ERR_C
+   #define BN_MP_INIT_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_INIT_SET_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_SET_C
+#endif
+
+#if defined(BN_MP_INIT_SET_INT_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_SET_INT_C
+#endif
+
+#if defined(BN_MP_INIT_SIZE_C)
+   #define BN_MP_INIT_C
+#endif
+
+#if defined(BN_MP_INVMOD_C)
+   #define BN_MP_ISZERO_C
+   #define BN_MP_ISODD_C
+   #define BN_FAST_MP_INVMOD_C
+   #define BN_MP_INVMOD_SLOW_C
+#endif
+
+#if defined(BN_MP_INVMOD_SLOW_C)
+   #define BN_MP_ISZERO_C
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_MOD_C
+   #define BN_MP_COPY_C
+   #define BN_MP_ISEVEN_C
+   #define BN_MP_SET_C
+   #define BN_MP_DIV_2_C
+   #define BN_MP_ISODD_C
+   #define BN_MP_ADD_C
+   #define BN_MP_SUB_C
+   #define BN_MP_CMP_C
+   #define BN_MP_CMP_D_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_IS_SQUARE_C)
+   #define BN_MP_MOD_D_C
+   #define BN_MP_INIT_SET_INT_C
+   #define BN_MP_MOD_C
+   #define BN_MP_GET_INT_C
+   #define BN_MP_SQRT_C
+   #define BN_MP_SQR_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_JACOBI_C)
+   #define BN_MP_CMP_D_C
+   #define BN_MP_ISZERO_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_CNT_LSB_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_MOD_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_KARATSUBA_MUL_C)
+   #define BN_MP_MUL_C
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_SUB_C
+   #define BN_MP_ADD_C
+   #define BN_MP_LSHD_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_KARATSUBA_SQR_C)
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_SQR_C
+   #define BN_MP_SUB_C
+   #define BN_S_MP_ADD_C
+   #define BN_MP_LSHD_C
+   #define BN_MP_ADD_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_LCM_C)
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_GCD_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_MP_DIV_C
+   #define BN_MP_MUL_C
+   #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_LSHD_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_RSHD_C
+#endif
+
+#if defined(BN_MP_MOD_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_DIV_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_ADD_C
+   #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_MOD_2D_C)
+   #define BN_MP_ZERO_C
+   #define BN_MP_COPY_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_MOD_D_C)
+   #define BN_MP_DIV_D_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_CALC_NORMALIZATION_C)
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_2EXPT_C
+   #define BN_MP_SET_C
+   #define BN_MP_MUL_2_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_REDUCE_C)
+   #define BN_FAST_MP_MONTGOMERY_REDUCE_C
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_SETUP_C)
+#endif
+
+#if defined(BN_MP_MUL_C)
+   #define BN_MP_TOOM_MUL_C
+   #define BN_MP_KARATSUBA_MUL_C
+   #define BN_FAST_S_MP_MUL_DIGS_C
+   #define BN_S_MP_MUL_C
+   #define BN_S_MP_MUL_DIGS_C
+#endif
+
+#if defined(BN_MP_MUL_2_C)
+   #define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_MUL_2D_C)
+   #define BN_MP_COPY_C
+   #define BN_MP_GROW_C
+   #define BN_MP_LSHD_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_MUL_D_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_MULMOD_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_MUL_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_N_ROOT_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_SET_C
+   #define BN_MP_COPY_C
+   #define BN_MP_EXPT_D_C
+   #define BN_MP_MUL_C
+   #define BN_MP_SUB_C
+   #define BN_MP_MUL_D_C
+   #define BN_MP_DIV_C
+   #define BN_MP_CMP_C
+   #define BN_MP_SUB_D_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_NEG_C)
+   #define BN_MP_COPY_C
+   #define BN_MP_ISZERO_C
+#endif
+
+#if defined(BN_MP_OR_C)
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_FERMAT_C)
+   #define BN_MP_CMP_D_C
+   #define BN_MP_INIT_C
+   #define BN_MP_EXPTMOD_C
+   #define BN_MP_CMP_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_IS_DIVISIBLE_C)
+   #define BN_MP_MOD_D_C
+#endif
+
+#if defined(BN_MP_PRIME_IS_PRIME_C)
+   #define BN_MP_CMP_D_C
+   #define BN_MP_PRIME_IS_DIVISIBLE_C
+   #define BN_MP_INIT_C
+   #define BN_MP_SET_C
+   #define BN_MP_PRIME_MILLER_RABIN_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_MILLER_RABIN_C)
+   #define BN_MP_CMP_D_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_SUB_D_C
+   #define BN_MP_CNT_LSB_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_EXPTMOD_C
+   #define BN_MP_CMP_C
+   #define BN_MP_SQRMOD_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_NEXT_PRIME_C)
+   #define BN_MP_CMP_D_C
+   #define BN_MP_SET_C
+   #define BN_MP_SUB_D_C
+   #define BN_MP_ISEVEN_C
+   #define BN_MP_MOD_D_C
+   #define BN_MP_INIT_C
+   #define BN_MP_ADD_D_C
+   #define BN_MP_PRIME_MILLER_RABIN_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_RABIN_MILLER_TRIALS_C)
+#endif
+
+#if defined(BN_MP_PRIME_RANDOM_EX_C)
+   #define BN_MP_READ_UNSIGNED_BIN_C
+   #define BN_MP_PRIME_IS_PRIME_C
+   #define BN_MP_SUB_D_C
+   #define BN_MP_DIV_2_C
+   #define BN_MP_MUL_2_C
+   #define BN_MP_ADD_D_C
+#endif
+
+#if defined(BN_MP_RADIX_SIZE_C)
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_ISZERO_C
+   #define BN_MP_DIV_D_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_RADIX_SMAP_C)
+   #define BN_MP_S_RMAP_C
+#endif
+
+#if defined(BN_MP_RAND_C)
+   #define BN_MP_ZERO_C
+   #define BN_MP_ADD_D_C
+   #define BN_MP_LSHD_C
+#endif
+
+#if defined(BN_MP_READ_RADIX_C)
+   #define BN_MP_ZERO_C
+   #define BN_MP_S_RMAP_C
+   #define BN_MP_RADIX_SMAP_C
+   #define BN_MP_MUL_D_C
+   #define BN_MP_ADD_D_C
+   #define BN_MP_ISZERO_C
+#endif
+
+#if defined(BN_MP_READ_SIGNED_BIN_C)
+   #define BN_MP_READ_UNSIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_READ_UNSIGNED_BIN_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_ZERO_C
+   #define BN_MP_MUL_2D_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_REDUCE_C)
+   #define BN_MP_REDUCE_SETUP_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_MUL_C
+   #define BN_S_MP_MUL_HIGH_DIGS_C
+   #define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+   #define BN_MP_MOD_2D_C
+   #define BN_S_MP_MUL_DIGS_C
+   #define BN_MP_SUB_C
+   #define BN_MP_CMP_D_C
+   #define BN_MP_SET_C
+   #define BN_MP_LSHD_C
+   #define BN_MP_ADD_C
+   #define BN_MP_CMP_C
+   #define BN_S_MP_SUB_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_MUL_D_C
+   #define BN_S_MP_ADD_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_L_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_MUL_C
+   #define BN_S_MP_ADD_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_SETUP_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_2EXPT_C
+   #define BN_MP_CLEAR_C
+   #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_SETUP_L_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_2EXPT_C
+   #define BN_MP_COUNT_BITS_C
+   #define BN_S_MP_SUB_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_IS_2K_C)
+   #define BN_MP_REDUCE_2K_C
+   #define BN_MP_COUNT_BITS_C
+#endif
+
+#if defined(BN_MP_REDUCE_IS_2K_L_C)
+#endif
+
+#if defined(BN_MP_REDUCE_SETUP_C)
+   #define BN_MP_2EXPT_C
+   #define BN_MP_DIV_C
+#endif
+
+#if defined(BN_MP_RSHD_C)
+   #define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_SET_C)
+   #define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_SET_INT_C)
+   #define BN_MP_ZERO_C
+   #define BN_MP_MUL_2D_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_SHRINK_C)
+#endif
+
+#if defined(BN_MP_SIGNED_BIN_SIZE_C)
+   #define BN_MP_UNSIGNED_BIN_SIZE_C
+#endif
+
+#if defined(BN_MP_SQR_C)
+   #define BN_MP_TOOM_SQR_C
+   #define BN_MP_KARATSUBA_SQR_C
+   #define BN_FAST_S_MP_SQR_C
+   #define BN_S_MP_SQR_C
+#endif
+
+#if defined(BN_MP_SQRMOD_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_SQR_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_SQRT_C)
+   #define BN_MP_N_ROOT_C
+   #define BN_MP_ISZERO_C
+   #define BN_MP_ZERO_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_DIV_C
+   #define BN_MP_ADD_C
+   #define BN_MP_DIV_2_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_SUB_C)
+   #define BN_S_MP_ADD_C
+   #define BN_MP_CMP_MAG_C
+   #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_SUB_D_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_ADD_D_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_SUBMOD_C)
+   #define BN_MP_INIT_C
+   #define BN_MP_SUB_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_TO_SIGNED_BIN_C)
+   #define BN_MP_TO_UNSIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_TO_SIGNED_BIN_N_C)
+   #define BN_MP_SIGNED_BIN_SIZE_C
+   #define BN_MP_TO_SIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_TO_UNSIGNED_BIN_C)
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_ISZERO_C
+   #define BN_MP_DIV_2D_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_TO_UNSIGNED_BIN_N_C)
+   #define BN_MP_UNSIGNED_BIN_SIZE_C
+   #define BN_MP_TO_UNSIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_TOOM_MUL_C)
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_MOD_2D_C
+   #define BN_MP_COPY_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_MUL_C
+   #define BN_MP_MUL_2_C
+   #define BN_MP_ADD_C
+   #define BN_MP_SUB_C
+   #define BN_MP_DIV_2_C
+   #define BN_MP_MUL_2D_C
+   #define BN_MP_MUL_D_C
+   #define BN_MP_DIV_3_C
+   #define BN_MP_LSHD_C
+   #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_TOOM_SQR_C)
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_MOD_2D_C
+   #define BN_MP_COPY_C
+   #define BN_MP_RSHD_C
+   #define BN_MP_SQR_C
+   #define BN_MP_MUL_2_C
+   #define BN_MP_ADD_C
+   #define BN_MP_SUB_C
+   #define BN_MP_DIV_2_C
+   #define BN_MP_MUL_2D_C
+   #define BN_MP_MUL_D_C
+   #define BN_MP_DIV_3_C
+   #define BN_MP_LSHD_C
+   #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_TORADIX_C)
+   #define BN_MP_ISZERO_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_DIV_D_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_S_RMAP_C
+#endif
+
+#if defined(BN_MP_TORADIX_N_C)
+   #define BN_MP_ISZERO_C
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_DIV_D_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_S_RMAP_C
+#endif
+
+#if defined(BN_MP_UNSIGNED_BIN_SIZE_C)
+   #define BN_MP_COUNT_BITS_C
+#endif
+
+#if defined(BN_MP_XOR_C)
+   #define BN_MP_INIT_COPY_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_ZERO_C)
+#endif
+
+#if defined(BN_PRIME_TAB_C)
+#endif
+
+#if defined(BN_REVERSE_C)
+#endif
+
+#if defined(BN_S_MP_ADD_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_S_MP_EXPTMOD_C)
+   #define BN_MP_COUNT_BITS_C
+   #define BN_MP_INIT_C
+   #define BN_MP_CLEAR_C
+   #define BN_MP_REDUCE_SETUP_C
+   #define BN_MP_REDUCE_C
+   #define BN_MP_REDUCE_2K_SETUP_L_C
+   #define BN_MP_REDUCE_2K_L_C
+   #define BN_MP_MOD_C
+   #define BN_MP_COPY_C
+   #define BN_MP_SQR_C
+   #define BN_MP_MUL_C
+   #define BN_MP_SET_C
+   #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_S_MP_MUL_DIGS_C)
+   #define BN_FAST_S_MP_MUL_DIGS_C
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_S_MP_MUL_HIGH_DIGS_C)
+   #define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_S_MP_SQR_C)
+   #define BN_MP_INIT_SIZE_C
+   #define BN_MP_CLAMP_C
+   #define BN_MP_EXCH_C
+   #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_S_MP_SUB_C)
+   #define BN_MP_GROW_C
+   #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BNCORE_C)
+#endif
+
+#ifdef LTM3
+#define LTM_LAST
+#endif
+#include "mpi_superclass.h"
+#include "mpi_class.h"
+#else
+#define LTM_LAST
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/mpi_superclass.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,96 @@
+/* mpi_superclass.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+/* super class file for PK algos */
+
+/* default ... include all MPI */
+#define LTM_ALL
+
+/* RSA only (does not support DH/DSA/ECC) */
+/* #define SC_RSA_1 */
+
+/* For reference.... On an Athlon64 optimizing for speed...
+
+   LTM's mpi.o with all functions [striped] is 142KiB in size.
+
+*/
+
+/* Works for RSA only, mpi.o is 68KiB */
+#ifdef SC_RSA_1
+   #define BN_MP_SHRINK_C
+   #define BN_MP_LCM_C
+   #define BN_MP_PRIME_RANDOM_EX_C
+   #define BN_MP_INVMOD_C
+   #define BN_MP_GCD_C
+   #define BN_MP_MOD_C
+   #define BN_MP_MULMOD_C
+   #define BN_MP_ADDMOD_C
+   #define BN_MP_EXPTMOD_C
+   #define BN_MP_SET_INT_C
+   #define BN_MP_INIT_MULTI_C
+   #define BN_MP_CLEAR_MULTI_C
+   #define BN_MP_UNSIGNED_BIN_SIZE_C
+   #define BN_MP_TO_UNSIGNED_BIN_C
+   #define BN_MP_MOD_D_C
+   #define BN_MP_PRIME_RABIN_MILLER_TRIALS_C
+   #define BN_REVERSE_C
+   #define BN_PRIME_TAB_C
+
+   /* other modifiers */
+   #define BN_MP_DIV_SMALL                    /* Slower division, not critical */
+
+   /* here we are on the last pass so we turn things off.  The functions classes are still there
+    * but we remove them specifically from the build.  This also invokes tweaks in functions
+    * like removing support for even moduli, etc...
+    */
+#ifdef LTM_LAST
+   #undef  BN_MP_TOOM_MUL_C
+   #undef  BN_MP_TOOM_SQR_C
+   #undef  BN_MP_KARATSUBA_MUL_C
+   #undef  BN_MP_KARATSUBA_SQR_C
+   #undef  BN_MP_REDUCE_C
+   #undef  BN_MP_REDUCE_SETUP_C
+   #undef  BN_MP_DR_IS_MODULUS_C
+   #undef  BN_MP_DR_SETUP_C
+   #undef  BN_MP_DR_REDUCE_C
+   #undef  BN_MP_REDUCE_IS_2K_C
+   #undef  BN_MP_REDUCE_2K_SETUP_C
+   #undef  BN_MP_REDUCE_2K_C
+   #undef  BN_S_MP_EXPTMOD_C
+   #undef  BN_MP_DIV_3_C
+   #undef  BN_S_MP_MUL_HIGH_DIGS_C
+   #undef  BN_FAST_S_MP_MUL_HIGH_DIGS_C
+   #undef  BN_FAST_MP_INVMOD_C
+
+   /* To safely undefine these you have to make sure your RSA key won't exceed the Comba threshold
+    * which is roughly 255 digits [7140 bits for 32-bit machines, 15300 bits for 64-bit machines] 
+    * which means roughly speaking you can handle upto 2536-bit RSA keys with these defined without
+    * trouble.  
+    */
+   #undef  BN_S_MP_MUL_DIGS_C
+   #undef  BN_S_MP_SQR_C
+   #undef  BN_MP_MONTGOMERY_REDUCE_C
+#endif
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/pkcs7.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,127 @@
+/* pkcs7.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_PKCS7_H
+#define WOLF_CRYPT_PKCS7_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef HAVE_PKCS7
+
+#ifndef NO_ASN
+    #include <wolfssl/wolfcrypt/asn.h>
+#endif
+#include <wolfssl/wolfcrypt/asn_public.h>
+#include <wolfssl/wolfcrypt/random.h>
+#ifndef NO_DES3
+    #include <wolfssl/wolfcrypt/des3.h>
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* PKCS#7 content types, ref RFC 2315 (Section 14) */
+enum PKCS7_TYPES {
+    PKCS7_MSG                 = 650,   /* 1.2.840.113549.1.7   */
+    DATA                      = 651,   /* 1.2.840.113549.1.7.1 */
+    SIGNED_DATA               = 652,   /* 1.2.840.113549.1.7.2 */
+    ENVELOPED_DATA            = 653,   /* 1.2.840.113549.1.7.3 */
+    SIGNED_AND_ENVELOPED_DATA = 654,   /* 1.2.840.113549.1.7.4 */
+    DIGESTED_DATA             = 655,   /* 1.2.840.113549.1.7.5 */
+    ENCRYPTED_DATA            = 656    /* 1.2.840.113549.1.7.6 */
+};
+
+enum Pkcs7_Misc {
+    PKCS7_NONCE_SZ       = 16,
+    MAX_ENCRYPTED_KEY_SZ = 512,           /* max enc. key size, RSA <= 4096 */
+    MAX_CONTENT_KEY_LEN  = DES3_KEYLEN,   /* highest current cipher is 3DES */
+    MAX_RECIP_SZ         = MAX_VERSION_SZ +
+                           MAX_SEQ_SZ + ASN_NAME_MAX + MAX_SN_SZ +
+                           MAX_SEQ_SZ + MAX_ALGO_SZ + 1 + MAX_ENCRYPTED_KEY_SZ
+};
+
+
+typedef struct PKCS7Attrib {
+    byte* oid;
+    word32 oidSz;
+    byte* value;
+    word32 valueSz;
+} PKCS7Attrib;
+
+
+typedef struct PKCS7 {
+    byte* content;                /* inner content, not owner             */
+    word32 contentSz;             /* content size                         */
+    int contentOID;               /* PKCS#7 content type OID sum          */
+
+    RNG* rng;
+
+    int hashOID;
+    int encryptOID;               /* key encryption algorithm OID         */
+
+    byte*  singleCert;            /* recipient cert, DER, not owner       */
+    word32 singleCertSz;          /* size of recipient cert buffer, bytes */
+    byte issuerHash[KEYID_SIZE];  /* hash of all alt Names                */
+    byte*  issuer;                /* issuer name of singleCert            */
+    word32 issuerSz;              /* length of issuer name                */
+    byte issuerSn[MAX_SN_SZ];     /* singleCert's serial number           */
+    word32 issuerSnSz;            /* length of serial number              */
+    byte publicKey[512];
+    word32 publicKeySz;
+    byte*  privateKey;            /* private key, DER, not owner          */
+    word32 privateKeySz;          /* size of private key buffer, bytes    */
+
+    PKCS7Attrib* signedAttribs;
+    word32 signedAttribsSz;
+} PKCS7;
+
+
+WOLFSSL_LOCAL int wc_SetContentType(int pkcs7TypeOID, byte* output);
+WOLFSSL_LOCAL int wc_GetContentType(const byte* input, word32* inOutIdx,
+                                word32* oid, word32 maxIdx);
+WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz,
+                                     int keyEncAlgo, int blockKeySz,
+                                     RNG* rng, byte* contentKeyPlain,
+                                     byte* contentKeyEnc,
+                                     int* keyEncSz, byte* out, word32 outSz);
+
+WOLFSSL_API int  wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz);
+WOLFSSL_API void wc_PKCS7_Free(PKCS7* pkcs7);
+WOLFSSL_API int  wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, word32 outputSz);
+WOLFSSL_API int  wc_PKCS7_EncodeSignedData(PKCS7* pkcs7,
+                                       byte* output, word32 outputSz);
+WOLFSSL_API int  wc_PKCS7_VerifySignedData(PKCS7* pkcs7,
+                                       byte* pkiMsg, word32 pkiMsgSz);
+WOLFSSL_API int  wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7,
+                                          byte* output, word32 outputSz);
+WOLFSSL_API int  wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg,
+                                          word32 pkiMsgSz, byte* output,
+                                          word32 outputSz);
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* HAVE_PKCS7 */
+#endif /* WOLF_CRYPT_PKCS7_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/poly1305.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,82 @@
+/* poly1305.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_POLY1305_H
+#define WOLF_CRYPT_POLY1305_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef HAVE_POLY1305
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* auto detect between 32bit / 64bit */
+#define HAS_SIZEOF_INT128_64BIT (defined(__SIZEOF_INT128__) && defined(__LP64__))
+#define HAS_MSVC_64BIT (defined(_MSC_VER) && defined(_M_X64))
+#define HAS_GCC_4_4_64BIT (defined(__GNUC__) && defined(__LP64__) && \
+        ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4))))
+
+#if (HAS_SIZEOF_INT128_64BIT || HAS_MSVC_64BIT || HAS_GCC_4_4_64BIT)
+#define POLY130564
+#else
+#define POLY130532
+#endif
+
+enum {
+    POLY1305 = 7,
+    POLY1305_BLOCK_SIZE = 16,
+    POLY1305_DIGEST_SIZE = 16,
+    POLY1305_PAD_SIZE = 56
+};
+
+/* Poly1305 state */
+typedef struct Poly1305 {
+#if defined(POLY130564)
+	word64 r[3];
+	word64 h[3];
+	word64 pad[2];
+#else
+	word32 r[5];
+	word32 h[5];
+	word32 pad[4];
+#endif
+	size_t leftover;
+	unsigned char buffer[POLY1305_BLOCK_SIZE];
+	unsigned char final;
+} Poly1305;
+
+
+/* does init */
+
+WOLFSSL_API int wc_Poly1305SetKey(Poly1305* poly1305, const byte* key, word32 kySz);
+WOLFSSL_API int wc_Poly1305Update(Poly1305* poly1305, const byte*, word32);
+WOLFSSL_API int wc_Poly1305Final(Poly1305* poly1305, byte* tag);
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* HAVE_POLY1305 */
+#endif /* WOLF_CRYPT_POLY1305_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/pwdbased.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,66 @@
+/* pwdbased.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_PWDBASED_H
+#define WOLF_CRYPT_PWDBASED_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifndef NO_PWDBASED
+
+#ifndef NO_MD5
+    #include <wolfssl/wolfcrypt/md5.h>       /* for hash type */
+#endif
+
+#include <wolfssl/wolfcrypt/sha.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/*
+ * hashType renamed to typeH to avoid shadowing global declation here:
+ * wolfssl/wolfcrypt/asn.h line 173 in enum Oid_Types
+ */
+WOLFSSL_API int wc_PBKDF1(byte* output, const byte* passwd, int pLen,
+                      const byte* salt, int sLen, int iterations, int kLen,
+                      int typeH);
+WOLFSSL_API int wc_PBKDF2(byte* output, const byte* passwd, int pLen,
+                      const byte* salt, int sLen, int iterations, int kLen,
+                      int typeH);
+WOLFSSL_API int wc_PKCS12_PBKDF(byte* output, const byte* passwd, int pLen,
+                            const byte* salt, int sLen, int iterations,
+                            int kLen, int typeH, int purpose);
+
+/* helper functions */
+WOLFSSL_LOCAL int GetDigestSize(int hashType);
+WOLFSSL_LOCAL int GetPKCS12HashSizes(int hashType, word32* v, word32* u);
+WOLFSSL_LOCAL int DoPKCS12Hash(int hashType, byte* buffer, word32 totalLen,
+                               byte* Ai, word32 u, int iterations);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* NO_PWDBASED */
+#endif /* WOLF_CRYPT_PWDBASED_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/rabbit.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,65 @@
+/* rabbit.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_RABBIT_H
+#define WOLF_CRYPT_RABBIT_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifndef NO_RABBIT
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+enum {
+	RABBIT_ENC_TYPE  = 5     /* cipher unique type */
+};
+
+
+/* Rabbit Context */
+typedef struct RabbitCtx {
+    word32 x[8];
+    word32 c[8];
+    word32 carry;
+} RabbitCtx;
+
+
+/* Rabbit stream cipher */
+typedef struct Rabbit {
+    RabbitCtx masterCtx;
+    RabbitCtx workCtx;
+} Rabbit;
+
+
+WOLFSSL_API int wc_RabbitProcess(Rabbit*, byte*, const byte*, word32);
+WOLFSSL_API int wc_RabbitSetKey(Rabbit*, const byte* key, const byte* iv);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* NO_RABBIT */
+#endif /* WOLF_CRYPT_RABBIT_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/random.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,144 @@
+/* random.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef WOLF_CRYPT_RANDOM_H
+#define WOLF_CRYPT_RANDOM_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef HAVE_FIPS
+/* for fips @wc_fips */
+#include <cyassl/ctaocrypt/random.h>
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#ifndef HAVE_FIPS /* avoid redefining structs and macros */
+#if defined(HAVE_HASHDRBG) || defined(NO_RC4)
+    #ifdef NO_SHA256
+        #error "Hash DRBG requires SHA-256."
+    #endif /* NO_SHA256 */
+
+    #include <wolfssl/wolfcrypt/sha256.h>
+#else /* HAVE_HASHDRBG || NO_RC4 */
+    #include <wolfssl/wolfcrypt/arc4.h>
+#endif /* HAVE_HASHDRBG || NO_RC4 */
+
+#if defined(USE_WINDOWS_API)
+    #if defined(_WIN64)
+        typedef unsigned __int64 ProviderHandle;
+        /* type HCRYPTPROV, avoid #include <windows.h> */
+    #else
+        typedef unsigned long ProviderHandle;
+    #endif
+#endif
+
+
+/* OS specific seeder */
+typedef struct OS_Seed {
+    #if defined(USE_WINDOWS_API)
+        ProviderHandle handle;
+    #else
+        int fd;
+    #endif
+} OS_Seed;
+
+
+#if defined(WOLFSSL_MDK_ARM)
+#undef RNG
+#define RNG wolfSSL_RNG   /* for avoiding name conflict in "stm32f2xx.h" */
+#endif
+
+
+#if defined(HAVE_HASHDRBG) || defined(NO_RC4)
+
+
+#define DRBG_SEED_LEN (440/8)
+
+
+struct DRBG; /* Private DRBG state */
+
+
+/* Hash-based Deterministic Random Bit Generator */
+typedef struct RNG {
+    struct DRBG* drbg;
+    OS_Seed seed;
+    byte status;
+} RNG;
+
+
+#else /* HAVE_HASHDRBG || NO_RC4 */
+
+
+#define WOLFSSL_RNG_CAVIUM_MAGIC 0xBEEF0004
+
+/* secure Random Number Generator */
+
+
+typedef struct RNG {
+    OS_Seed seed;
+    Arc4    cipher;
+#ifdef HAVE_CAVIUM
+    int    devId;           /* nitrox device id */
+    word32 magic;           /* using cavium magic */
+#endif
+} RNG;
+
+
+#endif /* HAVE_HASH_DRBG || NO_RC4 */
+
+#endif /* HAVE_FIPS */
+
+WOLFSSL_LOCAL
+int wc_GenerateSeed(OS_Seed* os, byte* seed, word32 sz);
+
+#if defined(HAVE_HASHDRBG) || defined(NO_RC4)
+
+#ifdef HAVE_CAVIUM
+    WOLFSSL_API int  wc_InitRngCavium(RNG*, int);
+#endif
+
+#endif /* HAVE_HASH_DRBG || NO_RC4 */
+
+
+WOLFSSL_API int  wc_InitRng(RNG*);
+WOLFSSL_API int  wc_RNG_GenerateBlock(RNG*, byte*, word32 sz);
+WOLFSSL_API int  wc_RNG_GenerateByte(RNG*, byte*);
+WOLFSSL_API int  wc_FreeRng(RNG*);
+
+
+#if defined(HAVE_HASHDRBG) || defined(NO_RC4)
+    WOLFSSL_API int wc_RNG_HealthTest(int reseed,
+                                        const byte* entropyA, word32 entropyASz,
+                                        const byte* entropyB, word32 entropyBSz,
+                                        byte* output, word32 outputSz);
+#endif /* HAVE_HASHDRBG || NO_RC4 */
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* WOLF_CRYPT_RANDOM_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/ripemd.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,64 @@
+/* ripemd.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_RIPEMD_H
+#define WOLF_CRYPT_RIPEMD_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef WOLFSSL_RIPEMD
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+/* in bytes */
+enum {
+    RIPEMD             =  3,    /* hash type unique */
+    RIPEMD_BLOCK_SIZE  = 64,
+    RIPEMD_DIGEST_SIZE = 20,
+    RIPEMD_PAD_SIZE    = 56
+};
+
+
+/* RipeMd 160 digest */
+typedef struct RipeMd {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word32  digest[RIPEMD_DIGEST_SIZE / sizeof(word32)];
+    word32  buffer[RIPEMD_BLOCK_SIZE  / sizeof(word32)];
+} RipeMd;
+
+
+WOLFSSL_API void wc_InitRipeMd(RipeMd*);
+WOLFSSL_API void wc_RipeMdUpdate(RipeMd*, const byte*, word32);
+WOLFSSL_API void wc_RipeMdFinal(RipeMd*, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* WOLFSSL_RIPEMD */
+#endif /* WOLF_CRYPT_RIPEMD_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/rsa.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,122 @@
+/* rsa.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_RSA_H
+#define WOLF_CRYPT_RSA_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifndef NO_RSA
+
+#ifdef HAVE_FIPS
+/* for fips @wc_fips */
+#include <cyassl/ctaocrypt/rsa.h>
+#if defined(CYASSL_KEY_GEN) && !defined(WOLFSSL_KEY_GEN)
+    #define WOLFSSL_KEY_GEN
+#endif
+#else
+    #include <wolfssl/wolfcrypt/integer.h>
+    #include <wolfssl/wolfcrypt/random.h>
+#endif /* HAVE_FIPS */
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#ifndef HAVE_FIPS /* avoid redefinition of structs */
+#define WOLFSSL_RSA_CAVIUM_MAGIC 0xBEEF0006
+
+enum {
+    RSA_PUBLIC   = 0,
+    RSA_PRIVATE  = 1
+};
+
+/* RSA */
+typedef struct RsaKey {
+    mp_int n, e, d, p, q, dP, dQ, u;
+    int   type;                               /* public or private */
+    void* heap;                               /* for user memory overrides */
+#ifdef HAVE_CAVIUM
+    int    devId;           /* nitrox device id */
+    word32 magic;           /* using cavium magic */
+    word64 contextHandle;   /* nitrox context memory handle */
+    byte*  c_n;             /* cavium byte buffers for key parts */
+    byte*  c_e;
+    byte*  c_d;
+    byte*  c_p;
+    byte*  c_q;
+    byte*  c_dP;
+    byte*  c_dQ;
+    byte*  c_u;             /* sizes in bytes */
+    word16 c_nSz, c_eSz, c_dSz, c_pSz, c_qSz, c_dP_Sz, c_dQ_Sz, c_uSz;
+#endif
+} RsaKey;
+#endif /*HAVE_FIPS */
+
+
+WOLFSSL_API int  wc_InitRsaKey(RsaKey* key, void*);
+WOLFSSL_API int  wc_FreeRsaKey(RsaKey* key);
+
+WOLFSSL_API int  wc_RsaPublicEncrypt(const byte* in, word32 inLen, byte* out,
+                                 word32 outLen, RsaKey* key, RNG* rng);
+WOLFSSL_API int  wc_RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out,
+                                        RsaKey* key);
+WOLFSSL_API int  wc_RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out,
+                                  word32 outLen, RsaKey* key);
+WOLFSSL_API int  wc_RsaSSL_Sign(const byte* in, word32 inLen, byte* out,
+                            word32 outLen, RsaKey* key, RNG* rng);
+WOLFSSL_API int  wc_RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out,
+                                    RsaKey* key);
+WOLFSSL_API int  wc_RsaSSL_Verify(const byte* in, word32 inLen, byte* out,
+                              word32 outLen, RsaKey* key);
+WOLFSSL_API int  wc_RsaEncryptSize(RsaKey* key);
+
+#ifndef HAVE_FIPS /* to avoid asn duplicate symbols @wc_fips */
+WOLFSSL_API int  wc_RsaPrivateKeyDecode(const byte* input, word32* inOutIdx,
+                                                               RsaKey*, word32);
+WOLFSSL_API int  wc_RsaPublicKeyDecode(const byte* input, word32* inOutIdx,
+                                                               RsaKey*, word32);
+WOLFSSL_API int  wc_RsaPublicKeyDecodeRaw(const byte* n, word32 nSz,
+                                        const byte* e, word32 eSz, RsaKey* key);
+#ifdef WOLFSSL_KEY_GEN
+    WOLFSSL_API int wc_RsaKeyToDer(RsaKey*, byte* output, word32 inLen);
+#endif
+#endif /* HAVE_FIPS*/
+WOLFSSL_API int  wc_RsaFlattenPublicKey(RsaKey*, byte*, word32*, byte*,
+                                                                       word32*);
+
+#ifdef WOLFSSL_KEY_GEN
+    WOLFSSL_API int wc_MakeRsaKey(RsaKey* key, int size, long e, RNG* rng);
+#endif
+
+#ifdef HAVE_CAVIUM
+    WOLFSSL_API int  wc_RsaInitCavium(RsaKey*, int);
+    WOLFSSL_API void wc_RsaFreeCavium(RsaKey*);
+#endif
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* NO_RSA */
+#endif /* WOLF_CRYPT_RSA_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/settings.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,802 @@
+/* settings.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+/* Place OS specific preprocessor flags, defines, includes here, will be
+   included into every file because types.h includes it */
+
+
+#ifndef WOLF_CRYPT_SETTINGS_H
+#define WOLF_CRYPT_SETTINGS_H
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* Uncomment next line if using IPHONE */
+/* #define IPHONE */
+
+/* Uncomment next line if using ThreadX */
+/* #define THREADX */
+
+/* Uncomment next line if using Micrium ucOS */
+/* #define MICRIUM */
+
+/* Uncomment next line if using Mbed */
+/* #define MBED */
+
+/* Uncomment next line if using Microchip PIC32 ethernet starter kit */
+/* #define MICROCHIP_PIC32 */
+
+/* Uncomment next line if using Microchip TCP/IP stack, version 5 */
+/* #define MICROCHIP_TCPIP_V5 */
+
+/* Uncomment next line if using Microchip TCP/IP stack, version 6 or later */
+/* #define MICROCHIP_TCPIP */
+
+/* Uncomment next line if using PIC32MZ Crypto Engine */
+/* #define WOLFSSL_MICROCHIP_PIC32MZ */
+
+/* Uncomment next line if using FreeRTOS */
+/* #define FREERTOS */
+
+/* Uncomment next line if using FreeRTOS Windows Simulator */
+/* #define FREERTOS_WINSIM */
+
+/* Uncomment next line if using RTIP */
+/* #define EBSNET */
+
+/* Uncomment next line if using lwip */
+/* #define WOLFSSL_LWIP */
+
+/* Uncomment next line if building wolfSSL for a game console */
+/* #define WOLFSSL_GAME_BUILD */
+
+/* Uncomment next line if building wolfSSL for LSR */
+/* #define WOLFSSL_LSR */
+
+/* Uncomment next line if building wolfSSL for Freescale MQX/RTCS/MFS */
+/* #define FREESCALE_MQX */
+
+/* Uncomment next line if using STM32F2 */
+/* #define WOLFSSL_STM32F2 */
+
+/* Uncomment next line if using Comverge settings */
+/* #define COMVERGE */
+
+/* Uncomment next line if using QL SEP settings */
+/* #define WOLFSSL_QL */
+
+/* Uncomment next line if building for EROAD */
+/* #define WOLFSSL_EROAD */
+
+/* Uncomment next line if building for IAR EWARM */
+/* #define WOLFSSL_IAR_ARM */
+
+/* Uncomment next line if using TI-RTOS settings */
+/* #define WOLFSSL_TIRTOS */
+
+/* Uncomment next line if building with PicoTCP */
+/* #define WOLFSSL_PICOTCP */
+
+/* Uncomment next line if building for PicoTCP demo bundle */
+/* #define WOLFSSL_PICOTCP_DEMO */
+
+/* Uncomment next line if building for uITRON4  */
+/* #define WOLFSSL_uITRON4 */
+
+/* Uncomment next line if building for uT-Kernel */
+/* #define WOLFSSL_uTKERNEL2 */
+
+/* Uncomment next line if using Max Strength build */
+/* #define WOLFSSL_MAX_STRENGTH */
+
+/* Uncomment next line if building for VxWorks */
+/* #define WOLFSSL_VXWORKS */
+
+#include <wolfssl/wolfcrypt/visibility.h>
+
+#define WOLFSSL_USER_SETTINGS
+#ifdef WOLFSSL_USER_SETTINGS
+    #include <user_settings.h>
+#endif
+
+
+#ifdef IPHONE
+    #define SIZEOF_LONG_LONG 8
+#endif
+
+
+#ifdef COMVERGE
+    #define THREADX
+    #define HAVE_NETX
+    #define WOLFSSL_USER_IO
+    #define NO_WRITEV
+    #define NO_DEV_RANDOM
+    #define NO_FILESYSTEM
+    #define NO_SHA512
+    #define NO_DH
+    #define NO_DSA
+    #define NO_HC128
+    #define NO_RSA
+    #define NO_SESSION_CACHE
+    #define HAVE_ECC
+#endif
+
+
+#ifdef THREADX
+    #define SIZEOF_LONG_LONG 8
+#endif
+
+#ifdef HAVE_NETX
+    #include "nx_api.h"
+#endif
+
+#if defined(HAVE_LWIP_NATIVE) /* using LwIP native TCP socket */
+    #define WOLFSSL_LWIP
+    #define NO_WRITEV
+    #define SINGLE_THREADED
+    #define WOLFSSL_USER_IO
+    #define NO_FILESYSTEM
+#endif
+
+#if defined(WOLFSSL_IAR_ARM)
+    #define NO_MAIN_DRIVER
+    #define SINGLE_THREADED
+    #define USE_CERT_BUFFERS_1024
+    #define BENCH_EMBEDDED
+    #define NO_FILESYSTEM
+    #define NO_WRITEV
+    #define WOLFSSL_USER_IO
+    #define  BENCH_EMBEDDED
+#endif
+
+#ifdef MICROCHIP_PIC32
+    /* #define WOLFSSL_MICROCHIP_PIC32MZ */
+    #define SIZEOF_LONG_LONG 8
+    #define SINGLE_THREADED
+    #define WOLFSSL_USER_IO
+    #define NO_WRITEV
+    #define NO_DEV_RANDOM
+    #define NO_FILESYSTEM
+    #define USE_FAST_MATH
+    #define TFM_TIMING_RESISTANT
+    #define NEED_AES_TABLES
+#endif
+
+#ifdef WOLFSSL_MICROCHIP_PIC32MZ
+    #define WOLFSSL_PIC32MZ_CE
+    #define WOLFSSL_PIC32MZ_CRYPT
+    #define HAVE_AES_ENGINE
+    #define WOLFSSL_PIC32MZ_RNG
+    /* #define WOLFSSL_PIC32MZ_HASH */
+    #define WOLFSSL_AES_COUNTER
+    #define HAVE_AESGCM
+    #define NO_BIG_INT
+#endif
+
+#ifdef MICROCHIP_TCPIP_V5
+    /* include timer functions */
+    #include "TCPIP Stack/TCPIP.h"
+#endif
+
+#ifdef MICROCHIP_TCPIP
+    /* include timer, NTP functions */
+    #ifdef MICROCHIP_MPLAB_HARMONY
+        #include "tcpip/tcpip.h"
+    #else
+        #include "system/system_services.h"
+        #include "tcpip/sntp.h"
+    #endif
+#endif
+
+#ifdef MBED
+    #define WOLFSSL_USER_IO
+    #define NO_FILESYSTEM
+    #define NO_CERT
+    #define USE_CERT_BUFFERS_1024
+    #define NO_WRITEV
+    #define NO_DEV_RANDOM
+    #define NO_SHA512
+    #define NO_DH
+    #define NO_DSA
+    #define NO_HC128
+    #define HAVE_ECC
+    #define NO_SESSION_CACHE
+    #define WOLFSSL_CMSIS_RTOS
+#endif
+
+
+#ifdef WOLFSSL_EROAD
+    #define FREESCALE_MQX
+    #define FREESCALE_MMCAU
+    #define SINGLE_THREADED
+    #define NO_STDIO_FILESYSTEM
+    #define WOLFSSL_LEANPSK
+    #define HAVE_NULL_CIPHER
+    #define NO_OLD_TLS
+    #define NO_ASN
+    #define NO_BIG_INT
+    #define NO_RSA
+    #define NO_DSA
+    #define NO_DH
+    #define NO_CERTS
+    #define NO_PWDBASED
+    #define NO_DES3
+    #define NO_MD4
+    #define NO_RC4
+    #define NO_MD5
+    #define NO_SESSION_CACHE
+    #define NO_MAIN_DRIVER
+#endif
+
+#ifdef WOLFSSL_PICOTCP
+    #ifndef errno
+        #define errno pico_err
+    #endif
+    #include "pico_defines.h"
+    #include "pico_stack.h"
+    #include "pico_constants.h"
+    #include "pico_protocol.h"
+    #define CUSTOM_RAND_GENERATE pico_rand
+#endif
+
+#ifdef WOLFSSL_PICOTCP_DEMO
+    #define WOLFSSL_STM32
+    #define USE_FAST_MATH
+    #define TFM_TIMING_RESISTANT
+    #define XMALLOC(s, h, type)  PICO_ZALLOC((s))
+    #define XFREE(p, h, type)    PICO_FREE((p))
+    #define SINGLE_THREADED
+    #define NO_WRITEV
+    #define WOLFSSL_USER_IO
+    #define NO_DEV_RANDOM
+    #define NO_FILESYSTEM
+#endif
+
+#ifdef FREERTOS_WINSIM
+    #define FREERTOS
+    #define USE_WINDOWS_API
+#endif
+
+
+#ifdef WOLFSSL_VXWORKS
+    #define NO_DEV_RANDOM
+    #define NO_WRITEV
+#endif
+
+
+/* Micrium will use Visual Studio for compilation but not the Win32 API */
+#if defined(_WIN32) && !defined(MICRIUM) && !defined(FREERTOS) \
+        && !defined(EBSNET) && !defined(WOLFSSL_EROAD)
+    #define USE_WINDOWS_API
+#endif
+
+
+#if defined(WOLFSSL_LEANPSK) && !defined(XMALLOC_USER)
+    #include <stdlib.h>
+    #define XMALLOC(s, h, type)  malloc((s))
+    #define XFREE(p, h, type)    free((p))
+    #define XREALLOC(p, n, h, t) realloc((p), (n))
+#endif
+
+#if defined(XMALLOC_USER) && defined(SSN_BUILDING_LIBYASSL)
+    #undef  XMALLOC
+    #define XMALLOC     yaXMALLOC
+    #undef  XFREE
+    #define XFREE       yaXFREE
+    #undef  XREALLOC
+    #define XREALLOC    yaXREALLOC
+#endif
+
+
+#ifdef FREERTOS
+    #ifndef NO_WRITEV
+        #define NO_WRITEV
+    #endif
+    #ifndef HAVE_SHA512
+        #ifndef NO_SHA512
+            #define NO_SHA512
+        #endif
+    #endif
+    #ifndef HAVE_DH
+        #ifndef NO_DH
+            #define NO_DH
+        #endif
+    #endif
+    #ifndef NO_DSA
+        #define NO_DSA
+    #endif
+    #ifndef NO_HC128
+        #define NO_HC128
+    #endif
+
+    #ifndef SINGLE_THREADED
+        #include "FreeRTOS.h"
+        #include "semphr.h"
+    #endif
+#endif
+
+#ifdef WOLFSSL_TIRTOS
+    #define SIZEOF_LONG_LONG 8
+    #define NO_WRITEV
+    #define NO_WOLFSSL_DIR
+    #define USE_FAST_MATH
+    #define TFM_TIMING_RESISTANT
+    #define NO_DEV_RANDOM
+    #define NO_FILESYSTEM
+    #define USE_CERT_BUFFERS_2048
+    #define NO_ERROR_STRINGS
+    #define USER_TIME
+
+    #ifdef __IAR_SYSTEMS_ICC__
+        #pragma diag_suppress=Pa089
+    #elif !defined(__GNUC__)
+        /* Suppress the sslpro warning */
+        #pragma diag_suppress=11
+    #endif
+
+    #include <ti/sysbios/hal/Seconds.h>
+#endif
+
+#ifdef EBSNET
+    #include "rtip.h"
+
+    /* #define DEBUG_WOLFSSL */
+    #define NO_WOLFSSL_DIR  /* tbd */
+
+    #if (POLLOS)
+        #define SINGLE_THREADED
+    #endif
+
+    #if (RTPLATFORM)
+        #if (!RTP_LITTLE_ENDIAN)
+            #define BIG_ENDIAN_ORDER
+        #endif
+    #else
+        #if (!KS_LITTLE_ENDIAN)
+            #define BIG_ENDIAN_ORDER
+        #endif
+    #endif
+
+    #if (WINMSP3)
+        #undef SIZEOF_LONG
+        #define SIZEOF_LONG_LONG 8
+    #else
+        #sslpro: settings.h - please implement SIZEOF_LONG and SIZEOF_LONG_LONG
+    #endif
+
+    #define XMALLOC(s, h, type) ((void *)rtp_malloc((s), SSL_PRO_MALLOC))
+    #define XFREE(p, h, type) (rtp_free(p))
+    #define XREALLOC(p, n, h, t) realloc((p), (n))
+
+#endif /* EBSNET */
+
+#ifdef WOLFSSL_GAME_BUILD
+    #define SIZEOF_LONG_LONG 8
+    #if defined(__PPU) || defined(__XENON)
+        #define BIG_ENDIAN_ORDER
+    #endif
+#endif
+
+#ifdef WOLFSSL_LSR
+    #define HAVE_WEBSERVER
+    #define SIZEOF_LONG_LONG 8
+    #define WOLFSSL_LOW_MEMORY
+    #define NO_WRITEV
+    #define NO_SHA512
+    #define NO_DH
+    #define NO_DSA
+    #define NO_HC128
+    #define NO_DEV_RANDOM
+    #define NO_WOLFSSL_DIR
+    #define NO_RABBIT
+    #ifndef NO_FILESYSTEM
+        #define LSR_FS
+        #include "inc/hw_types.h"
+        #include "fs.h"
+    #endif
+    #define WOLFSSL_LWIP
+    #include <errno.h>  /* for tcp errno */
+    #define WOLFSSL_SAFERTOS
+    #if defined(__IAR_SYSTEMS_ICC__)
+        /* enum uses enum */
+        #pragma diag_suppress=Pa089
+    #endif
+#endif
+
+#ifdef WOLFSSL_SAFERTOS
+    #ifndef SINGLE_THREADED
+        #include "SafeRTOS/semphr.h"
+    #endif
+
+    #include "SafeRTOS/heap.h"
+    #define XMALLOC(s, h, type)  pvPortMalloc((s))
+    #define XFREE(p, h, type)    vPortFree((p))
+    #define XREALLOC(p, n, h, t) pvPortRealloc((p), (n))
+#endif
+
+#ifdef WOLFSSL_LOW_MEMORY
+    #undef  RSA_LOW_MEM
+    #define RSA_LOW_MEM
+    #undef  WOLFSSL_SMALL_STACK
+    #define WOLFSSL_SMALL_STACK
+    #undef  TFM_TIMING_RESISTANT
+    #define TFM_TIMING_RESISTANT
+#endif
+
+#ifdef FREESCALE_MQX
+    #define SIZEOF_LONG_LONG 8
+    #define NO_WRITEV
+    #define NO_DEV_RANDOM
+    #define NO_RABBIT
+    #define NO_WOLFSSL_DIR
+    #define USE_FAST_MATH
+    #define TFM_TIMING_RESISTANT
+    #define FREESCALE_K70_RNGA
+    /* #define FREESCALE_K53_RNGB */
+    #include "mqx.h"
+    #ifndef NO_FILESYSTEM
+        #include "mfs.h"
+        #include "fio.h"
+    #endif
+    #ifndef SINGLE_THREADED
+        #include "mutex.h"
+    #endif
+
+    #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
+
+#ifdef WOLFSSL_STM32F2
+    #define SIZEOF_LONG_LONG 8
+    #define NO_DEV_RANDOM
+    #define NO_WOLFSSL_DIR
+    #define NO_RABBIT
+    #define STM32F2_RNG
+    #define STM32F2_CRYPTO
+    #define KEIL_INTRINSICS
+#endif
+
+#ifdef MICRIUM
+
+    #include "stdlib.h"
+    #include "net_cfg.h"
+    #include "ssl_cfg.h"
+    #include "net_secure_os.h"
+
+    #define WOLFSSL_TYPES
+
+    typedef CPU_INT08U byte;
+    typedef CPU_INT16U word16;
+    typedef CPU_INT32U word32;
+
+    #if (NET_SECURE_MGR_CFG_WORD_SIZE == CPU_WORD_SIZE_32)
+        #define SIZEOF_LONG        4
+        #undef  SIZEOF_LONG_LONG
+    #else
+        #undef  SIZEOF_LONG
+        #define SIZEOF_LONG_LONG   8
+    #endif
+
+    #define STRING_USER
+
+    #define XSTRLEN(pstr) ((CPU_SIZE_T)Str_Len((CPU_CHAR *)(pstr)))
+    #define XSTRNCPY(pstr_dest, pstr_src, len_max) \
+                    ((CPU_CHAR *)Str_Copy_N((CPU_CHAR *)(pstr_dest), \
+                     (CPU_CHAR *)(pstr_src), (CPU_SIZE_T)(len_max)))
+    #define XSTRNCMP(pstr_1, pstr_2, len_max) \
+                    ((CPU_INT16S)Str_Cmp_N((CPU_CHAR *)(pstr_1), \
+                     (CPU_CHAR *)(pstr_2), (CPU_SIZE_T)(len_max)))
+    #define XSTRSTR(pstr, pstr_srch) \
+                    ((CPU_CHAR *)Str_Str((CPU_CHAR *)(pstr), \
+                     (CPU_CHAR *)(pstr_srch)))
+    #define XMEMSET(pmem, data_val, size) \
+                    ((void)Mem_Set((void *)(pmem), (CPU_INT08U) (data_val), \
+                    (CPU_SIZE_T)(size)))
+    #define XMEMCPY(pdest, psrc, size) ((void)Mem_Copy((void *)(pdest), \
+                     (void *)(psrc), (CPU_SIZE_T)(size)))
+    #define XMEMCMP(pmem_1, pmem_2, size) \
+                   (((CPU_BOOLEAN)Mem_Cmp((void *)(pmem_1), (void *)(pmem_2), \
+                     (CPU_SIZE_T)(size))) ? DEF_NO : DEF_YES)
+    #define XMEMMOVE XMEMCPY
+
+#if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+    #define MICRIUM_MALLOC
+    #define XMALLOC(s, h, type) ((void *)NetSecure_BlkGet((CPU_INT08U)(type), \
+                                 (CPU_SIZE_T)(s), (void *)0))
+    #define XFREE(p, h, type)   (NetSecure_BlkFree((CPU_INT08U)(type), \
+                                 (p), (void *)0))
+    #define XREALLOC(p, n, h, t) realloc((p), (n))
+#endif
+
+    #if (NET_SECURE_MGR_CFG_FS_EN == DEF_ENABLED)
+        #undef  NO_FILESYSTEM
+    #else
+        #define NO_FILESYSTEM
+    #endif
+
+    #if (SSL_CFG_TRACE_LEVEL == WOLFSSL_TRACE_LEVEL_DBG)
+        #define DEBUG_WOLFSSL
+    #else
+        #undef  DEBUG_WOLFSSL
+    #endif
+
+    #if (SSL_CFG_OPENSSL_EN == DEF_ENABLED)
+        #define OPENSSL_EXTRA
+    #else
+        #undef  OPENSSL_EXTRA
+    #endif
+
+    #if (SSL_CFG_MULTI_THREAD_EN == DEF_ENABLED)
+        #undef  SINGLE_THREADED
+    #else
+        #define SINGLE_THREADED
+    #endif
+
+    #if (SSL_CFG_DH_EN == DEF_ENABLED)
+        #undef  NO_DH
+    #else
+        #define NO_DH
+    #endif
+
+    #if (SSL_CFG_DSA_EN == DEF_ENABLED)
+        #undef  NO_DSA
+    #else
+        #define NO_DSA
+    #endif
+
+    #if (SSL_CFG_PSK_EN == DEF_ENABLED)
+        #undef  NO_PSK
+    #else
+        #define NO_PSK
+    #endif
+
+    #if (SSL_CFG_3DES_EN == DEF_ENABLED)
+        #undef  NO_DES
+    #else
+        #define NO_DES
+    #endif
+
+    #if (SSL_CFG_AES_EN == DEF_ENABLED)
+        #undef  NO_AES
+    #else
+        #define NO_AES
+    #endif
+
+    #if (SSL_CFG_RC4_EN == DEF_ENABLED)
+        #undef  NO_RC4
+    #else
+        #define NO_RC4
+    #endif
+
+    #if (SSL_CFG_RABBIT_EN == DEF_ENABLED)
+        #undef  NO_RABBIT
+    #else
+        #define NO_RABBIT
+    #endif
+
+    #if (SSL_CFG_HC128_EN == DEF_ENABLED)
+        #undef  NO_HC128
+    #else
+        #define NO_HC128
+    #endif
+
+    #if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG)
+        #define BIG_ENDIAN_ORDER
+    #else
+        #undef  BIG_ENDIAN_ORDER
+        #define LITTLE_ENDIAN_ORDER
+    #endif
+
+    #if (SSL_CFG_MD4_EN == DEF_ENABLED)
+        #undef  NO_MD4
+    #else
+        #define NO_MD4
+    #endif
+
+    #if (SSL_CFG_WRITEV_EN == DEF_ENABLED)
+        #undef  NO_WRITEV
+    #else
+        #define NO_WRITEV
+    #endif
+
+    #if (SSL_CFG_USER_RNG_SEED_EN == DEF_ENABLED)
+        #define NO_DEV_RANDOM
+    #else
+        #undef  NO_DEV_RANDOM
+    #endif
+
+    #if (SSL_CFG_USER_IO_EN == DEF_ENABLED)
+        #define WOLFSSL_USER_IO
+    #else
+        #undef  WOLFSSL_USER_IO
+    #endif
+
+    #if (SSL_CFG_DYNAMIC_BUFFERS_EN == DEF_ENABLED)
+        #undef  LARGE_STATIC_BUFFERS
+        #undef  STATIC_CHUNKS_ONLY
+    #else
+        #define LARGE_STATIC_BUFFERS
+        #define STATIC_CHUNKS_ONLY
+    #endif
+
+    #if (SSL_CFG_DER_LOAD_EN == DEF_ENABLED)
+        #define  WOLFSSL_DER_LOAD
+    #else
+        #undef   WOLFSSL_DER_LOAD
+    #endif
+
+    #if (SSL_CFG_DTLS_EN == DEF_ENABLED)
+        #define  WOLFSSL_DTLS
+    #else
+        #undef   WOLFSSL_DTLS
+    #endif
+
+    #if (SSL_CFG_CALLBACKS_EN == DEF_ENABLED)
+         #define WOLFSSL_CALLBACKS
+    #else
+         #undef  WOLFSSL_CALLBACKS
+    #endif
+
+    #if (SSL_CFG_FAST_MATH_EN == DEF_ENABLED)
+         #define USE_FAST_MATH
+    #else
+         #undef  USE_FAST_MATH
+    #endif
+
+    #if (SSL_CFG_TFM_TIMING_RESISTANT_EN == DEF_ENABLED)
+         #define TFM_TIMING_RESISTANT
+    #else
+         #undef  TFM_TIMING_RESISTANT
+    #endif
+
+#endif /* MICRIUM */
+
+
+#ifdef WOLFSSL_QL
+    #ifndef WOLFSSL_SEP
+        #define WOLFSSL_SEP
+    #endif
+    #ifndef OPENSSL_EXTRA
+        #define OPENSSL_EXTRA
+    #endif
+    #ifndef SESSION_CERTS
+        #define SESSION_CERTS
+    #endif
+    #ifndef HAVE_AESCCM
+        #define HAVE_AESCCM
+    #endif
+    #ifndef ATOMIC_USER
+        #define ATOMIC_USER
+    #endif
+    #ifndef WOLFSSL_DER_LOAD
+        #define WOLFSSL_DER_LOAD
+    #endif
+    #ifndef KEEP_PEER_CERT
+        #define KEEP_PEER_CERT
+    #endif
+    #ifndef HAVE_ECC
+        #define HAVE_ECC
+    #endif
+    #ifndef SESSION_INDEX
+        #define SESSION_INDEX
+    #endif
+#endif /* WOLFSSL_QL */
+
+
+#if !defined(XMALLOC_USER) && !defined(MICRIUM_MALLOC) && \
+    !defined(WOLFSSL_LEANPSK) && !defined(NO_WOLFSSL_MEMORY)
+    #define USE_WOLFSSL_MEMORY
+#endif
+
+
+#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS)
+    #undef  KEEP_PEER_CERT
+    #define KEEP_PEER_CERT
+#endif
+
+
+/* stream ciphers except arc4 need 32bit alignment, intel ok without */
+#ifndef XSTREAM_ALIGN
+    #if defined(__x86_64__) || defined(__ia64__) || defined(__i386__)
+        #define NO_XSTREAM_ALIGN
+    #else
+        #define XSTREAM_ALIGN
+    #endif
+#endif
+
+
+/* FreeScale MMCAU hardware crypto has 4 byte alignment */
+#ifdef FREESCALE_MMCAU
+    #define WOLFSSL_MMCAU_ALIGNMENT 4
+#endif
+
+/* if using hardware crypto and have alignment requirements, specify the
+   requirement here.  The record header of SSL/TLS will prvent easy alignment.
+   This hint tries to help as much as possible.  */
+#ifndef WOLFSSL_GENERAL_ALIGNMENT
+    #ifdef WOLFSSL_AESNI
+        #define WOLFSSL_GENERAL_ALIGNMENT 16
+    #elif defined(XSTREAM_ALIGN)
+        #define WOLFSSL_GENERAL_ALIGNMENT  4
+    #elif defined(FREESCALE_MMCAU)
+        #define WOLFSSL_GENERAL_ALIGNMENT  WOLFSSL_MMCAU_ALIGNMENT
+    #else
+        #define WOLFSSL_GENERAL_ALIGNMENT  0
+    #endif
+#endif
+
+#if defined(WOLFSSL_GENERAL_ALIGNMENT) && (WOLFSSL_GENERAL_ALIGNMENT > 0)
+    #if defined(_MSC_VER)
+        #define XGEN_ALIGN __declspec(align(WOLFSSL_GENERAL_ALIGNMENT))
+    #elif defined(__GNUC__)
+        #define XGEN_ALIGN __attribute__((aligned(WOLFSSL_GENERAL_ALIGNMENT)))
+    #else
+        #define XGEN_ALIGN
+    #endif
+#else
+    #define XGEN_ALIGN
+#endif
+
+#ifdef HAVE_CRL
+    /* not widely supported yet */
+    #undef NO_SKID
+    #define NO_SKID
+#endif
+
+
+#ifdef __INTEL_COMPILER
+    #pragma warning(disable:2259) /* explicit casts to smaller sizes, disable */
+#endif
+
+/* user can specify what curves they want with ECC_USER_CURVES otherwise
+ * all curves are on by default for now */
+#ifndef ECC_USER_CURVES
+    #ifndef HAVE_ALL_CURVES
+        #define HAVE_ALL_CURVES
+    #endif
+#endif
+
+/* if desktop type system and fastmath increase default max bits */
+#ifdef WOLFSSL_X86_64_BUILD
+    #ifdef USE_FAST_MATH
+        #ifndef FP_MAX_BITS
+            #define FP_MAX_BITS 8192
+        #endif
+    #endif
+#endif
+
+/* If using the max strength build, ensure OLD TLS is disabled. */
+#ifdef WOLFSSL_MAX_STRENGTH
+    #undef NO_OLD_TLS
+    #define NO_OLD_TLS
+#endif
+
+/* Place any other flags or defines here */
+
+
+#ifdef __cplusplus
+    }   /* extern "C" */
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/sha.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,88 @@
+/* sha.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_SHA_H
+#define WOLF_CRYPT_SHA_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifndef NO_SHA
+
+#ifdef HAVE_FIPS
+/* for fips @wc_fips */
+#include <cyassl/ctaocrypt/sha.h>
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#ifndef HAVE_FIPS /* avoid redefining structs */
+/* in bytes */
+enum {
+#ifdef STM32F2_HASH
+    SHA_REG_SIZE     =  4,    /* STM32 register size, bytes */
+#endif
+    SHA              =  1,    /* hash type unique */
+    SHA_BLOCK_SIZE   = 64,
+    SHA_DIGEST_SIZE  = 20,
+    SHA_PAD_SIZE     = 56
+};
+
+#ifdef WOLFSSL_PIC32MZ_HASH
+#include "port/pic32/pic32mz-crypt.h"
+#endif
+
+#ifndef WOLFSSL_TI_HASH
+      
+/* Sha digest */
+typedef struct Sha {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word32  buffer[SHA_BLOCK_SIZE  / sizeof(word32)];
+    #ifndef WOLFSSL_PIC32MZ_HASH
+        word32  digest[SHA_DIGEST_SIZE / sizeof(word32)];
+    #else
+        word32  digest[PIC32_HASH_SIZE / sizeof(word32)];
+        pic32mz_desc desc; /* Crypt Engine descripter */
+    #endif
+} Sha;
+
+#else /* WOLFSSL_TI_HASH */
+    #include "wolfssl/wolfcrypt/port/ti/ti-hash.h"
+#endif
+
+#endif /* HAVE_FIPS */
+
+WOLFSSL_API int wc_InitSha(Sha*);
+WOLFSSL_API int wc_ShaUpdate(Sha*, const byte*, word32);
+WOLFSSL_API int wc_ShaFinal(Sha*, byte*);
+WOLFSSL_API int wc_ShaHash(const byte*, word32, byte*);
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* NO_SHA */
+#endif /* WOLF_CRYPT_SHA_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/sha256.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,86 @@
+/* sha256.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+/* code submitted by raphael.huck@efixo.com */
+
+#ifndef WOLF_CRYPT_SHA256_H
+#define WOLF_CRYPT_SHA256_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifndef NO_SHA256
+
+#ifdef HAVE_FIPS
+    /* for fips @wc_fips */
+    #include <cyassl/ctaocrypt/sha256.h>
+#endif
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#ifndef HAVE_FIPS /* avoid redefinition of structs */
+#ifdef WOLFSSL_PIC32MZ_HASH
+    #include "port/pic32/pic32mz-crypt.h"
+#endif
+
+/* in bytes */
+enum {
+    SHA256              =  2,   /* hash type unique */
+    SHA256_BLOCK_SIZE   = 64,
+    SHA256_DIGEST_SIZE  = 32,
+    SHA256_PAD_SIZE     = 56
+};
+
+#ifndef WOLFSSL_TI_HASH
+
+/* Sha256 digest */
+typedef struct Sha256 {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word32  digest[SHA256_DIGEST_SIZE / sizeof(word32)];
+    word32  buffer[SHA256_BLOCK_SIZE  / sizeof(word32)];
+    #ifdef WOLFSSL_PIC32MZ_HASH
+        pic32mz_desc desc ; /* Crypt Engine descripter */
+    #endif
+} Sha256;
+
+#else /* WOLFSSL_TI_HASH */
+    #include "wolfssl/wolfcrypt/port/ti/ti-hash.h"
+#endif
+
+#endif /* HAVE_FIPS */
+
+WOLFSSL_API int wc_InitSha256(Sha256*);
+WOLFSSL_API int wc_Sha256Update(Sha256*, const byte*, word32);
+WOLFSSL_API int wc_Sha256Final(Sha256*, byte*);
+WOLFSSL_API int wc_Sha256Hash(const byte*, word32, byte*);
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* NO_SHA256 */
+#endif /* WOLF_CRYPT_SHA256_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/sha512.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,105 @@
+/* sha512.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+#ifndef WOLF_CRYPT_SHA512_H
+#define WOLF_CRYPT_SHA512_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef WOLFSSL_SHA512
+
+/* for fips @wc_fips */
+#ifdef HAVE_FIPS
+    #define CYASSL_SHA512
+    #if defined(WOLFSSL_SHA384)
+        #define CYASSL_SHA384
+    #endif
+    #include <cyassl/ctaocrypt/sha512.h>
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#ifndef HAVE_FIPS /* avoid redefinition of structs */
+
+/* in bytes */
+enum {
+    SHA512              =   4,   /* hash type unique */
+    SHA512_BLOCK_SIZE   = 128,
+    SHA512_DIGEST_SIZE  =  64,
+    SHA512_PAD_SIZE     = 112
+};
+
+
+/* Sha512 digest */
+typedef struct Sha512 {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word64  digest[SHA512_DIGEST_SIZE / sizeof(word64)];
+    word64  buffer[SHA512_BLOCK_SIZE  / sizeof(word64)];
+} Sha512;
+
+#endif /* HAVE_FIPS */
+
+WOLFSSL_API int wc_InitSha512(Sha512*);
+WOLFSSL_API int wc_Sha512Update(Sha512*, const byte*, word32);
+WOLFSSL_API int wc_Sha512Final(Sha512*, byte*);
+WOLFSSL_API int wc_Sha512Hash(const byte*, word32, byte*);
+
+#if defined(WOLFSSL_SHA384)
+
+#ifndef HAVE_FIPS /* avoid redefinition of structs */
+/* in bytes */
+enum {
+    SHA384              =   5,   /* hash type unique */
+    SHA384_BLOCK_SIZE   = 128,
+    SHA384_DIGEST_SIZE  =  48,
+    SHA384_PAD_SIZE     = 112
+};
+
+
+/* Sha384 digest */
+typedef struct Sha384 {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word64  digest[SHA512_DIGEST_SIZE / sizeof(word64)]; /* for transform 512 */
+    word64  buffer[SHA384_BLOCK_SIZE  / sizeof(word64)];
+} Sha384;
+#endif /* HAVE_FIPS */
+
+WOLFSSL_API int wc_InitSha384(Sha384*);
+WOLFSSL_API int wc_Sha384Update(Sha384*, const byte*, word32);
+WOLFSSL_API int wc_Sha384Final(Sha384*, byte*);
+WOLFSSL_API int wc_Sha384Hash(const byte*, word32, byte*);
+
+#endif /* WOLFSSL_SHA384 */
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* WOLFSSL_SHA512 */
+#endif /* WOLF_CRYPT_SHA512_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/tfm.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,721 @@
+/* tfm.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+/*
+ * Based on public domain TomsFastMath 0.10 by Tom St Denis, tomstdenis@iahu.ca,
+ * http://math.libtomcrypt.com
+ */
+
+
+/**
+ *  Edited by Moisés Guimarães (moises.guimaraes@phoebus.com.br)
+ *  to fit CyaSSL's needs.
+ */
+
+
+#ifndef WOLF_CRYPT_TFM_H
+#define WOLF_CRYPT_TFM_H
+
+#include <wolfssl/wolfcrypt/types.h>
+#ifndef CHAR_BIT
+    #include <limits.h>
+#endif
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#ifndef MIN
+   #define MIN(x,y) ((x)<(y)?(x):(y))
+#endif
+
+#ifndef MAX
+   #define MAX(x,y) ((x)>(y)?(x):(y))
+#endif
+
+
+#ifndef NO_64BIT
+/* autodetect x86-64 and make sure we are using 64-bit digits with x86-64 asm */
+#if defined(__x86_64__)
+   #if defined(TFM_X86) || defined(TFM_SSE2) || defined(TFM_ARM)
+       #error x86-64 detected, x86-32/SSE2/ARM optimizations are not valid!
+   #endif
+   #if !defined(TFM_X86_64) && !defined(TFM_NO_ASM)
+      #define TFM_X86_64
+   #endif
+#endif
+#if defined(TFM_X86_64)
+    #if !defined(FP_64BIT)
+       #define FP_64BIT
+    #endif
+#endif
+/* use 64-bit digit even if not using asm on x86_64 */
+#if defined(__x86_64__) && !defined(FP_64BIT)
+    #define FP_64BIT
+#endif
+/* if intel compiler doesn't provide 128 bit type don't turn on 64bit */
+#if defined(FP_64BIT) && defined(__INTEL_COMPILER) && !defined(HAVE___UINT128_T)
+    #undef FP_64BIT
+    #undef TFM_X86_64
+#endif
+#endif /* NO_64BIT */
+
+/* try to detect x86-32 */
+#if defined(__i386__) && !defined(TFM_SSE2)
+   #if defined(TFM_X86_64) || defined(TFM_ARM)
+       #error x86-32 detected, x86-64/ARM optimizations are not valid!
+   #endif
+   #if !defined(TFM_X86) && !defined(TFM_NO_ASM)
+      #define TFM_X86
+   #endif
+#endif
+
+/* make sure we're 32-bit for x86-32/sse/arm/ppc32 */
+#if (defined(TFM_X86) || defined(TFM_SSE2) || defined(TFM_ARM) || defined(TFM_PPC32)) && defined(FP_64BIT)
+   #warning x86-32, SSE2 and ARM, PPC32 optimizations require 32-bit digits (undefining)
+   #undef FP_64BIT
+#endif
+
+/* multi asms? */
+#ifdef TFM_X86
+   #define TFM_ASM
+#endif
+#ifdef TFM_X86_64
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+#ifdef TFM_SSE2
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+#ifdef TFM_ARM
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+#ifdef TFM_PPC32
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+#ifdef TFM_PPC64
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+#ifdef TFM_AVR32
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+
+/* we want no asm? */
+#ifdef TFM_NO_ASM
+   #undef TFM_X86
+   #undef TFM_X86_64
+   #undef TFM_SSE2
+   #undef TFM_ARM
+   #undef TFM_PPC32
+   #undef TFM_PPC64
+   #undef TFM_AVR32
+   #undef TFM_ASM
+#endif
+
+/* ECC helpers */
+#ifdef TFM_ECC192
+   #ifdef FP_64BIT
+       #define TFM_MUL3
+       #define TFM_SQR3
+   #else
+       #define TFM_MUL6
+       #define TFM_SQR6
+   #endif
+#endif
+
+#ifdef TFM_ECC224
+   #ifdef FP_64BIT
+       #define TFM_MUL4
+       #define TFM_SQR4
+   #else
+       #define TFM_MUL7
+       #define TFM_SQR7
+   #endif
+#endif
+
+#ifdef TFM_ECC256
+   #ifdef FP_64BIT
+       #define TFM_MUL4
+       #define TFM_SQR4
+   #else
+       #define TFM_MUL8
+       #define TFM_SQR8
+   #endif
+#endif
+
+#ifdef TFM_ECC384
+   #ifdef FP_64BIT
+       #define TFM_MUL6
+       #define TFM_SQR6
+   #else
+       #define TFM_MUL12
+       #define TFM_SQR12
+   #endif
+#endif
+
+#ifdef TFM_ECC521
+   #ifdef FP_64BIT
+       #define TFM_MUL9
+       #define TFM_SQR9
+   #else
+       #define TFM_MUL17
+       #define TFM_SQR17
+   #endif
+#endif
+
+
+/* some default configurations.
+ */
+#if defined(FP_64BIT)
+   /* for GCC only on supported platforms */
+   typedef unsigned long long fp_digit;   /* 64bit, 128 uses mode(TI) below */
+   typedef unsigned long      fp_word __attribute__ ((mode(TI)));
+#else
+   #if defined(_MSC_VER) || defined(__BORLANDC__)
+      typedef unsigned __int64   ulong64;
+   #else
+      typedef unsigned long long ulong64;
+   #endif
+
+   #ifndef NO_64BIT
+      typedef unsigned int       fp_digit;
+      typedef ulong64            fp_word;
+      #define FP_32BIT
+   #else
+      /* some procs like coldfire prefer not to place multiply into 64bit type
+         even though it exists */
+      typedef unsigned short     fp_digit;
+      typedef unsigned int       fp_word;
+   #endif
+#endif
+
+/* # of digits this is */
+#define DIGIT_BIT  (int)((CHAR_BIT) * sizeof(fp_digit))
+
+/* Max size of any number in bits.  Basically the largest size you will be
+ * multiplying should be half [or smaller] of FP_MAX_SIZE-four_digit
+ *
+ * It defaults to 4096-bits [allowing multiplications upto 2048x2048 bits ]
+ */
+#ifndef FP_MAX_BITS
+    #define FP_MAX_BITS           4096
+#endif
+#define FP_MAX_SIZE           (FP_MAX_BITS+(8*DIGIT_BIT))
+
+/* will this lib work? */
+#if (CHAR_BIT & 7)
+   #error CHAR_BIT must be a multiple of eight.
+#endif
+#if FP_MAX_BITS % CHAR_BIT
+   #error FP_MAX_BITS must be a multiple of CHAR_BIT
+#endif
+
+#define FP_MASK    (fp_digit)(-1)
+#define FP_SIZE    (FP_MAX_SIZE/DIGIT_BIT)
+
+/* signs */
+#define FP_ZPOS     0
+#define FP_NEG      1
+
+/* return codes */
+#define FP_OKAY     0
+#define FP_VAL      1
+#define FP_MEM      2
+
+/* equalities */
+#define FP_LT        -1   /* less than */
+#define FP_EQ         0   /* equal to */
+#define FP_GT         1   /* greater than */
+
+/* replies */
+#define FP_YES        1   /* yes response */
+#define FP_NO         0   /* no response */
+
+/* a FP type */
+typedef struct {
+    int      used,
+             sign;
+#ifdef ALT_ECC_SIZE
+    int      size;
+#endif
+    fp_digit dp[FP_SIZE];
+} fp_int;
+
+/* externally define this symbol to ignore the default settings, useful for changing the build from the make process */
+#ifndef TFM_ALREADY_SET
+
+/* do we want the large set of small multiplications ?
+   Enable these if you are going to be doing a lot of small (<= 16 digit) multiplications say in ECC
+   Or if you're on a 64-bit machine doing RSA as a 1024-bit integer == 16 digits ;-)
+ */
+/* need to refactor the function */
+/*#define TFM_SMALL_SET */
+
+/* do we want huge code
+   Enable these if you are doing 20, 24, 28, 32, 48, 64 digit multiplications (useful for RSA)
+   Less important on 64-bit machines as 32 digits == 2048 bits
+ */
+#if 0
+#define TFM_MUL3
+#define TFM_MUL4
+#define TFM_MUL6
+#define TFM_MUL7
+#define TFM_MUL8
+#define TFM_MUL9
+#define TFM_MUL12
+#define TFM_MUL17
+#endif
+#ifdef TFM_HUGE_SET
+#define TFM_MUL20
+#define TFM_MUL24
+#define TFM_MUL28
+#define TFM_MUL32
+#if (FP_MAX_BITS >= 6144) && defined(FP_64BIT)
+    #define TFM_MUL48
+#endif
+#if (FP_MAX_BITS >= 8192) && defined(FP_64BIT)
+    #define TFM_MUL64
+#endif
+#endif
+
+#if 0
+#define TFM_SQR3
+#define TFM_SQR4
+#define TFM_SQR6
+#define TFM_SQR7
+#define TFM_SQR8
+#define TFM_SQR9
+#define TFM_SQR12
+#define TFM_SQR17
+#endif
+#ifdef TFM_HUGE_SET
+#define TFM_SQR20
+#define TFM_SQR24
+#define TFM_SQR28
+#define TFM_SQR32
+#define TFM_SQR48
+#define TFM_SQR64
+#endif
+
+/* do we want some overflow checks
+   Not required if you make sure your numbers are within range (e.g. by default a modulus for fp_exptmod() can only be upto 2048 bits long)
+ */
+/* #define TFM_CHECK */
+
+/* Is the target a P4 Prescott
+ */
+/* #define TFM_PRESCOTT */
+
+/* Do we want timing resistant fp_exptmod() ?
+ * This makes it slower but also timing invariant with respect to the exponent 
+ */
+/* #define TFM_TIMING_RESISTANT */
+
+#endif /* TFM_ALREADY_SET */
+
+/* functions */
+
+/* returns a TFM ident string useful for debugging... */
+/*const char *fp_ident(void);*/
+
+/* initialize [or zero] an fp int */
+#ifdef ALT_ECC_SIZE
+    void fp_init(fp_int *a);
+    void fp_zero(fp_int *a);
+#else
+    #define fp_init(a)  (void)XMEMSET((a), 0, sizeof(fp_int))
+    #define fp_zero(a)  fp_init(a)
+#endif
+
+/* zero/even/odd ? */
+#define fp_iszero(a) (((a)->used == 0) ? FP_YES : FP_NO)
+#define fp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? FP_YES : FP_NO)
+#define fp_isodd(a)  (((a)->used > 0  && (((a)->dp[0] & 1) == 1)) ? FP_YES : FP_NO)
+
+/* set to a small digit */
+void fp_set(fp_int *a, fp_digit b);
+
+/* copy from a to b */
+#ifndef ALT_ECC_SIZE
+    #define fp_copy(a, b)  (void)(((a) != (b)) ? ((void)XMEMCPY((b), (a), sizeof(fp_int))) : (void)0)
+    #define fp_init_copy(a, b) fp_copy(b, a)
+#else
+    void fp_copy(fp_int *a, fp_int *b);
+    void fp_init_copy(fp_int *a, fp_int *b);
+#endif
+
+/* clamp digits */
+#define fp_clamp(a)   { while ((a)->used && (a)->dp[(a)->used-1] == 0) --((a)->used); (a)->sign = (a)->used ? (a)->sign : FP_ZPOS; }
+
+/* negate and absolute */
+#define fp_neg(a, b)  { fp_copy(a, b); (b)->sign ^= 1; fp_clamp(b); }
+#define fp_abs(a, b)  { fp_copy(a, b); (b)->sign  = 0; }
+
+/* right shift x digits */
+void fp_rshd(fp_int *a, int x);
+
+/* right shift x bits */
+void fp_rshb(fp_int *a, int x);
+
+/* left shift x digits */
+void fp_lshd(fp_int *a, int x);
+
+/* signed comparison */
+int fp_cmp(fp_int *a, fp_int *b);
+
+/* unsigned comparison */
+int fp_cmp_mag(fp_int *a, fp_int *b);
+
+/* power of 2 operations */
+void fp_div_2d(fp_int *a, int b, fp_int *c, fp_int *d);
+void fp_mod_2d(fp_int *a, int b, fp_int *c);
+void fp_mul_2d(fp_int *a, int b, fp_int *c);
+void fp_2expt (fp_int *a, int b);
+void fp_mul_2(fp_int *a, fp_int *c);
+void fp_div_2(fp_int *a, fp_int *c);
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int fp_cnt_lsb(fp_int *a);
+
+/* c = a + b */
+void fp_add(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = a - b */
+void fp_sub(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = a * b */
+void fp_mul(fp_int *a, fp_int *b, fp_int *c);
+
+/* b = a*a  */
+void fp_sqr(fp_int *a, fp_int *b);
+
+/* a/b => cb + d == a */
+int fp_div(fp_int *a, fp_int *b, fp_int *c, fp_int *d);
+
+/* c = a mod b, 0 <= c < b  */
+int fp_mod(fp_int *a, fp_int *b, fp_int *c);
+
+/* compare against a single digit */
+int fp_cmp_d(fp_int *a, fp_digit b);
+
+/* c = a + b */
+void fp_add_d(fp_int *a, fp_digit b, fp_int *c);
+
+/* c = a - b */
+void fp_sub_d(fp_int *a, fp_digit b, fp_int *c);
+
+/* c = a * b */
+void fp_mul_d(fp_int *a, fp_digit b, fp_int *c);
+
+/* a/b => cb + d == a */
+/*int fp_div_d(fp_int *a, fp_digit b, fp_int *c, fp_digit *d);*/
+
+/* c = a mod b, 0 <= c < b  */
+/*int fp_mod_d(fp_int *a, fp_digit b, fp_digit *c);*/
+
+/* ---> number theory <--- */
+/* d = a + b (mod c) */
+/*int fp_addmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);*/
+
+/* d = a - b (mod c) */
+/*int fp_submod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);*/
+
+/* d = a * b (mod c) */
+int fp_mulmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);
+
+/* c = a * a (mod b) */
+int fp_sqrmod(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = 1/a (mod b) */
+int fp_invmod(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = (a, b) */
+/*void fp_gcd(fp_int *a, fp_int *b, fp_int *c);*/
+
+/* c = [a, b] */
+/*void fp_lcm(fp_int *a, fp_int *b, fp_int *c);*/
+
+/* setups the montgomery reduction */
+int fp_montgomery_setup(fp_int *a, fp_digit *mp);
+
+/* computes a = B**n mod b without division or multiplication useful for
+ * normalizing numbers in a Montgomery system.
+ */
+void fp_montgomery_calc_normalization(fp_int *a, fp_int *b);
+
+/* computes x/R == x (mod N) via Montgomery Reduction */
+void fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp);
+
+/* d = a**b (mod c) */
+int fp_exptmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);
+
+/* primality stuff */
+
+/* perform a Miller-Rabin test of a to the base b and store result in "result" */
+/*void fp_prime_miller_rabin (fp_int * a, fp_int * b, int *result);*/
+
+/* 256 trial divisions + 8 Miller-Rabins, returns FP_YES if probable prime  */
+/*int fp_isprime(fp_int *a);*/
+
+/* Primality generation flags */
+/*#define TFM_PRIME_BBS      0x0001 */ /* BBS style prime */
+/*#define TFM_PRIME_SAFE     0x0002 */ /* Safe prime (p-1)/2 == prime */
+/*#define TFM_PRIME_2MSB_OFF 0x0004 */ /* force 2nd MSB to 0 */
+/*#define TFM_PRIME_2MSB_ON  0x0008 */ /* force 2nd MSB to 1 */
+
+/* callback for fp_prime_random, should fill dst with random bytes and return how many read [upto len] */
+/*typedef int tfm_prime_callback(unsigned char *dst, int len, void *dat);*/
+
+/*#define fp_prime_random(a, t, size, bbs, cb, dat) fp_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?TFM_PRIME_BBS:0, cb, dat)*/
+
+/*int fp_prime_random_ex(fp_int *a, int t, int size, int flags, tfm_prime_callback cb, void *dat);*/
+
+/* radix conersions */
+int fp_count_bits(fp_int *a);
+int fp_leading_bit(fp_int *a);
+
+int fp_unsigned_bin_size(fp_int *a);
+void fp_read_unsigned_bin(fp_int *a, unsigned char *b, int c);
+void fp_to_unsigned_bin(fp_int *a, unsigned char *b);
+
+/*int fp_signed_bin_size(fp_int *a);*/
+/*void fp_read_signed_bin(fp_int *a, unsigned char *b, int c);*/
+/*void fp_to_signed_bin(fp_int *a, unsigned char *b);*/
+
+/*int fp_read_radix(fp_int *a, char *str, int radix);*/
+/*int fp_toradix(fp_int *a, char *str, int radix);*/
+/*int fp_toradix_n(fp_int * a, char *str, int radix, int maxlen);*/
+
+
+/* VARIOUS LOW LEVEL STUFFS */
+void s_fp_add(fp_int *a, fp_int *b, fp_int *c);
+void s_fp_sub(fp_int *a, fp_int *b, fp_int *c);
+void fp_reverse(unsigned char *s, int len);
+
+void fp_mul_comba(fp_int *a, fp_int *b, fp_int *c);
+
+#ifdef TFM_SMALL_SET
+void fp_mul_comba_small(fp_int *a, fp_int *b, fp_int *c);
+#endif
+
+#ifdef TFM_MUL3
+void fp_mul_comba3(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL4
+void fp_mul_comba4(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL6
+void fp_mul_comba6(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL7
+void fp_mul_comba7(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL8
+void fp_mul_comba8(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL9
+void fp_mul_comba9(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL12
+void fp_mul_comba12(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL17
+void fp_mul_comba17(fp_int *a, fp_int *b, fp_int *c);
+#endif
+
+#ifdef TFM_MUL20
+void fp_mul_comba20(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL24
+void fp_mul_comba24(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL28
+void fp_mul_comba28(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL32
+void fp_mul_comba32(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL48
+void fp_mul_comba48(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL64
+void fp_mul_comba64(fp_int *a, fp_int *b, fp_int *c);
+#endif
+
+void fp_sqr_comba(fp_int *a, fp_int *b);
+
+#ifdef TFM_SMALL_SET
+void fp_sqr_comba_small(fp_int *a, fp_int *b);
+#endif
+
+#ifdef TFM_SQR3
+void fp_sqr_comba3(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR4
+void fp_sqr_comba4(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR6
+void fp_sqr_comba6(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR7
+void fp_sqr_comba7(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR8
+void fp_sqr_comba8(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR9
+void fp_sqr_comba9(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR12
+void fp_sqr_comba12(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR17
+void fp_sqr_comba17(fp_int *a, fp_int *b);
+#endif
+
+#ifdef TFM_SQR20
+void fp_sqr_comba20(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR24
+void fp_sqr_comba24(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR28
+void fp_sqr_comba28(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR32
+void fp_sqr_comba32(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR48
+void fp_sqr_comba48(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR64
+void fp_sqr_comba64(fp_int *a, fp_int *b);
+#endif
+/*extern const char *fp_s_rmap;*/
+
+
+/**
+ * Used by wolfSSL
+ */
+
+/* Types */
+    typedef fp_digit mp_digit;
+    typedef fp_word  mp_word;
+    typedef fp_int mp_int;
+
+/* Constants */
+    #define MP_LT   FP_LT   /* less than    */
+    #define MP_EQ   FP_EQ   /* equal to     */
+    #define MP_GT   FP_GT   /* greater than */
+    #define MP_VAL  FP_VAL  /* invalid */
+    #define MP_OKAY FP_OKAY /* ok result    */
+    #define MP_NO   FP_NO   /* yes/no result */
+    #define MP_YES  FP_YES  /* yes/no result */
+
+/* Prototypes */
+#define mp_zero(a)  fp_zero(a)
+#define mp_iseven(a)  fp_iseven(a)
+int  mp_init (mp_int * a);
+void mp_clear (mp_int * a);
+int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e, mp_int* f);
+
+int  mp_add (mp_int * a, mp_int * b, mp_int * c);
+int  mp_sub (mp_int * a, mp_int * b, mp_int * c);
+int  mp_add_d (mp_int * a, mp_digit b, mp_int * c);
+
+int  mp_mul (mp_int * a, mp_int * b, mp_int * c);
+int  mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d);
+int  mp_mod(mp_int *a, mp_int *b, mp_int *c);
+int  mp_invmod(mp_int *a, mp_int *b, mp_int *c);
+int  mp_exptmod (mp_int * g, mp_int * x, mp_int * p, mp_int * y);
+
+int  mp_cmp(mp_int *a, mp_int *b);
+int  mp_cmp_d(mp_int *a, mp_digit b);
+
+int  mp_unsigned_bin_size(mp_int * a);
+int  mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c);
+int  mp_to_unsigned_bin (mp_int * a, unsigned char *b);
+
+int  mp_sub_d(fp_int *a, fp_digit b, fp_int *c);
+int  mp_copy(fp_int* a, fp_int* b);
+int  mp_isodd(mp_int* a);
+int  mp_iszero(mp_int* a);
+int  mp_count_bits(mp_int *a);
+int  mp_leading_bit(mp_int *a);
+int  mp_set_int(fp_int *a, fp_digit b);
+void mp_rshb(mp_int *a, int x);
+
+#ifdef HAVE_ECC
+    int mp_read_radix(mp_int* a, const char* str, int radix);
+    void mp_set(fp_int *a, fp_digit b);
+    int mp_sqr(fp_int *a, fp_int *b);
+    int mp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp);
+    int mp_montgomery_setup(fp_int *a, fp_digit *rho);
+    int mp_div_2(fp_int * a, fp_int * b);
+    int mp_init_copy(fp_int * a, fp_int * b);
+#endif
+
+#if defined(HAVE_ECC) || defined(WOLFSSL_KEY_GEN)
+    int mp_sqrmod(mp_int* a, mp_int* b, mp_int* c);
+    int mp_montgomery_calc_normalization(mp_int *a, mp_int *b);
+#endif
+
+#ifdef WOLFSSL_KEY_GEN
+int  mp_gcd(fp_int *a, fp_int *b, fp_int *c);
+int  mp_lcm(fp_int *a, fp_int *b, fp_int *c);
+int  mp_prime_is_prime(mp_int* a, int t, int* result);
+#endif /* WOLFSSL_KEY_GEN */
+
+int  mp_cnt_lsb(fp_int *a);
+int  mp_div_2d(fp_int *a, int b, fp_int *c, fp_int *d);
+int  mp_mod_d(fp_int* a, fp_digit b, fp_digit* c);
+
+WOLFSSL_API word32 CheckRunTimeFastMath(void);
+
+/* If user uses RSA, DH, DSA, or ECC math lib directly then fast math FP_SIZE
+   must match, return 1 if a match otherwise 0 */
+#define CheckFastMathSettings() (FP_SIZE == CheckRunTimeFastMath())
+#ifdef __cplusplus
+   }
+#endif
+
+#endif  /* WOLF_CRYPT_TFM_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/types.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,323 @@
+/* types.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef WOLF_CRYPT_TYPES_H
+#define WOLF_CRYPT_TYPES_H
+
+	#include <wolfssl/wolfcrypt/settings.h>
+	#include <wolfssl/wolfcrypt/wc_port.h>
+
+	#ifdef __cplusplus
+	    extern "C" {
+	#endif
+
+
+	#if defined(WORDS_BIGENDIAN)
+	    #define BIG_ENDIAN_ORDER
+	#endif
+
+	#ifndef BIG_ENDIAN_ORDER
+	    #define LITTLE_ENDIAN_ORDER
+	#endif
+
+	#ifndef WOLFSSL_TYPES
+	    #ifndef byte
+	        typedef unsigned char  byte;
+	    #endif
+	    typedef unsigned short word16;
+	    typedef unsigned int   word32;
+	#endif
+
+
+	/* try to set SIZEOF_LONG or LONG_LONG if user didn't */
+	#if !defined(_MSC_VER) && !defined(__BCPLUSPLUS__)
+	    #if !defined(SIZEOF_LONG_LONG) && !defined(SIZEOF_LONG)
+	        #if (defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) \
+	                || defined(__mips64)  || defined(__x86_64__))
+	            /* long should be 64bit */
+	            #define SIZEOF_LONG 8
+	        #elif defined(__i386__) || defined(__CORTEX_M3__)
+	            /* long long should be 64bit */
+	            #define SIZEOF_LONG_LONG 8
+	        #endif
+	    #endif
+	#endif
+
+
+	#if defined(_MSC_VER) || defined(__BCPLUSPLUS__)
+	    #define WORD64_AVAILABLE
+	    #define W64LIT(x) x##ui64
+	    typedef unsigned __int64 word64;
+	#elif defined(SIZEOF_LONG) && SIZEOF_LONG == 8
+	    #define WORD64_AVAILABLE
+	    #define W64LIT(x) x##LL
+	    typedef unsigned long word64;
+	#elif defined(SIZEOF_LONG_LONG) && SIZEOF_LONG_LONG == 8
+	    #define WORD64_AVAILABLE
+	    #define W64LIT(x) x##LL
+	    typedef unsigned long long word64;
+	#elif defined(__SIZEOF_LONG_LONG__) && __SIZEOF_LONG_LONG__ == 8
+	    #define WORD64_AVAILABLE
+	    #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
+
+
+	/* These platforms have 64-bit CPU registers.  */
+	#if (defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) || \
+	     defined(__mips64)  || defined(__x86_64__) || defined(_M_X64))
+	    typedef word64 wolfssl_word;
+	#else
+	    typedef word32 wolfssl_word;
+	    #ifdef WORD64_AVAILABLE
+	        #define WOLFCRYPT_SLOW_WORD64
+	    #endif
+	#endif
+
+
+	enum {
+	    WOLFSSL_WORD_SIZE  = sizeof(wolfssl_word),
+	    WOLFSSL_BIT_SIZE   = 8,
+	    WOLFSSL_WORD_BITS  = WOLFSSL_WORD_SIZE * WOLFSSL_BIT_SIZE
+	};
+
+	#define WOLFSSL_MAX_16BIT 0xffffU
+
+	/* use inlining if compiler allows */
+	#ifndef INLINE
+	#ifndef NO_INLINE
+	    #ifdef _MSC_VER
+	        #define INLINE __inline
+	    #elif defined(__GNUC__)
+	        #define INLINE inline
+	    #elif defined(__IAR_SYSTEMS_ICC__)
+	        #define INLINE inline
+	    #elif defined(THREADX)
+	        #define INLINE _Inline
+	    #else
+	        #define INLINE
+	    #endif
+	#else
+	    #define INLINE
+	#endif
+	#endif
+
+
+	/* set up rotate style */
+	#if defined(_MSC_VER) || defined(__BCPLUSPLUS__)
+	    #define INTEL_INTRINSICS
+	    #define FAST_ROTATE
+	#elif defined(__MWERKS__) && TARGET_CPU_PPC
+	    #define PPC_INTRINSICS
+	    #define FAST_ROTATE
+	#elif defined(__GNUC__) && defined(__i386__)
+	        /* GCC does peephole optimizations which should result in using rotate
+	           instructions  */
+	    #define FAST_ROTATE
+	#endif
+
+
+	/* set up thread local storage if available */
+	#ifdef HAVE_THREAD_LS
+	    #if defined(_MSC_VER)
+	        #define THREAD_LS_T __declspec(thread)
+	    #else
+	        #define THREAD_LS_T __thread
+	    #endif
+	#else
+	    #define THREAD_LS_T
+	#endif
+
+
+	/* Micrium will use Visual Studio for compilation but not the Win32 API */
+	#if defined(_WIN32) && !defined(MICRIUM) && !defined(FREERTOS) \
+	        && !defined(EBSNET)
+	    #define USE_WINDOWS_API
+	#endif
+
+
+	/* idea to add global alloc override by Moisés Guimarães  */
+	/* 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  */
+	#if defined(XMALLOC_USER)
+	    /* prototypes for user heap override functions */
+	    #include <stddef.h>  /* for size_t */
+	    extern void *XMALLOC(size_t n, void* heap, int type);
+	    extern void *XREALLOC(void *p, size_t n, void* heap, int type);
+	    extern void XFREE(void *p, void* heap, int type);
+	#elif defined(NO_WOLFSSL_MEMORY)
+	    /* just use plain C stdlib stuff if desired */
+	    #include <stdlib.h>
+	    #define XMALLOC(s, h, t)     ((void)h, (void)t, malloc((s)))
+	    #define XFREE(p, h, t)       {void* xp = (p); if((xp)) free((xp));}
+	    #define XREALLOC(p, n, h, t) realloc((p), (n))
+	#elif !defined(MICRIUM_MALLOC) && !defined(EBSNET) \
+	        && !defined(WOLFSSL_SAFERTOS) && !defined(FREESCALE_MQX) \
+	        && !defined(WOLFSSL_LEANPSK)
+	    /* default C runtime, can install different routines at runtime via cbs */
+	    #include <wolfssl/wolfcrypt/memory.h>
+	    #define XMALLOC(s, h, t)     ((void)h, (void)t, wolfSSL_Malloc((s)))
+	    #define XFREE(p, h, t)       {void* xp = (p); if((xp)) wolfSSL_Free((xp));}
+	    #define XREALLOC(p, n, h, t) wolfSSL_Realloc((p), (n))
+	#endif
+
+	#ifndef STRING_USER
+	    #include <string.h>
+	    char* mystrnstr(const char* s1, const char* s2, unsigned int n);
+
+	    #define XMEMCPY(d,s,l)    memcpy((d),(s),(l))
+	    #define XMEMSET(b,c,l)    memset((b),(c),(l))
+	    #define XMEMCMP(s1,s2,n)  memcmp((s1),(s2),(n))
+	    #define XMEMMOVE(d,s,l)   memmove((d),(s),(l))
+
+	    #define XSTRLEN(s1)       strlen((s1))
+	    #define XSTRNCPY(s1,s2,n) strncpy((s1),(s2),(n))
+	    /* strstr, strncmp, and strncat only used by wolfSSL proper, not required for
+	       CTaoCrypt only */
+	    #define XSTRSTR(s1,s2)    strstr((s1),(s2))
+	    #define XSTRNSTR(s1,s2,n) mystrnstr((s1),(s2),(n))
+	    #define XSTRNCMP(s1,s2,n) strncmp((s1),(s2),(n))
+	    #define XSTRNCAT(s1,s2,n) strncat((s1),(s2),(n))
+	    #ifndef USE_WINDOWS_API
+	        #define XSTRNCASECMP(s1,s2,n) strncasecmp((s1),(s2),(n))
+	        #define XSNPRINTF snprintf
+	    #else
+	        #define XSTRNCASECMP(s1,s2,n) _strnicmp((s1),(s2),(n))
+	        #define XSNPRINTF _snprintf
+	    #endif
+	#endif
+
+	#ifndef CTYPE_USER
+	    #include <ctype.h>
+	    #if defined(HAVE_ECC) || defined(HAVE_OCSP)
+	        #define XTOUPPER(c)     toupper((c))
+	        #define XISALPHA(c)     isalpha((c))
+	    #endif
+	    /* needed by wolfSSL_check_domain_name() */
+	    #define XTOLOWER(c)      tolower((c))
+	#endif
+
+
+	/* memory allocation types for user hints */
+	enum {
+	    DYNAMIC_TYPE_CA           = 1,
+	    DYNAMIC_TYPE_CERT         = 2,
+	    DYNAMIC_TYPE_KEY          = 3,
+	    DYNAMIC_TYPE_FILE         = 4,
+	    DYNAMIC_TYPE_SUBJECT_CN   = 5,
+	    DYNAMIC_TYPE_PUBLIC_KEY   = 6,
+	    DYNAMIC_TYPE_SIGNER       = 7,
+	    DYNAMIC_TYPE_NONE         = 8,
+	    DYNAMIC_TYPE_BIGINT       = 9,
+	    DYNAMIC_TYPE_RSA          = 10,
+	    DYNAMIC_TYPE_METHOD       = 11,
+	    DYNAMIC_TYPE_OUT_BUFFER   = 12,
+	    DYNAMIC_TYPE_IN_BUFFER    = 13,
+	    DYNAMIC_TYPE_INFO         = 14,
+	    DYNAMIC_TYPE_DH           = 15,
+	    DYNAMIC_TYPE_DOMAIN       = 16,
+	    DYNAMIC_TYPE_SSL          = 17,
+	    DYNAMIC_TYPE_CTX          = 18,
+	    DYNAMIC_TYPE_WRITEV       = 19,
+	    DYNAMIC_TYPE_OPENSSL      = 20,
+	    DYNAMIC_TYPE_DSA          = 21,
+	    DYNAMIC_TYPE_CRL          = 22,
+	    DYNAMIC_TYPE_REVOKED      = 23,
+	    DYNAMIC_TYPE_CRL_ENTRY    = 24,
+	    DYNAMIC_TYPE_CERT_MANAGER = 25,
+	    DYNAMIC_TYPE_CRL_MONITOR  = 26,
+	    DYNAMIC_TYPE_OCSP_STATUS  = 27,
+	    DYNAMIC_TYPE_OCSP_ENTRY   = 28,
+	    DYNAMIC_TYPE_ALTNAME      = 29,
+	    DYNAMIC_TYPE_SUITES       = 30,
+	    DYNAMIC_TYPE_CIPHER       = 31,
+	    DYNAMIC_TYPE_RNG          = 32,
+	    DYNAMIC_TYPE_ARRAYS       = 33,
+	    DYNAMIC_TYPE_DTLS_POOL    = 34,
+	    DYNAMIC_TYPE_SOCKADDR     = 35,
+	    DYNAMIC_TYPE_LIBZ         = 36,
+	    DYNAMIC_TYPE_ECC          = 37,
+	    DYNAMIC_TYPE_TMP_BUFFER   = 38,
+	    DYNAMIC_TYPE_DTLS_MSG     = 39,
+	    DYNAMIC_TYPE_CAVIUM_TMP   = 40,
+	    DYNAMIC_TYPE_CAVIUM_RSA   = 41,
+	    DYNAMIC_TYPE_X509         = 42,
+	    DYNAMIC_TYPE_TLSX         = 43,
+	    DYNAMIC_TYPE_OCSP         = 44,
+	    DYNAMIC_TYPE_SIGNATURE    = 45,
+	    DYNAMIC_TYPE_HASHES       = 46
+	};
+
+	/* max error buffer string size */
+	enum {
+	    WOLFSSL_MAX_ERROR_SZ = 80
+	};
+
+	/* stack protection */
+	enum {
+	    MIN_STACK_BUFFER = 8
+	};
+
+
+
+	/* settings detection for compile vs runtime math incombatibilities */
+	enum {
+	#if !defined(USE_FAST_MATH) && !defined(SIZEOF_LONG) && !defined(SIZEOF_LONG_LONG)
+	    CTC_SETTINGS = 0x0
+	#elif !defined(USE_FAST_MATH) && defined(SIZEOF_LONG) && (SIZEOF_LONG == 8)
+	    CTC_SETTINGS = 0x1
+	#elif !defined(USE_FAST_MATH) && defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG == 8)
+	    CTC_SETTINGS = 0x2
+	#elif !defined(USE_FAST_MATH) && defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG == 4)
+	    CTC_SETTINGS = 0x4
+	#elif defined(USE_FAST_MATH) && !defined(SIZEOF_LONG) && !defined(SIZEOF_LONG_LONG)
+	    CTC_SETTINGS = 0x8
+	#elif defined(USE_FAST_MATH) && defined(SIZEOF_LONG) && (SIZEOF_LONG == 8)
+	    CTC_SETTINGS = 0x10
+	#elif defined(USE_FAST_MATH) && defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG == 8)
+	    CTC_SETTINGS = 0x20
+	#elif defined(USE_FAST_MATH) && defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG == 4)
+	    CTC_SETTINGS = 0x40
+	#else
+	    #error "bad math long / long long settings"
+	#endif
+	};
+
+
+	WOLFSSL_API word32 CheckRunTimeSettings(void);
+
+	/* If user uses RSA, DH, DSA, or ECC math lib directly then fast math and long
+	   types need to match at compile time and run time, CheckCtcSettings will
+	   return 1 if a match otherwise 0 */
+	#define CheckCtcSettings() (CTC_SETTINGS == CheckRunTimeSettings())
+
+
+	#ifdef __cplusplus
+	    }   /* extern "C" */
+	#endif
+
+#endif /* WOLF_CRYPT_TYPES_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/visibility.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,76 @@
+/* visibility.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+/* Visibility control macros */
+
+#ifndef WOLF_CRYPT_VISIBILITY_H
+#define WOLF_CRYPT_VISIBILITY_H
+
+
+/* for compatibility and so that fips is using same name of macro @wc_fips */
+#ifdef HAVE_FIPS
+    #include <cyassl/ctaocrypt/visibility.h>
+    #define WOLFSSL_API   CYASSL_API
+	#define WOLFSSL_LOCAL CYASSL_LOCAL
+#else
+
+/* WOLFSSL_API is used for the public API symbols.
+        It either imports or exports (or does nothing for static builds)
+
+   WOLFSSL_LOCAL is used for non-API symbols (private).
+*/
+
+#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)
+        #ifdef WOLFSSL_DLL
+            #define WOLFSSL_API __declspec(dllexport)
+        #else
+            #define WOLFSSL_API
+        #endif
+        #define WOLFSSL_LOCAL
+    #else
+        #define WOLFSSL_API
+        #define WOLFSSL_LOCAL
+    #endif /* HAVE_VISIBILITY */
+#else /* BUILDING_WOLFSSL */
+    #if defined(_MSC_VER)
+        #ifdef WOLFSSL_DLL
+            #define WOLFSSL_API __declspec(dllimport)
+        #else
+            #define WOLFSSL_API
+        #endif
+        #define WOLFSSL_LOCAL
+    #else
+        #define WOLFSSL_API
+        #define WOLFSSL_LOCAL
+    #endif
+#endif /* BUILDING_WOLFSSL */
+
+#endif /* HAVE_FIPS */
+#endif /* WOLF_CRYPT_VISIBILITY_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfssl/wolfcrypt/wc_port.h	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,208 @@
+/* wc_port.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * 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-1301, USA
+ */
+
+
+#ifndef WOLF_CRYPT_PORT_H
+#define WOLF_CRYPT_PORT_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#ifdef USE_WINDOWS_API
+    #ifdef WOLFSSL_GAME_BUILD
+        #include "system/xtl.h"
+    #else
+        #ifndef WIN32_LEAN_AND_MEAN
+            #define WIN32_LEAN_AND_MEAN
+        #endif
+        #if defined(_WIN32_WCE) || defined(WIN32_LEAN_AND_MEAN)
+            /* On WinCE winsock2.h must be included before windows.h */
+            #include <winsock2.h>
+        #endif
+        #include <windows.h>
+    #endif
+#elif defined(THREADX)
+    #ifndef SINGLE_THREADED
+        #include "tx_api.h"
+    #endif
+#elif defined(MICRIUM)
+    /* do nothing, just don't pick Unix */
+#elif defined(FREERTOS) || defined(WOLFSSL_SAFERTOS)
+    /* do nothing */
+#elif defined(EBSNET)
+    /* do nothing */
+#elif defined(FREESCALE_MQX)
+    /* do nothing */
+#elif defined(WOLFSSL_MDK_ARM)
+    #if defined(WOLFSSL_MDK5)
+         #include "cmsis_os.h"
+    #else
+        #include <rtl.h>
+    #endif
+#elif defined(WOLFSSL_CMSIS_RTOS)
+    #include "cmsis_os.h"
+#elif defined(WOLFSSL_TIRTOS)
+    #include <ti/sysbios/BIOS.h>
+    #include <ti/sysbios/knl/Semaphore.h>
+#else
+    #ifndef SINGLE_THREADED
+        #define WOLFSSL_PTHREADS
+        #include <pthread.h>
+    #endif
+    #if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+        #include <unistd.h>      /* for close of BIO */
+    #endif
+#endif
+
+
+#ifdef SINGLE_THREADED
+    typedef int wolfSSL_Mutex;
+#else /* MULTI_THREADED */
+    /* FREERTOS comes first to enable use of FreeRTOS Windows simulator only */
+    #ifdef FREERTOS
+        typedef xSemaphoreHandle wolfSSL_Mutex;
+    #elif defined(WOLFSSL_SAFERTOS)
+        typedef struct wolfSSL_Mutex {
+            signed char mutexBuffer[portQUEUE_OVERHEAD_BYTES];
+            xSemaphoreHandle mutex;
+        } wolfSSL_Mutex;
+    #elif defined(USE_WINDOWS_API)
+        typedef CRITICAL_SECTION wolfSSL_Mutex;
+    #elif defined(WOLFSSL_PTHREADS)
+        typedef pthread_mutex_t wolfSSL_Mutex;
+    #elif defined(THREADX)
+        typedef TX_MUTEX wolfSSL_Mutex;
+    #elif defined(MICRIUM)
+        typedef OS_MUTEX wolfSSL_Mutex;
+    #elif defined(EBSNET)
+        typedef RTP_MUTEX wolfSSL_Mutex;
+    #elif defined(FREESCALE_MQX)
+        typedef MUTEX_STRUCT wolfSSL_Mutex;
+    #elif defined(WOLFSSL_MDK_ARM)
+        #if defined(WOLFSSL_CMSIS_RTOS)
+            typedef osMutexId wolfSSL_Mutex;
+        #else
+            typedef OS_MUT wolfSSL_Mutex;
+        #endif
+    #elif defined(WOLFSSL_CMSIS_RTOS)
+        typedef osMutexId wolfSSL_Mutex;
+    #elif defined(WOLFSSL_TIRTOS)
+        typedef ti_sysbios_knl_Semaphore_Handle wolfSSL_Mutex;
+    #else
+        #error Need a mutex type in multithreaded mode
+    #endif /* USE_WINDOWS_API */
+#endif /* SINGLE_THREADED */
+
+WOLFSSL_LOCAL int InitMutex(wolfSSL_Mutex*);
+WOLFSSL_LOCAL int FreeMutex(wolfSSL_Mutex*);
+WOLFSSL_LOCAL int LockMutex(wolfSSL_Mutex*);
+WOLFSSL_LOCAL int UnLockMutex(wolfSSL_Mutex*);
+
+
+/* filesystem abstraction layer, used by ssl.c */
+#ifndef NO_FILESYSTEM
+
+#if defined(EBSNET)
+    #define XFILE                    int
+    #define XFOPEN(NAME, MODE)       vf_open((const char *)NAME, VO_RDONLY, 0);
+    #define XFSEEK                   vf_lseek
+    #define XFTELL                   vf_tell
+    #define XREWIND                  vf_rewind
+    #define XFREAD(BUF, SZ, AMT, FD) vf_read(FD, BUF, SZ*AMT)
+    #define XFWRITE(BUF, SZ, AMT, FD) vf_write(FD, BUF, SZ*AMT)
+    #define XFCLOSE                  vf_close
+    #define XSEEK_END                VSEEK_END
+    #define XBADFILE                 -1
+#elif defined(LSR_FS)
+    #include <fs.h>
+    #define XFILE                   struct fs_file*
+    #define XFOPEN(NAME, MODE)      fs_open((char*)NAME);
+    #define XFSEEK(F, O, W)         (void)F
+    #define XFTELL(F)               (F)->len
+    #define XREWIND(F)              (void)F
+    #define XFREAD(BUF, SZ, AMT, F) fs_read(F, (char*)BUF, SZ*AMT)
+    #define XFWRITE(BUF, SZ, AMT, F) fs_write(F, (char*)BUF, SZ*AMT)
+    #define XFCLOSE                 fs_close
+    #define XSEEK_END               0
+    #define XBADFILE                NULL
+#elif defined(FREESCALE_MQX)
+    #define XFILE                   MQX_FILE_PTR
+    #define XFOPEN                  fopen
+    #define XFSEEK                  fseek
+    #define XFTELL                  ftell
+    #define XREWIND(F)              fseek(F, 0, IO_SEEK_SET)
+    #define XFREAD                  fread
+    #define XFWRITE                 fwrite
+    #define XFCLOSE                 fclose
+    #define XSEEK_END               IO_SEEK_END
+    #define XBADFILE                NULL
+#elif defined(MICRIUM)
+    #include <fs.h>
+    #define XFILE      FS_FILE*
+    #define XFOPEN     fs_fopen
+    #define XFSEEK     fs_fseek
+    #define XFTELL     fs_ftell
+    #define XREWIND    fs_rewind
+    #define XFREAD     fs_fread
+    #define XFWRITE    fs_fwrite
+    #define XFCLOSE    fs_fclose
+    #define XSEEK_END  FS_SEEK_END
+    #define XBADFILE   NULL
+#else
+    /* stdio, default case */
+    #define XFILE      FILE*
+    #if defined(WOLFSSL_MDK_ARM)
+        #include <stdio.h>
+        extern FILE * wolfSSL_fopen(const char *name, const char *mode) ;
+        #define XFOPEN     wolfSSL_fopen
+    #else
+        #define XFOPEN     fopen
+    #endif
+    #define XFSEEK     fseek
+    #define XFTELL     ftell
+    #define XREWIND    rewind
+    #define XFREAD     fread
+    #define XFWRITE    fwrite
+    #define XFCLOSE    fclose
+    #define XSEEK_END  SEEK_END
+    #define XBADFILE   NULL
+#endif
+
+#endif /* NO_FILESYSTEM */
+
+
+/* Windows API defines its own min() macro. */
+#if defined(USE_WINDOWS_API) && defined(min)
+    #define WOLFSSL_HAVE_MIN
+#endif
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+#endif /* WOLF_CRYPT_PORT_H */
+
+