fork of cyassl-lib

Dependents:   TLS_cyassl TLS_cyassl

Files at this revision

API Documentation at this revision

Comitter:
ashleymills
Date:
Thu Sep 05 10:33:04 2013 +0000
Child:
1:c0ce1562443a
Commit message:
Initial commit

Changed in this revision

crl.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/aes.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/arc4.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/asm.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/asn.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/blake2b.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/camellia.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/coding.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/compress.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/des3.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/dh.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/dsa.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/ecc.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/ecc_fp.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/error.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/hc128.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/hmac.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/integer.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/logging.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/md2.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/md4.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/md5.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/memory.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/misc.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/pwdbased.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/rabbit.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/random.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/ripemd.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/rsa.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/sha.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/sha256.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/sha512.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/tfm.c Show annotated file Show diff for this revision Revisions of this file
cyassl/callbacks.h Show annotated file Show diff for this revision Revisions of this file
cyassl/certs_test.h Show annotated file Show diff for this revision Revisions of this file
cyassl/crl.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/aes.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/arc4.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/asn.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/asn_public.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/blake2-impl.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/blake2-int.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/blake2.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/camellia.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/coding.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/compress.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/ctaoerror2.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/des3.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/dh.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/dsa.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/ecc.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/hc128.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/hmac.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/integer.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/logging.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/md2.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/md4.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/md5.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/memory.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/misc.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/mpi_class.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/mpi_superclass.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/pwdbased.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/rabbit.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/random.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/ripemd.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/rsa.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/settings.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/sha.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/sha256.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/sha512.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/tfm.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/types.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/visibility.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaoerror.h Show annotated file Show diff for this revision Revisions of this file
cyassl/internal.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ocsp.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/asn1.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/bio.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/bn.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/conf.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/crypto.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/des.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/dh.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/dsa.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/ec.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/ecdsa.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/engine.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/err.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/evp.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/hmac.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/lhash.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/md4.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/md5.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/ocsp.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/opensslconf.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/opensslv.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/ossl_typ.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/pem.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/pkcs12.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/rand.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/ripemd.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/rsa.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/sha.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/ssl.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/stack.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/ui.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/x509.h Show annotated file Show diff for this revision Revisions of this file
cyassl/openssl/x509v3.h Show annotated file Show diff for this revision Revisions of this file
cyassl/options.h Show annotated file Show diff for this revision Revisions of this file
cyassl/sniffer.h Show annotated file Show diff for this revision Revisions of this file
cyassl/sniffer_error.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ssl.h Show annotated file Show diff for this revision Revisions of this file
cyassl/test.h Show annotated file Show diff for this revision Revisions of this file
cyassl/version.h Show annotated file Show diff for this revision Revisions of this file
internal.c Show annotated file Show diff for this revision Revisions of this file
io.c Show annotated file Show diff for this revision Revisions of this file
keys.c Show annotated file Show diff for this revision Revisions of this file
ocsp.c Show annotated file Show diff for this revision Revisions of this file
sniffer.c Show annotated file Show diff for this revision Revisions of this file
ssl.c Show annotated file Show diff for this revision Revisions of this file
tls.c Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crl.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,600 @@
+/* crl.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef HAVE_CRL
+
+#include <cyassl/internal.h>
+#include <cyassl/ctaoerror.h>
+
+#include <dirent.h>
+#include <sys/stat.h>
+#include <string.h>
+
+
+/* Initialze CRL members */
+int InitCRL(CYASSL_CRL* crl, CYASSL_CERT_MANAGER* cm)
+{
+    CYASSL_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;
+#endif
+    if (InitMutex(&crl->crlLock) != 0)
+        return BAD_MUTEX_ERROR; 
+
+    return 0;
+}
+
+
+/* Initialze CRL Entry */
+static int InitCRL_Entry(CRL_Entry* crle, DecodedCRL* dcrl)
+{
+    CYASSL_ENTER("InitCRL_Entry");
+
+    XMEMCPY(crle->issuerHash, dcrl->issuerHash, SHA_DIGEST_SIZE);
+    /* XMEMCPY(crle->crlHash, dcrl->crlHash, SHA_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; 
+
+    CYASSL_ENTER("FreeCRL_Entry");
+
+    while(tmp) {
+        RevokedCert* next = tmp->next;
+        XFREE(tmp, NULL, DYNAMIC_TYPE_REVOKED);
+        tmp = next;
+    }
+}
+
+
+
+/* Free all CRL resources */
+void FreeCRL(CYASSL_CRL* crl, int dynamic)
+{
+    CRL_Entry* tmp = crl->crlList;
+
+    CYASSL_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) {
+        CYASSL_MSG("Canceling monitor thread");
+        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(CYASSL_CRL* crl, DecodedCert* cert)
+{
+    CRL_Entry* crle;
+    int        foundEntry = 0;
+    int        ret = 0;
+
+    CYASSL_ENTER("CheckCertCRL");
+
+    if (LockMutex(&crl->crlLock) != 0) {
+        CYASSL_MSG("LockMutex failed");
+        return BAD_MUTEX_ERROR;
+    }
+
+    crle = crl->crlList;
+
+    while (crle) {
+        if (XMEMCMP(crle->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE) == 0) {
+            CYASSL_MSG("Found CRL Entry on list");
+            CYASSL_MSG("Checking next date validity");
+
+            if (!ValidateDate(crle->nextDate, crle->nextDateFormat, AFTER)) {
+                CYASSL_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) {
+                CYASSL_MSG("Cert revoked");
+                ret = CRL_CERT_REVOKED;
+                break;
+            }
+            rc = rc->next;	
+        }
+    }
+
+    UnLockMutex(&crl->crlLock);
+
+    if (foundEntry == 0) {
+        CYASSL_MSG("Couldn't find CRL for status check");
+        ret = CRL_MISSING;
+        if (crl->cm->cbMissingCRL) {
+            char url[256];
+
+            CYASSL_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  {
+                CYASSL_MSG("CRL url too long");
+            }
+            crl->cm->cbMissingCRL(url);
+        }
+    }
+
+
+    return ret;	
+}
+
+
+/* Add Decoded CRL, 0 on success */
+static int AddCRL(CYASSL_CRL* crl, DecodedCRL* dcrl)
+{
+    CRL_Entry* crle;
+
+    CYASSL_ENTER("AddCRL");
+
+    crle = (CRL_Entry*)XMALLOC(sizeof(CRL_Entry), NULL, DYNAMIC_TYPE_CRL_ENTRY);
+    if (crle == NULL) {
+        CYASSL_MSG("alloc CRL Entry failed");
+        return -1;
+    }
+
+    if (InitCRL_Entry(crle, dcrl) < 0) {
+        CYASSL_MSG("Init CRL Entry failed");
+        XFREE(crle, NULL, DYNAMIC_TYPE_CRL_ENTRY);
+        return -1;
+    }
+
+    if (LockMutex(&crl->crlLock) != 0) {
+        CYASSL_MSG("LockMutex failed");
+        FreeCRL_Entry(crle);
+        XFREE(crle, NULL, DYNAMIC_TYPE_CRL_ENTRY);
+        return BAD_MUTEX_ERROR;
+    }
+    crle->next = crl->crlList;
+    crl->crlList = crle;
+    UnLockMutex(&crl->crlLock);
+
+    return 0;
+}
+
+
+/* Load CRL File of type, SSL_SUCCESS on ok */
+int BufferLoadCRL(CYASSL_CRL* crl, const byte* buff, long sz, int type)
+{
+    int          ret = SSL_SUCCESS;
+    const byte*  myBuffer = buff;    /* if DER ok, otherwise switch */
+    buffer       der;
+    DecodedCRL   dcrl;
+
+    der.buffer = NULL;
+
+    CYASSL_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 {
+            CYASSL_MSG("Pem to Der failed");
+            return -1;
+        }
+    }
+
+    InitDecodedCRL(&dcrl);
+    ret = ParseCRL(&dcrl, myBuffer, (word32)sz, crl->cm);
+    if (ret != 0) {
+        CYASSL_MSG("ParseCRL error");
+    }
+    else {
+        ret = AddCRL(crl, &dcrl);
+        if (ret != 0) {
+            CYASSL_MSG("AddCRL error");
+        }
+    }
+    FreeDecodedCRL(&dcrl);
+
+    if (der.buffer)
+        XFREE(der.buffer, NULL, DYNAMIC_TYPE_CRL);
+
+    if (ret == 0)
+        return SSL_SUCCESS;  /* convert */
+    return ret;
+}
+
+
+#ifdef HAVE_CRL_MONITOR
+
+
+/* read in new CRL entries and save new list */
+static int SwapLists(CYASSL_CRL* crl)
+{
+    int        ret;
+    CYASSL_CRL tmp;
+    CRL_Entry* newList;
+
+    if (InitCRL(&tmp, crl->cm) < 0) {
+        CYASSL_MSG("Init tmp CRL failed");
+        return -1;
+    }
+
+    if (crl->monitors[0].path) {
+        ret = LoadCRL(&tmp, crl->monitors[0].path, SSL_FILETYPE_PEM, 0);
+        if (ret != SSL_SUCCESS) {
+            CYASSL_MSG("PEM LoadCRL on dir change failed");
+            FreeCRL(&tmp, 0);
+            return -1;
+        }
+    }
+
+    if (crl->monitors[1].path) {
+        ret = LoadCRL(&tmp, crl->monitors[1].path, SSL_FILETYPE_ASN1, 0);
+        if (ret != SSL_SUCCESS) {
+            CYASSL_MSG("DER LoadCRL on dir change failed");
+            FreeCRL(&tmp, 0);
+            return -1;
+        }
+    }
+
+    if (LockMutex(&crl->crlLock) != 0) {
+        CYASSL_MSG("LockMutex failed");
+        FreeCRL(&tmp, 0);
+        return -1;
+    }
+
+    newList = tmp.crlList;
+
+    /* swap lists */
+    tmp.crlList  = crl->crlList;
+    crl->crlList = newList;
+
+    UnLockMutex(&crl->crlLock);
+
+    FreeCRL(&tmp, 0);
+
+    return 0;
+}
+
+
+#if (defined(__MACH__) || defined(__FreeBSD__))
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <fcntl.h>
+
+#ifdef __MACH__
+    #define XEVENT_MODE O_EVTONLY
+#elif defined(__FreeBSD__)
+    #define XEVENT_MODE EVFILT_VNODE
+#endif
+
+
+/* OS X  monitoring */
+static void* DoMonitor(void* arg)
+{
+    int fPEM, fDER, kq;
+    struct kevent change;
+
+    CYASSL_CRL* crl = (CYASSL_CRL*)arg;
+
+    CYASSL_ENTER("DoMonitor");
+
+    kq = kqueue();
+    if (kq == -1) {
+        CYASSL_MSG("kqueue failed");
+        return NULL;
+    }
+
+    fPEM = -1;
+    fDER = -1;
+
+    if (crl->monitors[0].path) {
+        fPEM = open(crl->monitors[0].path, XEVENT_MODE);
+        if (fPEM == -1) {
+            CYASSL_MSG("PEM event dir open failed");
+            return NULL;
+        }
+    }
+
+    if (crl->monitors[1].path) {
+        fDER = open(crl->monitors[1].path, XEVENT_MODE);
+        if (fDER == -1) {
+            CYASSL_MSG("DER event dir open failed");
+            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(kq, &change, 1, &event, 1, NULL);
+       
+        CYASSL_MSG("Got kevent");
+
+        if (numEvents == -1) {
+            CYASSL_MSG("kevent problem, continue");
+            continue;
+        }
+
+        if (SwapLists(crl) < 0) {
+            CYASSL_MSG("SwapLists problem, continue");
+        }
+    }
+
+    return NULL;
+}
+
+
+#elif defined(__linux__)
+
+#include <sys/types.h>
+#include <sys/inotify.h>
+#include <unistd.h>
+
+/* linux monitoring */
+static void* DoMonitor(void* arg)
+{
+    int         notifyFd;
+    int         wd;
+    CYASSL_CRL* crl = (CYASSL_CRL*)arg;
+
+    CYASSL_ENTER("DoMonitor");
+
+    notifyFd = inotify_init();
+    if (notifyFd < 0) {
+        CYASSL_MSG("inotify failed");
+        return NULL;
+    }
+
+    if (crl->monitors[0].path) {
+        wd = inotify_add_watch(notifyFd, crl->monitors[0].path, IN_CLOSE_WRITE |
+                                                                IN_DELETE);
+        if (wd < 0) {
+            CYASSL_MSG("PEM notify add watch failed");
+            return NULL;
+        }
+    }
+
+    if (crl->monitors[1].path) {
+        wd = inotify_add_watch(notifyFd, crl->monitors[1].path, IN_CLOSE_WRITE |
+                                                                IN_DELETE);
+        if (wd < 0) {
+            CYASSL_MSG("DER notify add watch failed");
+            return NULL;
+        }
+    }
+
+    for (;;) {
+        char          buff[8192];
+        int           length = read(notifyFd, buff, sizeof(buff));
+       
+        CYASSL_MSG("Got notify event");
+
+        if (length < 0) {
+            CYASSL_MSG("notify read problem, continue");
+            continue;
+        } 
+
+        if (SwapLists(crl) < 0) {
+            CYASSL_MSG("SwapLists problem, continue");
+        }
+    }
+
+    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(CYASSL_CRL* crl)
+{
+    pthread_attr_t attr;
+
+    CYASSL_ENTER("StartMonitorCRL");
+
+    if (crl == NULL) 
+        return BAD_FUNC_ARG;
+
+    if (crl->tid != 0) {
+        CYASSL_MSG("Monitor thread already running");
+        return MONITOR_RUNNING_E;
+    }
+
+    pthread_attr_init(&attr);
+
+    if (pthread_create(&crl->tid, &attr, DoMonitor, crl) != 0) {
+        CYASSL_MSG("Thread creation error");
+        return THREAD_CREATE_E;
+    }
+
+    return SSL_SUCCESS;
+}
+
+
+#else /* HAVE_CRL_MONITOR */
+
+static int StartMonitorCRL(CYASSL_CRL* crl)
+{
+    (void)crl;
+
+    CYASSL_ENTER("StartMonitorCRL");
+    CYASSL_MSG("Not compiled in");
+
+    return NOT_COMPILED_IN;
+}
+
+#endif  /* HAVE_CRL_MONITOR */
+
+
+/* Load CRL path files of type, SSL_SUCCESS on ok */ 
+int LoadCRL(CYASSL_CRL* crl, const char* path, int type, int monitor)
+{
+    struct dirent* entry;
+    DIR*   dir;
+    int    ret = SSL_SUCCESS;
+
+    CYASSL_ENTER("LoadCRL");
+    if (crl == NULL)
+        return BAD_FUNC_ARG;
+
+    dir = opendir(path);
+    if (dir == NULL) {
+        CYASSL_MSG("opendir path crl load failed");
+        return BAD_PATH_ERROR;
+    }
+    while ( (entry = readdir(dir)) != NULL) {
+        char name[MAX_FILENAME_SZ];
+        struct stat s;
+
+        XMEMSET(name, 0, sizeof(name));
+        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) {
+            CYASSL_MSG("stat on name failed");
+            continue;
+        }
+        if (s.st_mode & S_IFREG) {
+
+            if (type == SSL_FILETYPE_PEM) {
+                if (strstr(entry->d_name, ".pem") == NULL) {
+                    CYASSL_MSG("not .pem file, skipping");
+                    continue;
+                }
+            }
+            else {
+                if (strstr(entry->d_name, ".der") == NULL &&
+                    strstr(entry->d_name, ".crl") == NULL) {
+
+                    CYASSL_MSG("not .der or .crl file, skipping");
+                    continue;
+                }
+            }
+
+            if (ProcessFile(NULL, name, type, CRL_TYPE, NULL, 0, crl)
+                                                               != SSL_SUCCESS) {
+                CYASSL_MSG("CRL file load failed, continuing");
+            }
+        }
+    }
+
+    if (monitor & CYASSL_CRL_MONITOR) {
+        CYASSL_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 & CYASSL_CRL_START_MON) {
+            CYASSL_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/ctaocrypt/src/aes.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,2927 @@
+/* aes.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifndef NO_AES
+
+#include <cyassl/ctaocrypt/aes.h>
+#include <cyassl/ctaocrypt/ctaoerror2.h>
+#include <cyassl/ctaocrypt/logging.h>
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/src/misc.c>
+#endif
+
+
+#ifdef _MSC_VER
+    /* 4127 warning constant while(1)  */
+    #pragma warning(disable: 4127)
+#endif
+
+
+#ifdef HAVE_CAVIUM
+    static int  AesCaviumSetKey(Aes* aes, const byte* key, word32 length,
+                                const byte* iv);
+    static void AesCaviumCbcEncrypt(Aes* aes, byte* out, const byte* in,
+                                    word32 length);
+    static void AesCaviumCbcDecrypt(Aes* aes, byte* out, const byte* in,
+                                    word32 length);
+#endif
+
+#ifdef STM32F2_CRYPTO
+    /*
+     * STM32F2 hardware AES 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 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 AesSetIV(aes, iv);
+    }
+
+    int 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 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;
+    }
+
+    #ifdef CYASSL_AES_COUNTER
+
+    /* AES-CTR calls this for key setup */
+    int AesSetKeyDirect(Aes* aes, const byte* userKey, word32 keylen,
+                        const byte* iv, int dir)
+    {
+        return AesSetKey(aes, userKey, keylen, iv, dir);
+    }
+
+    void 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);
+    }
+
+    #endif /* CYASSL_AES_COUNTER */
+
+#else /* CTaoCrypt software implementation */
+
+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 CYASSL_AESNI
+
+#ifndef _MSC_VER
+
+    #define cpuid(func,ax,bx,cx,dx)\
+        __asm__ __volatile__ ("cpuid":\
+                       "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func));
+
+#else
+
+    #define cpuid(func,ax,bx,cx,dx)\
+        __asm mov eax, func \
+        __asm cpuid \
+        __asm mov ax, eax \
+        __asm mov bx, ebx \
+        __asm mov cx, ecx \
+        __asm mov dx, edx
+
+#endif /* _MSC_VER */
+
+            
+static int Check_CPU_support_AES(void)
+{
+    unsigned int a,b,c,d;
+    cpuid(1,a,b,c,d);
+
+    if (c & 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)
+                     asm ("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)
+                     asm ("AES_CBC_decrypt");
+
+void AES_128_Key_Expansion(const unsigned char* userkey, 
+                           unsigned char* key_schedule)
+                           asm ("AES_128_Key_Expansion");
+
+void AES_192_Key_Expansion(const unsigned char* userkey, 
+                           unsigned char* key_schedule)
+                           asm ("AES_192_Key_Expansion");
+
+void AES_256_Key_Expansion(const unsigned char* userkey, 
+                           unsigned char* key_schedule)
+                           asm ("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 /* CYASSL_AESNI */
+
+
+static int AesSetKeyLocal(Aes* aes, const byte* userKey, word32 keylen,
+            const byte* iv, int dir)
+{
+    word32 temp, *rk = aes->key;
+    unsigned int i = 0;
+
+    #ifdef CYASSL_AESNI
+        aes->use_aesni = 0;
+    #endif /* CYASSL_AESNI */
+    aes->rounds = keylen/4 + 6;
+
+    XMEMCPY(rk, userKey, keylen);
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords(rk, rk, keylen);
+    #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:
+        while (1)  /* for (;;) here triggers a bug in VC60 SP4 w/ Pro Pack */
+        {
+            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 AesSetIV(aes, iv);
+}
+
+
+int 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 == CYASSL_AES_CAVIUM_MAGIC)
+        return AesCaviumSetKey(aes, userKey, keylen, iv);
+#endif
+
+#ifdef CYASSL_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 /* CYASSL_AESNI */
+
+    return AesSetKeyLocal(aes, userKey, keylen, iv, dir);
+}
+
+
+static void 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) {
+        CYASSL_MSG("AesEncrypt encountered improper key, set it up");
+        return;  /* stop instead of segfaulting, set up your keys! */
+    }
+#ifdef CYASSL_AESNI
+    if (aes->use_aesni) {
+        CYASSL_MSG("AesEncrypt encountered aesni keysetup, don't use direct");
+        return;  /* just stop now */
+    } 
+#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 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) {
+        CYASSL_MSG("AesDecrypt encountered improper key, set it up");
+        return;  /* stop instead of segfaulting, set up your keys! */
+    }
+#ifdef CYASSL_AESNI
+    if (aes->use_aesni) {
+        CYASSL_MSG("AesEncrypt encountered aesni keysetup, don't use direct");
+        return;  /* just stop now */
+    } 
+#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));
+}
+
+
+int AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / AES_BLOCK_SIZE;
+
+#ifdef HAVE_CAVIUM
+    if (aes->magic == CYASSL_AES_CAVIUM_MAGIC)
+        return AesCaviumCbcEncrypt(aes, out, in, sz);
+#endif
+
+#ifdef CYASSL_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 ((word)in % 16) {
+        #ifndef NO_CYASSL_ALLOC_ALIGN
+            byte* tmp = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            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);
+        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 AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / AES_BLOCK_SIZE;
+
+#ifdef HAVE_CAVIUM
+    if (aes->magic == CYASSL_AES_CAVIUM_MAGIC)
+        return AesCaviumCbcDecrypt(aes, out, in, sz);
+#endif
+
+#ifdef CYASSL_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);
+        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;
+}
+
+
+#ifdef CYASSL_AES_DIRECT
+
+/* Allow direct access to one block encrypt */
+void AesEncryptDirect(Aes* aes, byte* out, const byte* in)
+{
+    return AesEncrypt(aes, in, out);
+}
+
+
+/* Allow direct access to one block decrypt */
+void AesDecryptDirect(Aes* aes, byte* out, const byte* in)
+{
+    return AesDecrypt(aes, in, out);
+}
+
+
+#endif /* CYASSL_AES_DIRECT */
+
+
+#if defined(CYASSL_AES_DIRECT) || defined(CYASSL_AES_COUNTER)
+
+/* AES-CTR and AES-DIRECT need to use this for key setup, no aesni yet */
+int AesSetKeyDirect(Aes* aes, const byte* userKey, word32 keylen,
+                    const byte* iv, int dir)
+{
+    return AesSetKeyLocal(aes, userKey, keylen, iv, dir);
+}
+
+#endif /* CYASSL_AES_DIRECT || CYASSL_AES_COUNTER */
+
+
+#ifdef CYASSL_AES_COUNTER
+
+/* 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 AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks = sz / AES_BLOCK_SIZE;
+
+    while (blocks--) {
+        AesEncrypt(aes, (byte*)aes->reg, out);
+        IncrementAesCounter((byte*)aes->reg);
+        xorbuf(out, in, AES_BLOCK_SIZE);
+
+        out += AES_BLOCK_SIZE;
+        in  += AES_BLOCK_SIZE; 
+    }
+}
+
+#endif /* CYASSL_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.
+ */
+
+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 */
+
+
+void AesGcmSetKey(Aes* aes, const byte* key, word32 len)
+{
+    byte iv[AES_BLOCK_SIZE];
+
+    if (!((len == 16) || (len == 24) || (len == 32)))
+        return;
+
+    XMEMSET(iv, 0, AES_BLOCK_SIZE);
+    AesSetKeyLocal(aes, key, len, iv, AES_ENCRYPTION);
+
+    AesEncrypt(aes, iv, aes->H);
+#ifdef GCM_TABLE
+    GenerateM0(aes);
+#endif /* GCM_TABLE */
+}
+
+
+#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 & 0x8000000000000000) {
+                Z[0] ^= V[0];
+                Z[1] ^= V[1];
+            }
+
+            if (V[1] & 0x0000000000000001) {
+                V[1] >>= 1;
+                V[1] |= ((V[0] & 0x0000000000000001) ? 0x8000000000000000 : 0);
+                V[0] >>= 1;
+                V[0] ^= 0xE100000000000000;
+            }
+            else {
+                V[1] >>= 1;
+                V[1] |= ((V[0] & 0x0000000000000001) ? 0x8000000000000000 : 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 */
+
+
+void 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 ctr[AES_BLOCK_SIZE];
+    byte scratch[AES_BLOCK_SIZE];
+
+    CYASSL_ENTER("AesGcmEncrypt");
+
+    XMEMSET(ctr, 0, AES_BLOCK_SIZE);
+    XMEMCPY(ctr, iv, ivSz);
+    InitGcmCounter(ctr);
+
+    while (blocks--) {
+        IncrementGcmCounter(ctr);
+        AesEncrypt(aes, ctr, scratch);
+        xorbuf(scratch, p, AES_BLOCK_SIZE);
+        XMEMCPY(c, scratch, AES_BLOCK_SIZE);
+
+        p += AES_BLOCK_SIZE;
+        c += AES_BLOCK_SIZE;
+    }
+    if (partial != 0) {
+        IncrementGcmCounter(ctr);
+        AesEncrypt(aes, ctr, scratch);
+        xorbuf(scratch, p, partial);
+        XMEMCPY(c, scratch, partial);
+    }
+    GHASH(aes, authIn, authInSz, out, sz, authTag, authTagSz);
+    InitGcmCounter(ctr);
+    AesEncrypt(aes, ctr, scratch);
+    xorbuf(authTag, scratch, authTagSz);
+}
+
+
+int  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 ctr[AES_BLOCK_SIZE];
+    byte scratch[AES_BLOCK_SIZE];
+
+    CYASSL_ENTER("AesGcmDecrypt");
+
+    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));
+        AesEncrypt(aes, ctr, EKY0);
+        xorbuf(Tprime, EKY0, sizeof(Tprime));
+        if (XMEMCMP(authTag, Tprime, authTagSz) != 0) {
+            return AES_GCM_AUTH_E;
+        }
+    }
+
+    while (blocks--) {
+        IncrementGcmCounter(ctr);
+        AesEncrypt(aes, ctr, scratch);
+        xorbuf(scratch, c, AES_BLOCK_SIZE);
+        XMEMCPY(p, scratch, AES_BLOCK_SIZE);
+
+        p += AES_BLOCK_SIZE;
+        c += AES_BLOCK_SIZE;
+    }
+    if (partial != 0) {
+        IncrementGcmCounter(ctr);
+        AesEncrypt(aes, ctr, scratch);
+        xorbuf(scratch, c, partial);
+        XMEMCPY(p, scratch, partial);
+    }
+
+    return 0;
+}
+
+#endif /* HAVE_AESGCM */
+
+#ifdef HAVE_AESCCM
+
+void 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));
+    AesSetKeyLocal(aes, key, keySz, nonce, AES_ENCRYPTION);
+}
+
+
+static void roll_x(Aes* aes, const byte* in, word32 inSz, byte* out)
+{
+    /* 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;
+
+        AesEncrypt(aes, out, out);
+    }
+
+    /* process remainder of the data */
+    if (inSz > 0) {
+        xorbuf(out, in, inSz);
+        AesEncrypt(aes, out, out);
+    }
+}
+
+
+static void roll_auth(Aes* aes, const byte* in, word32 inSz, byte* out)
+{
+    word32 authLenSz;
+    word32 remainder;
+
+    /* 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;
+    }
+    AesEncrypt(aes, out, out);
+
+    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 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];
+    word32 i, lenSz;
+
+    XMEMCPY(B+1, nonce, nonceSz);
+    lenSz = AES_BLOCK_SIZE - 1 - nonceSz;
+    B[0] = (authInSz > 0 ? 64 : 0)
+         + (8 * ((authTagSz - 2) / 2))
+         + (lenSz - 1);
+    for (i = 0; i < lenSz; i++)
+        B[AES_BLOCK_SIZE - 1 - i] = (inSz >> (8 * i)) & 0xFF;
+
+    AesEncrypt(aes, B, A);
+    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;
+    AesEncrypt(aes, B, A);
+    xorbuf(authTag, A, authTagSz);
+
+    B[15] = 1;
+    while (inSz >= AES_BLOCK_SIZE) {
+        AesEncrypt(aes, B, A);
+        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) {
+        AesEncrypt(aes, B, A);
+        xorbuf(A, in, inSz);
+        XMEMCPY(out, A, inSz);
+    }
+
+    XMEMSET(A, 0, AES_BLOCK_SIZE);
+    XMEMSET(B, 0, AES_BLOCK_SIZE);
+}
+
+
+int  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;
+    word32 i, lenSz, oSz; int result = 0;
+
+    o = out;
+    oSz = inSz;
+    XMEMCPY(B+1, nonce, nonceSz);
+    lenSz = AES_BLOCK_SIZE - 1 - 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) {
+        AesEncrypt(aes, B, A);
+        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) {
+        AesEncrypt(aes, B, A);
+        xorbuf(A, in, oSz);
+        XMEMCPY(o, A, oSz);
+    }
+
+    for (i = 0; i < lenSz; i++)
+        B[AES_BLOCK_SIZE - 1 - i] = 0;
+    AesEncrypt(aes, B, A);
+
+    o = out;
+    oSz = inSz;
+
+    B[0] = (authInSz > 0 ? 64 : 0)
+         + (8 * ((authTagSz - 2) / 2))
+         + (lenSz - 1);
+    for (i = 0; i < lenSz; i++)
+        B[AES_BLOCK_SIZE - 1 - i] = (inSz >> (8 * i)) & 0xFF;
+
+    AesEncrypt(aes, B, A);
+    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;
+    AesEncrypt(aes, B, B);
+    xorbuf(A, B, authTagSz);
+
+    if (XMEMCMP(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;
+    }
+
+    XMEMSET(A, 0, AES_BLOCK_SIZE);
+    XMEMSET(B, 0, AES_BLOCK_SIZE);
+    o = NULL;
+
+    return result;
+}
+
+#endif
+
+#endif /* STM32F2_CRYPTO */
+
+int AesSetIV(Aes* aes, const byte* iv)
+{
+    if (aes == NULL)
+        return BAD_FUNC_ARG;
+
+    if (iv)
+        XMEMCPY(aes->reg, iv, AES_BLOCK_SIZE);
+
+    return 0;
+}
+
+
+#ifdef HAVE_CAVIUM
+
+#include <cyassl/ctaocrypt/logging.h>
+#include "cavium_common.h"
+
+/* Initiliaze Aes for use with Nitrox device */
+int 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 = CYASSL_AES_CAVIUM_MAGIC;
+   
+    return 0;
+}
+
+
+/* Free Aes from use with Nitrox device */
+void AesFreeCavium(Aes* aes)
+{
+    if (aes == NULL)
+        return;
+
+    if (aes->magic != CYASSL_AES_CAVIUM_MAGIC)
+        return;
+
+    CspFreeContext(CONTEXT_SSL, aes->contextHandle, aes->devId);
+    aes->magic = 0;
+}
+
+
+static int 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 AesSetIV(aes, iv);
+}
+
+
+static void AesCaviumCbcEncrypt(Aes* aes, byte* out, const byte* in,
+                                word32 length)
+{
+    word   offset = 0;
+    word32 requestId;
+
+    while (length > CYASSL_MAX_16BIT) {
+        word16 slen = (word16)CYASSL_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) {
+            CYASSL_MSG("Bad Cavium Aes Encrypt");
+        }
+        length -= CYASSL_MAX_16BIT;
+        offset += CYASSL_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) {
+            CYASSL_MSG("Bad Cavium Aes Encrypt");
+        }
+        XMEMCPY(aes->reg, out + offset+length - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+    }
+}
+
+static void AesCaviumCbcDecrypt(Aes* aes, byte* out, const byte* in,
+                                word32 length)
+{
+    word32 requestId;
+    word   offset = 0;
+
+    while (length > CYASSL_MAX_16BIT) {
+        word16 slen = (word16)CYASSL_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) {
+            CYASSL_MSG("Bad Cavium Aes Decrypt");
+        }
+        length -= CYASSL_MAX_16BIT;
+        offset += CYASSL_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) {
+            CYASSL_MSG("Bad Cavium Aes Decrypt");
+        }
+        XMEMCPY(aes->reg, aes->tmp, AES_BLOCK_SIZE);
+    }
+}
+
+#endif /* HAVE_CAVIUM */
+
+#endif /* NO_AES */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/arc4.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,179 @@
+/* arc4.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifndef NO_RC4
+
+#include <cyassl/ctaocrypt/arc4.h>
+
+
+#ifdef HAVE_CAVIUM
+    static void Arc4CaviumSetKey(Arc4* arc4, const byte* key, word32 length);
+    static void Arc4CaviumProcess(Arc4* arc4, byte* out, const byte* in,
+                                  word32 length);
+#endif
+
+
+void Arc4SetKey(Arc4* arc4, const byte* key, word32 length)
+{
+    word32 i;
+    word32 keyIndex = 0, stateIndex = 0;
+
+#ifdef HAVE_CAVIUM
+    if (arc4->magic == CYASSL_ARC4_CAVIUM_MAGIC)
+        return 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 Arc4Process(Arc4* arc4, byte* out, const byte* in, word32 length)
+{
+    word32 x;
+    word32 y;
+
+#ifdef HAVE_CAVIUM
+    if (arc4->magic == CYASSL_ARC4_CAVIUM_MAGIC)
+        return 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 <cyassl/ctaocrypt/logging.h>
+#include "cavium_common.h"
+
+/* Initiliaze Arc4 for use with Nitrox device */
+int 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 = CYASSL_ARC4_CAVIUM_MAGIC;
+   
+    return 0;
+}
+
+
+/* Free Arc4 from use with Nitrox device */
+void Arc4FreeCavium(Arc4* arc4)
+{
+    if (arc4 == NULL)
+        return;
+
+    if (arc4->magic != CYASSL_ARC4_CAVIUM_MAGIC)
+        return;
+
+    CspFreeContext(CONTEXT_SSL, arc4->contextHandle, arc4->devId);
+    arc4->magic = 0;
+}
+
+
+static void Arc4CaviumSetKey(Arc4* arc4, const byte* key, word32 length)
+{
+    word32 requestId;
+
+    if (CspInitializeRc4(CAVIUM_BLOCKING, arc4->contextHandle, length,
+                         (byte*)key, &requestId, arc4->devId) != 0) {
+        CYASSL_MSG("Bad Cavium Arc4 Init");
+    }
+}
+
+
+static void Arc4CaviumProcess(Arc4* arc4, byte* out, const byte* in,
+                              word32 length)
+{
+    word   offset = 0;
+    word32 requestId;
+
+    while (length > CYASSL_MAX_16BIT) {
+        word16 slen = (word16)CYASSL_MAX_16BIT;
+        if (CspEncryptRc4(CAVIUM_BLOCKING, arc4->contextHandle,CAVIUM_UPDATE,
+                          slen, (byte*)in + offset, out + offset, &requestId,
+                          arc4->devId) != 0) {
+            CYASSL_MSG("Bad Cavium Arc4 Encrypt");
+        }
+        length -= CYASSL_MAX_16BIT;
+        offset += CYASSL_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) {
+            CYASSL_MSG("Bad Cavium Arc4 Encrypt");
+        }
+    }
+}
+
+#endif /* HAVE_CAVIUM */
+
+#endif /* NO_ARC4 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/asm.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,1312 @@
+/* asm.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/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 */
+#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")
+
+#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
+
+#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");
+
+#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,%6,%7              \n\t"                         \
+"  SUB    %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__(                                                             \
+"  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 = t;                            \
+   t = sc1 + (t >> DIGIT_BIT);             sc1 = t; sc2 += t >> DIGIT_BIT;     \
+   } while (0);
+
+#define SQRADDDB                                                               \
+   do { fp_word t;                                                             \
+   t = ((fp_word)sc0) + ((fp_word)sc0) + c0; c0 = t;                                                 \
+   t = ((fp_word)sc1) + ((fp_word)sc1) + c1 + (t >> DIGIT_BIT); c1 = t;                              \
+   c2 = c2 + ((fp_word)sc2) + ((fp_word)sc2) + (t >> DIGIT_BIT);                                     \
+   } while (0);
+
+#endif
+
+#ifdef TFM_SMALL_SET
+#include "fp_sqr_comba_small_set.i"
+#include "fp_sqr_comba_3.i"
+#include "fp_sqr_comba_4.i"
+#include "fp_sqr_comba_6.i"
+#include "fp_sqr_comba_7.i"
+#include "fp_sqr_comba_8.i"
+#include "fp_sqr_comba_9.i"
+#include "fp_sqr_comba_12.i"
+#include "fp_sqr_comba_17.i"
+#include "fp_sqr_comba_20.i"
+#include "fp_sqr_comba_24.i"
+#include "fp_sqr_comba_28.i"
+#include "fp_sqr_comba_32.i"
+#include "fp_sqr_comba_48.i"
+#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");
+
+#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"
+#include "fp_mul_comba_3.i"
+#include "fp_mul_comba_4.i"
+#include "fp_mul_comba_6.i"
+#include "fp_mul_comba_7.i"
+#include "fp_mul_comba_8.i"
+#include "fp_mul_comba_9.i"
+#include "fp_mul_comba_12.i"
+#include "fp_mul_comba_17.i"
+#include "fp_mul_comba_20.i"
+#include "fp_mul_comba_24.i"
+#include "fp_mul_comba_28.i"
+#include "fp_mul_comba_32.i"
+#include "fp_mul_comba_48.i"
+#include "fp_mul_comba_64.i"
+#endif
+
+/* end fp_mul_comba.c asm */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/asn.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,5340 @@
+/* asn.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/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 <cyassl/ctaocrypt/integer.h>
+#include <cyassl/ctaocrypt/asn.h>
+#include <cyassl/ctaocrypt/coding.h>
+#include <cyassl/ctaocrypt/sha.h>
+#include <cyassl/ctaocrypt/md5.h>
+#include <cyassl/ctaocrypt/md2.h>
+#include <cyassl/ctaocrypt/ctaoerror2.h>
+#include <cyassl/ctaocrypt/pwdbased.h>
+#include <cyassl/ctaocrypt/des3.h>
+#include <cyassl/ctaocrypt/sha256.h>
+#include <cyassl/ctaocrypt/sha512.h>
+#include <cyassl/ctaocrypt/logging.h>
+
+#include <cyassl/ctaocrypt/random.h>
+
+
+#ifndef NO_RC4
+    #include <cyassl/ctaocrypt/arc4.h>
+#endif
+
+#ifdef HAVE_NTRU
+    #include "crypto_ntru.h"
+#endif
+
+#ifdef HAVE_ECC
+    #include <cyassl/ctaocrypt/ecc.h>
+#endif
+
+#ifdef CYASSL_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) 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) gmtime((c))
+    #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t))
+#elif defined(CYASSL_MDK_ARM)
+    #include <rtl.h>
+    #undef RNG
+    #include "cyassl_MDK_ARM.h"
+    #undef RNG
+    #define RNG CyaSSL_RNG /*for avoiding name conflict in "stm32f2xx.h" */
+    #define XTIME(tl)  (0)
+    #define XGMTIME(c) Cyassl_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) 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 */
+#else
+    /* default */
+    /* uses complete <time.h> facility */
+    #include <time.h>
+    #define XTIME(tl)  time((tl))
+    #define XGMTIME(c) 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;
+
+    sec = SNTPGetUTCSeconds();
+    *timer = (time_t) sec;
+
+    return *timer;
+}
+
+#endif /* MICROCHIP_TCPIP */
+
+
+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 */
+
+
+static int GetLength(const byte* input, word32* inOutIdx, int* len,
+                     word32 maxIdx)
+{
+    int     length = 0;
+    word32  i = *inOutIdx;
+    byte    b;
+
+    if ( (i+1) > maxIdx) {   /* for first read */
+        CYASSL_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 */
+            CYASSL_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 */
+        CYASSL_MSG("GetLength value exceeds buffer length");
+        return BUFFER_E;
+    }
+
+    *inOutIdx = i;
+    *len      = length;
+
+    return length;
+}
+
+
+static 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;
+}
+
+
+static 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 */
+static int GetMyVersion(const byte* input, word32* inOutIdx, int* version)
+{
+    word32 idx = *inOutIdx;
+
+    CYASSL_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;
+
+    CYASSL_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;
+}
+
+
+static 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;
+}
+
+
+static int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid,
+                     word32 maxIdx)
+{
+    int    length;
+    word32 i = *inOutIdx;
+    byte   b;
+    *oid = 0;
+   
+    CYASSL_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 RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
+                        word32 inSz)
+{
+    int    version, length;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == CYASSL_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 0;
+}
+
+
+#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)
+{
+    byte   key[MAX_KEY_SIZE];
+    int    typeH;
+    int    derivedLen;
+    int    decryptionType;
+    int    ret = 0; 
+
+    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;
+    }
+
+    if (version == PKCS5v2)
+        ret = PBKDF2(key, (byte*)password, passwordSz, salt, saltSz, iterations,
+               derivedLen, typeH);
+    else if (version == PKCS5)
+        ret = PBKDF1(key, (byte*)password, passwordSz, salt, saltSz, iterations,
+               derivedLen, typeH);
+    else if (version == PKCS12) {
+        int  i, idx = 0;
+        byte unicodePasswd[MAX_UNICODE_SZ];
+
+        if ( (passwordSz * 2 + 2) > (int)sizeof(unicodePasswd))
+            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 =  PKCS12_PBKDF(key, unicodePasswd, idx, salt, saltSz,
+                            iterations, derivedLen, typeH, 1);
+        if (decryptionType != RC4_TYPE)
+            ret += PKCS12_PBKDF(cbcIv, unicodePasswd, idx, salt, saltSz,
+                                iterations, 8, typeH, 2);
+    }
+    else
+        return ALGO_ID_E;
+
+    if (ret != 0)
+        return ret;
+
+    switch (decryptionType) {
+#ifndef NO_DES3
+        case DES_TYPE:
+        {
+            Des    dec;
+            byte*  desIv = key + 8;
+
+            if (version == PKCS5v2 || version == PKCS12)
+                desIv = cbcIv;
+            Des_SetKey(&dec, key, desIv, DES_DECRYPTION);
+            Des_CbcDecrypt(&dec, input, input, length);
+            break;
+        }
+
+        case DES3_TYPE:
+        {
+            Des3   dec;
+            byte*  desIv = key + 24;
+
+            if (version == PKCS5v2 || version == PKCS12)
+                desIv = cbcIv;
+            Des3_SetKey(&dec, key, desIv, DES_DECRYPTION);
+            Des3_CbcDecrypt(&dec, input, input, length);
+            break;
+        }
+#endif
+#ifndef NO_RC4
+        case RC4_TYPE:
+        {
+            Arc4    dec;
+
+            Arc4SetKey(&dec, key, derivedLen);
+            Arc4Process(&dec, input, input, length);
+            break;
+        }
+#endif
+
+        default:
+            return ALGO_ID_E; 
+    }
+
+    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;
+    byte   salt[MAX_SALT_SIZE];
+    byte   cbcIv[MAX_IV_SIZE];
+    
+    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;
+     
+    XMEMCPY(salt, &input[inOutIdx], saltSz);
+    inOutIdx += saltSz;
+
+    if (GetShortInt(input, &inOutIdx, &iterations) < 0)
+        return ASN_PARSE_E;
+
+    if (version == PKCS5v2) {
+        /* get encryption algo */
+        if (GetAlgoId(input, &inOutIdx, &oid, sz) < 0)
+            return ASN_PARSE_E;
+
+        if (CheckAlgoV2(oid, &id) < 0)
+            return ASN_PARSE_E;  /* PKCS v2 algo id error */
+
+        if (input[inOutIdx++] != ASN_OCTET_STRING)
+            return ASN_PARSE_E;
+    
+        if (GetLength(input, &inOutIdx, &length, sz) < 0)
+            return ASN_PARSE_E;
+
+        XMEMCPY(cbcIv, &input[inOutIdx], length);
+        inOutIdx += length;
+    }
+
+    if (input[inOutIdx++] != ASN_OCTET_STRING)
+        return ASN_PARSE_E;
+    
+    if (GetLength(input, &inOutIdx, &length, sz) < 0)
+        return ASN_PARSE_E;
+
+    if (DecryptKey(password, passwordSz, salt, saltSz, iterations, id,
+                   input + inOutIdx, length, version, cbcIv) < 0)
+        return ASN_INPUT_E;  /* decrypt failure */
+
+    XMEMMOVE(input, input + inOutIdx, length);
+    return ToTraditional(input, length);
+}
+
+#endif /* NO_PWDBASED */
+
+#ifndef NO_RSA
+
+int 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;
+
+#ifdef OPENSSL_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;
+}
+
+#endif
+
+#ifndef NO_DH
+
+int 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 DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g, word32 gSz)
+{
+    /* 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;
+}
+
+
+#ifdef OPENSSL_EXTRA
+
+int 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 /* OPENSSL_EXTRA */
+#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->pubKeyStored    = 0;
+    cert->signature       = 0;
+    cert->subjectCN       = 0;
+    cert->subjectCNLen    = 0;
+    cert->subjectCNStored = 0;
+    cert->altNames        = NULL;
+    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, SHA_SIZE);
+    cert->extSubjKeyIdSet = 0;
+    XMEMSET(cert->extAuthKeyId, 0, SHA_SIZE);
+    cert->extAuthKeyIdSet = 0;
+    cert->isCA            = 0;
+#ifdef CYASSL_CERT_GEN
+    cert->subjectSN       = 0;
+    cert->subjectSNLen    = 0;
+    cert->subjectC        = 0;
+    cert->subjectCLen     = 0;
+    cert->subjectL        = 0;
+    cert->subjectLLen     = 0;
+    cert->subjectST       = 0;
+    cert->subjectSTLen    = 0;
+    cert->subjectO        = 0;
+    cert->subjectOLen     = 0;
+    cert->subjectOU       = 0;
+    cert->subjectOULen    = 0;
+    cert->subjectEmail    = 0;
+    cert->subjectEmailLen = 0;
+    cert->beforeDate      = 0;
+    cert->beforeDateLen   = 0;
+    cert->afterDate       = 0;
+    cert->afterDateLen    = 0;
+#endif /* CYASSL_CERT_GEN */
+}
+
+
+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;
+    }
+}
+
+
+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->altNames)
+        FreeAltNames(cert->altNames, cert->heap);
+}
+
+
+static int GetCertHeader(DecodedCert* cert)
+{
+    int    ret = 0, version, len;
+    byte   serialTmp[EXTERNAL_SERIAL_SIZE];
+    mp_int mpi;
+
+    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, &version) < 0)
+        return ASN_PARSE_E;
+
+    if (GetInt(&mpi, cert->source, &cert->srcIdx, cert->maxIdx) < 0) 
+        return ASN_PARSE_E;
+
+    len = mp_unsigned_bin_size(&mpi);
+    if (len < (int)sizeof(serialTmp)) {
+        if (mp_to_unsigned_bin(&mpi, serialTmp) == MP_OKAY) {
+            if (len > EXTERNAL_SERIAL_SIZE)
+                len = EXTERNAL_SERIAL_SIZE;
+            XMEMCPY(cert->serial, serialTmp, len);
+            cert->serialSz = len;
+        }
+    }
+    mp_clear(&mpi);
+    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 read = cert->srcIdx;
+
+    if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0)
+        return ASN_PARSE_E;
+   
+    read = cert->srcIdx - read;
+    length += read;
+
+    while (read--)
+       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)
+    {
+        if (oid != ECC_256R1 && oid != ECC_384R1 && oid != ECC_521R1 && oid !=
+                   ECC_160R1 && oid != ECC_192R1 && oid != ECC_224R1)
+            return ALGO_ID_E; 
+
+        return 0;
+    }
+
+#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) {
+        case DSAk:
+            /* do nothing */
+        break;
+   #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;
+            byte        keyBlob[MAX_NTRU_KEY_SZ];
+
+            word32 rc = crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey(key,
+                                &keyLen, NULL, &next);
+
+            if (rc != NTRU_OK)
+                return ASN_NTRU_KEY_E;
+            if (keyLen > sizeof(keyBlob))
+                return ASN_NTRU_KEY_E;
+
+            rc = crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey(key,&keyLen,
+                                                                keyBlob, &next);
+            if (rc != NTRU_OK)
+                return ASN_NTRU_KEY_E;
+
+            if ( (next - key) < 0)
+                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)
+                return MEMORY_E;
+            XMEMCPY(cert->publicKey, keyBlob, keyLen);
+            cert->pubKeyStored = 1;
+            cert->pubKeySize   = keyLen;
+        }
+        break;
+    #endif /* HAVE_NTRU */
+    #ifdef HAVE_ECC
+        case ECDSAk:
+        {
+            word32 oid = 0;
+            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--)
+                oid += cert->source[cert->srcIdx++];
+            if (CheckCurve(oid) < 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;
+        }
+        break;
+    #endif /* HAVE_ECC */
+        default:
+            return ASN_UNKNOWN_OID_E;
+    }
+   
+    return 0;
+}
+
+
+/* process NAME, either issuer or subject */
+static int GetName(DecodedCert* cert, int nameType)
+{
+    Sha    sha;     /* MUST have SHA-1 hash for cert names */
+    int    length;  /* length of all distinguished names */
+    int    dummy;
+    char* full = (nameType == ISSUER) ? cert->issuer : cert->subject;
+    word32 idx;
+
+    CYASSL_MSG("Getting Cert Name");
+
+    if (cert->source[cert->srcIdx] == ASN_OBJECT_ID) {
+        CYASSL_MSG("Trying optional prefix...");
+
+        if (GetLength(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0)
+            return ASN_PARSE_E;
+
+        cert->srcIdx += length;
+        CYASSL_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;
+
+    InitSha(&sha);
+    ShaUpdate(&sha, &cert->source[idx], length + cert->srcIdx - idx);
+    if (nameType == ISSUER)
+        ShaFinal(&sha, cert->issuerHash);
+    else
+        ShaFinal(&sha, cert->subjectHash);
+
+    length += cert->srcIdx;
+    idx = 0;
+
+    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) {
+            CYASSL_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++];    /* strType */
+            (void)b;                              /* may want to validate? */
+
+            if (GetLength(cert->source, &cert->srcIdx, &strLen,
+                          cert->maxIdx) < 0)
+                return ASN_PARSE_E;
+
+            if ( (strLen + 4) > (int)(ASN_NAME_MAX - idx)) {
+                /* include biggest pre fix header too 4 = "/CN=" */
+                CYASSL_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;
+                }
+
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/CN=", 4);
+                    idx += 4;
+                    copy = TRUE;
+                }
+            }
+            else if (id == ASN_SUR_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/SN=", 4);
+                    idx += 4;
+                    copy = TRUE;
+                }
+#ifdef CYASSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectSN = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectSNLen = strLen;
+                }
+#endif /* CYASSL_CERT_GEN */
+            }
+            else if (id == ASN_COUNTRY_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/C=", 3);
+                    idx += 3;
+                    copy = TRUE;
+                }
+#ifdef CYASSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectC = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectCLen = strLen;
+                }
+#endif /* CYASSL_CERT_GEN */
+            }
+            else if (id == ASN_LOCALITY_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/L=", 3);
+                    idx += 3;
+                    copy = TRUE;
+                }
+#ifdef CYASSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectL = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectLLen = strLen;
+                }
+#endif /* CYASSL_CERT_GEN */
+            }
+            else if (id == ASN_STATE_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/ST=", 4);
+                    idx += 4;
+                    copy = TRUE;
+                }
+#ifdef CYASSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectST = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectSTLen = strLen;
+                }
+#endif /* CYASSL_CERT_GEN */
+            }
+            else if (id == ASN_ORG_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/O=", 3);
+                    idx += 3;
+                    copy = TRUE;
+                }
+#ifdef CYASSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectO = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectOLen = strLen;
+                }
+#endif /* CYASSL_CERT_GEN */
+            }
+            else if (id == ASN_ORGUNIT_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/OU=", 4);
+                    idx += 4;
+                    copy = TRUE;
+                }
+#ifdef CYASSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectOU = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectOULen = strLen;
+                }
+#endif /* CYASSL_CERT_GEN */
+            }
+
+            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)) {
+                CYASSL_MSG("ASN name too big, skipping");
+                tooBig = TRUE;
+            }
+
+            if (email) {
+                if ( (14 + adv) > (int)(ASN_NAME_MAX - idx)) {
+                    CYASSL_MSG("ASN name too big, skipping");
+                    tooBig = TRUE;
+                }
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/emailAddress=", 14);
+                    idx += 14;
+                }
+
+#ifdef CYASSL_CERT_GEN
+                if (nameType == SUBJECT) {
+                    cert->subjectEmail = (char*)&cert->source[cert->srcIdx];
+                    cert->subjectEmailLen = adv;
+                }
+#endif /* CYASSL_CERT_GEN */
+
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], &cert->source[cert->srcIdx], adv);
+                    idx += adv;
+                }
+            }
+
+            if (uid) {
+                if ( (5 + adv) > (int)(ASN_NAME_MAX - idx)) {
+                    CYASSL_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;
+                }
+            }
+
+            cert->srcIdx += adv;
+        }
+    }
+    full[idx++] = 0;
+
+    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(a,b);
+}
+
+
+/* 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;
+    int    i = 0;
+
+    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;
+    }
+
+    GetTime(&certTime.tm_year, date, &i); certTime.tm_year -= 1900; /* adjust */
+    GetTime(&certTime.tm_mon,  date, &i); certTime.tm_mon  -= 1;    /* adjust */
+    GetTime(&certTime.tm_mday, date, &i);
+    GetTime(&certTime.tm_hour, date, &i); 
+    GetTime(&certTime.tm_min,  date, &i); 
+    GetTime(&certTime.tm_sec,  date, &i); 
+        
+        if (date[i] != 'Z') {     /* only Zulu supported for this profile */
+        CYASSL_MSG("Only Zulu time supported for this profile"); 
+        return 0;
+    }
+
+    //localTime = XGMTIME(&ltime);
+    // XXX gmtime seems to be broken on mbed, need to find out why
+    localTime = localtime(&ltime);
+    
+    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;
+
+#ifdef CYASSL_CERT_GEN
+    word32 startIdx = 0;
+    if (dateType == BEFORE)
+        cert->beforeDate = &cert->source[cert->srcIdx];
+    else
+        cert->afterDate = &cert->source[cert->srcIdx];
+    startIdx = cert->srcIdx;
+#endif
+
+    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;
+
+#ifdef CYASSL_CERT_GEN
+    if (dateType == BEFORE)
+        cert->beforeDateLen = cert->srcIdx - startIdx;
+    else
+        cert->afterDateLen  = cert->srcIdx - startIdx;
+#endif
+
+    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;
+
+    if ( (ret = GetAlgoId(cert->source, &cert->srcIdx, &cert->signatureOID,
+                          cert->maxIdx)) < 0)
+        return ret;
+
+    if ( (ret = GetName(cert, ISSUER)) < 0)
+        return ret;
+
+    if ( (ret = GetValidity(cert, verify)) < 0)
+        badDate = ret;
+
+    if ( (ret = GetName(cert, SUBJECT)) < 0)
+        return ret;
+
+    if ( (ret = GetKey(cert)) < 0)
+        return ret;
+
+    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) * CYASSL_BIT_SIZE))
+            break;
+
+    return i;
+}
+
+
+static 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) * CYASSL_BIT_SIZE));
+            i++;
+        }
+    }
+
+    return i;
+}
+
+
+static word32 SetSequence(word32 len, byte* output)
+{
+    output[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
+    return SetLength(len, output + 1) + 1;
+}
+
+
+static word32 SetAlgoID(int algoOID, byte* output, int type)
+{
+    /* 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};
+
+    /* 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 */
+ 
+    /* keyTypes */
+    #ifndef NO_RSA
+        static const byte RSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+                                            0x01, 0x01, 0x01, 0x05, 0x00};
+    #endif /* NO_RSA */
+
+    int    algoSz = 0;
+    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:
+            CYASSL_MSG("Unknown Hash Algo");
+            return 0;  /* UNKOWN_HASH_E; */
+        }
+    }
+    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 */
+        default:
+            CYASSL_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 */
+        default:
+            CYASSL_MSG("Unknown Key Algo");
+            return 0;
+        }
+    }
+    else {
+        CYASSL_MSG("Unknown Algo type");
+        return 0;
+    }
+
+    idSz  = SetLength(algoSz - 2, ID_Length); /* don't include TAG_NULL/0 */
+    seqSz = SetSequence(idSz + algoSz + 1, seqArray);
+    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 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);
+    seqSz    = SetSequence(encDigSz + algoSz, seqArray);
+
+    XMEMCPY(out, seqArray, seqSz);
+    XMEMCPY(out + seqSz, algoArray, algoSz);
+    XMEMCPY(out + seqSz + algoSz, digArray, encDigSz);
+
+    return encDigSz + algoSz + seqSz;
+}
+
+
+/* return true (1) 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)
+{
+#ifdef CYASSL_SHA512
+    byte digest[SHA512_DIGEST_SIZE]; /* max size */
+#elif !defined(NO_SHA256)
+    byte digest[SHA256_DIGEST_SIZE]; /* max size */
+#else
+    byte digest[SHA_DIGEST_SIZE];    /* max size */
+#endif
+    int  typeH, digestSz, ret = 0;
+
+    (void)key;
+    (void)keySz;
+    (void)sig;
+    (void)sigSz;
+    (void)heap;
+    (void)ret;
+
+    switch (sigOID) {
+#ifndef NO_MD5
+        case CTC_MD5wRSA:
+        {
+            Md5 md5;
+            InitMd5(&md5);
+            Md5Update(&md5, buf, bufSz);
+            Md5Final(&md5, digest);
+            typeH    = MD5h;
+            digestSz = MD5_DIGEST_SIZE;
+        }
+        break;
+#endif
+    #if defined(CYASSL_MD2)
+        case CTC_MD2wRSA:
+        {
+            Md2 md2;
+            InitMd2(&md2);
+            Md2Update(&md2, buf, bufSz);
+            Md2Final(&md2, digest);
+            typeH    = MD2h;
+            digestSz = MD2_DIGEST_SIZE;
+        }
+        break;
+    #endif
+#ifndef NO_SHA
+        case CTC_SHAwRSA:
+        case CTC_SHAwDSA:
+        case CTC_SHAwECDSA:
+        {
+            Sha sha;
+            InitSha(&sha);
+            ShaUpdate(&sha, buf, bufSz);
+            ShaFinal(&sha, digest);
+            typeH    = SHAh;
+            digestSz = SHA_DIGEST_SIZE;
+        }
+        break;
+#endif
+    #ifndef NO_SHA256
+        case CTC_SHA256wRSA:
+        case CTC_SHA256wECDSA:
+        {
+            Sha256 sha256;
+            InitSha256(&sha256);
+            Sha256Update(&sha256, buf, bufSz);
+            Sha256Final(&sha256, digest);
+            typeH    = SHA256h;
+            digestSz = SHA256_DIGEST_SIZE;
+        }
+        break;
+    #endif
+    #ifdef CYASSL_SHA512
+        case CTC_SHA512wRSA:
+        case CTC_SHA512wECDSA:
+        {
+            Sha512 sha512;
+            InitSha512(&sha512);
+            Sha512Update(&sha512, buf, bufSz);
+            Sha512Final(&sha512, digest);
+            typeH    = SHA512h;
+            digestSz = SHA512_DIGEST_SIZE;
+        }
+        break;
+    #endif
+    #ifdef CYASSL_SHA384
+        case CTC_SHA384wRSA:
+        case CTC_SHA384wECDSA:
+        {
+            Sha384 sha384;
+            InitSha384(&sha384);
+            Sha384Update(&sha384, buf, bufSz);
+            Sha384Final(&sha384, digest);
+            typeH    = SHA384h;
+            digestSz = SHA384_DIGEST_SIZE;
+        }
+        break;
+    #endif
+        default:
+            CYASSL_MSG("Verify Signautre has unsupported type");
+            return 0;
+    }
+
+    switch (keyOID) {
+    #ifndef NO_RSA
+        case RSAk:
+        {
+            RsaKey pubKey;
+            byte   encodedSig[MAX_ENCODED_SIG_SZ];
+            byte   plain[MAX_ENCODED_SIG_SZ];
+            word32 idx = 0;
+            int    encodedSigSz, verifySz;
+            byte*  out;
+
+            if (sigSz > MAX_ENCODED_SIG_SZ) {
+                CYASSL_MSG("Verify Signautre is too big");
+                return 0;
+            }
+                
+            InitRsaKey(&pubKey, heap);
+            if (RsaPublicKeyDecode(key, &idx, &pubKey, keySz) < 0) {
+                CYASSL_MSG("ASN Key decode error RSA");
+                ret = 0;
+            }
+            else {
+                XMEMCPY(plain, sig, sigSz);
+                if ( (verifySz = RsaSSL_VerifyInline(plain, sigSz, &out,
+                                               &pubKey)) < 0) {
+                    CYASSL_MSG("Rsa SSL verify error");
+                    ret = 0;
+                }
+                else {
+                    /* make sure we're right justified */
+                    encodedSigSz =
+                        EncodeSignature(encodedSig, digest, digestSz, typeH);
+                    if (encodedSigSz != verifySz ||
+                                XMEMCMP(out, encodedSig, encodedSigSz) != 0) {
+                        CYASSL_MSG("Rsa SSL verify match encode error");
+                        ret = 0;
+                    }
+                    else
+                        ret = 1; /* match */
+
+                    #ifdef CYASSL_DEBUG_ENCODING
+                    {
+                    int x;
+                    printf("cyassl 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 /* CYASSL_DEBUG_ENCODING */
+                }
+            }
+            FreeRsaKey(&pubKey);
+            return ret;
+        }
+
+    #endif /* NO_RSA */
+    #ifdef HAVE_ECC
+        case ECDSAk:
+        {
+            ecc_key pubKey;
+            int     verify = 0;
+            
+            if (ecc_import_x963(key, keySz, &pubKey) < 0) {
+                CYASSL_MSG("ASN Key import error ECC");
+                return 0;
+            }
+        
+            ret = ecc_verify_hash(sig,sigSz,digest,digestSz,&verify,&pubKey);
+            ecc_free(&pubKey);
+            if (ret == 0 && verify == 1)
+                return 1;  /* match */
+
+            CYASSL_MSG("ECC Verify didn't match");
+            return 0;
+        }
+    #endif /* HAVE_ECC */
+        default:
+            CYASSL_MSG("Verify Key type unknown");
+            return 0;
+    }
+}
+
+
+static void DecodeAltNames(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length = 0;
+
+    CYASSL_ENTER("DecodeAltNames");
+
+    if (GetSequence(input, &idx, &length, sz) < 0) {
+        CYASSL_MSG("\tBad Sequence");
+        return;
+    }
+
+    while (length > 0) {
+        DNS_entry* entry;
+        int        strLen;
+        byte       b = input[idx++];
+
+        length--;
+
+        if (b != (ASN_CONTEXT_SPECIFIC | ASN_DNS_TYPE)) {
+            CYASSL_MSG("\tNot DNS type");
+            return;
+        }
+
+        if (GetLength(input, &idx, &strLen, sz) < 0) {
+            CYASSL_MSG("\tfail: str length");
+            return;
+        }
+
+        entry = (DNS_entry*)XMALLOC(sizeof(DNS_entry), cert->heap,
+                                    DYNAMIC_TYPE_ALTNAME);
+        if (entry == NULL) {
+            CYASSL_MSG("\tOut of Memory");
+            return;
+        }
+
+        entry->name = (char*)XMALLOC(strLen + 1, cert->heap,
+                                     DYNAMIC_TYPE_ALTNAME);
+        if (entry->name == NULL) {
+            CYASSL_MSG("\tOut of Memory");
+            XFREE(entry, cert->heap, DYNAMIC_TYPE_ALTNAME);
+            return;
+        }
+
+        XMEMCPY(entry->name, &input[idx], strLen);
+        entry->name[strLen] = '\0';
+
+        entry->next    = cert->altNames;
+        cert->altNames = entry;
+
+        length -= strLen;
+        idx    += strLen;
+    }   
+}
+
+
+static void DecodeBasicCaConstraint(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length = 0;
+
+    CYASSL_ENTER("DecodeBasicCaConstraint");
+    if (GetSequence(input, &idx, &length, sz) < 0) return;
+
+    if (length == 0) return;
+    /* 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)
+    {
+        CYASSL_MSG("\tfail: constraint not BOOLEAN");
+        return;
+    }
+
+    if (GetLength(input, &idx, &length, sz) < 0)
+    {
+        CYASSL_MSG("\tfail: length");
+        return;
+    }
+
+    if (input[idx])
+        cert->isCA = 1;
+}
+
+
+#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 void DecodeCrlDist(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length = 0;
+
+    CYASSL_ENTER("DecodeCrlDist");
+
+    /* Unwrap the list of Distribution Points*/
+    if (GetSequence(input, &idx, &length, sz) < 0) return;
+
+    /* Unwrap a single Distribution Point */
+    if (GetSequence(input, &idx, &length, sz) < 0) return;
+
+    /* 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;
+
+        if (input[idx] == 
+                    (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | CRLDP_FULL_NAME))
+        {
+            idx++;
+            if (GetLength(input, &idx, &length, sz) < 0) return;
+
+            if (input[idx] == (ASN_CONTEXT_SPECIFIC | GENERALNAME_URI))
+            {
+                idx++;
+                if (GetLength(input, &idx, &length, sz) < 0) return;
+
+                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;
+        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;
+        idx += length;
+    }
+
+    if (idx < (word32)sz)
+    {
+        CYASSL_MSG("\tThere are more CRL Distribution Point records, "
+                   "but we only use the first one.");
+    }
+
+    return;
+}
+
+
+static void 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;
+    word32 oid;
+
+    /* Unwrap the list of AIAs */
+    if (GetSequence(input, &idx, &length, sz) < 0) return;
+
+    /* Unwrap a single AIA */
+    if (GetSequence(input, &idx, &length, sz) < 0) return;
+
+    oid = 0;
+    if (GetObjectId(input, &idx, &oid, sz) < 0) return;
+
+    /* Only supporting URIs right now. */
+    if (input[idx] == (ASN_CONTEXT_SPECIFIC | GENERALNAME_URI))
+    {
+        idx++;
+        if (GetLength(input, &idx, &length, sz) < 0) return;
+
+        cert->extAuthInfoSz = length;
+        cert->extAuthInfo = input + idx;
+        idx += length;
+    }
+    else
+    {
+        /* Skip anything else. */
+        idx++;
+        if (GetLength(input, &idx, &length, sz) < 0) return;
+        idx += length;
+    }
+
+    if (idx < (word32)sz)
+    {
+        CYASSL_MSG("\tThere are more Authority Information Access records, "
+                   "but we only use first one.");
+    }
+
+    return;
+}
+
+
+static void DecodeAuthKeyId(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length = 0;
+
+    CYASSL_ENTER("DecodeAuthKeyId");
+
+    if (GetSequence(input, &idx, &length, sz) < 0) {
+        CYASSL_MSG("\tfail: should be a SEQUENCE\n");
+        return;
+    }
+
+    if (input[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) {
+        CYASSL_MSG("\tfail: wanted OPTIONAL item 0, not available\n");
+    }
+
+    if (GetLength(input, &idx, &length, sz) < 0) {
+        CYASSL_MSG("\tfail: extension data length");
+        return;
+    }
+
+    if (length == SHA_SIZE) {
+        XMEMCPY(cert->extAuthKeyId, input + idx, length);
+    }
+    else {
+        Sha sha;
+        InitSha(&sha);
+        ShaUpdate(&sha, input + idx, length);
+        ShaFinal(&sha, cert->extAuthKeyId);
+    }
+    cert->extAuthKeyIdSet = 1;
+
+    return;
+}
+
+
+static void DecodeSubjKeyId(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length = 0;
+
+    CYASSL_ENTER("DecodeSubjKeyId");
+
+    if (input[idx++] != ASN_OCTET_STRING) {
+        CYASSL_MSG("\tfail: should be an OCTET STRING");
+        return;
+    }
+
+    if (GetLength(input, &idx, &length, sz) < 0) {
+        CYASSL_MSG("\tfail: extension data length");
+        return;
+    }
+
+    if (length == SIGNER_DIGEST_SIZE) {
+        XMEMCPY(cert->extSubjKeyId, input + idx, length);
+    }
+    else {
+        Sha sha;
+        InitSha(&sha);
+        ShaUpdate(&sha, input + idx, length);
+        ShaFinal(&sha, cert->extSubjKeyId);
+    }
+    cert->extSubjKeyIdSet = 1;
+
+    return;
+}
+
+
+static void 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;
+
+    CYASSL_ENTER("DecodeCertExtensions");
+
+    if (input == NULL || sz == 0) return;
+
+    if (input[idx++] != ASN_EXTENSIONS) return;
+
+    if (GetLength(input, &idx, &length, sz) < 0) return;
+
+    if (GetSequence(input, &idx, &length, sz) < 0) return;
+    
+    while (idx < (word32)sz) {
+        if (GetSequence(input, &idx, &length, sz) < 0) {
+            CYASSL_MSG("\tfail: should be a SEQUENCE");
+            return;
+        }
+
+        oid = 0;
+        if (GetObjectId(input, &idx, &oid, sz) < 0) {
+            CYASSL_MSG("\tfail: OBJECT ID");
+            return;
+        }
+
+        /* check for critical flag */
+        if (input[idx] == ASN_BOOLEAN) {
+            CYASSL_MSG("\tfound optional critical flag, moving past");
+            idx += (ASN_BOOL_SIZE + 1);
+        }
+
+        /* process the extension based on the OID */
+        if (input[idx++] != ASN_OCTET_STRING) {
+            CYASSL_MSG("\tfail: should be an OCTET STRING");
+            return;
+        }
+
+        if (GetLength(input, &idx, &length, sz) < 0) {
+            CYASSL_MSG("\tfail: extension data length");
+            return;
+        }
+
+        switch (oid) {
+            case BASIC_CA_OID:
+                DecodeBasicCaConstraint(&input[idx], length, cert);
+                break;
+
+            case CRL_DIST_OID:
+                DecodeCrlDist(&input[idx], length, cert);
+                break;
+
+            case AUTH_INFO_OID:
+                DecodeAuthInfo(&input[idx], length, cert);
+                break;
+
+            case ALT_NAMES_OID:
+                DecodeAltNames(&input[idx], length, cert);
+
+            case AUTH_KEY_OID:
+                DecodeAuthKeyId(&input[idx], length, cert);
+                break;
+
+            case SUBJ_KEY_OID:
+                DecodeSubjKeyId(&input[idx], length, cert);
+                break;
+
+            default:
+                CYASSL_MSG("\tExtension type not handled, skipping");
+                break;
+        }
+        idx += length;
+    }
+
+    return;
+}
+
+
+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->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
+    CYASSL_LOCAL Signer* GetCA(void* signers, byte* hash);
+    #ifndef NO_SKID
+        CYASSL_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;
+
+    if ((ret = DecodeToKey(cert, verify)) < 0) {
+        if (ret == ASN_BEFORE_DATE_E || ret == ASN_AFTER_DATE_E)
+            badDate = ret;
+        else
+            return ret;
+    }
+
+    if (cert->srcIdx != cert->sigIndex) {
+        if (cert->srcIdx < cert->sigIndex) {
+            /* save extensions */
+            cert->extensions    = &cert->source[cert->srcIdx];
+            cert->extensionsSz  =  cert->sigIndex - cert->srcIdx;
+            cert->extensionsIdx = cert->srcIdx;   /* for potential later use */
+        }
+        DecodeCertExtensions(cert);
+        /* 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) {
+            Sha sha;
+            InitSha(&sha);
+            ShaUpdate(&sha, cert->publicKey, cert->pubKeySize);
+            ShaFinal(&sha, cert->extSubjKeyId);
+            cert->extSubjKeyIdSet = 1;
+        }
+    #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 */
+        CYASSL_MSG("About to verify certificate signature");
+ 
+        if (ca) {
+#ifdef HAVE_OCSP
+            /* Need the ca's public key hash for OCSP */
+            {
+                Sha sha;
+                InitSha(&sha);
+                ShaUpdate(&sha, ca->publicKey, ca->pubKeySize);
+                ShaFinal(&sha, cert->issuerKeyHash);
+            }
+#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)) {
+                CYASSL_MSG("Confirm signature failed");
+                return ASN_SIG_CONFIRM_E;
+            }
+        }
+        else {
+            /* no signer */
+            CYASSL_MSG("No CA signer to verify with");
+            return ASN_NO_SIGNER_E;
+        }
+    }
+
+    if (badDate != 0)
+        return badDate;
+
+    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;
+        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);
+    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;
+    }
+}
+
+
+#if defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN)
+
+static 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;
+}
+
+
+int DerToPem(const byte* der, word32 derSz, byte* output, word32 outSz,
+             int type)
+{
+    char header[80];
+    char footer[80];
+
+    int headerLen;
+    int footerLen;
+    int i;
+    int err;
+    int outLen;   /* return length or error */
+
+    if (type == CERT_TYPE) {
+        XSTRNCPY(header, "-----BEGIN CERTIFICATE-----\n", sizeof(header));
+        XSTRNCPY(footer, "-----END CERTIFICATE-----\n", sizeof(footer));
+    }
+    else if (type == PRIVATEKEY_TYPE) {
+        XSTRNCPY(header, "-----BEGIN RSA PRIVATE KEY-----\n", sizeof(header));
+        XSTRNCPY(footer, "-----END RSA PRIVATE KEY-----\n", sizeof(footer));
+    }
+    #ifdef HAVE_ECC
+    else if (type == ECC_PRIVATEKEY_TYPE) {
+        XSTRNCPY(header, "-----BEGIN EC PRIVATE KEY-----\n", sizeof(header));
+        XSTRNCPY(footer, "-----END EC PRIVATE KEY-----\n", sizeof(footer));
+    }
+    #endif
+    else
+        return BAD_FUNC_ARG;
+
+    headerLen = (int)XSTRLEN(header);
+    footerLen = (int)XSTRLEN(footer);
+
+    if (!der || !output)
+        return BAD_FUNC_ARG;
+
+    /* don't even try if outSz too short */
+    if (outSz < headerLen + footerLen + derSz)
+        return BAD_FUNC_ARG;
+
+    /* header */
+    XMEMCPY(output, header, headerLen);
+    i = headerLen;
+
+    /* body */
+    outLen = outSz - (headerLen + footerLen);  /* input to Base64_Encode */
+    if ( (err = Base64_Encode(der, derSz, output + i, (word32*)&outLen)) < 0)
+        return err;
+    i += outLen;
+
+    /* footer */
+    if ( (i + footerLen) > (int)outSz)
+        return BAD_FUNC_ARG;
+    XMEMCPY(output + i, footer, footerLen);
+
+    return outLen + headerLen + footerLen;
+}
+
+
+#endif /* CYASSL_KEY_GEN || CYASSL_CERT_GEN */
+
+
+#if defined(CYASSL_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 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 /* CYASSL_KEY_GEN && !NO_RSA */
+
+
+#if defined(CYASSL_CERT_GEN) && !defined(NO_RSA)
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* 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 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 CYASSL_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.state[0] = '\0';
+    cert->issuer.locality[0] = '\0';
+    cert->issuer.sur[0] = '\0';
+    cert->issuer.org[0] = '\0';
+    cert->issuer.unit[0] = '\0';
+    cert->issuer.commonName[0] = '\0';
+    cert->issuer.email[0] = '\0';
+
+    cert->subject.country[0] = '\0';
+    cert->subject.state[0] = '\0';
+    cert->subject.locality[0] = '\0';
+    cert->subject.sur[0] = '\0';
+    cert->subject.org[0] = '\0';
+    cert->subject.unit[0] = '\0';
+    cert->subject.commonName[0] = '\0';
+    cert->subject.email[0] = '\0';
+}
+
+
+/* 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 */
+    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 */
+} DerCert;
+
+
+/* Write a set header to output */
+static word32 SetSet(word32 len, byte* output)
+{
+    output[0] = ASN_SET | ASN_CONSTRUCTED;
+    return SetLength(len, output + 1) + 1;
+}
+
+
+/* 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;
+}
+
+
+/* Write a public RSA key to output */
+static int SetPublicKey(byte* output, RsaKey* key)
+{
+    byte n[MAX_RSA_INT_SZ];
+    byte e[MAX_RSA_E_SZ];
+    byte algo[MAX_ALGO_SZ];
+    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;
+
+    /* n */
+    rawLen = mp_unsigned_bin_size(&key->n);
+    n[0] = ASN_INTEGER;
+    nSz  = SetLength(rawLen, n + 1) + 1;  /* int tag */
+
+    if ( (nSz + rawLen) < (int)sizeof(n)) {
+        int err = mp_to_unsigned_bin(&key->n, n + nSz);
+        if (err == MP_OKAY)
+            nSz += rawLen;
+        else
+            return MP_TO_E;
+    }
+    else
+        return BUFFER_E;
+
+    /* e */
+    rawLen = mp_unsigned_bin_size(&key->e);
+    e[0] = ASN_INTEGER;
+    eSz  = SetLength(rawLen, e + 1) + 1;  /* int tag */
+
+    if ( (eSz + rawLen) < (int)sizeof(e)) {
+        int err = mp_to_unsigned_bin(&key->e, e + eSz);
+        if (err == MP_OKAY)
+            eSz += rawLen;
+        else
+            return MP_TO_E;
+    }
+    else
+        return BUFFER_E;
+
+    /* headers */
+    algoSz = SetAlgoID(RSAk, algo, keyType);
+    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;
+
+    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 CYASSL_ALT_NAMES
+
+/* Copy Dates from cert, return bytes written */
+static int CopyValidity(byte* output, Cert* cert)
+{
+    int seqSz;
+
+    CYASSL_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
+
+
+/* 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;
+    struct tm* now;
+    struct tm  local;
+
+    ticks = XTIME(0);
+    now   = XGMTIME(&ticks);
+
+    /* 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;
+    mktime(&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;
+    mktime(&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 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)
+{
+    byte sequence[MAX_SEQ_SZ];
+    byte len[MAX_LENGTH_SZ];
+
+    int sz = 0;
+    int seqSz = SetSequence(extSz, sequence);
+    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;
+    EncodedName names[NAME_ENTRIES];
+
+    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))
+                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 */
+                names[i].encoded[idx++] = 0x55;
+                names[i].encoded[idx++] = 0x04;
+                /* id type */
+                names[i].encoded[idx++] = GetNameId(i);
+                /* str type */
+                names[i].encoded[idx++] = 0x13;
+            }
+            /* 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)
+        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;
+        }
+    }
+    return totalBytes;
+}
+
+/* encode info from cert into DER enocder format */
+static int EncodeCert(
+Cert* cert, 
+DerCert* der, 
+RsaKey* rsaKey, 
+RNG* rng,
+                      const byte* ntruKey, 
+word16 ntruSz)
+{
+    (void)ntruKey;
+    (void)ntruSz;
+
+    /* init */
+    XMEMSET(der, 0, sizeof(DerCert));
+
+    /* version */
+    der->versionSz = SetMyVersion(cert->version, der->version, TRUE);
+
+    /* serial number */
+    RNG_GenerateBlock(rng, cert->serial, CTC_SERIAL_SIZE);
+    cert->serial[0] = 0x01;   /* ensure positive */
+    der->serialSz  = SetSerial(cert->serial, der->serial);
+
+    /* signature algo */
+    der->sigAlgoSz = SetAlgoID(cert->sigType, der->sigAlgo, sigType);
+    if (der->sigAlgoSz == 0)
+        return ALGO_ID_E;
+
+    /* public key */
+    if (cert->keyType == RSA_KEY) {
+        der->publicKeySz = SetPublicKey(der->publicKey, rsaKey);
+        if (der->publicKeySz == 0)
+            return PUBLIC_KEY_E;
+    }
+    else {
+#ifdef HAVE_NTRU
+        word32 rc;
+        word16 encodedSz;
+
+        rc  = 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  = crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo( ntruSz,
+                              ntruKey, &encodedSz, der->publicKey);
+        if (rc != NTRU_OK)
+            return PUBLIC_KEY_E;
+
+        der->publicKeySz = encodedSz;
+#endif
+    }
+
+    der->validitySz = 0;
+#ifdef CYASSL_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);
+        if (der->extensionsSz == 0)
+            return EXTENSIONS_E;
+    }
+    else
+        der->extensionsSz = 0;
+
+#ifdef CYASSL_ALT_NAMES
+    if (der->extensionsSz == 0 && cert->altNamesSz) {
+        der->extensionsSz = SetExtensions(der->extensions, cert->altNames,
+                                          cert->altNamesSz);
+        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* key, RNG* rng, int sigAlgoType)
+{
+    byte    digest[SHA256_DIGEST_SIZE];     /* max size */
+    byte    encSig[MAX_ENCODED_DIG_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ];
+    int     encSigSz, digestSz, typeH;
+
+    if (sigAlgoType == CTC_MD5wRSA) {
+        Md5     md5;
+        InitMd5(&md5);
+        Md5Update(&md5, buffer, sz);
+        Md5Final(&md5, digest);
+        digestSz = MD5_DIGEST_SIZE;
+        typeH    = MD5h;
+    }
+    else if (sigAlgoType == CTC_SHAwRSA) {
+        Sha     sha;
+        InitSha(&sha);
+        ShaUpdate(&sha, buffer, sz);
+        ShaFinal(&sha, digest);
+        digestSz = SHA_DIGEST_SIZE;
+        typeH    = SHAh;
+    }
+    else if (sigAlgoType == CTC_SHA256wRSA) {
+        Sha256     sha256;
+        InitSha256(&sha256);
+        Sha256Update(&sha256, buffer, sz);
+        Sha256Final(&sha256, digest);
+        digestSz = SHA256_DIGEST_SIZE;
+        typeH    = SHA256h;
+    }
+    else
+        return ALGO_ID_E;
+
+    /* signature */
+    encSigSz = EncodeSignature(encSig, digest, digestSz, typeH);
+    return RsaSSL_Sign(encSig, encSigSz, sig, sigSz, key, rng);
+}
+
+
+/* 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);
+    /* 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, RNG* rng, const byte* ntruKey, word16 ntruSz)
+{
+    DerCert der;
+    int     ret;
+
+    cert->keyType = rsaKey ? RSA_KEY : NTRU_KEY;
+    ret = EncodeCert(cert, &der, rsaKey, rng, ntruKey, ntruSz);
+    if (ret != 0)
+        return ret;
+
+    if (der.total + MAX_SEQ_SZ * 2 > (int)derSz)
+        return BUFFER_E;
+
+    return cert->bodySz = WriteCertBody(&der, derBuffer);
+}
+
+
+/* Make an x509 Certificate v3 RSA from cert input, write to buffer */
+int MakeCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey,RNG* rng)
+{
+    return MakeAnyCert(cert, derBuffer, derSz, rsaKey, rng, NULL, 0);
+}
+
+
+#ifdef HAVE_NTRU
+
+int  MakeNtruCert(Cert* cert, byte* derBuffer, word32 derSz,
+                  const byte* ntruKey, word16 keySz, RNG* rng)
+{
+    return MakeAnyCert(cert, derBuffer, derSz, NULL, rng, ntruKey, keySz);
+}
+
+#endif /* HAVE_NTRU */
+
+
+int SignCert(Cert* cert, byte* buffer, word32 buffSz, RsaKey* key, RNG* rng)
+{
+    byte    sig[MAX_ENCODED_SIG_SZ];
+    int     sigSz;
+    int     bodySz = cert->bodySz;
+
+    if (bodySz < 0)
+        return bodySz;
+
+    sigSz  = MakeSignature(buffer, bodySz, sig, sizeof(sig), key, rng,
+                           cert->sigType);
+    if (sigSz < 0)
+        return sigSz; 
+
+    if (bodySz + MAX_SEQ_SZ * 2 + sigSz > (int)buffSz)
+        return BUFFER_E; 
+
+    return AddSignature(buffer, bodySz, sig, sigSz, cert->sigType);
+}
+
+
+int MakeSelfCert(Cert* cert, byte* buffer, word32 buffSz, RsaKey* key, RNG* rng)
+{
+    int ret = MakeCert(cert, buffer, buffSz, key, rng);
+
+    if (ret < 0)
+        return ret;
+
+    return SignCert(cert, buffer, buffSz, key, rng);
+}
+
+
+#ifdef CYASSL_ALT_NAMES 
+
+/* Set Alt Names from der cert, return 0 on success */
+static int SetAltNamesFromCert(Cert* cert, const byte* der, int derSz)
+{
+    DecodedCert decoded;
+    int         ret;
+
+    if (derSz < 0)
+        return derSz;
+
+    InitDecodedCert(&decoded, (byte*)der, derSz, 0);
+    ret = ParseCertRelative(&decoded, CA_TYPE, NO_VERIFY, 0);
+
+    if (ret < 0) {
+        FreeDecodedCert(&decoded);
+        return ret;
+    }
+
+    if (decoded.extensions) {
+        byte   b;
+        int    length;
+        word32 maxExtensionsIdx;
+
+        decoded.srcIdx = decoded.extensionsIdx;
+        b = decoded.source[decoded.srcIdx++];
+        if (b != ASN_EXTENSIONS) {
+            FreeDecodedCert(&decoded);
+            return ASN_PARSE_E;
+        }
+
+        if (GetLength(decoded.source, &decoded.srcIdx, &length,
+                      decoded.maxIdx) < 0) {
+            FreeDecodedCert(&decoded);
+            return ASN_PARSE_E;
+        }
+
+        if (GetSequence(decoded.source, &decoded.srcIdx, &length,
+                        decoded.maxIdx) < 0) {
+            FreeDecodedCert(&decoded);
+            return ASN_PARSE_E;
+        }
+
+        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) {
+                FreeDecodedCert(&decoded);
+                return ASN_PARSE_E;
+            }
+
+            tmpIdx = decoded.srcIdx;
+            decoded.srcIdx = startIdx;
+
+            if (GetAlgoId(decoded.source, &decoded.srcIdx, &oid,
+                          decoded.maxIdx) < 0) {
+                FreeDecodedCert(&decoded);
+                return ASN_PARSE_E;
+            }
+
+            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;
+                    CYASSL_MSG("AltNames extensions too big");
+                    FreeDecodedCert(&decoded);
+                    return ALT_NAME_E;
+                }
+            }
+            decoded.srcIdx = tmpIdx + length;
+        }
+    }
+    FreeDecodedCert(&decoded);
+
+    return 0;
+}
+
+
+/* Set Dates from der cert, return 0 on success */
+static int SetDatesFromCert(Cert* cert, const byte* der, int derSz)
+{
+    DecodedCert decoded;
+    int         ret;
+
+    CYASSL_ENTER("SetDatesFromCert");
+    if (derSz < 0)
+        return derSz;
+
+    InitDecodedCert(&decoded, (byte*)der, derSz, 0);
+    ret = ParseCertRelative(&decoded, CA_TYPE, NO_VERIFY, 0);
+
+    if (ret < 0) {
+        CYASSL_MSG("ParseCertRelative error");
+        FreeDecodedCert(&decoded);
+        return ret;
+    }
+
+    if (decoded.beforeDate == NULL || decoded.afterDate == NULL) {
+        CYASSL_MSG("Couldn't extract dates");
+        FreeDecodedCert(&decoded);
+        return -1;
+    }
+
+    if (decoded.beforeDateLen > MAX_DATE_SIZE || decoded.afterDateLen >
+                                                 MAX_DATE_SIZE) {
+        CYASSL_MSG("Bad date size");
+        FreeDecodedCert(&decoded);
+        return -1;
+    }
+
+    XMEMCPY(cert->beforeDate, decoded.beforeDate, decoded.beforeDateLen);
+    XMEMCPY(cert->afterDate,  decoded.afterDate,  decoded.afterDateLen);
+
+    cert->beforeDateSz = decoded.beforeDateLen;
+    cert->afterDateSz  = decoded.afterDateLen;
+
+    return 0;
+}
+
+
+#endif /* CYASSL_ALT_NAMES && !NO_RSA */
+
+
+/* Set cn name from der buffer, return 0 on success */
+static int SetNameFromCert(CertName* cn, const byte* der, int derSz)
+{
+    DecodedCert decoded;
+    int         ret;
+    int         sz;
+
+    if (derSz < 0)
+        return derSz;
+
+    InitDecodedCert(&decoded, (byte*)der, derSz, 0);
+    ret = ParseCertRelative(&decoded, CA_TYPE, NO_VERIFY, 0);
+
+    if (ret < 0)
+        return ret;
+
+    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;
+    }
+    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;
+    }
+    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;
+    }
+    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;
+    }
+    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;
+    }
+    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;
+    }
+    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;
+    }
+    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);
+
+    return 0;
+}
+
+
+#ifndef NO_FILESYSTEM
+
+/* forward from CyaSSL */
+int CyaSSL_PemCertToDer(const char* fileName, unsigned char* derBuf, int derSz);
+
+/* Set cert issuer from issuerFile in PEM */
+int SetIssuer(Cert* cert, const char* issuerFile)
+{
+    int         ret;
+    int         derSz;
+    byte*       der = (byte*)XMALLOC(EIGHTK_BUF, NULL, DYNAMIC_TYPE_CERT);
+
+    if (der == NULL) {
+        CYASSL_MSG("SetIssuer OOF Problem");
+        return MEMORY_E;
+    }
+    derSz = CyaSSL_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 SetSubject(Cert* cert, const char* subjectFile)
+{
+    int         ret;
+    int         derSz;
+    byte*       der = (byte*)XMALLOC(EIGHTK_BUF, NULL, DYNAMIC_TYPE_CERT);
+
+    if (der == NULL) {
+        CYASSL_MSG("SetSubject OOF Problem");
+        return MEMORY_E;
+    }
+    derSz = CyaSSL_PemCertToDer(subjectFile, der, EIGHTK_BUF);
+    ret = SetNameFromCert(&cert->subject, der, derSz);
+    XFREE(der, NULL, DYNAMIC_TYPE_CERT);
+
+    return ret;
+}
+
+
+#ifdef CYASSL_ALT_NAMES
+
+/* Set atl names from file in PEM */
+int SetAltNames(Cert* cert, const char* file)
+{
+    int         ret;
+    int         derSz;
+    byte*       der = (byte*)XMALLOC(EIGHTK_BUF, NULL, DYNAMIC_TYPE_CERT);
+
+    if (der == NULL) {
+        CYASSL_MSG("SetAltNames OOF Problem");
+        return MEMORY_E;
+    }
+    derSz = CyaSSL_PemCertToDer(file, der, EIGHTK_BUF);
+    ret = SetAltNamesFromCert(cert, der, derSz);
+    XFREE(der, NULL, DYNAMIC_TYPE_CERT);
+
+    return ret;
+}
+
+#endif /* CYASSL_ALT_NAMES */
+
+#endif /* NO_FILESYSTEM */
+
+/* Set cert issuer from DER buffer */
+int SetIssuerBuffer(Cert* cert, const byte* der, int derSz)
+{
+    cert->selfSigned = 0;
+    return SetNameFromCert(&cert->issuer, der, derSz);
+}
+
+
+/* Set cert subject from DER buffer */
+int SetSubjectBuffer(Cert* cert, const byte* der, int derSz)
+{
+    return SetNameFromCert(&cert->subject, der, derSz);
+}
+
+
+#ifdef CYASSL_ALT_NAMES
+
+/* Set cert alt names from DER buffer */
+int SetAltNamesBuffer(Cert* cert, const byte* der, int derSz)
+{
+    return SetAltNamesFromCert(cert, der, derSz);
+}
+
+/* Set cert dates from DER buffer */
+int SetDatesBuffer(Cert* cert, const byte* der, int derSz)
+{
+    return SetDatesFromCert(cert, der, derSz);
+}
+
+#endif /* CYASSL_ALT_NAMES */
+
+#endif /* CYASSL_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) */
+
+    int rLen = mp_unsigned_bin_size(r);   /* big int size */
+    int sLen = mp_unsigned_bin_size(s);
+    int err;
+
+    if (*outLen < (rLen + sLen + headerSz + 2))  /* SEQ_TAG + LEN(ENUM) */
+        return BAD_FUNC_ARG;
+
+    idx = SetSequence(rLen + sLen + headerSz, out);
+
+    /* store r */
+    out[idx++] = ASN_INTEGER;
+    rSz = SetLength(rLen, &out[idx]);
+    idx += rSz;
+    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, &out[idx]);
+    idx += sSz;
+    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 EccPrivateKeyDecode(const byte* input, word32* inOutIdx, ecc_key* key,
+                        word32 inSz)
+{
+    word32 oid = 0;
+    int    version, length;
+    int    privSz, pubSz;
+    byte   b;
+    byte   priv[ECC_MAXSIZE];
+    byte   pub[ECC_MAXSIZE * 2 + 1]; /* public key has two parts plus header */
+
+    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;
+
+    /* 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)
+            return ASN_PARSE_E;
+
+        /* object id */
+        b = input[*inOutIdx];
+        *inOutIdx += 1;
+    
+        if (b != ASN_OBJECT_ID) 
+            return ASN_OBJECT_ID_E;
+
+        if (GetLength(input, inOutIdx, &length, inSz) < 0)
+            return ASN_PARSE_E;
+
+        while(length--) {
+            oid += input[*inOutIdx];
+            *inOutIdx += 1;
+        }
+        if (CheckCurve(oid) < 0)
+            return ECC_CURVE_OID_E;
+    }
+    
+    /* prefix 1 */
+    b = input[*inOutIdx];
+    *inOutIdx += 1;
+    if (b != ECC_PREFIX_1)
+        return ASN_ECC_KEY_E;
+
+    if (GetLength(input, inOutIdx, &length, inSz) < 0)
+        return ASN_PARSE_E;
+
+    /* key header */
+    b = input[*inOutIdx];
+    *inOutIdx += 1;
+    if (b != ASN_BIT_STRING)
+        return ASN_BITSTR_E;
+
+    if (GetLength(input, inOutIdx, &length, inSz) < 0)
+        return ASN_PARSE_E;
+    b = input[*inOutIdx];
+    *inOutIdx += 1;
+    if (b != 0x00)
+        return ASN_EXPECT_0_E;
+
+    pubSz = length - 1;  /* null prefix */
+    XMEMCPY(pub, &input[*inOutIdx], pubSz);
+
+    *inOutIdx += length;
+    
+    return ecc_import_private_key(priv, privSz, pub, pubSz, key);
+}
+
+#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;
+
+    CYASSL_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;
+
+    CYASSL_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;
+
+    CYASSL_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;
+
+    CYASSL_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) {
+            CYASSL_MSG("\tfail: should be a SEQUENCE");
+            return ASN_PARSE_E;
+        }
+
+        oid = 0;
+        if (GetObjectId(source, &idx, &oid, sz) < 0) {
+            CYASSL_MSG("\tfail: OBJECT ID");
+            return ASN_PARSE_E;
+        }
+
+        /* check for critical flag */
+        if (source[idx] == ASN_BOOLEAN) {
+            CYASSL_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) {
+            CYASSL_MSG("\tfail: should be an OCTET STRING");
+            return ASN_PARSE_E;
+        }
+
+        if (GetLength(source, &idx, &length, sz) < 0) {
+            CYASSL_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;
+
+    CYASSL_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;
+
+    CYASSL_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;
+
+    CYASSL_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)
+        {
+            CYASSL_MSG("\tOCSP Confirm signature failed");
+            return ASN_OCSP_CONFIRM_E;
+        }
+    }
+
+    *ioIndex = idx;
+    return 0;
+}
+
+
+void InitOcspResponse(OcspResponse* resp, CertStatus* status,
+                                                    byte* source, word32 inSz)
+{
+    CYASSL_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;
+
+    CYASSL_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 int SetSerialNumber(const byte* sn, word32 snSz, byte* output)
+{
+    int result = 0;
+
+    CYASSL_ENTER("SetSerialNumber");
+
+    if (snSz <= EXTERNAL_SERIAL_SIZE) {
+        output[0] = ASN_INTEGER;
+        output[1] = snSz + 1;
+        output[2] = 0;
+        XMEMCPY(&output[3], sn, snSz);
+        result = snSz + 3;
+    }
+    return result;
+}
+
+
+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;
+
+    CYASSL_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;
+
+    CYASSL_ENTER("EncodeOcspRequest");
+
+    algoSz = SetAlgoID(SHAh, algoArray, hashType);
+
+    req->issuerHash = req->cert->issuerHash;
+    issuerSz = SetDigest(req->cert->issuerHash, SHA_SIZE, issuerArray);
+    
+    req->issuerKeyHash = req->cert->issuerKeyHash;
+    issuerKeySz = SetDigest(req->cert->issuerKeyHash, SHA_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 (InitRng(&rng) != 0) {
+            CYASSL_MSG("\tCannot initialize RNG. Skipping the OSCP Nonce.");
+        } else {
+            req->nonceSz = MAX_OCSP_NONCE_SZ;
+            RNG_GenerateBlock(&rng, req->nonce, req->nonceSz);
+            extSz = SetOcspReqExtensions(MAX_OCSP_EXT_SZ, extArray,
+                                                      req->nonce, req->nonceSz);
+        }
+    }
+
+    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)
+{
+    CYASSL_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;
+
+    CYASSL_ENTER("CompareOcspReqResp");
+
+    if (req == NULL)
+    {
+        CYASSL_MSG("\tReq missing");
+        return -1;
+    }
+
+    if (resp == NULL)
+    {
+        CYASSL_MSG("\tResp missing");
+        return 1;
+    }
+
+    if (req->useNonce) {
+        cmp = req->nonceSz - resp->nonceSz;
+        if (cmp != 0)
+        {
+            CYASSL_MSG("\tnonceSz mismatch");
+            return cmp;
+        }
+    
+        cmp = XMEMCMP(req->nonce, resp->nonce, req->nonceSz);
+        if (cmp != 0)
+        {
+            CYASSL_MSG("\tnonce mismatch");
+            return cmp;
+        }
+    }
+
+    cmp = XMEMCMP(req->issuerHash, resp->issuerHash, SHA_DIGEST_SIZE);
+    if (cmp != 0)
+    {
+        CYASSL_MSG("\tissuerHash mismatch");
+        return cmp;
+    }
+
+    cmp = XMEMCMP(req->issuerKeyHash, resp->issuerKeyHash, SHA_DIGEST_SIZE);
+    if (cmp != 0)
+    {
+        CYASSL_MSG("\tissuerKeyHash mismatch");
+        return cmp;
+    }
+
+    cmp = req->serialSz - resp->status->serialSz;
+    if (cmp != 0)
+    {
+        CYASSL_MSG("\tserialSz mismatch");
+        return cmp;
+    }
+
+    cmp = XMEMCMP(req->serial, resp->status->serial, req->serialSz);
+    if (cmp != 0)
+    {
+        CYASSL_MSG("\tserial mismatch");
+        return cmp;
+    }
+
+    return 0;
+}
+
+#endif
+
+
+#ifdef HAVE_CRL
+
+/* initialize decoded CRL */
+void InitDecodedCRL(DecodedCRL* dcrl)
+{
+    CYASSL_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;
+
+    CYASSL_MSG("FreeDecodedCRL");
+
+    while(tmp) {
+        RevokedCert* next = tmp->next;
+        XFREE(tmp, NULL, DYNAMIC_TYPE_REVOKED);
+        tmp = next;
+    }
+}
+
+
+/* store SHA1 hash of NAME */
+static int GetNameHash(const byte* source, word32* idx, byte* hash, int maxIdx)
+{
+    Sha    sha;
+    int    length;  /* length of all distinguished names */
+    word32 dummy;
+
+    CYASSL_ENTER("GetNameHash");
+
+    if (source[*idx] == ASN_OBJECT_ID) {
+        CYASSL_MSG("Trying optional prefix...");
+
+        if (GetLength(source, idx, &length, maxIdx) < 0)
+            return ASN_PARSE_E;
+
+        *idx += length;
+        CYASSL_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;
+
+    InitSha(&sha);
+    ShaUpdate(&sha, source + dummy, length + *idx - dummy);
+    ShaFinal(&sha, hash);
+
+    *idx += length;
+
+    return 0;
+}
+
+
+/* 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;
+
+    CYASSL_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) {
+        CYASSL_MSG("Expecting Integer");
+        return ASN_PARSE_E;
+    }
+
+    if (GetLength(buff, idx, &len, maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    if (len > EXTERNAL_SERIAL_SIZE) {
+        CYASSL_MSG("Serial Size too big");
+        return ASN_PARSE_E;
+    }
+
+    rc = (RevokedCert*)XMALLOC(sizeof(RevokedCert), NULL, DYNAMIC_TYPE_CRL);
+    if (rc == NULL) {
+        CYASSL_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) {
+        CYASSL_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;
+
+    CYASSL_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;
+
+    CYASSL_MSG("ParseCRL");
+
+    /* raw crl hash */
+    /* hash here if needed for optimized comparisons
+     * Sha     sha;
+     * InitSha(&sha);
+     * ShaUpdate(&sha, buff, sz);
+     * 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)) {
+        CYASSL_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 */
+    CYASSL_MSG("About to verify CRL signature");
+
+    if (ca) {
+        CYASSL_MSG("Found CRL issuer CA");
+        /* try to confirm/verify signature */
+        if (!ConfirmSignature(buff + dcrl->certBegin,
+                dcrl->sigIndex - dcrl->certBegin,
+                ca->publicKey, ca->pubKeySize, ca->keyOID,
+                dcrl->signature, dcrl->sigLength, dcrl->signatureOID, NULL)) {
+            CYASSL_MSG("CRL Confirm signature failed");
+            return ASN_CRL_CONFIRM_E;
+        }
+    }
+    else {
+        CYASSL_MSG("Did NOT find CRL issuer CA");
+        return ASN_CRL_NO_SIGNER_E;
+    }
+
+    return 0;
+}
+
+#endif /* HAVE_CRL */
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/blake2b.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,467 @@
+/*
+   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-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef HAVE_BLAKE2
+
+#include <cyassl/ctaocrypt/blake2.h>
+#include <cyassl/ctaocrypt/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;
+}
+
+static INLINE int blake2b_clear_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_clear_lastblock( blake2b_state *S )
+{
+  if( S->last_node ) blake2b_clear_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;
+}
+
+
+
+/* Parameter-related functions */
+static INLINE int blake2b_param_set_digest_length( blake2b_param *P,
+                                                   const byte digest_length )
+{
+  P->digest_length = digest_length;
+  return 0;
+}
+
+static INLINE int blake2b_param_set_fanout( blake2b_param *P, const byte fanout)
+{
+  P->fanout = fanout;
+  return 0;
+}
+
+static INLINE int blake2b_param_set_max_depth( blake2b_param *P,
+                                               const byte depth )
+{
+  P->depth = depth;
+  return 0;
+}
+
+static INLINE int blake2b_param_set_leaf_length( blake2b_param *P,
+                                                 const word32 leaf_length )
+{
+  store32( &P->leaf_length, leaf_length );
+  return 0;
+}
+
+static INLINE int blake2b_param_set_node_offset( blake2b_param *P,
+                                                 const word64 node_offset )
+{
+  store64( &P->node_offset, node_offset );
+  return 0;
+}
+
+static INLINE int blake2b_param_set_node_depth( blake2b_param *P,
+                                                const byte node_depth )
+{
+  P->node_depth = node_depth;
+  return 0;
+}
+
+static INLINE int blake2b_param_set_inner_length( blake2b_param *P,
+                                                  const byte inner_length )
+{
+  P->inner_length = inner_length;
+  return 0;
+}
+
+static INLINE int blake2b_param_set_salt( blake2b_param *P,
+                                          const byte salt[BLAKE2B_SALTBYTES] )
+{
+  XMEMCPY( P->salt, salt, BLAKE2B_SALTBYTES );
+  return 0;
+}
+
+static INLINE int blake2b_param_set_personal( blake2b_param *P,
+                                    const byte personal[BLAKE2B_PERSONALBYTES] )
+{
+  XMEMCPY( P->personal, personal, BLAKE2B_PERSONALBYTES );
+  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;
+
+  {
+    byte block[BLAKE2B_BLOCKBYTES];
+    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 */
+                                                     /*stack */
+  }
+  return 0;
+}
+
+static int blake2b_compress( blake2b_state *S,
+                             const byte block[BLAKE2B_BLOCKBYTES] )
+{
+  word64 m[16];
+  word64 v[16];
+  int i;
+
+  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
+  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, (word)fill ); /* Fill buffer */
+      S->buflen += fill;
+      blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
+      blake2b_compress( S, S->buf ); /* 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, (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 );
+    blake2b_compress( S, S->buf );
+    S->buflen -= BLAKE2B_BLOCKBYTES;
+    XMEMCPY( S->buf, S->buf + BLAKE2B_BLOCKBYTES, (word)S->buflen );
+  }
+
+  blake2b_increment_counter( S, S->buflen );
+  blake2b_set_lastblock( S );
+  XMEMSET( S->buf + S->buflen, 0, (word)(2 * BLAKE2B_BLOCKBYTES - S->buflen) );
+         /* Padding */
+  blake2b_compress( S, S->buf );
+
+  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;
+  }
+
+  blake2b_update( S, ( byte * )in, inlen );
+  blake2b_final( S, out, outlen );
+  return 0;
+}
+
+#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];
+    blake2b( hash, buf, key, BLAKE2B_OUTBYTES, i, BLAKE2B_KEYBYTES );
+
+    if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) )
+    {
+      puts( "error" );
+      return -1;
+    }
+  }
+
+  puts( "ok" );
+  return 0;
+}
+#endif
+
+
+/* CTaoCrypt API */
+
+/* Init Blake2b digest, track size incase final doesn't want to "remember" */
+int InitBlake2b(Blake2b* b2b, word32 digestSz)
+{
+    b2b->digestSz = digestSz;
+
+    return blake2b_init(b2b->S, (byte)digestSz);
+}
+
+
+/* Blake2b Update */
+int 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 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/ctaocrypt/src/camellia.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,1570 @@
+/* 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-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/*
+ * Algorithm Specification 
+ *  http://info.isl.ntt.co.jp/crypt/eng/camellia/specifications.html
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef HAVE_CAMELLIA
+
+#include <cyassl/ctaocrypt/camellia.h>
+#include <cyassl/ctaocrypt/ctaoerror2.h>
+#include <cyassl/ctaocrypt/logging.h>
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/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 void 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;
+    u32 subL[26];
+    u32 subR[26];
+
+    /**
+     *  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;
+
+    return;
+}
+
+static void 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;
+    u32 subL[34];
+    u32 subR[34];
+
+    /**
+     *  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;
+    
+    return;
+}
+
+static void 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);
+    camellia_setup256(kk, subkey);
+    return;
+}
+
+
+/**
+ * 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]);
+}
+
+
+
+/* CTaoCrypt wrappers to the Camellia code */
+
+int CamelliaSetKey(Camellia* cam, const byte* key, word32 len, const byte* iv)
+{
+    if (cam == NULL) return BAD_FUNC_ARG;
+
+    XMEMSET(cam->key, 0, sizeof(KEY_TABLE_TYPE));
+    switch (len) {
+        case 16:
+        	camellia_setup128(key, cam->key);
+            break;
+        case 24:
+        	camellia_setup192(key, cam->key);
+            break;
+        case 32:
+	        camellia_setup256(key, cam->key);
+            break;
+        default:
+            return BAD_FUNC_ARG;
+    }
+    cam->keySz = len * 8;
+
+    return CamelliaSetIV(cam, iv);
+}
+
+
+int CamelliaSetIV(Camellia* cam, const byte* iv)
+{
+    if (cam == NULL)
+        return BAD_FUNC_ARG;
+
+    if (iv)
+        XMEMCPY(cam->reg, iv, CAMELLIA_BLOCK_SIZE);
+
+    return 0;
+}
+
+
+void CamelliaEncryptDirect(Camellia* cam, byte* out, const byte* in)
+{
+    Camellia_EncryptBlock(cam->keySz, in, cam->key, out);
+}
+
+
+void CamelliaDecryptDirect(Camellia* cam, byte* out, const byte* in)
+{
+    Camellia_DecryptBlock(cam->keySz, in, cam->key, out);
+}
+
+
+void 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 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/ctaocrypt/src/coding.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,272 @@
+/* coding.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifndef NO_CODING
+
+#include <cyassl/ctaocrypt/coding.h>
+#include <cyassl/ctaocrypt/ctaoerror2.h>
+#include <cyassl/ctaocrypt/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) {
+            CYASSL_MSG("Bad Base64 Decode data, too small");
+            return ASN_INPUT_E;
+        }
+
+        if (e1 > maxIdx || e2 > maxIdx || e3 > maxIdx || e4 > maxIdx) {
+            CYASSL_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 = (e1 << 2) | (e2 >> 4);
+        b2 = ((e2 & 0xF) << 4) | (e3 >> 2);
+        b3 = ((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') {
+                CYASSL_MSG("Bad end of line in Base64 Decode");
+                return ASN_INPUT_E;
+            }
+        }
+    }
+    *outLen = i;
+
+    return 0;
+}
+
+
+#if defined(OPENSSL_EXTRA) || defined (SESSION_CERTS) || defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN) || defined(HAVE_WEBSERVER)
+
+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',
+                              '+', '/'
+                            };
+
+
+/* porting assistance from yaSSL by Raphael HUCK */
+int Base64_Encode(const byte* in, word32 inLen, byte* out, word32* outLen)
+{
+    word32 i = 0,
+           j = 0,
+           n = 0;   /* new line counter */
+
+    word32 outSz = (inLen + 3 - 1) / 3 * 4;
+    outSz += (outSz + PEM_LINE_SZ - 1) / PEM_LINE_SZ;  /* new lines */
+
+    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 = ((b1 & 0x3) << 4) | (b2 >> 4);
+        byte e3 = ((b2 & 0xF) << 2) | (b3 >> 6);
+        byte e4 = b3 & 0x3F;
+
+        /* store */
+        out[i++] = base64Encode[e1];
+        out[i++] = base64Encode[e2];
+        out[i++] = base64Encode[e3];
+        out[i++] = base64Encode[e4];
+
+        inLen -= 3;
+
+        if ((++n % (PEM_LINE_SZ / 4)) == 0 && inLen)
+            out[i++] = '\n';
+    }
+
+    /* last integral */
+    if (inLen) {
+        int twoBytes = (inLen == 2);
+
+        byte b1 = in[j++];
+        byte b2 = (twoBytes) ? in[j++] : 0;
+
+        byte e1 = b1 >> 2;
+        byte e2 = ((b1 & 0x3) << 4) | (b2 >> 4);
+        byte e3 =  (b2 & 0xF) << 2;
+
+        out[i++] = base64Encode[e1];
+        out[i++] = base64Encode[e2];
+        out[i++] = (twoBytes) ? base64Encode[e3] : PAD;
+        out[i++] = PAD;
+    } 
+
+    out[i++] = '\n';
+    if (i != outSz)
+        return ASN_INPUT_E; 
+    *outLen = outSz;
+
+    return 0; 
+}
+
+
+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 
+                         };  /* 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++] = (b << 4) | b2;
+        inLen -= 2;
+    }
+
+    *outLen = outIdx;
+    return 0;
+}
+
+
+#endif  /* defined(OPENSSL_EXTRA) || defined (SESSION_CERTS) || defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN) || defined(HAVE_WEBSERVER) */
+#endif /* NO_CODING */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/compress.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,169 @@
+/* compress.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef HAVE_LIBZ
+
+
+#include <cyassl/ctaocrypt/compress.h>
+#include <cyassl/ctaocrypt/ctaoerror2.h>
+#include <cyassl/ctaocrypt/logging.h>
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/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 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 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/ctaocrypt/src/des3.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,886 @@
+/* des3.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifndef NO_DES3
+
+#include <cyassl/ctaocrypt/des3.h>
+
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/src/misc.c>
+#endif
+
+
+#ifdef HAVE_CAVIUM
+    static void Des3_CaviumSetKey(Des3* des3, const byte* key, const byte* iv);
+    static void Des3_CaviumCbcEncrypt(Des3* des3, byte* out, const byte* in,
+                                      word32 length);
+    static void 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"
+
+    void Des_SetKey(Des* des, const byte* key, const byte* iv, int dir)
+    {
+        word32 *dkey = des->key;
+
+        XMEMCPY(dkey, key, 8);
+        ByteReverseWords(dkey, dkey, 8);
+
+        Des_SetIV(des, iv);
+    }
+
+    void 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);
+
+        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);
+    }
+
+    void Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz)
+    {
+        DesCrypt(des, out, in, sz, DES_ENCRYPTION, DES_CBC);
+    }
+
+    void Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz)
+    {
+        DesCrypt(des, out, in, sz, DES_DECRYPTION, DES_CBC);
+    }
+
+    void Des_EcbEncrypt(Des* des, byte* out, const byte* in, word32 sz)
+    {
+        DesCrypt(des, out, in, sz, DES_ENCRYPTION, DES_ECB);
+    }
+
+    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);
+
+    }
+
+    void Des3_CbcEncrypt(Des3* des, byte* out, const byte* in, word32 sz)
+    {
+        Des3Crypt(des, out, in, sz, DES_ENCRYPTION);
+    }
+
+    void Des3_CbcDecrypt(Des3* des, byte* out, const byte* in, word32 sz)
+    {
+        Des3Crypt(des, out, in, sz, DES_DECRYPTION);
+    }
+
+#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
+};
+
+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 void DesSetKey(const byte* key, int dir, word32* out)
+{
+    byte buffer[56+56+8];
+    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 */
+            /* check bit that goes to ks[j] */
+            if (pcr[pc2[j] - 1]){
+                /* mask it in if it's there */
+                l= j % 6;
+                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;
+        }
+   
+}
+
+
+static INLINE int Reverse(int dir)
+{
+    return !dir;
+}
+
+
+void Des_SetKey(Des* des, const byte* key, const byte* iv, int dir)
+{
+    DesSetKey(key, dir, des->key);
+
+    Des_SetIV(des, iv);
+}
+
+
+void Des3_SetKey(Des3* des, const byte* key, const byte* iv, int dir)
+{
+#ifdef HAVE_CAVIUM
+    if (des->magic == CYASSL_3DES_CAVIUM_MAGIC)
+        return Des3_CaviumSetKey(des, key, iv);
+#endif
+
+    DesSetKey(key + (dir == DES_ENCRYPTION ? 0 : 16), dir, des->key[0]);
+    DesSetKey(key + 8, Reverse(dir), des->key[1]);
+    DesSetKey(key + (dir == DES_DECRYPTION ? 0 : 16), dir, des->key[2]);
+
+    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));
+}
+
+
+void 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; 
+    }
+}
+
+
+void 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; 
+    }
+}
+
+
+void Des3_CbcEncrypt(Des3* des, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks;
+
+#ifdef HAVE_CAVIUM
+    if (des->magic == CYASSL_3DES_CAVIUM_MAGIC)
+        return 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; 
+    }
+}
+
+
+void Des3_CbcDecrypt(Des3* des, byte* out, const byte* in, word32 sz)
+{
+    word32 blocks;
+
+#ifdef HAVE_CAVIUM
+    if (des->magic == CYASSL_3DES_CAVIUM_MAGIC)
+        return 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; 
+    }
+}
+
+#ifdef CYASSL_DES_ECB
+
+/* One block, compatibility only */
+void 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; 
+    }
+}
+
+#endif /* CYASSL_DES_ECB */
+
+#endif /* STM32F2_CRYPTO */
+
+void Des_SetIV(Des* des, const byte* iv)
+{
+    if (des && iv)
+        XMEMCPY(des->reg, iv, DES_BLOCK_SIZE);
+}
+
+
+void Des3_SetIV(Des3* des, const byte* iv)
+{
+    if (des && iv)
+        XMEMCPY(des->reg, iv, DES_BLOCK_SIZE);
+}
+
+
+#ifdef HAVE_CAVIUM
+
+#include <cyassl/ctaocrypt/logging.h>
+#include "cavium_common.h"
+
+/* Initiliaze Des3 for use with Nitrox device */
+int 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 = CYASSL_3DES_CAVIUM_MAGIC;
+   
+    return 0;
+}
+
+
+/* Free Des3 from use with Nitrox device */
+void Des3_FreeCavium(Des3* des3)
+{
+    if (des3 == NULL)
+        return;
+
+    if (des3->magic != CYASSL_3DES_CAVIUM_MAGIC)
+        return;
+
+    CspFreeContext(CONTEXT_SSL, des3->contextHandle, des3->devId);
+    des3->magic = 0;
+}
+
+
+static void Des3_CaviumSetKey(Des3* des3, const byte* key, const byte* iv)
+{
+    if (des3 == NULL)
+        return;
+
+    /* key[0] holds key, iv in reg */
+    XMEMCPY(des3->key[0], key, DES_BLOCK_SIZE*3);
+
+    Des3_SetIV(des3, iv);
+}
+
+
+static void Des3_CaviumCbcEncrypt(Des3* des3, byte* out, const byte* in,
+                                  word32 length)
+{
+    word   offset = 0;
+    word32 requestId;
+   
+    while (length > CYASSL_MAX_16BIT) {
+        word16 slen = (word16)CYASSL_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) {
+            CYASSL_MSG("Bad Cavium 3DES Cbc Encrypt");
+        }
+        length -= CYASSL_MAX_16BIT;
+        offset += CYASSL_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) {
+            CYASSL_MSG("Bad Cavium 3DES Cbc Encrypt");
+        }
+        XMEMCPY(des3->reg, out+offset+length - DES_BLOCK_SIZE, DES_BLOCK_SIZE);
+    }
+}
+
+static void Des3_CaviumCbcDecrypt(Des3* des3, byte* out, const byte* in,
+                                  word32 length)
+{
+    word32 requestId;
+    word   offset = 0;
+
+    while (length > CYASSL_MAX_16BIT) {
+        word16 slen = (word16)CYASSL_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) {
+            CYASSL_MSG("Bad Cavium 3Des Decrypt");
+        }
+        length -= CYASSL_MAX_16BIT;
+        offset += CYASSL_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) {
+            CYASSL_MSG("Bad Cavium 3Des Decrypt");
+        }
+        XMEMCPY(des3->reg, des3->tmp, DES_BLOCK_SIZE);
+    }
+}
+
+#endif /* HAVE_CAVIUM */
+
+#endif /* NO_DES3 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/dh.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,171 @@
+/* dh.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifndef NO_DH
+
+#include <cyassl/ctaocrypt/dh.h>
+#include <cyassl/ctaocrypt/ctaoerror2.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 min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+void 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 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 void GeneratePrivate(DhKey* key, RNG* rng, byte* priv, word32* privSz)
+{
+    word32 sz = mp_unsigned_bin_size(&key->p);
+    sz = min(sz, 2 * DiscreteLogWorkFactor(sz * CYASSL_BIT_SIZE) /
+                                           CYASSL_BIT_SIZE + 1);
+    RNG_GenerateBlock(rng, priv, sz);
+    priv[0] |= 0x0C;
+
+    *privSz = sz;
+}
+
+
+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 DhGenerateKeyPair(DhKey* key, RNG* rng, byte* priv, word32* privSz,
+                      byte* pub, word32* pubSz)
+{
+    GeneratePrivate(key, rng, priv, privSz);
+    return GeneratePublic(key, priv, *privSz, pub, pubSz);
+
+}
+
+int 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;
+}
+
+
+#endif /* NO_DH */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/dsa.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,223 @@
+/* dsa.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifndef NO_DSA
+
+#include <cyassl/ctaocrypt/dsa.h>
+#include <cyassl/ctaocrypt/sha.h>
+#include <cyassl/ctaocrypt/random.h>
+#include <cyassl/ctaocrypt/ctaoerror2.h>
+
+
+enum {
+    DSA_HALF_SIZE = 20,   /* r and s size  */
+    DSA_SIG_SIZE  = 40    /* signature size */
+};
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+void 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 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 DsaSign(const byte* digest, byte* out, DsaKey* key, RNG* rng)
+{
+    mp_int k, kInv, r, s, H;
+    int    ret = 0, sz;
+    byte   buffer[DSA_HALF_SIZE];
+
+    if (mp_init_multi(&k, &kInv, &r, &s, &H, 0) != MP_OKAY)
+        return MP_INIT_E;
+
+    sz = min(sizeof(buffer), mp_unsigned_bin_size(&key->q)); 
+
+    /* generate k */
+    RNG_GenerateBlock(rng, buffer, sz);
+    buffer[0] |= 0x0C;
+
+    if (mp_read_unsigned_bin(&k, buffer, sz) != MP_OKAY)
+        ret = MP_READ_E;
+
+    if (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 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 */
+
+
+    /* 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/ctaocrypt/src/ecc.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,1537 @@
+/* ecc.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+/* in case user set HAVE_ECC there */
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef HAVE_ECC
+
+#include <cyassl/ctaocrypt/ecc.h>
+#include <cyassl/ctaocrypt/asn.h>
+#include <cyassl/ctaocrypt/ctaoerror2.h>
+
+
+/* map
+
+   ptmul -> mulmod
+
+*/
+
+#define ECC112
+#define ECC128
+#define ECC160
+#define ECC192
+#define ECC224
+#define ECC256
+#define ECC384
+#define ECC521
+
+
+
+/* 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",
+        "659EF8BA043916EEDE8911702B22",
+        "DB7C2ABF62E35E7628DFAC6561C5",
+        "09487239995A5EE76B55F9C2F098",
+        "A89CE5AF8724C0A23E0E0FF77500"
+},
+#endif
+#ifdef ECC128
+{
+        16,
+        "SECP128R1",
+        "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF",
+        "E87579C11079F43DD824993C2CEE5ED3",
+        "FFFFFFFE0000000075A30D1B9038A115",
+        "161FF7528B899B2D0C28607CA52C5B86",
+        "CF5AC8395BAFEB13C02DA292DDED7A83",
+},
+#endif
+#ifdef ECC160
+{
+        20,
+        "SECP160R1",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF",
+        "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45",
+        "0100000000000000000001F4C8F927AED3CA752257",
+        "4A96B5688EF573284664698968C38BB913CBFC82",
+        "23A628553168947D59DCC912042351377AC5FB32",
+},
+#endif
+#ifdef ECC192
+{
+        24,
+        "ECC-192",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
+        "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1",
+        "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831",
+        "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
+        "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
+},
+#endif
+#ifdef ECC224
+{
+        28,
+        "ECC-224",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001",
+        "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D",
+        "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21",
+        "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34",
+},
+#endif
+#ifdef ECC256
+{
+        32,
+        "ECC-256",
+        "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
+        "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
+        "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
+        "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
+        "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
+},
+#endif
+#ifdef ECC384
+{
+        48,
+        "ECC-384",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
+        "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
+        "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
+        "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
+},
+#endif
+#ifdef ECC521
+{
+        66,
+        "ECC-521",
+        "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+        "51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
+        "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
+        "C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
+        "11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
+},
+#endif
+{
+   0,
+   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);
+
+
+/* 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 unsigned long get_digit(mp_int* a, int n)
+{
+    if (a == NULL)
+        return 0;
+
+    return (n >= a->used || n < 0) ? 0 : a->dp[n];
+}
+
+
+/**
+   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;
+}
+
+
+/**
+  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;
+
+   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
+*/
+static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus,
+                      int map)
+{
+   ecc_point *tG, *M[8];
+   int           i, j, err;
+   mp_int        mu;
+   mp_digit      mp;
+   unsigned long buf;
+   int           first, bitbuf, bitcpy, bitcnt, mode, digidx;
+
+   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
+#endif /* ECC_TIMING_RESISTANT */
+
+
+/**
+   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_BIGINT);
+   if (p == NULL) {
+      return NULL;
+   }
+   XMEMSET(p, 0, sizeof(ecc_point));
+   if (mp_init_multi(&p->x, &p->y, &p->z, NULL, NULL, NULL) != MP_OKAY) {
+      XFREE(p, 0, DYNAMIC_TYPE_BIGINT);
+      return NULL;
+   }
+   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_BIGINT);
+   }
+}
+
+
+/** 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 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;
+}
+
+
+int 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 ecc_make_key(RNG* rng, int keysize, ecc_key* key)
+{
+   int x, err;
+
+   /* 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 = ecc_make_key_ex(rng, key, &ecc_sets[x]);
+   key->idx = x;
+
+   return err;
+}
+
+int 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;
+   byte           buf[ECC_MAXSIZE];
+   int            keysize;
+
+   if (key == NULL || rng == NULL || dp == NULL)
+       return ECC_BAD_ARG_E;
+
+   key->idx = -1;
+   key->dp  = dp;
+   keysize  = dp->size;
+
+   /* allocate ram */
+   base = NULL;
+
+   /* make up random string */
+   RNG_GenerateBlock(rng, buf, keysize);
+   buf[0] |= 0x0c;
+
+   /* setup the key variables */
+   if ((err = mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z,
+                            &key->k, &prime, &order)) != MP_OKAY)
+       return MEMORY_E;
+
+   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);
+   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);
+   mp_clear(&prime);
+   mp_clear(&order);
+#ifdef ECC_CLEAN_STACK
+   XMEMSET(buff, 0, ECC_MAXSIZE);
+#endif
+   return err;
+}
+
+
+/* Setup dynamic pointers is using normal math for proper freeing */
+void 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
+}
+
+
+/**
+  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 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) {
+       int truncLen = (int)inlen;
+       if (truncLen > ecc_size(key))
+           truncLen = ecc_size(key);
+       err = mp_read_unsigned_bin(&e, (byte*)in, truncLen);
+   }
+
+   /* make up a key and export the public copy */
+   if (err == MP_OKAY) {
+       ecc_key pubkey;
+       ecc_init(&pubkey);
+       for (;;) {
+           err = 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)
+               ecc_free(&pubkey);
+           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;
+
+               ecc_free(&pubkey);
+               if (mp_iszero(&s) == MP_NO)
+                   break;
+            }
+       }
+       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 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);
+}
+
+
+/* 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 ecc_verify_hash(const byte* sig, word32 siglen, 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;
+   mp_digit      mp;
+   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) {
+       int truncLen = (int)hashlen;
+       if (truncLen > ecc_size(key))
+           truncLen = ecc_size(key);
+       err = mp_read_unsigned_bin(&e, (byte*)hash, truncLen);
+   }
+
+   /*  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
+       /* 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 ecc_export_x963(ecc_key* key, byte* out, word32* outLen)
+{
+   byte   buf[ECC_BUFSIZE];
+   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 < (1 + 2*numlen)) {
+      *outLen = 1 + 2*numlen;
+      return BUFFER_E;
+   }
+
+   /* store byte 0x04 */
+   out[0] = 0x04;
+
+   /* pad and store x */
+   XMEMSET(buf, 0, sizeof(buf));
+   mp_to_unsigned_bin(&key->pubkey.x,
+                      buf + (numlen - mp_unsigned_bin_size(&key->pubkey.x)));
+   XMEMCPY(out+1, buf, numlen);
+
+   /* pad and store y */
+   XMEMSET(buf, 0, sizeof(buf));
+   mp_to_unsigned_bin(&key->pubkey.y,
+                      buf + (numlen - mp_unsigned_bin_size(&key->pubkey.y)));
+   XMEMCPY(out+1+numlen, buf, numlen);
+
+   *outLen = 1 + 2*numlen;
+
+   return 0;
+}
+
+
+/* import public ECC key in ANSI X9.63 format */
+int ecc_import_x963(const byte* in, word32 inLen, ecc_key* key)
+{
+   int x, err;
+
+   
+   if (in == NULL || key == NULL)
+       return ECC_BAD_ARG_E;
+
+   /* must be odd */
+   if ((inLen & 1) == 0) {
+      return ECC_BAD_ARG_E;
+   }
+
+   /* init key */
+   if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k,
+                     NULL, NULL) != MP_OKAY) {
+      return MEMORY_E;
+   }
+   err = MP_OKAY;
+
+   /* check for 4, 6 or 7 */
+   if (in[0] != 4 && in[0] != 6 && in[0] != 7) {
+      err = ASN_PARSE_E;
+   }
+
+   /* read data */
+   if (err == MP_OKAY) 
+       err = mp_read_unsigned_bin(&key->pubkey.x, (byte*)in+1, (inLen-1)>>1);
+
+   if (err == MP_OKAY) 
+       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);
+
+   if (err == MP_OKAY) {
+     /* determine the idx */
+      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;
+      }
+   }
+
+   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;
+}
+
+
+/* ecc private key import, public key in ANSI X9.63 format, private raw */
+int ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub,
+                           word32 pubSz, ecc_key* key)
+{
+    int ret = ecc_import_x963(pub, pubSz, key);
+    if (ret != 0)
+        return ret;
+
+    key->type = ECC_PRIVATEKEY;
+
+    return mp_read_unsigned_bin(&key->k, priv, privSz);
+}
+
+
+/* key size in octets */
+int ecc_size(ecc_key* key)
+{
+    if (key == NULL) return 0;
+
+    return key->dp->size;
+}
+
+
+/* signature size in octets */
+int ecc_sig_size(ecc_key* key)
+{
+    int sz = ecc_size(key);
+    if (sz < 0)
+        return sz;
+
+    return sz * 2 + SIG_HEADER_SZ;
+}
+
+#endif /* HAVE_ECC */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/ecc_fp.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,1 @@
+/* dummy ecc_fp.c for dist */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/error.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,329 @@
+/* error.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+ 
+#include <cyassl/ctaocrypt/settings.h>
+
+#include <cyassl/ctaocrypt/ctaoerror2.h>
+
+#ifdef _MSC_VER
+    /* 4996 warning to use MS extensions e.g., strcpy_s instead of XSTRNCPY */
+    #pragma warning(disable: 4996)
+#endif
+
+
+void CTaoCryptErrorString(int error, char* buffer)
+{
+    const int max = MAX_ERROR_SZ;   /* shorthand */
+
+#ifdef NO_ERROR_STRINGS
+
+    (void)error;
+    XSTRNCPY(buffer, "no support for error strings built in", max);
+
+#else
+
+    switch (error) {
+
+    case OPEN_RAN_E :        
+        XSTRNCPY(buffer, "opening random device error", max);
+        break;
+
+    case READ_RAN_E :
+        XSTRNCPY(buffer, "reading random device error", max);
+        break;
+
+    case WINCRYPT_E :
+        XSTRNCPY(buffer, "windows crypt init error", max);
+        break;
+
+    case CRYPTGEN_E : 
+        XSTRNCPY(buffer, "windows crypt generation error", max);
+        break;
+
+    case RAN_BLOCK_E : 
+        XSTRNCPY(buffer, "random device read would block error", max);
+        break;
+
+    case MP_INIT_E :
+        XSTRNCPY(buffer, "mp_init error state", max);
+        break;
+
+    case MP_READ_E :
+        XSTRNCPY(buffer, "mp_read error state", max);
+        break;
+
+    case MP_EXPTMOD_E :
+        XSTRNCPY(buffer, "mp_exptmod error state", max);
+        break;
+
+    case MP_TO_E :
+        XSTRNCPY(buffer, "mp_to_xxx error state, can't convert", max);
+        break;
+
+    case MP_SUB_E :
+        XSTRNCPY(buffer, "mp_sub error state, can't subtract", max);
+        break;
+
+    case MP_ADD_E :
+        XSTRNCPY(buffer, "mp_add error state, can't add", max);
+        break;
+
+    case MP_MUL_E :
+        XSTRNCPY(buffer, "mp_mul error state, can't multiply", max);
+        break;
+
+    case MP_MULMOD_E :
+        XSTRNCPY(buffer, "mp_mulmod error state, can't multiply mod", max);
+        break;
+
+    case MP_MOD_E :
+        XSTRNCPY(buffer, "mp_mod error state, can't mod", max);
+        break;
+
+    case MP_INVMOD_E :
+        XSTRNCPY(buffer, "mp_invmod error state, can't inv mod", max);
+        break; 
+        
+    case MP_CMP_E :
+        XSTRNCPY(buffer, "mp_cmp error state", max);
+        break; 
+        
+    case MP_ZERO_E :
+        XSTRNCPY(buffer, "mp zero result, not expected", max);
+        break; 
+        
+    case MEMORY_E :
+        XSTRNCPY(buffer, "out of memory error", max);
+        break;
+
+    case RSA_WRONG_TYPE_E :
+        XSTRNCPY(buffer, "RSA wrong block type for RSA function", max);
+        break; 
+
+    case RSA_BUFFER_E :
+        XSTRNCPY(buffer, "RSA buffer error, output too small or input too big",
+                max);
+        break; 
+
+    case BUFFER_E :
+        XSTRNCPY(buffer, "Buffer error, output too small or input too big",max);
+        break; 
+
+    case ALGO_ID_E :
+        XSTRNCPY(buffer, "Setting Cert AlogID error", max);
+        break; 
+
+    case PUBLIC_KEY_E :
+        XSTRNCPY(buffer, "Setting Cert Public Key error", max);
+        break; 
+
+    case DATE_E :
+        XSTRNCPY(buffer, "Setting Cert Date validity error", max);
+        break; 
+
+    case SUBJECT_E :
+        XSTRNCPY(buffer, "Setting Cert Subject name error", max);
+        break; 
+
+    case ISSUER_E :
+        XSTRNCPY(buffer, "Setting Cert Issuer name error", max);
+        break; 
+
+    case CA_TRUE_E :
+        XSTRNCPY(buffer, "Setting basic constraint CA true error", max);
+        break; 
+
+    case EXTENSIONS_E :
+        XSTRNCPY(buffer, "Setting extensions error", max);
+        break; 
+
+    case ASN_PARSE_E :
+        XSTRNCPY(buffer, "ASN parsing error, invalid input", max);
+        break;
+
+    case ASN_VERSION_E :
+        XSTRNCPY(buffer, "ASN version error, invalid number", max);
+        break;
+
+    case ASN_GETINT_E :
+        XSTRNCPY(buffer, "ASN get big int error, invalid data", max);
+        break;
+
+    case ASN_RSA_KEY_E :
+        XSTRNCPY(buffer, "ASN key init error, invalid input", max);
+        break;
+
+    case ASN_OBJECT_ID_E :
+        XSTRNCPY(buffer, "ASN object id error, invalid id", max);
+        break;
+
+    case ASN_TAG_NULL_E :
+        XSTRNCPY(buffer, "ASN tag error, not null", max);
+        break;
+
+    case ASN_EXPECT_0_E :
+        XSTRNCPY(buffer, "ASN expect error, not zero", max);
+        break;
+
+    case ASN_BITSTR_E :
+        XSTRNCPY(buffer, "ASN bit string error, wrong id", max);
+        break;
+
+    case ASN_UNKNOWN_OID_E :
+        XSTRNCPY(buffer, "ASN oid error, unknown sum id", max);
+        break;
+
+    case ASN_DATE_SZ_E :
+        XSTRNCPY(buffer, "ASN date error, bad size", max);
+        break;
+
+    case ASN_BEFORE_DATE_E :
+        XSTRNCPY(buffer, "ASN date error, current date before", max);
+        break;
+
+    case ASN_AFTER_DATE_E :
+        XSTRNCPY(buffer, "ASN date error, current date after", max);
+        break;
+
+    case ASN_SIG_OID_E :
+        XSTRNCPY(buffer, "ASN signature error, mismatched oid", max);
+        break;
+
+    case ASN_TIME_E :
+        XSTRNCPY(buffer, "ASN time error, unkown time type", max);
+        break;
+
+    case ASN_INPUT_E :
+        XSTRNCPY(buffer, "ASN input error, not enough data", max);
+        break;
+
+    case ASN_SIG_CONFIRM_E :
+        XSTRNCPY(buffer, "ASN sig error, confirm failure", max);
+        break;
+
+    case ASN_SIG_HASH_E :
+        XSTRNCPY(buffer, "ASN sig error, unsupported hash type", max);
+        break;
+
+    case ASN_SIG_KEY_E :
+        XSTRNCPY(buffer, "ASN sig error, unsupported key type", max);
+        break;
+
+    case ASN_DH_KEY_E :
+        XSTRNCPY(buffer, "ASN key init error, invalid input", max);
+        break;
+
+    case ASN_NTRU_KEY_E :
+        XSTRNCPY(buffer, "ASN NTRU key decode error, invalid input", max);
+        break;
+
+    case ECC_BAD_ARG_E :
+        XSTRNCPY(buffer, "ECC input argument wrong type, invalid input", max);
+        break;
+
+    case ASN_ECC_KEY_E :
+        XSTRNCPY(buffer, "ECC ASN1 bad key data, invalid input", max);
+        break;
+
+    case ECC_CURVE_OID_E :
+        XSTRNCPY(buffer, "ECC curve sum OID unsupported, invalid input", max);
+        break;
+
+    case BAD_FUNC_ARG :
+        XSTRNCPY(buffer, "Bad function argument", max);
+        break;
+
+    case NOT_COMPILED_IN :
+        XSTRNCPY(buffer, "Feature not compiled in", max);
+        break;
+
+    case UNICODE_SIZE_E :
+        XSTRNCPY(buffer, "Unicode password too big", max);
+        break;
+
+    case NO_PASSWORD :
+        XSTRNCPY(buffer, "No password provided by user", max);
+        break;
+
+    case ALT_NAME_E :
+        XSTRNCPY(buffer, "Alt Name problem, too big", max);
+        break;
+
+    case AES_GCM_AUTH_E:
+        XSTRNCPY(buffer, "AES-GCM Authentication check fail", max);
+        break;
+
+    case AES_CCM_AUTH_E:
+        XSTRNCPY(buffer, "AES-CCM Authentication check fail", max);
+        break;
+
+    case CAVIUM_INIT_E:
+        XSTRNCPY(buffer, "Cavium Init type error", max);
+        break;
+
+    case COMPRESS_INIT_E:
+        XSTRNCPY(buffer, "Compress Init error", max);
+        break;
+
+    case COMPRESS_E:
+        XSTRNCPY(buffer, "Compress error", max);
+        break;
+
+    case DECOMPRESS_INIT_E:
+        XSTRNCPY(buffer, "DeCompress Init error", max);
+        break;
+
+    case DECOMPRESS_E:
+        XSTRNCPY(buffer, "DeCompress error", max);
+        break;
+
+    case BAD_ALIGN_E:
+        XSTRNCPY(buffer, "Bad alignment error, no alloc help", max);
+        break;
+
+    case ASN_NO_SIGNER_E :
+        XSTRNCPY(buffer, "ASN no signer error to confirm failure", max);
+        break;
+
+    case ASN_CRL_CONFIRM_E :
+        XSTRNCPY(buffer, "ASN CRL sig error, confirm failure", max);
+        break;
+
+    case ASN_CRL_NO_SIGNER_E :
+        XSTRNCPY(buffer, "ASN CRL no signer error to confirm failure", max);
+        break;
+
+    case ASN_OCSP_CONFIRM_E :
+        XSTRNCPY(buffer, "ASN OCSP sig error, confirm failure", max);
+        break;
+
+    default:
+        XSTRNCPY(buffer, "unknown error number", max);
+
+    }
+
+#endif /* NO_ERROR_STRINGS */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/hc128.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,393 @@
+/* hc128.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef HAVE_HC128
+
+#include <cyassl/ctaocrypt/hc128.h>
+#include <cyassl/ctaocrypt/ctaoerror2.h>
+#include <cyassl/ctaocrypt/logging.h>
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/hc128.h>
+		#include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/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* iv)
+{ 
+    word32 i;
+	
+	for (i = 0; i < (128 >> 5); i++)
+        ctx->iv[i] = LITTLE32(((word32*)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 Hc128_SetKey(HC128* ctx, const byte* key, const byte* iv)
+{
+#ifdef XSTREAM_ALIGN
+    if ((word)key % 4 || (word)iv % 4) {
+        int alignKey[4];
+        int alignIv[4];
+
+        CYASSL_MSG("Hc128SetKey unaligned key/iv");
+
+        XMEMCPY(alignKey, key, sizeof(alignKey));
+        XMEMCPY(alignIv,  iv,  sizeof(alignIv));
+
+        return DoKey(ctx, (const byte*)alignKey, (const byte*)alignIv);
+    }
+#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)
+  {
+      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 Hc128_Process(HC128* ctx, byte* output, const byte* input, word32 msglen)
+{
+#ifdef XSTREAM_ALIGN
+    if ((word)input % 4 || (word)output % 4) {
+        #ifndef NO_CYASSL_ALLOC_ALIGN
+            byte* tmp;
+            CYASSL_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/ctaocrypt/src/hmac.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,491 @@
+/* hmac.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifndef NO_HMAC
+
+#include <cyassl/ctaocrypt/hmac.h>
+#include <cyassl/ctaocrypt/ctaoerror2.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)
+{
+    hmac->innerHashKeyed = 0;
+    hmac->macType = (byte)type;
+
+    if (!(type == MD5 || type == SHA || type == SHA256 || type == SHA384
+                      || type == SHA512))
+        return BAD_FUNC_ARG;
+
+    switch (type) {
+        #ifndef NO_MD5
+        case MD5:
+            InitMd5(&hmac->hash.md5);
+        break;
+        #endif
+
+        #ifndef NO_SHA
+        case SHA:
+            InitSha(&hmac->hash.sha);
+        break;
+        #endif
+        
+        #ifndef NO_SHA256
+        case SHA256:
+            InitSha256(&hmac->hash.sha256);
+        break;
+        #endif
+        
+        #ifdef CYASSL_SHA384
+        case SHA384:
+            InitSha384(&hmac->hash.sha384);
+        break;
+        #endif
+        
+        #ifdef CYASSL_SHA512
+        case SHA512:
+            InitSha512(&hmac->hash.sha512);
+        break;
+        #endif
+        
+        default:
+        break;
+    }
+
+    return 0;
+}
+
+
+void 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;
+
+#ifdef HAVE_CAVIUM
+    if (hmac->magic == CYASSL_HMAC_CAVIUM_MAGIC)
+        return HmacCaviumSetKey(hmac, type, key, length);
+#endif
+
+    InitHmac(hmac, type);
+
+    switch (hmac->macType) {
+        #ifndef NO_MD5
+        case MD5:
+        {
+            hmac_block_size = MD5_BLOCK_SIZE;
+            if (length <= MD5_BLOCK_SIZE) {
+                XMEMCPY(ip, key, length);
+            }
+            else {
+                Md5Update(&hmac->hash.md5, key, length);
+                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 {
+                ShaUpdate(&hmac->hash.sha, key, length);
+                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 {
+                Sha256Update(&hmac->hash.sha256, key, length);
+                Sha256Final(&hmac->hash.sha256, ip);
+                length = SHA256_DIGEST_SIZE;
+            }
+        }
+        break;
+        #endif
+
+        #ifdef CYASSL_SHA384
+        case SHA384:
+        {
+            hmac_block_size = SHA384_BLOCK_SIZE;
+            if (length <= SHA384_BLOCK_SIZE) {
+                XMEMCPY(ip, key, length);
+            }
+            else {
+                Sha384Update(&hmac->hash.sha384, key, length);
+                Sha384Final(&hmac->hash.sha384, ip);
+                length = SHA384_DIGEST_SIZE;
+            }
+        }
+        break;
+        #endif
+
+        #ifdef CYASSL_SHA512
+        case SHA512:
+        {
+            hmac_block_size = SHA512_BLOCK_SIZE;
+            if (length <= SHA512_BLOCK_SIZE) {
+                XMEMCPY(ip, key, length);
+            }
+            else {
+                Sha512Update(&hmac->hash.sha512, key, length);
+                Sha512Final(&hmac->hash.sha512, ip);
+                length = SHA512_DIGEST_SIZE;
+            }
+        }
+        break;
+        #endif
+
+        default:
+        break;
+    }
+    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;
+    }
+}
+
+
+static void HmacKeyInnerHash(Hmac* hmac)
+{
+    switch (hmac->macType) {
+        #ifndef NO_MD5
+        case MD5:
+            Md5Update(&hmac->hash.md5, (byte*) hmac->ipad, MD5_BLOCK_SIZE);
+        break;
+        #endif
+
+        #ifndef NO_SHA
+        case SHA:
+            ShaUpdate(&hmac->hash.sha, (byte*) hmac->ipad, SHA_BLOCK_SIZE);
+        break;
+        #endif
+
+        #ifndef NO_SHA256
+        case SHA256:
+            Sha256Update(&hmac->hash.sha256,
+                                         (byte*) hmac->ipad, SHA256_BLOCK_SIZE);
+        break;
+        #endif
+
+        #ifdef CYASSL_SHA384
+        case SHA384:
+            Sha384Update(&hmac->hash.sha384,
+                                         (byte*) hmac->ipad, SHA384_BLOCK_SIZE);
+        break;
+        #endif
+
+        #ifdef CYASSL_SHA512
+        case SHA512:
+            Sha512Update(&hmac->hash.sha512,
+                                         (byte*) hmac->ipad, SHA512_BLOCK_SIZE);
+        break;
+        #endif
+
+        default:
+        break;
+    }
+
+    hmac->innerHashKeyed = 1;
+}
+
+
+void HmacUpdate(Hmac* hmac, const byte* msg, word32 length)
+{
+#ifdef HAVE_CAVIUM
+    if (hmac->magic == CYASSL_HMAC_CAVIUM_MAGIC)
+        return HmacCaviumUpdate(hmac, msg, length);
+#endif
+
+    if (!hmac->innerHashKeyed)
+        HmacKeyInnerHash(hmac);
+
+    switch (hmac->macType) {
+        #ifndef NO_MD5
+        case MD5:
+            Md5Update(&hmac->hash.md5, msg, length);
+        break;
+        #endif
+
+        #ifndef NO_SHA
+        case SHA:
+            ShaUpdate(&hmac->hash.sha, msg, length);
+        break;
+        #endif
+
+        #ifndef NO_SHA256
+        case SHA256:
+            Sha256Update(&hmac->hash.sha256, msg, length);
+        break;
+        #endif
+
+        #ifdef CYASSL_SHA384
+        case SHA384:
+            Sha384Update(&hmac->hash.sha384, msg, length);
+        break;
+        #endif
+
+        #ifdef CYASSL_SHA512
+        case SHA512:
+            Sha512Update(&hmac->hash.sha512, msg, length);
+        break;
+        #endif
+
+        default:
+        break;
+    }
+
+}
+
+
+void HmacFinal(Hmac* hmac, byte* hash)
+{
+#ifdef HAVE_CAVIUM
+    if (hmac->magic == CYASSL_HMAC_CAVIUM_MAGIC)
+        return HmacCaviumFinal(hmac, hash);
+#endif
+
+    if (!hmac->innerHashKeyed)
+        HmacKeyInnerHash(hmac);
+
+    switch (hmac->macType) {
+        #ifndef NO_MD5
+        case MD5:
+        {
+            Md5Final(&hmac->hash.md5, (byte*) hmac->innerHash);
+
+            Md5Update(&hmac->hash.md5, (byte*) hmac->opad, MD5_BLOCK_SIZE);
+            Md5Update(&hmac->hash.md5,
+                                     (byte*) hmac->innerHash, MD5_DIGEST_SIZE);
+
+            Md5Final(&hmac->hash.md5, hash);
+        }
+        break;
+        #endif
+
+        #ifndef NO_SHA
+        case SHA:
+        {
+            ShaFinal(&hmac->hash.sha, (byte*) hmac->innerHash);
+
+            ShaUpdate(&hmac->hash.sha, (byte*) hmac->opad, SHA_BLOCK_SIZE);
+            ShaUpdate(&hmac->hash.sha,
+                                     (byte*) hmac->innerHash, SHA_DIGEST_SIZE);
+
+            ShaFinal(&hmac->hash.sha, hash);
+        }
+        break;
+        #endif
+
+        #ifndef NO_SHA256
+        case SHA256:
+        {
+            Sha256Final(&hmac->hash.sha256, (byte*) hmac->innerHash);
+
+            Sha256Update(&hmac->hash.sha256,
+                                (byte*) hmac->opad, SHA256_BLOCK_SIZE);
+            Sha256Update(&hmac->hash.sha256,
+                                (byte*) hmac->innerHash, SHA256_DIGEST_SIZE);
+
+            Sha256Final(&hmac->hash.sha256, hash);
+        }
+        break;
+        #endif
+
+        #ifdef CYASSL_SHA384
+        case SHA384:
+        {
+            Sha384Final(&hmac->hash.sha384, (byte*) hmac->innerHash);
+
+            Sha384Update(&hmac->hash.sha384,
+                                 (byte*) hmac->opad, SHA384_BLOCK_SIZE);
+            Sha384Update(&hmac->hash.sha384,
+                                 (byte*) hmac->innerHash, SHA384_DIGEST_SIZE);
+
+            Sha384Final(&hmac->hash.sha384, hash);
+        }
+        break;
+        #endif
+
+        #ifdef CYASSL_SHA512
+        case SHA512:
+        {
+            Sha512Final(&hmac->hash.sha512, (byte*) hmac->innerHash);
+
+            Sha512Update(&hmac->hash.sha512,
+                                 (byte*) hmac->opad, SHA512_BLOCK_SIZE);
+            Sha512Update(&hmac->hash.sha512,
+                                 (byte*) hmac->innerHash, SHA512_DIGEST_SIZE);
+
+            Sha512Final(&hmac->hash.sha512, hash);
+        }
+        break;
+        #endif
+
+        default:
+        break;
+    }
+
+    hmac->innerHashKeyed = 0;
+}
+
+
+#ifdef HAVE_CAVIUM
+
+/* Initiliaze Hmac for use with Nitrox device */
+int 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   = CYASSL_HMAC_CAVIUM_MAGIC;
+    hmac->data    = NULL;        /* buffered input data */
+   
+    hmac->innerHashKeyed = 0;
+
+    return 0;
+}
+
+
+/* Free Hmac from use with Nitrox device */
+void 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) {
+        CYASSL_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 > CYASSL_MAX_16BIT) {
+        CYASSL_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 > CYASSL_MAX_16BIT) {
+        CYASSL_MSG("Too big msg for cavium hmac");
+        return;
+    }
+
+    tmp = XMALLOC(hmac->dataLen + add, NULL,DYNAMIC_TYPE_CAVIUM_TMP);
+    if (tmp == NULL) {
+        CYASSL_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  {
+        CYASSL_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 */
+
+#endif /* NO_HMAC */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/integer.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,4459 @@
+/* integer.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 <cyassl/ctaocrypt/settings.h>
+
+#ifndef NO_BIG_INT 
+
+#ifndef USE_FAST_MATH
+
+#include <cyassl/ctaocrypt/integer.h>
+
+#ifndef NO_CYASSL_SMALL_STACK
+    #ifndef CYASSL_SMALL_STACK
+        #define CYASSL_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;
+}
+
+
+/* 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)
+{
+  mp_digit D, r, rr;
+  int     x, 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 = (mp_digit) (b % DIGIT_BIT);
+  if (D != 0) {
+    register mp_digit *tmpc, mask, shift;
+
+    /* 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 the previous
+         word */
+      *tmpc = (*tmpc >> D) | (r << shift);
+      --tmpc;
+
+      /* set the carry to the carry bits of the current word found above */
+      r = rr;
+    }
+  }
+  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 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;
+
+  /* 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) {
+    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  M[TAB_SIZE], res;
+  mp_digit buf, mp;
+  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+
+  /* 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);
+
+  /* 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;
+    }
+  }
+
+  /* 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[1 << (winsize - 1)])) != MP_OKAY) {
+    goto LBL_RES;
+  }
+
+  for (x = 0; x < (winsize - 1); x++) {
+    if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
+      goto LBL_RES;
+    }
+    if ((err = redux (&M[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]);
+  }
+  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 CYASSL_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 CYASSL_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 CYASSL_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_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 CYASSL_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 CYASSL_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 CYASSL_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 CYASSL_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 CYASSL_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 CYASSL_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[1 << (winsize - 1)])) != MP_OKAY) {
+    goto LBL_MU;
+  }
+
+  for (x = 0; x < (winsize - 1); x++) {
+    /* square it */
+    if ((err = mp_sqr (&M[1 << (winsize - 1)], 
+                       &M[1 << (winsize - 1)])) != MP_OKAY) {
+      goto LBL_MU;
+    }
+
+    /* reduce modulo P */
+    if ((err = redux (&M[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 CYASSL_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 CYASSL_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 CYASSL_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(CYASSL_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)
+
+/* 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) */
+
+
+#ifdef CYASSL_KEY_GEN
+
+int mp_cnt_lsb(mp_int *a);
+
+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;
+}
+
+
+static int mp_mod_d (mp_int * a, mp_digit b, mp_digit * c)
+{
+  return mp_div_d(a, b, NULL, c);
+}
+
+
+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;
+}
+
+
+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;
+}
+
+
+/* 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 /* CYASSL_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(*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/ctaocrypt/src/logging.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,162 @@
+/* logging.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+/* submitted by eof */
+
+#include <cyassl/ctaocrypt/logging.h>
+#include <cyassl/ctaocrypt/ctaoerror2.h>
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+    CYASSL_API int  CyaSSL_Debugging_ON(void);
+    CYASSL_API void CyaSSL_Debugging_OFF(void);
+#ifdef __cplusplus
+    } 
+#endif
+
+
+#ifdef DEBUG_CYASSL
+
+/* Set these to default values initially. */
+static CyaSSL_Logging_cb log_function = 0;
+static int loggingEnabled = 0;
+
+#endif /* DEBUG_CYASSL */
+
+
+int CyaSSL_SetLoggingCb(CyaSSL_Logging_cb f)
+{
+#ifdef DEBUG_CYASSL
+    int res = 0;
+
+    if (f)
+        log_function = f;
+    else
+        res = BAD_FUNC_ARG;
+
+    return res;
+#else
+    (void)f;
+    return NOT_COMPILED_IN;
+#endif
+}
+
+
+int CyaSSL_Debugging_ON(void)
+{
+#ifdef DEBUG_CYASSL
+    loggingEnabled = 1;
+    return 0;
+#else
+    return NOT_COMPILED_IN;
+#endif
+}
+
+
+void CyaSSL_Debugging_OFF(void)
+{
+#ifdef DEBUG_CYASSL
+    loggingEnabled = 0;
+#endif
+}
+
+
+#ifdef DEBUG_CYASSL
+
+#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 cyassl_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(CYASSL_MDK_ARM)
+            fflush(stdout) ;
+            printf("%s\n", logMessage);
+            fflush(stdout) ;
+#else
+            fprintf(stderr, "%s\n", logMessage);
+#endif
+        }
+    }
+}
+
+
+void CYASSL_MSG(const char* msg)
+{
+    if (loggingEnabled)
+        cyassl_log(INFO_LOG , msg);
+}
+
+
+void CYASSL_ENTER(const char* msg)
+{
+    if (loggingEnabled) {
+        char buffer[80];
+        sprintf(buffer, "CyaSSL Entering %s", msg);
+        cyassl_log(ENTER_LOG , buffer);
+    }
+}
+
+
+void CYASSL_LEAVE(const char* msg, int ret)
+{
+    if (loggingEnabled) {
+        char buffer[80];
+        sprintf(buffer, "CyaSSL Leaving %s, return %d", msg, ret);
+        cyassl_log(LEAVE_LOG , buffer);
+    }
+}
+
+
+void CYASSL_ERROR(int error)
+{
+    if (loggingEnabled) {
+        char buffer[80];
+        sprintf(buffer, "CyaSSL error occured, error = %d", error);
+        cyassl_log(ERROR_LOG , buffer);
+    }
+}
+
+#endif  /* DEBUG_CYASSL */ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/md2.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,131 @@
+/* md2.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef CYASSL_MD2
+
+#include <cyassl/ctaocrypt/md2.h>
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/src/misc.c>
+#endif
+
+
+void 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 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 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;
+
+    Md2Update(md2, padding, padLen);
+    Md2Update(md2, md2->C, MD2_BLOCK_SIZE);
+
+    XMEMCPY(hash, md2->X, MD2_DIGEST_SIZE);
+
+    InitMd2(md2);
+}
+
+
+#endif /* CYASSL_MD2 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/md4.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,219 @@
+/* md4.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifndef NO_MD4
+
+#include <cyassl/ctaocrypt/md4.h>
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/src/misc.c>
+#endif
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+void 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 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
+                ByteReverseBytes(local, local, MD4_BLOCK_SIZE);
+            #endif
+            Transform(md4);
+            AddLength(md4, MD4_BLOCK_SIZE);
+            md4->buffLen = 0;
+        }
+    }
+}
+
+
+void 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
+            ByteReverseBytes(local, local, 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
+        ByteReverseBytes(local, local, 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);
+
+    InitMd4(md4);  /* reset state */
+}
+
+
+#endif /* NO_MD4 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/md5.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,348 @@
+/* md5.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifndef NO_MD5
+
+#include <cyassl/ctaocrypt/md5.h>
+
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/src/misc.c>
+#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 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 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 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);
+
+        InitMd5(md5);  /* reset state */
+    }
+
+#else /* CTaoCrypt software implementation */
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+void 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;
+}
+
+
+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;
+}
+
+
+static INLINE void AddLength(Md5* md5, word32 len)
+{
+    word32 tmp = md5->loLen;
+    if ( (md5->loLen += len) < tmp)
+        md5->hiLen++;                       /* carry low to high */
+}
+
+
+void 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) {
+            #ifdef BIG_ENDIAN_ORDER
+                ByteReverseBytes(local, local, MD5_BLOCK_SIZE);
+            #endif
+            Transform(md5);
+            AddLength(md5, MD5_BLOCK_SIZE);
+            md5->buffLen = 0;
+        }
+    }
+}
+
+
+void 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;
+
+        #ifdef BIG_ENDIAN_ORDER
+            ByteReverseBytes(local, local, MD5_BLOCK_SIZE);
+        #endif
+        Transform(md5);
+        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 */
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseBytes(local, local, 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));
+
+    Transform(md5);
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseWords(md5->digest, md5->digest, MD5_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, md5->digest, MD5_DIGEST_SIZE);
+
+    InitMd5(md5);  /* reset state */
+}
+
+#endif /* STM32F2_HASH */
+
+#endif /* NO_MD5 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/memory.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,104 @@
+/* memory.c 
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef USE_CYASSL_MEMORY
+
+#include <cyassl/ctaocrypt/memory.h>
+#include <cyassl/ctaocrypt/ctaoerror2.h>
+
+#ifdef CYASSL_MALLOC_CHECK
+    #include <stdio.h>
+#endif
+
+/* Set these to default values initially. */
+static CyaSSL_Malloc_cb  malloc_function = 0;
+static CyaSSL_Free_cb    free_function = 0;
+static CyaSSL_Realloc_cb realloc_function = 0;
+
+int CyaSSL_SetAllocators(CyaSSL_Malloc_cb  mf,
+                         CyaSSL_Free_cb    ff,
+                         CyaSSL_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* CyaSSL_Malloc(size_t size)
+{
+    void* res = 0;
+
+    if (malloc_function)
+        res = malloc_function(size);
+    else
+        res = malloc(size);
+
+    #ifdef CYASSL_MALLOC_CHECK
+        if (res == NULL)
+            printf("CyaSSL_malloc failed\n");
+    #endif
+				
+    return res;
+}
+
+void CyaSSL_Free(void *ptr)
+{
+    if (free_function)
+        free_function(ptr);
+    else
+        free(ptr);
+}
+
+void* CyaSSL_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_CYASSL_MEMORY */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/misc.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,176 @@
+/* misc.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#include <cyassl/ctaocrypt/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 cyassl, 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 */
+
+    #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 CTAOCRYPT_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 ByteReverseBytes(byte* out, const byte* in, word32 byteCount)
+{
+    word32* op       = (word32*)out;
+    const word32* ip = (const word32*)in;
+
+    ByteReverseWords(op, ip, byteCount);
+}
+
+
+STATIC INLINE void XorWords(word* r, const word* a, word32 n)
+{
+    word32 i;
+
+    for (i = 0; i < n; i++) r[i] ^= a[i];
+}
+
+
+STATIC INLINE void xorbuf(byte* buf, const byte* mask, word32 count)
+{
+    if (((word)buf | (word)mask | count) % CYASSL_WORD_SIZE == 0)
+        XorWords( (word*)buf, (const word*)mask, count / CYASSL_WORD_SIZE);
+    else {
+        word32 i;
+        for (i = 0; i < count; i++) buf[i] ^= mask[i];
+    }
+}
+#undef STATIC
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/pwdbased.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,360 @@
+/* pwdbased.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifndef NO_PWDBASED
+
+#include <cyassl/ctaocrypt/pwdbased.h>
+#include <cyassl/ctaocrypt/hmac.h>
+#include <cyassl/ctaocrypt/integer.h>
+#include <cyassl/ctaocrypt/ctaoerror2.h>
+#if defined(CYASSL_SHA512) || defined(CYASSL_SHA384)
+    #include <cyassl/ctaocrypt/sha512.h>
+#endif
+
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/src/misc.c>
+#endif
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+int PBKDF1(byte* output, const byte* passwd, int pLen, const byte* salt,
+           int sLen, int iterations, int kLen, int hashType)
+{
+    Md5  md5;
+    Sha  sha;
+    int  hLen = (hashType == MD5) ? (int)MD5_DIGEST_SIZE : (int)SHA_DIGEST_SIZE;
+    int  i;
+    byte buffer[SHA_DIGEST_SIZE];  /* max size */
+
+    if (hashType != MD5 && hashType != SHA)
+        return BAD_FUNC_ARG;
+
+    if (kLen > hLen)
+        return BAD_FUNC_ARG;
+
+    if (iterations < 1)
+        return BAD_FUNC_ARG;
+
+    if (hashType == MD5) {
+        InitMd5(&md5);
+        Md5Update(&md5, passwd, pLen);
+        Md5Update(&md5, salt,   sLen);
+        Md5Final(&md5,  buffer);
+    }
+    else {
+        InitSha(&sha);
+        ShaUpdate(&sha, passwd, pLen);
+        ShaUpdate(&sha, salt,   sLen);
+        ShaFinal(&sha,  buffer);
+    }
+
+    for (i = 1; i < iterations; i++) {
+        if (hashType == MD5) {
+            Md5Update(&md5, buffer, hLen);
+            Md5Final(&md5,  buffer);
+        }
+        else {
+            ShaUpdate(&sha, buffer, hLen);
+            ShaFinal(&sha,  buffer);
+        }
+    }
+    XMEMCPY(output, buffer, kLen);
+
+    return 0;
+}
+
+
+int 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;
+    Hmac   hmac;
+#ifdef CYASSL_SHA512
+    byte   buffer[SHA512_DIGEST_SIZE];
+#else
+    byte   buffer[INNER_HASH_SIZE];  /* max size, doesn't handle 512 yet */
+#endif
+
+    if (hashType == MD5) {
+        hLen = MD5_DIGEST_SIZE;
+    }
+    else if (hashType == SHA) {
+        hLen = SHA_DIGEST_SIZE;
+    }
+#ifndef NO_SHA256
+    else if (hashType == SHA256) {
+        hLen = SHA256_DIGEST_SIZE;
+    }
+#endif
+#ifdef CYASSL_SHA512
+    else if (hashType == SHA512) {
+        hLen = SHA512_DIGEST_SIZE;
+    }
+#endif
+    else
+        return BAD_FUNC_ARG;
+
+    HmacSetKey(&hmac, hashType, passwd, pLen);
+
+    while (kLen) {
+        int currentLen;
+        HmacUpdate(&hmac, salt, sLen);
+
+        /* encode i */
+        for (j = 0; j < 4; j++) {
+            byte b = (byte)(i >> ((3-j) * 8));
+            HmacUpdate(&hmac, &b, 1);
+        }
+        HmacFinal(&hmac, buffer);
+
+        currentLen = min(kLen, hLen);
+        XMEMCPY(output, buffer, currentLen);
+
+        for (j = 1; j < iterations; j++) {
+            HmacUpdate(&hmac, buffer, hLen);
+            HmacFinal(&hmac, buffer);
+            xorbuf(output, buffer, currentLen);
+        }
+
+        output += currentLen;
+        kLen   -= currentLen;
+        i++;
+    }
+
+    return 0;
+}
+
+
+int 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;
+    byte   staticBuffer[1024];
+    byte*  buffer = staticBuffer;
+#ifdef CYASSL_SHA512
+    byte   Ai[SHA512_DIGEST_SIZE];
+    byte   B[SHA512_BLOCK_SIZE];
+#elif !defined(NO_SHA256)
+    byte   Ai[SHA256_DIGEST_SIZE];
+    byte   B[SHA256_BLOCK_SIZE];
+#else
+    byte   Ai[SHA_DIGEST_SIZE];
+    byte   B[SHA_BLOCK_SIZE];
+#endif
+
+    if (!iterations)
+        iterations = 1;
+
+    if (hashType == MD5) {
+        v = MD5_BLOCK_SIZE;
+        u = MD5_DIGEST_SIZE;
+    }
+    else if (hashType == SHA) {
+        v = SHA_BLOCK_SIZE;
+        u = SHA_DIGEST_SIZE;
+    }
+#ifndef NO_SHA256
+    else if (hashType == SHA256) {
+        v = SHA256_BLOCK_SIZE;
+        u = SHA256_DIGEST_SIZE;
+    }
+#endif
+#ifdef CYASSL_SHA512
+    else if (hashType == SHA512) {
+        v = SHA512_BLOCK_SIZE;
+        u = SHA512_DIGEST_SIZE;
+    }
+#endif
+    else
+        return BAD_FUNC_ARG; 
+
+    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) 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;
+
+        if (hashType == MD5) {
+            Md5 md5;
+
+            InitMd5(&md5);
+            Md5Update(&md5, buffer, totalLen);
+            Md5Final(&md5, Ai);
+
+            for (i = 1; i < iterations; i++) {
+                Md5Update(&md5, Ai, u);
+                Md5Final(&md5, Ai);
+            }
+        }
+        else if (hashType == SHA) {
+            Sha sha;
+
+            InitSha(&sha);
+            ShaUpdate(&sha, buffer, totalLen);
+            ShaFinal(&sha, Ai);
+
+            for (i = 1; i < iterations; i++) {
+                ShaUpdate(&sha, Ai, u);
+                ShaFinal(&sha, Ai);
+            }
+        }
+#ifndef NO_SHA256
+        else if (hashType == SHA256) {
+            Sha256 sha256;
+
+            InitSha256(&sha256);
+            Sha256Update(&sha256, buffer, totalLen);
+            Sha256Final(&sha256, Ai);
+
+            for (i = 1; i < iterations; i++) {
+                Sha256Update(&sha256, Ai, u);
+                Sha256Final(&sha256, Ai);
+            }
+        }
+#endif
+#ifdef CYASSL_SHA512
+        else if (hashType == SHA512) {
+            Sha512 sha512;
+
+            InitSha512(&sha512);
+            Sha512Update(&sha512, buffer, totalLen);
+            Sha512Final(&sha512, Ai);
+
+            for (i = 1; i < iterations; i++) {
+                Sha512Update(&sha512, Ai, u);
+                Sha512Final(&sha512, Ai);
+            }
+        }
+#endif
+
+        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];
+                    mp_to_unsigned_bin(&res, tmp);
+                    XMEMCPY(I + i, tmp + 1, v);
+                }
+                else if (outSz < (int)v) {
+                    XMEMSET(I + i, 0, v - outSz);
+                    mp_to_unsigned_bin(&res, I + i + v - outSz);
+                }
+                else
+                    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);
+    return ret;
+}
+
+#endif /* NO_PWDBASED */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/rabbit.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,308 @@
+/* rabbit.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifndef NO_RABBIT
+
+#include <cyassl/ctaocrypt/rabbit.h>
+#include <cyassl/ctaocrypt/ctaoerror2.h>
+#include <cyassl/ctaocrypt/logging.h>
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/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 RabbitSetIV(Rabbit* ctx, const byte* iv)
+{
+    /* Temporary variables */
+    word32 i0, i1, i2, i3, i;
+      
+    /* Generate four subvectors */
+    i0 = LITTLE32(*(word32*)(iv+0));
+    i2 = LITTLE32(*(word32*)(iv+4));
+    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;
+
+    if (iv) RabbitSetIV(ctx, iv);
+
+    return 0;
+}
+
+
+/* Key setup */
+int RabbitSetKey(Rabbit* ctx, const byte* key, const byte* iv)
+{
+#ifdef XSTREAM_ALIGN
+    if ((word)key % 4 || (iv && (word)iv % 4)) {
+        int alignKey[4];
+        int alignIv[2];
+
+        CYASSL_MSG("RabbitSetKey unaligned key/iv");
+
+        XMEMCPY(alignKey, key, sizeof(alignKey));
+        if (iv) {
+            XMEMCPY(alignIv,  iv,  sizeof(alignIv));
+            iv = (const byte*)alignIv;
+        }
+
+        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 RabbitProcess(Rabbit* ctx, byte* output, const byte* input, word32 msglen)
+{
+#ifdef XSTREAM_ALIGN
+    if ((word)input % 4 || (word)output % 4) {
+        #ifndef NO_CYASSL_ALLOC_ALIGN
+            byte* tmp;
+            CYASSL_MSG("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/ctaocrypt/src/random.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,637 @@
+/* random.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+/* on HPUX 11 you may need to install /dev/random see
+   http://h20293.www2.hp.com/portal/swdepot/displayProductInfo.do?productNumber=KRNG11I
+
+*/
+
+#include <cyassl/ctaocrypt/random.h>
+#include <cyassl/ctaocrypt/ctaoerror2.h>
+
+#ifdef NO_RC4
+    #include <cyassl/ctaocrypt/sha256.h>
+
+    #ifdef NO_INLINE
+        #include <cyassl/ctaocrypt/misc.h>
+    #else
+        #define MISC_DUMM_FUNC misc_dummy_random
+        #include <ctaocrypt/src/misc.c>
+    #endif
+#endif
+
+#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(CYASSL_MDK_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 NO_RC4
+
+/* Start NIST DRBG code */
+
+#define OUTPUT_BLOCK_LEN (256/8)
+#define MAX_REQUEST_LEN  (0x1000)
+#define MAX_STRING_LEN   (0x100000000)
+#define RESEED_MAX       (0x100000000000LL)
+#define ENTROPY_SZ       256
+
+#define DBRG_SUCCESS 0
+#define DBRG_ERROR 1
+#define DBRG_NEED_RESEED 2
+
+
+enum {
+    dbrgInitC     = 0,
+    dbrgReseed    = 1,
+    dbrgGenerateW = 2,
+    dbrgGenerateH = 3,
+    dbrgInitV
+};
+
+
+static int Hash_df(RNG* rng, byte* out, word32 outSz, byte type, byte* inA, word32 inASz,
+                               byte* inB, word32 inBSz, byte* inC, word32 inCSz)
+{
+    byte ctr;
+    int i;
+    int len;
+    word32 bits = (outSz * 8); /* reverse byte order */
+
+    #ifdef LITTLE_ENDIAN_ORDER
+        bits = ByteReverseWord32(bits);
+    #endif
+    len = (outSz / SHA256_DIGEST_SIZE)
+        + ((outSz % SHA256_DIGEST_SIZE) ? 1 : 0);
+
+    for (i = 0, ctr = 1; i < len; i++, ctr++)
+    {
+        InitSha256(&rng->sha);
+        Sha256Update(&rng->sha, &ctr, sizeof(ctr));
+        Sha256Update(&rng->sha, (byte*)&bits, sizeof(bits));
+        /* churning V is the only string that doesn't have 
+         * the type added */
+        if (type != dbrgInitV)
+            Sha256Update(&rng->sha, &type, sizeof(type));
+        Sha256Update(&rng->sha, inA, inASz);
+        if (inB != NULL && inBSz > 0)
+            Sha256Update(&rng->sha, inB, inBSz);
+        if (inC != NULL && inCSz > 0)
+            Sha256Update(&rng->sha, inC, inCSz);
+        Sha256Final(&rng->sha, rng->digest);
+
+        if (outSz > SHA256_DIGEST_SIZE) {
+            XMEMCPY(out, rng->digest, SHA256_DIGEST_SIZE);
+            outSz -= SHA256_DIGEST_SIZE;
+            out += SHA256_DIGEST_SIZE;
+        }
+        else {
+            XMEMCPY(out, rng->digest, outSz);
+        }
+    }
+
+    return DBRG_SUCCESS;
+}
+
+
+static int Hash_DBRG_Reseed(RNG* rng, byte* entropy, word32 entropySz)
+{
+    byte seed[DBRG_SEED_LEN];
+
+    Hash_df(rng, seed, sizeof(seed), dbrgInitV, rng->V, sizeof(rng->V),
+                                                  entropy, entropySz, NULL, 0);
+    XMEMCPY(rng->V, seed, sizeof(rng->V));
+    XMEMSET(seed, 0, sizeof(seed));
+
+    Hash_df(rng, rng->C, sizeof(rng->C), dbrgInitC, rng->V, sizeof(rng->V),
+                                                             NULL, 0, NULL, 0);
+    rng->reseed_ctr = 1;
+    return 0;
+}
+
+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;
+    }
+}
+
+static void Hash_gen(RNG* rng, byte* out, word32 outSz, byte* V)
+{
+    byte data[DBRG_SEED_LEN];
+    int i;
+    int len = (outSz / SHA256_DIGEST_SIZE)
+        + ((outSz % SHA256_DIGEST_SIZE) ? 1 : 0);
+
+    XMEMCPY(data, V, sizeof(data));
+    for (i = 0; i < len; i++) {
+        InitSha256(&rng->sha);
+        Sha256Update(&rng->sha, data, sizeof(data));
+        Sha256Final(&rng->sha, rng->digest);
+        if (outSz > SHA256_DIGEST_SIZE) {
+            XMEMCPY(out, rng->digest, SHA256_DIGEST_SIZE);
+            outSz -= SHA256_DIGEST_SIZE;
+            out += SHA256_DIGEST_SIZE;
+            array_add_one(data, DBRG_SEED_LEN);
+        }
+        else {
+            XMEMCPY(out, rng->digest, outSz);
+        }
+    }
+    XMEMSET(data, 0, sizeof(data));
+}
+
+
+static INLINE void array_add(byte* d, word32 dLen, 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] = carry;
+            carry >>= 8;
+        } 
+        if (dIdx > 0)
+            d[dIdx] += carry;
+    }
+}
+
+
+static int Hash_DBRG_Generate(RNG* rng, byte* out, word32 outSz)
+{
+    int ret;
+
+    if (rng->reseed_ctr != RESEED_MAX) {
+        byte type = dbrgGenerateH;
+
+        Hash_gen(rng, out, outSz, rng->V);
+        InitSha256(&rng->sha);
+        Sha256Update(&rng->sha, &type, sizeof(type));
+        Sha256Update(&rng->sha, rng->V, sizeof(rng->V));
+        Sha256Final(&rng->sha, rng->digest);
+        array_add(rng->V, sizeof(rng->V), rng->digest, sizeof(rng->digest));
+        array_add(rng->V, sizeof(rng->V), rng->C, sizeof(rng->C));
+        array_add(rng->V, sizeof(rng->V),
+                              (byte*)&rng->reseed_ctr, sizeof(rng->reseed_ctr));
+        rng->reseed_ctr++;
+        ret = DBRG_SUCCESS;
+    }
+    else {
+        ret = DBRG_NEED_RESEED;
+    }
+    return ret;
+}
+
+
+static void Hash_DBRG_Instantiate(RNG* rng, byte* seed, word32 seedSz)
+{
+    XMEMSET(rng, 0, sizeof(*rng));
+    Hash_df(rng, rng->V, sizeof(rng->V), dbrgInitV, seed, seedSz, NULL, 0, NULL, 0);
+    Hash_df(rng, rng->C, sizeof(rng->C), dbrgInitC, rng->V, sizeof(rng->V),
+                                                             NULL, 0, NULL, 0);
+    rng->reseed_ctr = 1;
+}
+
+
+static int Hash_DBRG_Uninstantiate(RNG* rng)
+{
+    int result = DBRG_ERROR;
+
+    if (rng != NULL) {
+        XMEMSET(rng, 0, sizeof(*rng));
+        result = DBRG_SUCCESS;
+    }
+
+    return result;
+}
+
+/* End NIST DRBG Code */
+
+
+
+/* Get seed and key cipher */
+int InitRng(RNG* rng)
+{
+    byte entropy[ENTROPY_SZ];
+    int  ret = DBRG_ERROR;
+
+    if (GenerateSeed(&rng->seed, entropy, sizeof(entropy)) == 0) {
+        Hash_DBRG_Instantiate(rng, entropy, sizeof(entropy));
+        ret = DBRG_SUCCESS;
+    }
+    XMEMSET(entropy, 0, sizeof(entropy));
+    return ret;
+}
+
+
+/* place a generated block in output */
+void RNG_GenerateBlock(RNG* rng, byte* output, word32 sz)
+{
+    int ret;
+
+    XMEMSET(output, 0, sz);
+    ret = Hash_DBRG_Generate(rng, output, sz);
+    if (ret == DBRG_NEED_RESEED) {
+        byte entropy[ENTROPY_SZ];
+        ret = GenerateSeed(&rng->seed, entropy, sizeof(entropy));
+        if (ret == 0) {
+            Hash_DBRG_Reseed(rng, entropy, sizeof(entropy));
+            ret = Hash_DBRG_Generate(rng, output, sz);
+        }
+        else
+            ret = DBRG_ERROR;
+        XMEMSET(entropy, 0, sizeof(entropy));
+    }
+}
+
+
+byte RNG_GenerateByte(RNG* rng)
+{
+    byte b;
+    RNG_GenerateBlock(rng, &b, 1);
+
+    return b;
+}
+
+
+void FreeRng(RNG* rng)
+{
+    Hash_DBRG_Uninstantiate(rng);
+}
+
+#else /* NO_RC4 */
+
+/* Get seed and key cipher */
+int InitRng(RNG* rng)
+{
+    byte key[32];
+    byte junk[256];
+    int  ret;
+
+#ifdef HAVE_CAVIUM
+    if (rng->magic == CYASSL_RNG_CAVIUM_MAGIC)
+        return 0; 
+#endif
+    ret = GenerateSeed(&rng->seed, key, sizeof(key));
+
+    if (ret == 0) {
+        Arc4SetKey(&rng->cipher, key, sizeof(key));
+        RNG_GenerateBlock(rng, junk, sizeof(junk));  /* rid initial state */
+    }
+
+    return ret;
+}
+
+#ifdef HAVE_CAVIUM
+    static void CaviumRNG_GenerateBlock(RNG* rng, byte* output, word32 sz);
+#endif
+
+/* place a generated block in output */
+void RNG_GenerateBlock(RNG* rng, byte* output, word32 sz)
+{
+#ifdef HAVE_CAVIUM
+    if (rng->magic == CYASSL_RNG_CAVIUM_MAGIC)
+        return CaviumRNG_GenerateBlock(rng, output, sz); 
+#endif
+    XMEMSET(output, 0, sz);
+    Arc4Process(&rng->cipher, output, output, sz);
+}
+
+
+byte RNG_GenerateByte(RNG* rng)
+{
+    byte b;
+    RNG_GenerateBlock(rng, &b, 1);
+
+    return b;
+}
+
+
+#ifdef HAVE_CAVIUM
+
+#include <cyassl/ctaocrypt/logging.h>
+#include "cavium_common.h"
+
+/* Initiliaze RNG for use with Nitrox device */
+int InitRngCavium(RNG* rng, int devId)
+{
+    if (rng == NULL)
+        return -1;
+
+    rng->devId = devId;
+    rng->magic = CYASSL_RNG_CAVIUM_MAGIC;
+   
+    return 0;
+}
+
+
+static void CaviumRNG_GenerateBlock(RNG* rng, byte* output, word32 sz)
+{
+    word   offset = 0;
+    word32 requestId;
+
+    while (sz > CYASSL_MAX_16BIT) {
+        word16 slen = (word16)CYASSL_MAX_16BIT;
+        if (CspRandom(CAVIUM_BLOCKING, slen, output + offset, &requestId,
+                      rng->devId) != 0) {
+            CYASSL_MSG("Cavium RNG failed");
+        }
+        sz     -= CYASSL_MAX_16BIT;
+        offset += CYASSL_MAX_16BIT;
+    }
+    if (sz) {
+        word16 slen = (word16)sz;
+        if (CspRandom(CAVIUM_BLOCKING, slen, output + offset, &requestId,
+                      rng->devId) != 0) {
+            CYASSL_MSG("Cavium RNG failed");
+        }
+    }
+}
+
+#endif /* HAVE_CAVIUM */
+
+#endif /* NO_RC4 */
+
+
+#if defined(USE_WINDOWS_API)
+
+
+int 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 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 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 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)
+
+#include <peripheral/timer.h>
+
+/* uses the core timer, in nanoseconds to seed srand */
+int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    int i;
+    srand(ReadCoreTimer() * 25);
+
+    for (i = 0; i < sz; i++ ) {
+        output[i] = rand() % 256;
+        if ( (i % 8) == 7)
+            srand(ReadCoreTimer() * 25);
+    }
+
+    return 0;
+}
+
+#elif defined(CYASSL_SAFERTOS) || defined(CYASSL_LEANPSK)
+
+#warning "write a real random seed!!!!, just for testing now"
+
+int 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(FREESCALE_MQX)
+
+    #ifdef FREESCALE_K70_RNGA
+        /*
+         * 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 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;
+        }
+	#else
+        #warning "write a real random seed!!!!, just for testing now"
+
+        int 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(STM32F2_RNG)
+    #undef RNG
+    #include "stm32f2xx_rng.h"
+    #include "stm32f2xx_rcc.h"
+    /*
+     * 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 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(CYASSL_LPC43xx) || defined(CYASSL_STM32F2xx)
+
+    #warning "write a real random seed!!!!, just for testing now"
+
+    int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+    {
+        int i;
+
+        for (i = 0; i < sz; i++ )
+            output[i] = i;
+
+        return 0;
+    }
+
+#elif defined(NO_DEV_RANDOM)
+
+#error "you need to write an os specific GenerateSeed() here"
+
+/*
+int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    return 0;
+}
+*/
+
+
+#else /* !USE_WINDOWS_API && !HAVE_RPT_SYS && !MICRIUM && !NO_DEV_RANDOM */
+
+
+/* may block */
+int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+{
+    int ret = 0;
+
+    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 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/ripemd.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,353 @@
+/* ripemd.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef CYASSL_RIPEMD
+
+#include <cyassl/ctaocrypt/ripemd.h>
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/src/misc.c>
+#endif
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+void 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 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
+                ByteReverseBytes(local, local, RIPEMD_BLOCK_SIZE);
+            #endif
+            Transform(ripemd);
+            AddLength(ripemd, RIPEMD_BLOCK_SIZE);
+            ripemd->buffLen = 0;
+        }
+    }
+}
+
+
+void 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
+            ByteReverseBytes(local, local, 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
+        ByteReverseBytes(local, local, 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);
+
+    InitRipeMd(ripemd);  /* reset state */
+}
+
+
+#endif /* CYASSL_RIPEMD */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/rsa.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,809 @@
+/* rsa.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifndef NO_RSA
+
+#include <cyassl/ctaocrypt/rsa.h>
+#include <cyassl/ctaocrypt/random.h>
+#include <cyassl/ctaocrypt/ctaoerror2.h>
+#include <cyassl/ctaocrypt/logging.h>
+
+#ifdef SHOW_GEN
+    #ifdef FREESCALE_MQX
+        #include <fio.h>
+    #else
+        #include <stdio.h>
+    #endif
+#endif
+
+#ifdef HAVE_CAVIUM
+    static void InitCaviumRsaKey(RsaKey* key, void* heap);
+    static void 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 */
+};
+
+
+void InitRsaKey(RsaKey* key, void* heap)
+{
+#ifdef HAVE_CAVIUM
+    if (key->magic == CYASSL_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;
+#endif
+}
+
+
+void FreeRsaKey(RsaKey* key)
+{
+    (void)key;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == CYASSL_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
+}
+
+static void RsaPad(const byte* input, word32 inputLen, byte* pkcsBlock,
+                   word32 pkcsBlockLen, byte padValue, RNG* rng)
+{
+    if (inputLen == 0) return;
+
+    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;
+        RNG_GenerateBlock(rng, &pkcsBlock[1], padLen);
+
+        /* 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);
+}
+
+
+static word32 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;
+
+    /* skip past the padding until we find the separator */
+    while (i<pkcsBlockLen && pkcsBlock[i++]) { /* null body */
+        }
+    if(!(i==pkcsBlockLen || pkcsBlock[i-1]==0)) {
+        CYASSL_MSG("RsaUnPad error, bad formatting");
+        return 0;
+    }
+
+    outputLen = pkcsBlockLen - i;
+    invalid = (outputLen > maxOutputLen) || invalid;
+
+    if (invalid) {
+        CYASSL_MSG("RsaUnPad error, bad formatting");
+        return 0;
+    }
+
+    *output = (byte *)(pkcsBlock + i);
+    return outputLen;
+}
+
+
+static int 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);
+    return ret;
+}
+
+
+int RsaPublicEncrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
+                     RsaKey* key, RNG* rng)
+{
+    int sz, ret;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == CYASSL_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;
+
+    RsaPad(in, inLen, out, sz, RSA_BLOCK_TYPE_2, rng);
+
+    if ((ret = RsaFunction(out, sz, out, &outLen, RSA_PUBLIC_ENCRYPT, key)) < 0)
+        sz = ret;
+
+    return sz;
+}
+
+
+int RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out, RsaKey* key)
+{
+    int plainLen, ret;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == CYASSL_RSA_CAVIUM_MAGIC) {
+        ret = CaviumRsaPrivateDecrypt(in, inLen, in, inLen, key);
+        if (ret > 0)
+            *out = in;
+        return ret;
+    }
+#endif
+
+    if ((ret = RsaFunction(in, inLen, in, &inLen, RSA_PRIVATE_DECRYPT, key))
+            < 0) {
+        return ret;
+    }
+ 
+    plainLen = RsaUnPad(in, inLen, out, RSA_BLOCK_TYPE_2);
+
+    return plainLen;
+}
+
+
+int RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
+                     RsaKey* key)
+{
+    int plainLen, ret;
+    byte*  tmp;
+    byte*  pad = 0;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == CYASSL_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 ((ret = plainLen = RsaPrivateDecryptInline(tmp, inLen, &pad, key))
+            < 0) {
+        XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+        return ret;
+    }
+    if (plainLen > (int)outLen)
+        plainLen = BAD_FUNC_ARG;
+    else
+        XMEMCPY(out, pad, plainLen);
+    XMEMSET(tmp, 0x00, inLen); 
+
+    XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+    return plainLen;
+}
+
+
+/* for Rsa Verify */
+int RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out, RsaKey* key)
+{
+    int plainLen, ret;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == CYASSL_RSA_CAVIUM_MAGIC) {
+        ret = CaviumRsaSSL_Verify(in, inLen, in, inLen, key);
+        if (ret > 0)
+            *out = in;
+        return ret;
+    }
+#endif
+
+    if ((ret = RsaFunction(in, inLen, in, &inLen, RSA_PUBLIC_DECRYPT, key))
+            < 0) {
+        return ret;
+    }
+  
+    plainLen = RsaUnPad(in, inLen, out, RSA_BLOCK_TYPE_1);
+
+    return plainLen;
+}
+
+
+int RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen,
+                     RsaKey* key)
+{
+    int plainLen, ret;
+    byte*  tmp;
+    byte*  pad = 0;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == CYASSL_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 ((ret = plainLen = RsaSSL_VerifyInline(tmp, inLen, &pad, key))
+            < 0) {
+        XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+        return ret;
+    }
+
+    if (plainLen > (int)outLen)
+        plainLen = BAD_FUNC_ARG;
+    else 
+        XMEMCPY(out, pad, plainLen);
+    XMEMSET(tmp, 0x00, inLen); 
+
+    XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA);
+    return plainLen;
+}
+
+
+/* for Rsa Sign */
+int RsaSSL_Sign(const byte* in, word32 inLen, byte* out, word32 outLen,
+                      RsaKey* key, RNG* rng)
+{
+    int sz, ret;
+
+#ifdef HAVE_CAVIUM
+    if (key->magic == CYASSL_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;
+
+    RsaPad(in, inLen, out, sz, RSA_BLOCK_TYPE_1, rng);
+
+    if ((ret = RsaFunction(out, sz, out, &outLen, RSA_PRIVATE_ENCRYPT,key)) < 0)
+        sz = ret;
+    
+    return sz;
+}
+
+
+int RsaEncryptSize(RsaKey* key)
+{
+#ifdef HAVE_CAVIUM
+    if (key->magic == CYASSL_RSA_CAVIUM_MAGIC)
+        return key->c_nSz;
+#endif
+    return mp_unsigned_bin_size(&key->n);
+}
+
+
+#ifdef CYASSL_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 */
+        RNG_GenerateBlock(rng, buf, len);
+
+        /* 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);
+
+#ifdef LTC_CLEAN_STACK
+    XMEMSET(buf, 0, len);
+#endif
+
+    XFREE(buf, heap, DYNAMIC_TYPE_RSA);
+    return 0;
+}
+
+
+/* Make an RSA key for size bits, with e specified, 65537 is a good e */
+int 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) {
+        FreeRsaKey(key);        
+        return err;
+    }
+
+    return 0;
+}
+
+
+#endif /* CYASSL_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 = CYASSL_RSA_CAVIUM_MAGIC;
+   
+    return 0;
+}
+
+
+/* Free RSA from use with Nitrox device */
+void RsaFreeCavium(RsaKey* rsa)
+{
+    if (rsa == NULL)
+        return;
+
+    CspFreeContext(CONTEXT_SSL, rsa->contextHandle, rsa->devId);
+    rsa->magic = 0;
+}
+
+
+/* Initialize cavium RSA key */
+static void InitCaviumRsaKey(RsaKey* key, void* heap)
+{
+    if (key == NULL)
+        return;
+
+    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;
+}
+
+
+/* Free cavium RSA key */
+static void FreeCaviumRsaKey(RsaKey* key)
+{
+    if (key == NULL)
+        return;
+
+    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);
+
+    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) {
+        CYASSL_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) {
+        CYASSL_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) {
+        CYASSL_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) {
+        CYASSL_MSG("Cavium Dec BT1 failed");
+        return -1;
+    }
+    outSz = ntohs(outSz);
+
+    return outSz;
+}
+
+
+#endif /* HAVE_CAVIUM */
+
+#endif /* NO_RSA */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/sha.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,354 @@
+/* sha.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifndef NO_SHA
+
+#include <cyassl/ctaocrypt/sha.h>
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/src/misc.c>
+#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"
+		
+    void 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;
+    }
+
+    void 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);
+    }
+
+    void 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);
+
+        InitSha(sha);  /* reset state */
+    }
+
+#else /* CTaoCrypt software implementation */
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+void InitSha(Sha* sha)
+{
+    sha->digest[0] = 0x67452301L;
+    sha->digest[1] = 0xEFCDAB89L;
+    sha->digest[2] = 0x98BADCFEL;
+    sha->digest[3] = 0x10325476L;
+    sha->digest[4] = 0xC3D2E1F0L;
+
+    sha->buffLen = 0;
+    sha->loLen   = 0;
+    sha->hiLen   = 0;
+}
+
+#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;
+}
+
+
+static INLINE void AddLength(Sha* sha, word32 len)
+{
+    word32 tmp = sha->loLen;
+    if ( (sha->loLen += len) < tmp)
+        sha->hiLen++;                       /* carry low to high */
+}
+
+
+void 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) {
+            #ifdef LITTLE_ENDIAN_ORDER
+                ByteReverseBytes(local, local, SHA_BLOCK_SIZE);
+            #endif
+            Transform(sha);
+            AddLength(sha, SHA_BLOCK_SIZE);
+            sha->buffLen = 0;
+        }
+    }
+}
+
+
+void 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;
+
+        #ifdef LITTLE_ENDIAN_ORDER
+            ByteReverseBytes(local, local, SHA_BLOCK_SIZE);
+        #endif
+        Transform(sha);
+        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 */
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseBytes(local, local, 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));
+
+    Transform(sha);
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords(sha->digest, sha->digest, SHA_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, sha->digest, SHA_DIGEST_SIZE);
+
+    InitSha(sha);  /* reset state */
+}
+
+#endif /* STM32F2_HASH */
+
+#endif /* NO_SHA */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/sha256.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,211 @@
+/* sha256.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/* code submitted by raphael.huck@efixo.com */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifndef NO_SHA256
+
+#include <cyassl/ctaocrypt/sha256.h>
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/src/misc.c>
+#endif
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+void InitSha256(Sha256* sha256)
+{
+    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;
+
+    sha256->buffLen = 0;
+    sha256->loLen   = 0;
+    sha256->hiLen   = 0;
+}
+
+static const 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
+};
+
+#define Ch(x,y,z)       (z ^ (x & (y ^ z)))
+#define Maj(x,y,z)      (((x | y) & z) | (x & y))
+#define S(x, n)         rotrFixed(x, n)
+#define R(x, n)         (((x)&0xFFFFFFFFU)>>(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;
+
+
+static void Transform(Sha256* sha256)
+{
+    word32 S[8], W[64], t0, t1;
+    int i;
+
+    /* 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];
+    }
+}
+
+
+static INLINE void AddLength(Sha256* sha256, word32 len)
+{
+    word32 tmp = sha256->loLen;
+    if ( (sha256->loLen += len) < tmp)
+        sha256->hiLen++;                       /* carry low to high */
+}
+
+
+void Sha256Update(Sha256* sha256, const byte* data, word32 len)
+{
+    /* do block size increments */
+    byte* local = (byte*)sha256->buffer;
+
+    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) {
+            #ifdef LITTLE_ENDIAN_ORDER
+                ByteReverseBytes(local, local, SHA256_BLOCK_SIZE);
+            #endif
+            Transform(sha256);
+            AddLength(sha256, SHA256_BLOCK_SIZE);
+            sha256->buffLen = 0;
+        }
+    }
+}
+
+
+void Sha256Final(Sha256* sha256, byte* hash)
+{
+    byte* local = (byte*)sha256->buffer;
+
+    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;
+
+        #ifdef LITTLE_ENDIAN_ORDER
+            ByteReverseBytes(local, local, SHA256_BLOCK_SIZE);
+        #endif
+        Transform(sha256);
+        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 */
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseBytes(local, local, 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));
+
+    Transform(sha256);
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords(sha256->digest, sha256->digest, SHA256_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, sha256->digest, SHA256_DIGEST_SIZE);
+
+    InitSha256(sha256);  /* reset state */
+}
+
+
+#endif /* NO_SHA256 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/sha512.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,387 @@
+/* sha512.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef CYASSL_SHA512
+
+#include <cyassl/ctaocrypt/sha512.h>
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/src/misc.c>
+#endif
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+void 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;
+}
+
+
+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 void Transform(Sha512* sha512)
+{
+    const word64* K = K512;
+
+    word32 j;
+    word64 W[16];
+    word64 T[8];
+
+    /* Copy digest to working vars */
+    XMEMCPY(T, sha512->digest, sizeof(T));
+
+    /* 64 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);
+    }
+
+    /* 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 */
+    XMEMSET(W, 0, sizeof(W));
+    XMEMSET(T, 0, sizeof(T));
+}
+
+
+static INLINE void AddLength(Sha512* sha512, word32 len)
+{
+    word32 tmp = sha512->loLen;
+    if ( (sha512->loLen += len) < tmp)
+        sha512->hiLen++;                       /* carry low to high */
+}
+
+
+void Sha512Update(Sha512* sha512, const byte* data, word32 len)
+{
+    /* do block size increments */
+    byte* local = (byte*)sha512->buffer;
+
+    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) {
+            #ifdef LITTLE_ENDIAN_ORDER
+                ByteReverseWords64(sha512->buffer, sha512->buffer,
+                                   SHA512_BLOCK_SIZE);
+            #endif
+            Transform(sha512);
+            AddLength(sha512, SHA512_BLOCK_SIZE);
+            sha512->buffLen = 0;
+        }
+    }
+}
+
+
+void Sha512Final(Sha512* sha512, byte* hash)
+{
+    byte* local = (byte*)sha512->buffer;
+
+    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;
+
+        #ifdef LITTLE_ENDIAN_ORDER
+            ByteReverseWords64(sha512->buffer,sha512->buffer,SHA512_BLOCK_SIZE);
+        #endif
+        Transform(sha512);
+        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 */
+    #ifdef LITTLE_ENDIAN_ORDER
+        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;
+
+    Transform(sha512);
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords64(sha512->digest, sha512->digest, SHA512_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, sha512->digest, SHA512_DIGEST_SIZE);
+
+    InitSha512(sha512);  /* reset state */
+}
+
+
+
+#ifdef CYASSL_SHA384
+
+void 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;
+}
+
+
+static void Transform384(Sha384* sha384)
+{
+    const word64* K = K512;
+
+    word32 j;
+    word64 W[16];
+    word64 T[8];
+
+    /* Copy digest to working vars */
+    XMEMCPY(T, sha384->digest, sizeof(T));
+
+    /* 64 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);
+    }
+
+    /* 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(W));
+    XMEMSET(T, 0, sizeof(T));
+}
+
+
+static INLINE void AddLength384(Sha384* sha384, word32 len)
+{
+    word32 tmp = sha384->loLen;
+    if ( (sha384->loLen += len) < tmp)
+        sha384->hiLen++;                       /* carry low to high */
+}
+
+
+void Sha384Update(Sha384* sha384, const byte* data, word32 len)
+{
+    /* do block size increments */
+    byte* local = (byte*)sha384->buffer;
+
+    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) {
+            #ifdef LITTLE_ENDIAN_ORDER
+                ByteReverseWords64(sha384->buffer, sha384->buffer,
+                                   SHA384_BLOCK_SIZE);
+            #endif
+            Transform384(sha384);
+            AddLength384(sha384, SHA384_BLOCK_SIZE);
+            sha384->buffLen = 0;
+        }
+    }
+}
+
+
+void Sha384Final(Sha384* sha384, byte* hash)
+{
+    byte* local = (byte*)sha384->buffer;
+
+    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;
+
+        #ifdef LITTLE_ENDIAN_ORDER
+            ByteReverseWords64(sha384->buffer,sha384->buffer,SHA384_BLOCK_SIZE);
+        #endif
+        Transform384(sha384);
+        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 */
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords64(sha384->buffer, sha384->buffer, SHA384_PAD_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;
+
+    Transform384(sha384);
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords64(sha384->digest, sha384->digest, SHA384_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, sha384->digest, SHA384_DIGEST_SIZE);
+
+    InitSha384(sha384);  /* reset state */
+}
+
+#endif /* CYASSL_SHA384 */
+
+#endif /* CYASSL_SHA512 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/tfm.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,2473 @@
+/* tfm.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 <cyassl/ctaocrypt/settings.h>
+
+#ifdef USE_FAST_MATH
+
+#include <cyassl/ctaocrypt/tfm.h>
+#include <ctaocrypt/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 = c->used;
+  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 */
+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;
+
+   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_zero(&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)
+{
+  fp_digit D, r, rr;
+  int      x;
+  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 = (fp_digit) (b % DIGIT_BIT);
+  if (D != 0) {
+    register fp_digit *tmpc, mask, shift;
+
+    /* 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 the previous word */
+      *tmpc = (*tmpc >> D) | (r << shift);
+      --tmpc;
+
+      /* set the carry to the carry bits of the current word found above */
+      r = rr;
+    }
+  }
+  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_zero(&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;
+
+  /* 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) {
+    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_zero(&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_zero(&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
+
+/* 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;
+
+   /* 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_64BIT)
+  /* 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;
+}
+
+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);
+}
+
+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_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;
+}
+
+/* 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;
+}
+
+
+/* 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);
+}
+
+
+/* fast math wrappers */
+int mp_set_int(fp_int *a, fp_digit b)
+{
+    fp_set(a, b);
+    return MP_OKAY;
+}
+
+
+#if defined(CYASSL_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_zero(&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 /* CYASSL_KEYGEN || HAVE_ECC */
+
+
+#ifdef CYASSL_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  fp_cnt_lsb(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;
+}
+
+
+
+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);
+}
+
+
+/* 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);
+   }   
+}
+
+
+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;
+}
+
+
+/* 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_zero(&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 /* CYASSL_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_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 */
+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(*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 */
+int mp_set(fp_int *a, fp_digit b)
+{
+    fp_set(a,b);
+    return MP_OKAY;
+}
+
+/* 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;
+}
+
+
+
+#endif /* HAVE_ECC */
+
+#endif /* USE_FAST_MATH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/callbacks.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,81 @@
+/* callbacks.h
+ *
+ * Copyright (C) 2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CYASSL_CALLBACKS_H
+#define CYASSL_CALLBACKS_H
+
+#include <time.h>
+#include "sockets.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 /* CYASSL_CALLBACKS_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/certs_test.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,800 @@
+/* certs_test.h */
+
+#ifndef CYASSL_CERTS_TEST_H
+#define CYASSL_CERTS_TEST_H
+
+#ifdef USE_CERT_BUFFERS_1024
+
+/* ./certs/1024/client-key.der, 1024-bit */
+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
+};
+const int sizeof_client_key_der_1024 = sizeof(client_key_der_1024) ;
+
+/* ./certs/1024/client-cert.der, 1024-bit */
+const unsigned char client_cert_der_1024[] =
+{
+	0x30, 0x82, 0x02, 0xEC, 0x30, 0x82, 0x02, 0x55, 0xA0, 0x03, 
+	0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x8D, 0x0D, 0xAC, 0xFE, 
+	0xC6, 0x98, 0x45, 0x26, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 
+	0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 
+	0x81, 0x8E, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 
+	0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0F, 0x30, 0x0D, 0x06, 
+	0x03, 0x55, 0x04, 0x08, 0x0C, 0x06, 0x4F, 0x72, 0x65, 0x67, 
+	0x6F, 0x6E, 0x31, 0x11, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x04, 
+	0x07, 0x0C, 0x08, 0x50, 0x6F, 0x72, 0x74, 0x6C, 0x61, 0x6E, 
+	0x64, 0x31, 0x0E, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x04, 0x0A, 
+	0x0C, 0x05, 0x79, 0x61, 0x53, 0x53, 0x4C, 0x31, 0x14, 0x30, 
+	0x12, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x0B, 0x50, 0x72, 
+	0x6F, 0x67, 0x72, 0x61, 0x6D, 0x6D, 0x69, 0x6E, 0x67, 0x31, 
+	0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0D, 
+	0x77, 0x77, 0x77, 0x2E, 0x79, 0x61, 0x73, 0x73, 0x6C, 0x2E, 
+	0x63, 0x6F, 0x6D, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x09, 0x2A, 
+	0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x0E, 
+	0x69, 0x6E, 0x66, 0x6F, 0x40, 0x79, 0x61, 0x73, 0x73, 0x6C, 
+	0x2E, 0x63, 0x6F, 0x6D, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x33, 
+	0x30, 0x31, 0x31, 0x38, 0x32, 0x31, 0x34, 0x32, 0x34, 0x39, 
+	0x5A, 0x17, 0x0D, 0x31, 0x35, 0x31, 0x30, 0x31, 0x35, 0x32, 
+	0x31, 0x34, 0x32, 0x34, 0x39, 0x5A, 0x30, 0x81, 0x8E, 0x31, 
+	0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 
+	0x55, 0x53, 0x31, 0x0F, 0x30, 0x0D, 0x06, 0x03, 0x55, 0x04, 
+	0x08, 0x0C, 0x06, 0x4F, 0x72, 0x65, 0x67, 0x6F, 0x6E, 0x31, 
+	0x11, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x08, 
+	0x50, 0x6F, 0x72, 0x74, 0x6C, 0x61, 0x6E, 0x64, 0x31, 0x0E, 
+	0x30, 0x0C, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x05, 0x79, 
+	0x61, 0x53, 0x53, 0x4C, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 
+	0x55, 0x04, 0x0B, 0x0C, 0x0B, 0x50, 0x72, 0x6F, 0x67, 0x72, 
+	0x61, 0x6D, 0x6D, 0x69, 0x6E, 0x67, 0x31, 0x16, 0x30, 0x14, 
+	0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0D, 0x77, 0x77, 0x77, 
+	0x2E, 0x79, 0x61, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 
+	0x31, 0x1D, 0x30, 0x1B, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 
+	0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x0E, 0x69, 0x6E, 0x66, 
+	0x6F, 0x40, 0x79, 0x61, 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, 0x50, 0x30, 0x4E, 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, 0x1F, 
+	0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 
+	0x14, 0x81, 0x69, 0x0F, 0xF8, 0xDF, 0xDD, 0xCF, 0x34, 0x29, 
+	0xD5, 0x67, 0x75, 0x71, 0x85, 0xC7, 0x75, 0x10, 0x69, 0x59, 
+	0xEC, 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, 0x05, 0x05, 0x00, 
+	0x03, 0x81, 0x81, 0x00, 0x72, 0x66, 0x0F, 0x6A, 0xA1, 0x85, 
+	0x95, 0x06, 0xE6, 0x87, 0x1A, 0xED, 0x2B, 0xDA, 0xED, 0x84, 
+	0x90, 0x89, 0xA6, 0x31, 0x4D, 0x60, 0xF2, 0x7B, 0x63, 0x0C, 
+	0xDC, 0x9B, 0x44, 0x4C, 0xD6, 0x62, 0x41, 0x24, 0x74, 0x30, 
+	0x70, 0x4E, 0x07, 0x10, 0x05, 0x12, 0x5E, 0x14, 0xB3, 0xDD, 
+	0xCF, 0x58, 0x27, 0x93, 0xCF, 0xAA, 0x4F, 0x85, 0x2C, 0x35, 
+	0x0E, 0xFF, 0x5B, 0xA8, 0x6B, 0xB5, 0x95, 0x32, 0xD5, 0xCC, 
+	0x73, 0x68, 0x5B, 0x1B, 0xC4, 0xF8, 0x89, 0x5E, 0x3D, 0xF8, 
+	0x02, 0x39, 0x32, 0x7D, 0x06, 0xA4, 0x32, 0xE9, 0xB3, 0xEF, 
+	0x62, 0xA0, 0x43, 0x5D, 0x4F, 0xFB, 0xCE, 0x3D, 0x08, 0x33, 
+	0xAF, 0x3D, 0x7F, 0x12, 0xCB, 0x8A, 0x5A, 0xC2, 0x63, 0xDB, 
+	0x3E, 0xDD, 0xEA, 0x5B, 0x67, 0x10, 0x49, 0x9F, 0x5B, 0x96, 
+	0x1B, 0x4E, 0x5D, 0xBC, 0x4E, 0x9A, 0x7C, 0x1F, 0xAB, 0x56, 
+	0x47, 0x4A
+};
+const int sizeof_client_cert_der_1024 = sizeof(client_cert_der_1024) ;
+
+/* ./certs/1024/dh1024.der, 1024-bit */
+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
+};
+const int sizeof_dh_key_der_1024 = sizeof(dh_key_der_1024) ;
+
+/* ./certs/1024/dsa1024.der, 1024-bit */
+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
+};
+const int sizeof_dsa_key_der_1024 = sizeof(dsa_key_der_1024) ;
+
+/* ./certs/1024/rsa1024.der, 1024-bit */
+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
+};
+const int sizeof_rsa_key_der_1024 = sizeof(rsa_key_der_1024) ;
+
+#elif defined(USE_CERT_BUFFERS_2048)
+
+/* ./certs/client-key.der, 2048-bit */
+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
+};
+const int sizeof_client_key_der_2048 = sizeof(client_key_der_2048) ;
+
+/* ./certs/client-cert.der, 2048-bit */
+const unsigned char client_cert_der_2048[] =
+{
+	0x30, 0x82, 0x04, 0x98, 0x30, 0x82, 0x03, 0x80, 0xA0, 0x03, 
+	0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x87, 0x4A, 0x75, 0xBE, 
+	0x91, 0x66, 0xD8, 0x3D, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 
+	0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 
+	0x81, 0x8E, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 
+	0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0F, 0x30, 0x0D, 0x06, 
+	0x03, 0x55, 0x04, 0x08, 0x13, 0x06, 0x4F, 0x72, 0x65, 0x67, 
+	0x6F, 0x6E, 0x31, 0x11, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x04, 
+	0x07, 0x13, 0x08, 0x50, 0x6F, 0x72, 0x74, 0x6C, 0x61, 0x6E, 
+	0x64, 0x31, 0x0E, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x04, 0x0A, 
+	0x13, 0x05, 0x79, 0x61, 0x53, 0x53, 0x4C, 0x31, 0x14, 0x30, 
+	0x12, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13, 0x0B, 0x50, 0x72, 
+	0x6F, 0x67, 0x72, 0x61, 0x6D, 0x6D, 0x69, 0x6E, 0x67, 0x31, 
+	0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0D, 
+	0x77, 0x77, 0x77, 0x2E, 0x79, 0x61, 0x73, 0x73, 0x6C, 0x2E, 
+	0x63, 0x6F, 0x6D, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x09, 0x2A, 
+	0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x0E, 
+	0x69, 0x6E, 0x66, 0x6F, 0x40, 0x79, 0x61, 0x73, 0x73, 0x6C, 
+	0x2E, 0x63, 0x6F, 0x6D, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x31, 
+	0x31, 0x30, 0x32, 0x34, 0x31, 0x38, 0x32, 0x31, 0x35, 0x35, 
+	0x5A, 0x17, 0x0D, 0x31, 0x34, 0x30, 0x37, 0x32, 0x30, 0x31, 
+	0x38, 0x32, 0x31, 0x35, 0x35, 0x5A, 0x30, 0x81, 0x8E, 0x31, 
+	0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 
+	0x55, 0x53, 0x31, 0x0F, 0x30, 0x0D, 0x06, 0x03, 0x55, 0x04, 
+	0x08, 0x13, 0x06, 0x4F, 0x72, 0x65, 0x67, 0x6F, 0x6E, 0x31, 
+	0x11, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 
+	0x50, 0x6F, 0x72, 0x74, 0x6C, 0x61, 0x6E, 0x64, 0x31, 0x0E, 
+	0x30, 0x0C, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x05, 0x79, 
+	0x61, 0x53, 0x53, 0x4C, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 
+	0x55, 0x04, 0x0B, 0x13, 0x0B, 0x50, 0x72, 0x6F, 0x67, 0x72, 
+	0x61, 0x6D, 0x6D, 0x69, 0x6E, 0x67, 0x31, 0x16, 0x30, 0x14, 
+	0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0D, 0x77, 0x77, 0x77, 
+	0x2E, 0x79, 0x61, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 
+	0x31, 0x1D, 0x30, 0x1B, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 
+	0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x0E, 0x69, 0x6E, 0x66, 
+	0x6F, 0x40, 0x79, 0x61, 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, 0x81, 0xF6, 0x30, 0x81, 
+	0xF3, 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, 0xC3, 0x06, 0x03, 0x55, 0x1D, 0x23, 
+	0x04, 0x81, 0xBB, 0x30, 0x81, 0xB8, 0x80, 0x14, 0x33, 0xD8, 
+	0x45, 0x66, 0xD7, 0x68, 0x87, 0x18, 0x7E, 0x54, 0x0D, 0x70, 
+	0x27, 0x91, 0xC7, 0x26, 0xD7, 0x85, 0x65, 0xC0, 0xA1, 0x81, 
+	0x94, 0xA4, 0x81, 0x91, 0x30, 0x81, 0x8E, 0x31, 0x0B, 0x30, 
+	0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 
+	0x31, 0x0F, 0x30, 0x0D, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 
+	0x06, 0x4F, 0x72, 0x65, 0x67, 0x6F, 0x6E, 0x31, 0x11, 0x30, 
+	0x0F, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x50, 0x6F, 
+	0x72, 0x74, 0x6C, 0x61, 0x6E, 0x64, 0x31, 0x0E, 0x30, 0x0C, 
+	0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x05, 0x79, 0x61, 0x53, 
+	0x53, 0x4C, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 
+	0x0B, 0x13, 0x0B, 0x50, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 
+	0x6D, 0x69, 0x6E, 0x67, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 
+	0x55, 0x04, 0x03, 0x13, 0x0D, 0x77, 0x77, 0x77, 0x2E, 0x79, 
+	0x61, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x1D, 
+	0x30, 0x1B, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 
+	0x01, 0x09, 0x01, 0x16, 0x0E, 0x69, 0x6E, 0x66, 0x6F, 0x40, 
+	0x79, 0x61, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x82, 
+	0x09, 0x00, 0x87, 0x4A, 0x75, 0xBE, 0x91, 0x66, 0xD8, 0x3D, 
+	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, 0x05, 0x05, 0x00, 0x03, 
+	0x82, 0x01, 0x01, 0x00, 0x1C, 0x7C, 0x42, 0x81, 0x29, 0x9E, 
+	0x21, 0xCF, 0xD0, 0xD8, 0xC1, 0x54, 0x6F, 0xCC, 0xAE, 0x14, 
+	0x09, 0x38, 0xFF, 0x68, 0x98, 0x9A, 0x95, 0x53, 0x76, 0x18, 
+	0x7B, 0xE6, 0x30, 0x76, 0xEC, 0x28, 0x0D, 0x75, 0xA7, 0xDE, 
+	0xE0, 0xCD, 0x8E, 0xD5, 0x55, 0x23, 0x6A, 0x47, 0x2B, 0x4E, 
+	0x8D, 0xFC, 0x7D, 0x06, 0xA3, 0xD8, 0x0F, 0xAD, 0x5E, 0xD6, 
+	0x04, 0xC9, 0x00, 0x33, 0xFB, 0x77, 0x27, 0xD3, 0xB5, 0x03, 
+	0xB3, 0x7B, 0x21, 0x74, 0x31, 0x0B, 0x4A, 0xAF, 0x2D, 0x1A, 
+	0xB3, 0x93, 0x8E, 0xCC, 0xF3, 0x5F, 0x3D, 0x90, 0x3F, 0xCC, 
+	0xE3, 0x55, 0x19, 0x91, 0x7B, 0x78, 0x24, 0x2E, 0x4A, 0x09, 
+	0xBB, 0x18, 0x4E, 0x61, 0x2D, 0x9C, 0xC6, 0x0A, 0xA0, 0x34, 
+	0x91, 0x88, 0x70, 0x6B, 0x3B, 0x48, 0x47, 0xBC, 0x79, 0x94, 
+	0xA2, 0xA0, 0x4D, 0x32, 0x47, 0x54, 0xC2, 0xA3, 0xDC, 0x2E, 
+	0xD2, 0x51, 0x4C, 0x29, 0x39, 0x11, 0xFF, 0xE2, 0x15, 0x5E, 
+	0x58, 0x97, 0x36, 0xF6, 0xE9, 0x06, 0x06, 0x86, 0x0E, 0x8D, 
+	0x9D, 0x95, 0x03, 0x72, 0xB2, 0x8B, 0x19, 0x7C, 0xE9, 0x14, 
+	0x6E, 0xA1, 0x88, 0x73, 0x68, 0x58, 0x6D, 0x71, 0x5E, 0xC2, 
+	0xD5, 0xD3, 0x13, 0xD2, 0x5F, 0xDE, 0xEA, 0x03, 0xBE, 0xE2, 
+	0x00, 0x40, 0xE5, 0xCE, 0xFD, 0xE6, 0x92, 0x31, 0x57, 0xC3, 
+	0xEB, 0xBB, 0x66, 0xAC, 0xCB, 0x2F, 0x1A, 0xFA, 0xE0, 0x62, 
+	0xA2, 0x47, 0xF4, 0x93, 0x43, 0x2A, 0x4B, 0x6C, 0x5E, 0x0A, 
+	0x2F, 0xF9, 0xE7, 0xE6, 0x4A, 0x63, 0x86, 0xB0, 0xAC, 0x2A, 
+	0xA1, 0xEB, 0xB4, 0x5B, 0x67, 0xCD, 0x32, 0xE4, 0xB6, 0x11, 
+	0x4B, 0x9A, 0x72, 0x66, 0x0D, 0xA2, 0x4A, 0x76, 0x8F, 0xFE, 
+	0x22, 0xBC, 0x83, 0xFD, 0xDB, 0xB7, 0xD5, 0xA9, 0xEE, 0x05, 
+	0xC9, 0xB1, 0x71, 0x7E, 0x1B, 0x2B, 0xE1, 0xE3, 0xAF, 0xC0
+
+};
+const int sizeof_client_cert_der_2048 = sizeof(client_cert_der_2048) ;
+
+/* ./certs/dh2048.der, 2048-bit */
+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
+};
+const int sizeof_dh_key_der_2048 = sizeof(dh_key_der_2048) ;
+
+/* ./certs/dsa2048.der, 2048-bit */
+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
+};
+const int sizeof_dsa_key_der_2048 = sizeof(dsa_key_der_2048) ;
+
+/* ./certs/rsa2048.der, 2048-bit */
+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
+};
+const int sizeof_rsa_key_der_2048 = sizeof(rsa_key_der_2048) ;
+
+#endif /* USE_CERT_BUFFERS_1024 */
+
+#endif /* CYASSL_CERTS_TEST_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/crl.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,51 @@
+/* crl.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CYASSL_CRL_H
+#define CYASSL_CRL_H
+
+
+#ifdef HAVE_CRL
+
+#include <cyassl/ssl.h>
+#include <cyassl/ctaocrypt/asn.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+typedef struct CYASSL_CRL CYASSL_CRL;
+
+CYASSL_LOCAL int  InitCRL(CYASSL_CRL*, CYASSL_CERT_MANAGER*);
+CYASSL_LOCAL void FreeCRL(CYASSL_CRL*, int dynamic);
+
+CYASSL_LOCAL int  LoadCRL(CYASSL_CRL* crl, const char* path, int type, int mon);
+CYASSL_LOCAL int  BufferLoadCRL(CYASSL_CRL*, const byte*, long, int);
+CYASSL_LOCAL int  CheckCertCRL(CYASSL_CRL*, DecodedCert*);
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+#endif /* HAVE_CRL */
+#endif /* CYASSL_CRL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/aes.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,143 @@
+/* aes.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_AES
+
+#ifndef CTAO_CRYPT_AES_H
+#define CTAO_CRYPT_AES_H
+
+
+#include <cyassl/ctaocrypt/types.h>
+
+#ifdef HAVE_CAVIUM
+    #include <cyassl/ctaocrypt/logging.h>
+    #include "cavium_common.h"
+#endif
+
+#ifdef CYASSL_AESNI
+
+#include <wmmintrin.h>
+
+#if !defined (ALIGN16)
+    #if defined (__GNUC__)
+        #define ALIGN16 __attribute__ ( (aligned (16)))
+    #elif defined(_MSC_VER)
+        #define ALIGN16 __declspec (align (16))
+    #else
+        #define ALIGN16
+    #endif
+#endif
+
+#endif /* CYASSL_AESNI */
+
+#if !defined (ALIGN16)
+    #define ALIGN16
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#define CYASSL_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 CYASSL_AESNI
+    byte use_aesni;
+#endif /* CYASSL_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
+} Aes;
+
+
+CYASSL_API int  AesSetKey(Aes* aes, const byte* key, word32 len, const byte* iv,
+                          int dir);
+CYASSL_API int  AesSetIV(Aes* aes, const byte* iv);
+CYASSL_API int  AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz);
+CYASSL_API int  AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz);
+CYASSL_API void AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz);
+CYASSL_API void AesEncryptDirect(Aes* aes, byte* out, const byte* in);
+CYASSL_API void AesDecryptDirect(Aes* aes, byte* out, const byte* in);
+CYASSL_API int  AesSetKeyDirect(Aes* aes, const byte* key, word32 len,
+                                const byte* iv, int dir);
+#ifdef HAVE_AESGCM
+CYASSL_API void AesGcmSetKey(Aes* aes, const byte* key, word32 len);
+CYASSL_API void AesGcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz,
+                              const byte* iv, word32 ivSz,
+                              byte* authTag, word32 authTagSz,
+                              const byte* authIn, word32 authInSz);
+CYASSL_API int  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);
+#endif /* HAVE_AESGCM */
+#ifdef HAVE_AESCCM
+CYASSL_API void AesCcmSetKey(Aes* aes, const byte* key, word32 keySz);
+CYASSL_API void AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
+                              const byte* nonce, word32 nonceSz,
+                              byte* authTag, word32 authTagSz,
+                              const byte* authIn, word32 authInSz);
+CYASSL_API int  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
+    CYASSL_API int  AesInitCavium(Aes*, int);
+    CYASSL_API void AesFreeCavium(Aes*);
+#endif
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* CTAO_CRYPT_AES_H */
+#endif /* NO_AES */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/arc4.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,68 @@
+/* arc4.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_ARC4_H
+#define CTAO_CRYPT_ARC4_H
+
+
+#include <cyassl/ctaocrypt/types.h>
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#define CYASSL_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;
+
+CYASSL_API void Arc4Process(Arc4*, byte*, const byte*, word32);
+CYASSL_API void Arc4SetKey(Arc4*, const byte*, word32);
+
+#ifdef HAVE_CAVIUM
+    CYASSL_API int  Arc4InitCavium(Arc4*, int);
+    CYASSL_API void Arc4FreeCavium(Arc4*);
+#endif
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* CTAO_CRYPT_ARC4_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/asn.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,509 @@
+/* asn.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef NO_ASN
+
+#ifndef CTAO_CRYPT_ASN_H
+#define CTAO_CRYPT_ASN_H
+
+#include <cyassl/ctaocrypt/types.h>
+#include <cyassl/ctaocrypt/rsa.h>
+#include <cyassl/ctaocrypt/dh.h>
+#include <cyassl/ctaocrypt/dsa.h>
+#include <cyassl/ctaocrypt/sha.h>
+#include <cyassl/ctaocrypt/md5.h>
+#include <cyassl/ctaocrypt/asn_public.h>   /* public interface */
+#ifdef HAVE_ECC
+    #include <cyassl/ctaocrypt/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_SEQUENCE          = 0x10,
+    ASN_SET               = 0x11,
+    ASN_UTC_TIME          = 0x17,
+    ASN_DNS_TYPE          = 0x02,
+    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_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 */
+    SHA_SIZE            =  20,
+    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_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 CYASSL_CERT_GEN
+    #ifdef CYASSL_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
+};
+
+
+enum Hash_Sum  {
+    MD2h    = 646,
+    MD5h    = 649,
+    SHAh    =  88,
+    SHA256h = 414,
+    SHA384h = 415,
+    SHA512h = 416
+};
+
+
+enum Key_Sum {
+    DSAk   = 515,
+    RSAk   = 645,
+    NTRUk  = 364,
+    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
+};
+
+
+enum VerifyType {
+    NO_VERIFY = 0,
+    VERIFY    = 1
+};
+
+
+typedef struct DNS_entry   DNS_entry;
+
+struct DNS_entry {
+    DNS_entry* next;   /* next on DNS list */
+    char*      name;   /* actual DNS name */
+};
+
+typedef struct DecodedCert DecodedCert;
+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       */
+    DNS_entry* altNames;             /* alt names list of dns entries    */
+    byte    subjectHash[SHA_SIZE];   /* hash of all Names                */
+    byte    issuerHash[SHA_SIZE];    /* hash of all Names                */
+#ifdef HAVE_OCSP
+    byte    issuerKeyHash[SHA_SIZE]; /* hash of the public Key           */
+#endif /* HAVE_OCSP */
+    byte*   signature;               /* not owned, points into raw cert  */
+    char*   subjectCN;               /* CommonName                       */
+    int     subjectCNLen;
+    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[SHA_SIZE];  /* Subject Key ID                   */
+    byte    extSubjKeyIdSet;         /* Set when the SKID was read from cert */
+    byte    extAuthKeyId[SHA_SIZE];  /* Authority Key ID                 */
+    byte    extAuthKeyIdSet;         /* Set when the AKID was read from cert */
+    byte    isCA;                    /* CA basic constraint true */
+#ifdef CYASSL_CERT_GEN
+    /* easy access to subject info for other sign */
+    char*   subjectSN;
+    int     subjectSNLen;
+    char*   subjectC;
+    int     subjectCLen;
+    char*   subjectL;
+    int     subjectLLen;
+    char*   subjectST;
+    int     subjectSTLen;
+    char*   subjectO;
+    int     subjectOLen;
+    char*   subjectOU;
+    int     subjectOULen;
+    char*   subjectEmail;
+    int     subjectEmailLen;
+    byte*   beforeDate;
+    int     beforeDateLen;
+    byte*   afterDate;
+    int     afterDateLen;
+#endif /* CYASSL_CERT_GEN */
+};
+
+#ifdef SHA_DIGEST_SIZE
+    #define SIGNER_DIGEST_SIZE SHA_DIGEST_SIZE
+#else
+    #define SIGNER_DIGEST_SIZE 20 
+#endif
+
+/* CA Signers */
+/* if change layout change PERSIST_CERT_CACHE functions too */
+struct Signer {
+    word32  pubKeySize;
+    word32  keyOID;                  /* key type */
+    byte*   publicKey;
+    int     nameLen;
+    char*   name;                    /* common name */
+    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 CYASSL_TEST_CERT
+    #define CYASSL_TEST_API CYASSL_API
+#else
+    #define CYASSL_TEST_API CYASSL_LOCAL
+#endif
+
+CYASSL_TEST_API void FreeAltNames(DNS_entry*, void*);
+CYASSL_TEST_API void InitDecodedCert(DecodedCert*, byte*, word32, void*);
+CYASSL_TEST_API void FreeDecodedCert(DecodedCert*);
+CYASSL_TEST_API int  ParseCert(DecodedCert*, int type, int verify, void* cm);
+
+CYASSL_LOCAL int ParseCertRelative(DecodedCert*, int type, int verify,void* cm);
+CYASSL_LOCAL int DecodeToKey(DecodedCert*, int verify);
+
+CYASSL_LOCAL word32 EncodeSignature(byte* out, const byte* digest, word32 digSz,
+                                    int hashOID);
+
+CYASSL_LOCAL Signer* MakeSigner(void*);
+CYASSL_LOCAL void    FreeSigner(Signer*, void*);
+CYASSL_LOCAL void    FreeSignerTable(Signer**, int, void*);
+
+
+CYASSL_LOCAL int ToTraditional(byte* buffer, word32 length);
+CYASSL_LOCAL int ToTraditionalEnc(byte* buffer, word32 length,const char*, int);
+
+CYASSL_LOCAL int ValidateDate(const byte* date, byte format, int dateType);
+
+#ifdef HAVE_ECC
+    /* ASN sig helpers */
+    CYASSL_LOCAL int StoreECC_DSA_Sig(byte* out, word32* outLen, mp_int* r,
+                                      mp_int* s);
+    CYASSL_LOCAL int DecodeECC_DSA_Sig(const byte* sig, word32 sigLen,
+                                       mp_int* r, mp_int* s);
+    /* private key helpers */
+    CYASSL_LOCAL int EccPrivateKeyDecode(const byte* input,word32* inOutIdx,
+                                         ecc_key*,word32);
+#endif
+
+#ifdef CYASSL_CERT_GEN
+
+enum cert_enums {
+    NAME_ENTRIES    =  8,
+    JOINT_LEN       =  2,
+    EMAIL_JOINT_LEN =  9,
+    RSA_KEY         = 10,
+    NTRU_KEY        = 11
+};
+
+
+#endif /* CYASSL_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 */
+};
+
+
+CYASSL_LOCAL void InitOcspResponse(OcspResponse*, CertStatus*, byte*, word32);
+CYASSL_LOCAL int  OcspResponseDecode(OcspResponse*);
+
+CYASSL_LOCAL void InitOcspRequest(OcspRequest*, DecodedCert*,
+                                                          byte, byte*, word32);
+CYASSL_LOCAL int  EncodeOcspRequest(OcspRequest*);
+
+CYASSL_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[SHA_DIGEST_SIZE];  /* issuer hash                 */ 
+    byte    crlHash[SHA_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     */
+};
+
+CYASSL_LOCAL void InitDecodedCRL(DecodedCRL*);
+CYASSL_LOCAL int  ParseCRL(DecodedCRL*, const byte* buff, word32 sz, void* cm);
+CYASSL_LOCAL void FreeDecodedCRL(DecodedCRL*);
+
+
+#endif /* HAVE_CRL */
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_ASN_H */
+
+#endif /* !NO_ASN */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/asn_public.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,156 @@
+/* asn_public.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_ASN_PUBLIC_H
+#define CTAO_CRYPT_ASN_PUBLIC_H
+
+#include <cyassl/ctaocrypt/types.h>
+#ifdef CYASSL_CERT_GEN
+    #include <cyassl/ctaocrypt/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
+};
+
+
+/* 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
+};
+
+
+#ifdef CYASSL_CERT_GEN
+
+enum Ctc_Misc {
+    CTC_NAME_SIZE    =   64,
+    CTC_DATE_SIZE    =   32,
+    CTC_MAX_ALT_SIZE = 8192,    /* may be huge */
+    CTC_SERIAL_SIZE  =    8
+};
+
+typedef struct CertName {
+    char country[CTC_NAME_SIZE];
+    char state[CTC_NAME_SIZE];
+    char locality[CTC_NAME_SIZE];
+    char sur[CTC_NAME_SIZE];
+    char org[CTC_NAME_SIZE];
+    char unit[CTC_NAME_SIZE];
+    char commonName[CTC_NAME_SIZE];
+    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 CYASSL_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
+} Cert;
+
+
+
+
+/* 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)
+*/
+CYASSL_API void InitCert(Cert*);
+CYASSL_API int  MakeCert(Cert*, byte* derBuffer, word32 derSz, RsaKey*, RNG*);
+CYASSL_API int  SignCert(Cert*, byte* derBuffer, word32 derSz, RsaKey*, RNG*);
+CYASSL_API int  MakeSelfCert(Cert*, byte* derBuffer, word32 derSz, RsaKey*,
+                             RNG*);
+CYASSL_API int  SetIssuer(Cert*, const char*);
+CYASSL_API int  SetSubject(Cert*, const char*);
+#ifdef CYASSL_ALT_NAMES
+    CYASSL_API int  SetAltNames(Cert*, const char*);
+#endif
+CYASSL_API int  SetIssuerBuffer(Cert*, const byte*, int);
+CYASSL_API int  SetSubjectBuffer(Cert*, const byte*, int);
+CYASSL_API int  SetAltNamesBuffer(Cert*, const byte*, int);
+CYASSL_API int  SetDatesBuffer(Cert*, const byte*, int);
+
+    #ifdef HAVE_NTRU
+        CYASSL_API int  MakeNtruCert(Cert*, byte* derBuffer, word32 derSz,
+                                     const byte* ntruKey, word16 keySz, RNG*);
+    #endif
+
+#endif /* CYASSL_CERT_GEN */
+
+
+#if defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN)
+    CYASSL_API int DerToPem(const byte* der, word32 derSz, byte* output,
+                            word32 outputSz, int type);
+#endif
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_ASN_PUBLIC_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/blake2-impl.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,154 @@
+/*
+   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-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAOCRYPT_BLAKE2_IMPL_H
+#define CTAOCRYPT_BLAKE2_IMPL_H
+
+#include <cyassl/ctaocrypt/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  /* CTAOCRYPT_BLAKE2_IMPL_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/blake2-int.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,183 @@
+/*
+   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-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+#ifndef CTAOCRYPT_BLAKE2_INT_H
+#define CTAOCRYPT_BLAKE2_INT_H
+
+#include <cyassl/ctaocrypt/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  /* CTAOCRYPT_BLAKE2_INT_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/blake2.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,59 @@
+/* blake2.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef HAVE_BLAKE2
+
+#ifndef CTAOCRYPT_BLAKE2_H
+#define CTAOCRYPT_BLAKE2_H
+
+#include <cyassl/ctaocrypt/blake2-int.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* in bytes, variable digest size up to 512 bits (64 bytes) */
+enum {
+    BLAKE2B_ID = 7    /* hash type unique */
+};
+
+
+/* BLAKE2b digest */
+typedef struct Blake2b {
+    blake2b_state S[1];         /* our state */
+    word32        digestSz;     /* digest size used on init */
+} Blake2b;
+
+
+CYASSL_API int InitBlake2b(Blake2b*, word32);
+CYASSL_API int Blake2bUpdate(Blake2b*, const byte*, word32);
+CYASSL_API int Blake2bFinal(Blake2b*, byte*, word32);
+
+
+
+#ifdef __cplusplus
+    } 
+#endif
+
+#endif  /* CTAOCRYPT_BLAKE2_H */
+#endif  /* HAVE_BLAKE2 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/camellia.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,96 @@
+/* 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-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CAMELLIA
+
+#ifndef CTAO_CRYPT_CAMELLIA_H
+#define CTAO_CRYPT_CAMELLIA_H
+
+
+#include <cyassl/ctaocrypt/types.h>
+
+#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;
+
+
+CYASSL_API int  CamelliaSetKey(Camellia* cam,
+                                   const byte* key, word32 len, const byte* iv);
+CYASSL_API int  CamelliaSetIV(Camellia* cam, const byte* iv);
+CYASSL_API void CamelliaEncryptDirect(Camellia* cam, byte* out, const byte* in);
+CYASSL_API void CamelliaDecryptDirect(Camellia* cam, byte* out, const byte* in);
+CYASSL_API void CamelliaCbcEncrypt(Camellia* cam,
+                                          byte* out, const byte* in, word32 sz);
+CYASSL_API void CamelliaCbcDecrypt(Camellia* cam,
+                                          byte* out, const byte* in, word32 sz);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_AES_H */
+#endif /* HAVE_CAMELLIA */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/coding.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,51 @@
+/* coding.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_CODING_H
+#define CTAO_CRYPT_CODING_H
+
+#include <cyassl/ctaocrypt/types.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+/* decode needed by CyaSSL */
+CYASSL_LOCAL int Base64_Decode(const byte* in, word32 inLen, byte* out,
+                               word32* outLen);
+
+#if defined(OPENSSL_EXTRA) || defined(SESSION_CERTS) || defined(CYASSL_KEY_GEN)  || defined(CYASSL_CERT_GEN) || defined(HAVE_WEBSERVER)
+    /* encode isn't */
+    CYASSL_API
+    int Base64_Encode(const byte* in, word32 inLen, byte* out,
+                                  word32* outLen);
+    CYASSL_LOCAL 
+    int Base16_Decode(const byte* in, word32 inLen, byte* out, word32* outLen);
+#endif
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_CODING_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/compress.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,52 @@
+/* compress.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef HAVE_LIBZ
+
+#ifndef CTAO_CRYPT_COMPRESS_H
+#define CTAO_CRYPT_COMPRESS_H
+
+
+#include <cyassl/ctaocrypt/types.h>
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#define COMPRESS_FIXED 1
+
+
+CYASSL_API int Compress(byte*, word32, const byte*, word32, word32);
+CYASSL_API int DeCompress(byte*, word32, const byte*, word32);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* CTAO_CRYPT_COMPRESS_H */
+
+#endif /* HAVE_LIBZ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/ctaoerror2.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,129 @@
+/* error.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_ERROR_H
+#define CTAO_CRYPT_ERROR_H
+
+#include <cyassl/ctaocrypt/types.h>
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+/* error codes */
+enum {
+    MAX_ERROR_SZ       =  80,   /* max size of error string */
+    MAX_CODE_E         = -100,  /* errors -101 - -199 */
+    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 */
+
+    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 */
+
+    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 */
+
+    MIN_CODE_E         = -200   /* errors -101 - -199 */
+};
+
+
+CYASSL_API void CTaoCryptErrorString(int err, char* buff);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_ERROR_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/des3.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,101 @@
+/* des3.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_DES3
+
+#ifndef CTAO_CRYPT_DES3_H
+#define CTAO_CRYPT_DES3_H
+
+
+#include <cyassl/ctaocrypt/types.h>
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#define CYASSL_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
+};
+
+#ifdef STM32F2_CRYPTO
+enum {
+    DES_CBC = 0,
+    DES_ECB = 1
+};
+#endif
+
+
+/* DES encryption and decryption */
+typedef struct Des {
+    word32 key[DES_KS_SIZE];
+    word32 reg[DES_BLOCK_SIZE / sizeof(word32)];      /* for CBC mode */
+    word32 tmp[DES_BLOCK_SIZE / sizeof(word32)];      /* same         */
+} 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;
+
+
+CYASSL_API void Des_SetKey(Des* des, const byte* key, const byte* iv, int dir);
+CYASSL_API void Des_SetIV(Des* des, const byte* iv);
+CYASSL_API void Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz);
+CYASSL_API void Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz);
+CYASSL_API void Des_EcbEncrypt(Des* des, byte* out, const byte* in, word32 sz);
+
+CYASSL_API void Des3_SetKey(Des3* des, const byte* key, const byte* iv,int dir);
+CYASSL_API void Des3_SetIV(Des3* des, const byte* iv);
+CYASSL_API void Des3_CbcEncrypt(Des3* des, byte* out, const byte* in,word32 sz);
+CYASSL_API void Des3_CbcDecrypt(Des3* des, byte* out, const byte* in,word32 sz);
+
+
+#ifdef HAVE_CAVIUM
+    CYASSL_API int  Des3_InitCavium(Des3*, int);
+    CYASSL_API void Des3_FreeCavium(Des3*);
+#endif
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* NO_DES3 */
+#endif /* CTAO_CRYPT_DES3_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/dh.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,67 @@
+/* dh.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_DH
+
+#ifndef CTAO_CRYPT_DH_H
+#define CTAO_CRYPT_DH_H
+
+#include <cyassl/ctaocrypt/types.h>
+#include <cyassl/ctaocrypt/integer.h>
+#include <cyassl/ctaocrypt/random.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+/* Diffie-Hellman Key */
+typedef struct DhKey {
+    mp_int p, g;                            /* group parameters  */
+} DhKey;
+
+
+CYASSL_API void InitDhKey(DhKey* key);
+CYASSL_API void FreeDhKey(DhKey* key);
+
+CYASSL_API int DhGenerateKeyPair(DhKey* key, RNG* rng, byte* priv,
+                                 word32* privSz, byte* pub, word32* pubSz);
+CYASSL_API int DhAgree(DhKey* key, byte* agree, word32* agreeSz,
+                       const byte* priv, word32 privSz, const byte* otherPub,
+                       word32 pubSz);
+
+CYASSL_API int DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key,
+                           word32);
+CYASSL_API int DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
+                        word32 gSz);
+CYASSL_API int DhParamsLoad(const byte* input, word32 inSz, byte* p,
+                            word32* pInOutSz, byte* g, word32* gInOutSz);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_DH_H */
+
+#endif /* NO_DH */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/dsa.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,67 @@
+/* dsa.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_DSA
+
+#ifndef CTAO_CRYPT_DSA_H
+#define CTAO_CRYPT_DSA_H
+
+#include <cyassl/ctaocrypt/types.h>
+#include <cyassl/ctaocrypt/integer.h>
+#include <cyassl/ctaocrypt/random.h>
+
+#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;
+
+
+CYASSL_API void InitDsaKey(DsaKey* key);
+CYASSL_API void FreeDsaKey(DsaKey* key);
+
+CYASSL_API int DsaSign(const byte* digest, byte* out, DsaKey* key, RNG* rng);
+CYASSL_API int DsaVerify(const byte* digest, const byte* sig, DsaKey* key,
+                         int* answer);
+
+CYASSL_API int DsaPublicKeyDecode(const byte* input, word32* inOutIdx, DsaKey*,
+                                  word32);
+CYASSL_API int DsaPrivateKeyDecode(const byte* input, word32* inOutIdx, DsaKey*,
+                                   word32);
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_DSA_H */
+#endif /* NO_DSA */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/ecc.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,129 @@
+/* ecc.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_ECC
+
+#ifndef CTAO_CRYPT_ECC_H
+#define CTAO_CRYPT_ECC_H
+
+#include <cyassl/ctaocrypt/types.h>
+#include <cyassl/ctaocrypt/integer.h>
+#include <cyassl/ctaocrypt/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* B;        /* 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;
+
+
+/* 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 {
+    mp_int x;        /* The x coordinate */
+    mp_int y;        /* The y coordinate */
+    mp_int z;        /* The z coordinate */
+} 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[];
+
+
+CYASSL_API
+int ecc_make_key(RNG* rng, int keysize, ecc_key* key);
+CYASSL_API
+int ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out,
+                      word32* outlen);
+CYASSL_API
+int ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, 
+                  RNG* rng, ecc_key* key);
+CYASSL_API
+int ecc_verify_hash(const byte* sig, word32 siglen, byte* hash, word32 hashlen, 
+                    int* stat, ecc_key* key);
+CYASSL_API
+void ecc_init(ecc_key* key);
+CYASSL_API
+void ecc_free(ecc_key* key);
+
+
+/* ASN key helpers */
+CYASSL_API
+int ecc_export_x963(ecc_key*, byte* out, word32* outLen);
+CYASSL_API
+int ecc_import_x963(const byte* in, word32 inLen, ecc_key* key);
+CYASSL_API
+int ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub,
+                           word32 pubSz, ecc_key* key);
+
+/* size helper */
+CYASSL_API
+int ecc_size(ecc_key* key);
+CYASSL_API
+int ecc_sig_size(ecc_key* key);
+
+/* TODO: fix mutex types */
+#define MUTEX_GLOBAL(x) int (x);
+#define MUTEX_LOCK(x)
+#define MUTEX_UNLOCK(x)
+
+
+
+#ifdef __cplusplus
+    }    /* extern "C" */    
+#endif
+
+#endif /* CTAO_CRYPT_ECC_H */
+#endif /* HAVE_ECC */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/hc128.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,60 @@
+/* hc128.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_HC128
+
+#ifndef CTAO_CRYPT_HC128_H
+#define CTAO_CRYPT_HC128_H
+
+#include <cyassl/ctaocrypt/types.h>
+
+#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;
+
+
+CYASSL_API int Hc128_Process(HC128*, byte*, const byte*, word32);
+CYASSL_API int Hc128_SetKey(HC128*, const byte* key, const byte* iv);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_HC128_H */
+
+#endif /* HAVE_HC128 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/hmac.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,158 @@
+/* hmac.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_HMAC
+
+#ifndef CTAO_CRYPT_HMAC_H
+#define CTAO_CRYPT_HMAC_H
+
+#include <cyassl/ctaocrypt/types.h>
+
+#ifndef NO_MD5
+    #include <cyassl/ctaocrypt/md5.h>
+#endif
+
+#ifndef NO_SHA
+    #include <cyassl/ctaocrypt/sha.h>
+#endif
+
+#ifndef NO_SHA256
+    #include <cyassl/ctaocrypt/sha256.h>
+#endif
+
+#ifdef CYASSL_SHA512
+    #include <cyassl/ctaocrypt/sha512.h>
+#endif
+
+#ifdef HAVE_CAVIUM
+    #include <cyassl/ctaocrypt/logging.h>
+    #include "cavium_common.h"
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#define CYASSL_HMAC_CAVIUM_MAGIC 0xBEEF0005
+
+enum {
+    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 CYASSL_SHA512
+    SHA512  = 4,
+#endif
+#ifndef CYASSL_SHA384
+    SHA384  = 5,
+#endif
+
+/* Select the largest available hash for the buffer size. */
+#if defined(CYASSL_SHA512)
+    INNER_HASH_SIZE = SHA512_DIGEST_SIZE,
+    HMAC_BLOCK_SIZE = SHA512_BLOCK_SIZE
+#elif defined(CYASSL_SHA384)
+    INNER_HASH_SIZE = SHA384_DIGEST_SIZE,
+    HMAC_BLOCK_SIZE = SHA384_BLOCK_SIZE
+#elif !defined(NO_SHA256)
+    INNER_HASH_SIZE = SHA256_DIGEST_SIZE,
+    HMAC_BLOCK_SIZE = SHA256_BLOCK_SIZE
+#elif !defined(NO_SHA)
+    INNER_HASH_SIZE = SHA_DIGEST_SIZE,
+    HMAC_BLOCK_SIZE = SHA_BLOCK_SIZE
+#elif !defined(NO_MD5)
+    INNER_HASH_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 CYASSL_SHA384
+        Sha384 sha384;
+    #endif
+    #ifdef CYASSL_SHA512
+        Sha512 sha512;
+    #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[INNER_HASH_SIZE / sizeof(word32)]; /* max size */
+    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;
+
+
+/* does init */
+CYASSL_API void HmacSetKey(Hmac*, int type, const byte* key, word32 keySz);
+CYASSL_API void HmacUpdate(Hmac*, const byte*, word32);
+CYASSL_API void HmacFinal(Hmac*, byte*);
+
+#ifdef HAVE_CAVIUM
+    CYASSL_API int  HmacInitCavium(Hmac*, int);
+    CYASSL_API void HmacFreeCavium(Hmac*);
+#endif
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_HMAC_H */
+
+#endif /* NO_HMAC */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/integer.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,318 @@
+/* integer.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/*
+ * Based on public domain LibTomMath 0.38 by Tom St Denis, tomstdenis@iahu.ca,
+ * http://math.libtomcrypt.com
+ */
+
+
+#ifndef CTAO_CRYPT_INTEGER_H
+#define CTAO_CRYPT_INTEGER_H
+
+/* may optionally use fast math instead, not yet supported on all platforms and
+   may not be faster on all
+*/
+#include <cyassl/ctaocrypt/types.h>       /* will set MP_xxBIT if not default */
+#ifdef USE_FAST_MATH
+    #include <cyassl/ctaocrypt/tfm.h>
+#else
+
+#ifndef CHAR_BIT
+    #include <limits.h>
+#endif
+
+#include <cyassl/ctaocrypt/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
+
+/* 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_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);
+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);
+/* 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(CYASSL_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 CYASSL_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
+
+#if defined(HAVE_ECC) || !defined(NO_PWDBASED)
+    int mp_sub_d (mp_int * a, mp_digit b, mp_int * c);
+#endif
+
+#ifdef __cplusplus
+   }
+#endif
+
+
+#endif /* USE_FAST_MATH */
+
+#endif  /* CTAO_CRYPT_INTEGER_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/logging.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,70 @@
+/* logging.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/* submitted by eof */
+
+
+#ifndef CYASSL_LOGGING_H
+#define CYASSL_LOGGING_H
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+enum  CYA_Log_Levels {
+    ERROR_LOG = 0,
+    INFO_LOG,
+    ENTER_LOG,
+    LEAVE_LOG,
+    OTHER_LOG
+};
+
+typedef void (*CyaSSL_Logging_cb)(const int logLevel,
+                                  const char *const logMessage);
+
+CYASSL_API int CyaSSL_SetLoggingCb(CyaSSL_Logging_cb log_function);
+
+
+#ifdef DEBUG_CYASSL
+
+    void CYASSL_ENTER(const char* msg);
+    void CYASSL_LEAVE(const char* msg, int ret);
+
+    void CYASSL_ERROR(int);
+    void CYASSL_MSG(const char* msg);
+
+#else /* DEBUG_CYASSL   */
+
+    #define CYASSL_ENTER(m)
+    #define CYASSL_LEAVE(m, r)
+
+    #define CYASSL_ERROR(e) 
+    #define CYASSL_MSG(m)
+
+#endif /* DEBUG_CYASSL  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CYASSL_MEMORY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/md2.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,64 @@
+/* md2.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef CYASSL_MD2
+
+#ifndef CTAO_CRYPT_MD2_H
+#define CTAO_CRYPT_MD2_H
+
+#include <cyassl/ctaocrypt/types.h>
+
+#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;
+
+
+CYASSL_API void InitMd2(Md2*);
+CYASSL_API void Md2Update(Md2*, const byte*, word32);
+CYASSL_API void Md2Final(Md2*, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_MD2_H */
+#endif /* CYASSL_MD2 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/md4.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,65 @@
+/* md4.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_MD4
+
+#ifndef CTAO_CRYPT_MD4_H
+#define CTAO_CRYPT_MD4_H
+
+#include <cyassl/ctaocrypt/types.h>
+
+#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;
+
+
+CYASSL_API void InitMd4(Md4*);
+CYASSL_API void Md4Update(Md4*, const byte*, word32);
+CYASSL_API void Md4Final(Md4*, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_MD4_H */
+
+#endif /* NO_MD4 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/md5.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,66 @@
+/* md5.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef NO_MD5
+
+#ifndef CTAO_CRYPT_MD5_H
+#define CTAO_CRYPT_MD5_H
+
+#include <cyassl/ctaocrypt/types.h>
+
+#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
+};
+
+
+/* MD5 digest */
+typedef struct Md5 {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word32  digest[MD5_DIGEST_SIZE / sizeof(word32)];
+    word32  buffer[MD5_BLOCK_SIZE  / sizeof(word32)];
+} Md5;
+
+
+CYASSL_API void InitMd5(Md5*);
+CYASSL_API void Md5Update(Md5*, const byte*, word32);
+CYASSL_API void Md5Final(Md5*, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_MD5_H */
+#endif /* NO_MD5 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/memory.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,55 @@
+/* memory.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/* submitted by eof */
+
+
+#ifndef CYASSL_MEMORY_H
+#define CYASSL_MEMORY_H
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+typedef void *(*CyaSSL_Malloc_cb)(size_t size);
+typedef void (*CyaSSL_Free_cb)(void *ptr);
+typedef void *(*CyaSSL_Realloc_cb)(void *ptr, size_t size);
+
+
+/* Public set function */
+CYASSL_API int CyaSSL_SetAllocators(CyaSSL_Malloc_cb  malloc_function,
+                                    CyaSSL_Free_cb    free_function,
+                                    CyaSSL_Realloc_cb realloc_function);
+
+/* Public in case user app wants to use XMALLOC/XFREE */
+CYASSL_API void* CyaSSL_Malloc(size_t size);
+CYASSL_API void  CyaSSL_Free(void *ptr);
+CYASSL_API void* CyaSSL_Realloc(void *ptr, size_t size);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CYASSL_MEMORY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/misc.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,74 @@
+/* misc.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_MISC_H
+#define CTAO_CRYPT_MISC_H
+
+
+#include <cyassl/ctaocrypt/types.h>
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#ifdef NO_INLINE
+CYASSL_LOCAL
+word32 rotlFixed(word32, word32);
+CYASSL_LOCAL
+word32 rotrFixed(word32, word32);
+
+CYASSL_LOCAL
+word32 ByteReverseWord32(word32);
+CYASSL_LOCAL
+void   ByteReverseWords(word32*, const word32*, word32);
+CYASSL_LOCAL
+void   ByteReverseBytes(byte*, const byte*, word32);
+
+CYASSL_LOCAL
+void XorWords(word*, const word*, word32);
+CYASSL_LOCAL
+void xorbuf(byte*, const byte*, word32);
+
+#ifdef WORD64_AVAILABLE
+CYASSL_LOCAL
+word64 rotlFixed64(word64, word64);
+CYASSL_LOCAL
+word64 rotrFixed64(word64, word64);
+
+CYASSL_LOCAL
+word64 ByteReverseWord64(word64);
+CYASSL_LOCAL
+void   ByteReverseWords64(word64*, const word64*, word32);
+#endif /* WORD64_AVAILABLE */
+
+#endif /* NO_INLINE */
+
+
+#ifdef __cplusplus
+    }   /* extern "C" */
+#endif
+
+
+#endif /* CTAO_CRYPT_MISC_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/mpi_class.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,1018 @@
+/* mpi_class.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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/cyassl/ctaocrypt/mpi_superclass.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,95 @@
+/* mpi_superclass.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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/cyassl/ctaocrypt/pwdbased.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,53 @@
+/* pwdbased.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_PWDBASED
+
+#ifndef CTAO_CRYPT_PWDBASED_H
+#define CTAO_CRYPT_PWDBASED_H
+
+#include <cyassl/ctaocrypt/types.h>
+#include <cyassl/ctaocrypt/md5.h>       /* for hash type */
+#include <cyassl/ctaocrypt/sha.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+CYASSL_API int PBKDF1(byte* output, const byte* passwd, int pLen,
+                      const byte* salt, int sLen, int iterations, int kLen,
+                      int hashType);
+CYASSL_API int PBKDF2(byte* output, const byte* passwd, int pLen,
+                      const byte* salt, int sLen, int iterations, int kLen,
+                      int hashType);
+CYASSL_API int PKCS12_PBKDF(byte* output, const byte* passwd, int pLen,
+                            const byte* salt, int sLen, int iterations,
+                            int kLen, int hashType, int purpose);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_PWDBASED_H */
+#endif /* NO_PWDBASED */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/rabbit.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,65 @@
+/* rabbit.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_RABBIT
+
+#ifndef CTAO_CRYPT_RABBIT_H
+#define CTAO_CRYPT_RABBIT_H
+
+#include <cyassl/ctaocrypt/types.h>
+
+#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;
+
+
+CYASSL_API int RabbitProcess(Rabbit*, byte*, const byte*, word32);
+CYASSL_API int RabbitSetKey(Rabbit*, const byte* key, const byte* iv);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_RABBIT_H */
+
+#endif /* NO_RABBIT */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/random.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,119 @@
+/* random.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_RANDOM_H
+#define CTAO_CRYPT_RANDOM_H
+
+#include <cyassl/ctaocrypt/types.h>
+
+#ifndef NO_RC4
+    #include <cyassl/ctaocrypt/arc4.h>
+#else
+    #include <cyassl/ctaocrypt/sha256.h>
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#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;
+
+
+CYASSL_LOCAL
+int GenerateSeed(OS_Seed* os, byte* seed, word32 sz);
+
+#if defined(CYASSL_MDK_ARM)
+#undef RNG
+#define RNG CyaSSL_RNG   /* for avoiding name conflict in "stm32f2xx.h" */
+#endif
+
+#ifndef NO_RC4
+
+#define CYASSL_RNG_CAVIUM_MAGIC 0xBEEF0004
+
+/* secure Random Nnumber Generator */
+
+
+typedef struct RNG {
+    OS_Seed seed;
+    Arc4    cipher;
+#ifdef HAVE_CAVIUM
+    int    devId;           /* nitrox device id */
+    word32 magic;           /* using cavium magic */
+#endif
+} RNG;
+
+
+#ifdef HAVE_CAVIUM
+    CYASSL_API int  InitRngCavium(RNG*, int);
+#endif
+
+#else /* NO_RC4 */
+
+#define DBRG_SEED_LEN (440/8)
+
+
+/* secure Random Nnumber Generator */
+typedef struct RNG {
+    OS_Seed seed;
+
+    Sha256 sha;
+    byte digest[SHA256_DIGEST_SIZE];
+    byte V[DBRG_SEED_LEN];
+    byte C[DBRG_SEED_LEN];
+    word64 reseed_ctr;
+} RNG;
+
+#endif
+
+CYASSL_API int  InitRng(RNG*);
+CYASSL_API void RNG_GenerateBlock(RNG*, byte*, word32 sz);
+CYASSL_API byte RNG_GenerateByte(RNG*);
+
+#ifdef NO_RC4
+    CYASSL_API void FreeRng(RNG*);
+#endif
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_RANDOM_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/ripemd.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,64 @@
+/* ripemd.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef CYASSL_RIPEMD
+
+#ifndef CTAO_CRYPT_RIPEMD_H
+#define CTAO_CRYPT_RIPEME_H
+
+#include <cyassl/ctaocrypt/types.h>
+
+#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;
+
+
+CYASSL_API void InitRipeMd(RipeMd*);
+CYASSL_API void RipeMdUpdate(RipeMd*, const byte*, word32);
+CYASSL_API void RipeMdFinal(RipeMd*, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_RIPEMD_H */
+#endif /* CYASSL_RIPEMD */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/rsa.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,102 @@
+/* rsa.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef NO_RSA
+
+#ifndef CTAO_CRYPT_RSA_H
+#define CTAO_CRYPT_RSA_H
+
+#include <cyassl/ctaocrypt/types.h>
+#include <cyassl/ctaocrypt/integer.h>
+#include <cyassl/ctaocrypt/random.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#define CYASSL_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;
+
+
+CYASSL_API void InitRsaKey(RsaKey* key, void*);
+CYASSL_API void FreeRsaKey(RsaKey* key);
+
+CYASSL_API int  RsaPublicEncrypt(const byte* in, word32 inLen, byte* out,
+                                 word32 outLen, RsaKey* key, RNG* rng);
+CYASSL_API int  RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out,
+                                        RsaKey* key);
+CYASSL_API int  RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out,
+                                  word32 outLen, RsaKey* key);
+CYASSL_API int  RsaSSL_Sign(const byte* in, word32 inLen, byte* out,
+                            word32 outLen, RsaKey* key, RNG* rng);
+CYASSL_API int  RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out,
+                                    RsaKey* key);
+CYASSL_API int  RsaSSL_Verify(const byte* in, word32 inLen, byte* out,
+                              word32 outLen, RsaKey* key);
+CYASSL_API int  RsaEncryptSize(RsaKey* key);
+
+CYASSL_API int RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey*,
+                                   word32);
+CYASSL_API int RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey*,
+                                  word32);
+#ifdef CYASSL_KEY_GEN
+    CYASSL_API int MakeRsaKey(RsaKey* key, int size, long e, RNG* rng);
+    CYASSL_API int RsaKeyToDer(RsaKey*, byte* output, word32 inLen);
+#endif
+
+#ifdef HAVE_CAVIUM
+    CYASSL_API int  RsaInitCavium(RsaKey*, int);
+    CYASSL_API void RsaFreeCavium(RsaKey*);
+#endif
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_RSA_H */
+
+#endif /* NO_RSA */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/settings.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,545 @@
+/* settings.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/* Place OS specific preprocessor flags, defines, includes here, will be
+   included into every file because types.h includes it */
+
+
+#ifndef CTAO_CRYPT_SETTINGS_H
+#define CTAO_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 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 CYASSL_LWIP
+
+/* Uncomment next line if building CyaSSL for a game console */
+/* #define CYASSL_GAME_BUILD */
+
+/* Uncomment next line if building CyaSSL for LSR */
+/* #define CYASSL_LSR */
+
+/* Uncomment next line if building CyaSSL for Freescale MQX/RTCS/MFS */
+/* #define FREESCALE_MQX */
+
+/* Uncomment next line if using STM32F2 */
+/* #define CYASSL_STM32F2 */
+
+
+#include <cyassl/ctaocrypt/visibility.h>
+
+#ifdef IPHONE
+    #define SIZEOF_LONG_LONG 8
+#endif
+
+#ifdef THREADX 
+    #define SIZEOF_LONG_LONG 8
+#endif
+
+#ifdef MICROCHIP_PIC32
+    #define SIZEOF_LONG_LONG 8
+    #define SINGLE_THREADED
+    #define CYASSL_USER_IO
+    #define NO_WRITEV
+    #define NO_DEV_RANDOM
+    #define NO_FILESYSTEM
+    #define USE_FAST_MATH
+    #define TFM_TIMING_RESISTANT
+#endif
+
+#ifdef MICROCHIP_TCPIP_V5
+    /* include timer functions */
+    #include "TCPIP Stack/TCPIP.h"
+#endif
+
+#ifdef MICROCHIP_TCPIP
+    /* include timer, NTP functions */
+    #include "system/system_services.h"
+    #include "tcpip/sntp.h"
+#endif
+
+#ifdef MBED
+    #define SINGLE_THREADED
+    //#define CYASSL_USER_IO
+    #define NO_WRITEV
+    #define NO_DEV_RANDOM // write an OS-specific GenerateSeed() function (found in “ctaocrypt/src/random.c”).
+    #define NO_SHA512
+    //#define NO_DH
+    #define NO_DSA
+    #define NO_HC128
+    #define NO_FILESYSTEM
+    #define DEBUG_CYASSL
+    //#define NO_CERTS
+    #define SSL_CFG_PSK_EN
+    #define CYASSL_DTLS
+    #define SSL_CFG_DTLS_EN
+    #define NO_DES3 // 3 des is being phased out
+    #define NO_MD4 // MD4 is broken and shouldn't be used
+    #define SMALL_SESSION_CACHE
+    //#define CYASSL_CALLBACKS
+    //#define USER_TIME
+    //#define USE_FAST_MATH // assembler implementation of bigInt routines
+    //#define TFM_TIMING_RESISTANT // uses less memory when fast math is enabled
+#endif /* MBED */
+
+#ifdef FREERTOS_WINSIM
+    #define FREERTOS
+    #define USE_WINDOWS_API
+#endif
+
+
+#if defined(CYASSL_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 NO_SHA512
+        #define NO_SHA512
+    #endif
+    #ifndef NO_DH
+        #define NO_DH
+    #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 EBSNET
+    #include "rtip.h"
+
+    /* #define DEBUG_CYASSL */
+    #define NO_CYASSL_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 CYASSL_GAME_BUILD
+    #define SIZEOF_LONG_LONG 8
+    #if defined(__PPU) || defined(__XENON)
+        #define BIG_ENDIAN_ORDER
+    #endif
+#endif
+
+#ifdef CYASSL_LSR
+    #define HAVE_WEBSERVER
+    #define SIZEOF_LONG_LONG 8
+    #define CYASSL_LOW_MEMORY
+    #define NO_WRITEV
+    #define NO_SHA512
+    #define NO_DH
+    #define NO_DSA
+    #define NO_HC128
+    #define NO_DEV_RANDOM
+    #define NO_CYASSL_DIR
+    #define NO_RABBIT
+    #ifndef NO_FILESYSTEM
+        #define LSR_FS
+        #include "inc/hw_types.h"
+        #include "fs.h"
+    #endif
+    #define CYASSL_LWIP
+    #include <errno.h>  /* for tcp errno */
+    #define CYASSL_SAFERTOS
+    #if defined(__IAR_SYSTEMS_ICC__)
+        /* enum uses enum */
+        #pragma diag_suppress=Pa089
+    #endif
+#endif
+
+#ifdef CYASSL_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 CYASSL_LOW_MEMORY
+    #undef  RSA_LOW_MEM
+    #define RSA_LOW_MEM
+    #undef  CYASSL_SMALL_STACK
+    #define CYASSL_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_CYASSL_DIR
+    #define USE_FAST_MATH
+    #define TFM_TIMING_RESISTANT
+    #define FREESCALE_K70_RNGA
+    #ifndef NO_FILESYSTEM
+        #include "mfs.h"
+        #include "fio.h"
+    #endif
+    #ifndef SINGLE_THREADED
+        #include "mutex.h"
+    #endif
+
+    #define XMALLOC(s, h, type) (void *)_mem_alloc_system((s))
+    #define XFREE(p, h, type)   _mem_free(p)
+    /* Note: MQX has no realloc, using fastmath above */
+#endif
+
+#ifdef CYASSL_STM32F2
+    #define SIZEOF_LONG_LONG 8
+    #define NO_DEV_RANDOM
+    #define NO_CYASSL_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 CYASSL_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 == CYASSL_TRACE_LEVEL_DBG)
+        #define DEBUG_CYASSL
+    #else
+        #undef  DEBUG_CYASSL
+    #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 CYASSL_USER_IO   
+    #else
+        #undef  CYASSL_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  CYASSL_DER_LOAD
+    #else
+        #undef   CYASSL_DER_LOAD
+    #endif
+
+    #if (SSL_CFG_DTLS_EN == DEF_ENABLED)
+        #define  CYASSL_DTLS
+    #else
+        #undef   CYASSL_DTLS
+    #endif
+
+    #if (SSL_CFG_CALLBACKS_EN == DEF_ENABLED)
+         #define CYASSL_CALLBACKS
+    #else
+         #undef  CYASSL_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 */
+
+
+#if !defined(XMALLOC_USER) && !defined(MICRIUM_MALLOC) && \
+    !defined(CYASSL_LEANPSK) && !defined(NO_CYASSL_MEMORY)
+    #define USE_CYASSL_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_ALIGNMENT
+    #if defined(__x86_64__) || defined(__ia64__) || defined(__i386__)
+        #define NO_XSTREAM_ALIGNMENT
+    #else
+        #define XSTREAM_ALIGNMENT
+    #endif
+#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 CYASSL_GENERAL_ALIGNMENT
+    #ifdef CYASSL_AESNI
+        #define CYASSL_GENERAL_ALIGNMENT 16
+    #elif defined(XSTREAM_ALIGNMENT)
+        #define CYASSL_GENERAL_ALIGNMENT  4
+    #else 
+        #define CYASSL_GENERAL_ALIGNMENT  0 
+    #endif
+#endif
+
+#ifdef HAVE_CRL
+    /* not widely supported yet */
+    #undef NO_SKID
+    #define NO_SKID
+#endif
+
+/* Place any other flags or defines here */
+
+
+#ifdef __cplusplus
+    }   /* extern "C" */
+#endif
+
+
+#endif /* CTAO_CRYPT_SETTINGS_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/sha.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,68 @@
+/* sha.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef NO_SHA
+
+#ifndef CTAO_CRYPT_SHA_H
+#define CTAO_CRYPT_SHA_H
+
+#include <cyassl/ctaocrypt/types.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+/* 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
+};
+
+
+/* Sha digest */
+typedef struct Sha {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word32  digest[SHA_DIGEST_SIZE / sizeof(word32)];
+    word32  buffer[SHA_BLOCK_SIZE  / sizeof(word32)];
+} Sha;
+
+
+CYASSL_API void InitSha(Sha*);
+CYASSL_API void ShaUpdate(Sha*, const byte*, word32);
+CYASSL_API void ShaFinal(Sha*, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_SHA_H */
+#endif /* NO_SHA */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/sha256.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,68 @@
+/* sha256.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/* code submitted by raphael.huck@efixo.com */
+
+
+#ifndef NO_SHA256
+
+#ifndef CTAO_CRYPT_SHA256_H
+#define CTAO_CRYPT_SHA256_H
+
+#include <cyassl/ctaocrypt/types.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+/* in bytes */
+enum {
+    SHA256              =  2,   /* hash type unique */
+    SHA256_BLOCK_SIZE   = 64,
+    SHA256_DIGEST_SIZE  = 32,
+    SHA256_PAD_SIZE     = 56
+};
+
+
+/* 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)];
+} Sha256;
+
+
+CYASSL_API void InitSha256(Sha256*);
+CYASSL_API void Sha256Update(Sha256*, const byte*, word32);
+CYASSL_API void Sha256Final(Sha256*, byte*);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_SHA256_H */
+#endif /* NO_SHA256 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/sha512.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,91 @@
+/* sha512.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef CYASSL_SHA512
+
+#ifndef CTAO_CRYPT_SHA512_H
+#define CTAO_CRYPT_SHA512_H
+
+#include <cyassl/ctaocrypt/types.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+/* 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;
+
+
+CYASSL_API void InitSha512(Sha512*);
+CYASSL_API void Sha512Update(Sha512*, const byte*, word32);
+CYASSL_API void Sha512Final(Sha512*, byte*);
+
+
+#if defined(CYASSL_SHA384) || defined(HAVE_AESGCM)
+
+/* 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;
+
+
+CYASSL_API void InitSha384(Sha384*);
+CYASSL_API void Sha384Update(Sha384*, const byte*, word32);
+CYASSL_API void Sha384Final(Sha384*, byte*);
+
+#endif /* CYASSL_SHA384 */
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_SHA512_H */
+#endif /* CYASSL_SHA512 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/tfm.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,688 @@
+/* tfm.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 CTAO_CRYPT_TFM_H
+#define CTAO_CRYPT_TFM_H
+
+#include <cyassl/ctaocrypt/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
+#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;
+   #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 {
+    fp_digit dp[FP_SIZE];
+    int      used, 
+             sign;
+} 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_SMALL_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_SMALL_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 */
+#define fp_init(a)  (void)XMEMSET((a), 0, sizeof(fp_int))
+#define fp_zero(a)  fp_init(a)
+
+/* 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 */
+#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)
+
+/* 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);
+
+/* 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_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 CyaSSL 
+ */
+
+/* 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_OKAY FP_OKAY /* ok result    */
+    #define MP_NO   FP_NO   /* yes/no result */
+    #define MP_YES  FP_YES  /* yes/no result */
+
+/* Prototypes */
+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_set_int(fp_int *a, fp_digit b);
+
+#ifdef HAVE_ECC
+    int mp_read_radix(mp_int* a, const char* str, int radix);
+    int 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(CYASSL_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 CYASSL_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 /* CYASSL_KEY_GEN */
+
+CYASSL_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  /* CTAO_CRYPT_TFM_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/types.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,295 @@
+/* types.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CTAO_CRYPT_TYPES_H
+#define CTAO_CRYPT_TYPES_H
+
+#include <cyassl/ctaocrypt/settings.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 CYASSL_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 word;
+#else
+    typedef word32 word;
+    #ifdef WORD64_AVAILABLE
+        #define CTAOCRYPT_SLOW_WORD64
+    #endif
+#endif
+
+
+enum {
+    CYASSL_WORD_SIZE  = sizeof(word),
+    CYASSL_BIT_SIZE   = 8,
+    CYASSL_WORD_BITS  = CYASSL_WORD_SIZE * CYASSL_BIT_SIZE
+};
+
+#define CYASSL_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
+
+
+/* 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_CYASSL_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(CYASSL_SAFERTOS) && !defined(FREESCALE_MQX) \
+        && !defined(CYASSL_LEANPSK)
+    /* default C runtime, can install different routines at runtime via cbs */
+    #include <cyassl/ctaocrypt/memory.h>
+    #define XMALLOC(s, h, t)     ((void)h, (void)t, CyaSSL_Malloc((s)))
+    #define XFREE(p, h, t)       {void* xp = (p); if((xp)) CyaSSL_Free((xp));}
+    #define XREALLOC(p, n, h, t) CyaSSL_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 CyaSSL 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))
+    #define XSTRNCASECMP(s1,s2,n) strncasecmp((s1),(s2),(n))
+#endif
+
+#if defined(HAVE_ECC) || defined(HAVE_OCSP)
+    #ifndef CTYPE_USER
+        #include <ctype.h>
+        #define XTOUPPER(c)     toupper((c))
+        #define XISALPHA(c)     isalpha((c))
+    #endif
+#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
+};
+
+/* 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
+};
+
+
+CYASSL_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 /* CTAO_CRYPT_TYPES_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/visibility.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,69 @@
+/* visibility.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/* Visibility control macros */
+
+
+#ifndef CTAO_CRYPT_VISIBILITY_H
+#define CTAO_CRYPT_VISIBILITY_H
+
+
+/* CYASSL_API is used for the public API symbols.
+        It either imports or exports (or does nothing for static builds)
+
+   CYASSL_LOCAL is used for non-API symbols (private).
+*/
+
+#if defined(BUILDING_CYASSL)
+    #if defined(HAVE_VISIBILITY) && HAVE_VISIBILITY
+        #define CYASSL_API   __attribute__ ((visibility("default")))
+        #define CYASSL_LOCAL __attribute__ ((visibility("hidden")))
+    #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+        #define CYASSL_API   __global  
+        #define CYASSL_LOCAL __hidden
+    #elif defined(_MSC_VER)
+        #ifdef CYASSL_DLL
+            #define CYASSL_API extern __declspec(dllexport)
+        #else
+            #define CYASSL_API
+        #endif
+        #define CYASSL_LOCAL
+    #else
+        #define CYASSL_API
+        #define CYASSL_LOCAL
+    #endif /* HAVE_VISIBILITY */
+#else /* BUILDING_CYASSL */
+    #if defined(_MSC_VER)
+        #ifdef CYASSL_DLL
+            #define CYASSL_API extern __declspec(dllimport)
+        #else
+            #define CYASSL_API
+        #endif
+        #define CYASSL_LOCAL
+    #else
+        #define CYASSL_API
+        #define CYASSL_LOCAL
+    #endif
+#endif /* BUILDING_CYASSL */
+
+
+#endif /* CTAO_CRYPT_VISIBILITY_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaoerror.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,145 @@
+/* error.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CYASSL_ERROR_H
+#define CYASSL_ERROR_H
+
+#include <cyassl/ctaocrypt/ctaoerror2.h>   /* pull in CTaoCrypt errors */
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+enum CyaSSL_ErrorCodes {
+    INPUT_CASE_ERROR        = -201,            /* process input state error */
+    PREFIX_ERROR            = -202,            /* bad index to key rounds  */
+    MEMORY_ERROR            = -203,            /* out of memory            */
+    VERIFY_FINISHED_ERROR   = -204,            /* verify problem on finished */
+    VERIFY_MAC_ERROR        = -205,            /* verify mac problem       */
+    PARSE_ERROR             = -206,            /* parse error on header    */
+    UNKNOWN_HANDSHAKE_TYPE  = -207,            /* weird handshake type     */
+    SOCKET_ERROR_E          = -208,            /* error state on socket    */
+    SOCKET_NODATA           = -209,            /* expected data, not there */
+    INCOMPLETE_DATA         = -210,            /* don't have enough data to
+                                                  complete task            */
+    UNKNOWN_RECORD_TYPE     = -211,            /* unknown type in record hdr */
+    DECRYPT_ERROR           = -212,            /* error during decryption  */
+    FATAL_ERROR             = -213,            /* recvd alert fatal error  */
+    ENCRYPT_ERROR           = -214,            /* error during encryption  */
+    FREAD_ERROR             = -215,            /* fread problem            */
+    NO_PEER_KEY             = -216,            /* need peer's key          */
+    NO_PRIVATE_KEY          = -217,            /* need the private key     */
+    RSA_PRIVATE_ERROR       = -218,            /* error during rsa priv op */
+    NO_DH_PARAMS            = -219,            /* server missing DH params */
+    BUILD_MSG_ERROR         = -220,            /* build message failure    */
+
+    BAD_HELLO               = -221,            /* client hello malformed   */
+    DOMAIN_NAME_MISMATCH    = -222,            /* peer subject name mismatch */
+    WANT_READ               = -223,            /* want read, call again    */
+    NOT_READY_ERROR         = -224,            /* handshake layer not ready */
+    PMS_VERSION_ERROR       = -225,            /* pre m secret version error */
+    VERSION_ERROR           = -226,            /* record layer version error */
+    WANT_WRITE              = -227,            /* want write, call again   */
+    BUFFER_ERROR            = -228,            /* malformed buffer input   */
+    VERIFY_CERT_ERROR       = -229,            /* verify cert error        */
+    VERIFY_SIGN_ERROR       = -230,            /* verify sign error        */
+    CLIENT_ID_ERROR         = -231,            /* psk client identity error  */
+    SERVER_HINT_ERROR       = -232,            /* psk server hint error  */
+    PSK_KEY_ERROR           = -233,            /* psk key error  */
+    ZLIB_INIT_ERROR         = -234,            /* zlib init error  */
+    ZLIB_COMPRESS_ERROR     = -235,            /* zlib compression error  */
+    ZLIB_DECOMPRESS_ERROR   = -236,            /* zlib decompression error  */
+
+    GETTIME_ERROR           = -237,            /* gettimeofday failed ??? */
+    GETITIMER_ERROR         = -238,            /* getitimer failed ??? */
+    SIGACT_ERROR            = -239,            /* sigaction failed ??? */
+    SETITIMER_ERROR         = -240,            /* setitimer failed ??? */
+    LENGTH_ERROR            = -241,            /* record layer length error */
+    PEER_KEY_ERROR          = -242,            /* can't decode peer key */
+    ZERO_RETURN             = -243,            /* peer sent close notify */
+    SIDE_ERROR              = -244,            /* wrong client/server type */
+    NO_PEER_CERT            = -245,            /* peer didn't send key */
+    NTRU_KEY_ERROR          = -246,            /* NTRU key error  */
+    NTRU_DRBG_ERROR         = -247,            /* NTRU drbg error  */
+    NTRU_ENCRYPT_ERROR      = -248,            /* NTRU encrypt error  */
+    NTRU_DECRYPT_ERROR      = -249,            /* NTRU decrypt error  */
+    ECC_CURVETYPE_ERROR     = -250,            /* Bad ECC Curve Type */
+    ECC_CURVE_ERROR         = -251,            /* Bad ECC Curve */
+    ECC_PEERKEY_ERROR       = -252,            /* Bad Peer ECC Key */
+    ECC_MAKEKEY_ERROR       = -253,            /* Bad Make ECC Key */
+    ECC_EXPORT_ERROR        = -254,            /* Bad ECC Export Key */
+    ECC_SHARED_ERROR        = -255,            /* Bad ECC Shared Secret */
+    BAD_MUTEX_ERROR         = -256,            /* Bad mutex */
+    NOT_CA_ERROR            = -257,            /* Not a CA cert error */
+    BAD_PATH_ERROR          = -258,            /* Bad path for opendir */
+    BAD_CERT_MANAGER_ERROR  = -259,            /* Bad Cert Manager */
+    OCSP_CERT_REVOKED       = -260,            /* OCSP Certificate revoked */
+    CRL_CERT_REVOKED        = -261,            /* CRL Certificate revoked */
+    CRL_MISSING             = -262,            /* CRL Not loaded */
+    MONITOR_RUNNING_E       = -263,            /* CRL Monitor already running */
+    THREAD_CREATE_E         = -264,            /* Thread Create Error */
+    OCSP_NEED_URL           = -265,            /* OCSP need an URL for lookup */
+    OCSP_CERT_UNKNOWN       = -266,            /* OCSP responder doesn't know */
+    OCSP_LOOKUP_FAIL        = -267,            /* OCSP lookup not successful */
+    MAX_CHAIN_ERROR         = -268,            /* max chain depth exceeded */
+    COOKIE_ERROR            = -269,            /* dtls cookie error */
+    SEQUENCE_ERROR          = -270,           /* dtls sequence error */
+    SUITES_ERROR            = -271,           /* suites pointer error */
+    SSL_NO_PEM_HEADER       = -272,           /* no PEM header found */
+    OUT_OF_ORDER_E          = -273,           /* out of order message */
+    BAD_KEA_TYPE_E          = -274,           /* bad KEA type found */
+    SANITY_CIPHER_E         = -275,           /* sanity check on cipher error */
+    RECV_OVERFLOW_E         = -276,           /* RXCB returned more than rqed */
+    GEN_COOKIE_E            = -277,           /* Generate Cookie Error */
+    NO_PEER_VERIFY          = -278,           /* Need peer cert verify Error */
+    FWRITE_ERROR            = -279,           /* fwrite problem */
+    CACHE_MATCH_ERROR       = -280,           /* chache hdr match error */
+    UNKNOWN_SNI_HOST_NAME_E = -281,           /* Unrecognized host name Error */
+    /* add strings to SetErrorString !!!!! */
+
+    /* begin negotiation parameter errors */
+    UNSUPPORTED_SUITE       = -290,            /* unsupported cipher suite */
+    MATCH_SUITE_ERROR       = -291             /* can't match cipher suite */
+    /* end negotiation parameter errors only 10 for now */
+    /* add strings to SetErrorString !!!!! */
+};
+
+
+#ifdef CYASSL_CALLBACKS
+    enum {
+        MIN_PARAM_ERR = UNSUPPORTED_SUITE,
+        MAX_PARAM_ERR = MIN_PARAM_ERR - 10
+    };
+#endif
+
+
+CYASSL_LOCAL
+void SetErrorString(int err, char* buff);
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+
+#endif /* CyaSSL_ERROR_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/internal.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,2014 @@
+/* internal.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CYASSL_INT_H
+#define CYASSL_INT_H
+
+
+#include <cyassl/ctaocrypt/types.h>
+#include <cyassl/ssl.h>
+#include <cyassl/crl.h>
+#include <cyassl/ctaocrypt/random.h>
+#include <cyassl/ctaocrypt/des3.h>
+#include <cyassl/ctaocrypt/hc128.h>
+#include <cyassl/ctaocrypt/rabbit.h>
+#include <cyassl/ctaocrypt/asn.h>
+#include <cyassl/ctaocrypt/md5.h>
+#include <cyassl/ctaocrypt/sha.h>
+#include <cyassl/ctaocrypt/aes.h>
+#include <cyassl/ctaocrypt/camellia.h>
+#include <cyassl/ctaocrypt/logging.h>
+#ifndef NO_RC4
+    #include <cyassl/ctaocrypt/arc4.h>
+#endif
+#ifdef HAVE_ECC
+    #include <cyassl/ctaocrypt/ecc.h>
+#endif
+#ifndef NO_SHA256
+    #include <cyassl/ctaocrypt/sha256.h>
+#endif
+#ifdef HAVE_OCSP
+    #include <cyassl/ocsp.h>
+#endif
+#ifdef CYASSL_SHA512
+    #include <cyassl/ctaocrypt/sha512.h>
+#endif
+
+#ifdef HAVE_AESGCM
+    #include <cyassl/ctaocrypt/sha512.h>
+#endif
+
+#ifdef CYASSL_RIPEMD
+    #include <cyassl/ctaocrypt/ripemd.h>
+#endif
+
+#ifdef CYASSL_CALLBACKS
+    #include <cyassl/callbacks.h>
+    #include <signal.h>
+#endif
+
+#ifdef USE_WINDOWS_API 
+    #ifdef CYASSL_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(CYASSL_SAFERTOS)
+    /* do nothing */
+#elif defined(EBSNET)
+    /* do nothing */
+#elif defined(FREESCALE_MQX)
+    /* do nothing */
+#elif defined(CYASSL_MDK_ARM)
+    #include <rtl.h>
+#else
+    #ifndef SINGLE_THREADED
+        #define CYASSL_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 __cplusplus
+    extern "C" {
+#endif
+
+
+#ifdef USE_WINDOWS_API 
+    typedef unsigned int SOCKET_T;
+#else
+    typedef int SOCKET_T;
+#endif
+
+
+typedef byte word24[3];
+
+/* used by ssl.c and cyassl_int.c */
+void c32to24(word32 in, word24 out);
+
+/* 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
+*/
+#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 (CYASSL_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
+#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) && defined(OPENSSL_EXTRA)
+          #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_AESCCM
+            #define BUILD_TLS_PSK_WITH_AES_128_CCM_8
+            #define BUILD_TLS_PSK_WITH_AES_256_CCM_8
+        #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
+    #endif
+#endif
+
+#if !defined(NO_HC128) && !defined(NO_RSA) && !defined(NO_TLS)
+    #define BUILD_TLS_RSA_WITH_HC_128_CBC_MD5
+  #if !defined(NO_SHA)
+    #define BUILD_TLS_RSA_WITH_HC_128_CBC_SHA
+  #endif
+#endif
+
+#if !defined(NO_RABBIT) && !defined(NO_TLS) && !defined(NO_RSA)
+  #if !defined(NO_SHA)
+    #define BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA
+  #endif
+#endif
+
+#if !defined(NO_DH) && !defined(NO_AES) && !defined(NO_TLS) && \
+    !defined(NO_RSA) && defined(OPENSSL_EXTRA)
+  #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
+        #if defined (HAVE_AESGCM)
+            #define BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+            #if defined (CYASSL_SHA384)
+                #define BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+            #endif
+        #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 CYASSL_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_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+                #define BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+                #if defined(CYASSL_SHA384)
+                    #define BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+                    #define BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+                #endif
+            #endif
+
+            #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+            #define BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+            
+            #if defined(CYASS_SHA384)
+                #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+                #define BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+            #endif
+        #endif
+        #if defined (HAVE_AESCCM)
+            #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+            #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
+        #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)
+        #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
+#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_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
+    #define BUILD_AESGCM
+#endif
+
+#if defined(BUILD_TLS_RSA_WITH_HC_128_CBC_SHA) || \
+    defined(BUILD_TLS_RSA_WITH_HC_128_CBC_MD5)
+    #define BUILD_HC128
+#endif
+
+#if defined(BUILD_TLS_RSA_WITH_RABBIT_CBC_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
+
+
+
+#if defined(BUILD_AESGCM) || defined(HAVE_AESCCM)
+    #define HAVE_AEAD
+#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_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_128_CBC_SHA      = 0x8c,
+    TLS_PSK_WITH_NULL_SHA256          = 0xb0,
+    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,
+
+    /* CyaSSL extension - eSTREAM */
+    TLS_RSA_WITH_HC_128_CBC_MD5       = 0xFB,
+    TLS_RSA_WITH_HC_128_CBC_SHA       = 0xFC,
+    TLS_RSA_WITH_RABBIT_CBC_SHA       = 0xFD,
+
+    /* CyaSSL 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,  /* clases 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,
+
+    /* 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,
+
+    /* 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 = 0xc6, /* Still TBD, made up */
+    TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 = 0xc7, /* Still TBD, made up */
+    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_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
+
+};
+
+
+#if defined(CYASSL_SHA384)
+    #define MAX_DIGEST_SIZE SHA384_DIGEST_SIZE
+#elif !defined(NO_SHA256)
+    #define MAX_DIGEST_SIZE SHA256_DIGEST_SIZE
+#elif !defined(NO_MD5) && !defined(NO_SHA)
+    #define MAX_DIGEST_SIZE (SHA_DIGEST_SIZE + MD5_DIGEST_SIZE)
+#else
+    #error "You have configured the build so there isn't any hashing."
+#endif
+
+
+enum Misc {
+    SERVER_END = 0,
+    CLIENT_END,
+
+    ECC_BYTE =  0xC0,           /* ECC first cipher suite byte */
+
+    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 */
+    INVALID_BYTE    = 0xff,     /* Used to initialize cipher specs values */
+    NO_COMPRESSION  =  0,
+    ZLIB_COMPRESSION = 221,     /* CyaSSL 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       = 612,      /* 2240 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     */
+    REQUEST_HEADER =  2,       /* always use 2 bytes      */
+    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 */
+
+    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           */
+    OPAQUE16_LEN =  2,         /* always 2 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 */
+    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        = 128, /* 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 */
+
+    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 */
+    DEFAULT_TIMEOUT    = 500,  /* default resumption timeout in seconds */
+
+    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_CYASSL_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 */
+};
+
+
+/* max cert chain peer depth */
+#ifndef MAX_CHAIN_DEPTH
+    #define MAX_CHAIN_DEPTH 9
+#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 CYASSL_PACK __attribute__ ((packed))
+#else
+    #define CYASSL_PACK
+#endif
+
+/* SSL Version */
+typedef struct ProtocolVersion {
+    byte major;
+    byte minor;
+} CYASSL_PACK ProtocolVersion;
+
+
+CYASSL_LOCAL ProtocolVersion MakeSSLv3(void);
+CYASSL_LOCAL ProtocolVersion MakeTLSv1(void);
+CYASSL_LOCAL ProtocolVersion MakeTLSv1_1(void);
+CYASSL_LOCAL ProtocolVersion MakeTLSv1_2(void);
+
+#ifdef CYASSL_DTLS
+    CYASSL_LOCAL ProtocolVersion MakeDTLSv1(void);
+    CYASSL_LOCAL ProtocolVersion MakeDTLSv1_2(void);
+#endif
+
+
+enum BIO_TYPE {
+    BIO_BUFFER = 1,
+    BIO_SOCKET = 2,
+    BIO_SSL    = 3,
+    BIO_MEMORY = 4
+};
+
+
+/* CyaSSL BIO_METHOD type */
+struct CYASSL_BIO_METHOD {
+    byte type;               /* method type */
+};
+
+
+/* CyaSSL BIO type */
+struct CYASSL_BIO {
+    byte        type;          /* method type */
+    byte        close;         /* close flag */
+    byte        eof;           /* eof flag */
+    CYASSL*     ssl;           /* possible associated ssl */
+    byte*       mem;           /* memory buffer */
+    int         memLen;        /* memory buffer length */
+    int         fd;            /* possible file descriptor */
+    CYASSL_BIO* prev;          /* previous in chain */
+    CYASSL_BIO* next;          /* next in chain */
+};
+
+
+/* CyaSSL method type */
+struct CYASSL_METHOD {
+    ProtocolVersion version;
+    byte            side;         /* connection side, server or client */
+    byte            downgrade;    /* whether to downgrade version, default no */
+};
+
+
+/* defautls to client */
+CYASSL_LOCAL void InitSSL_Method(CYASSL_METHOD*, ProtocolVersion);
+
+/* for sniffer */
+CYASSL_LOCAL int DoFinished(CYASSL* ssl, const byte* input, word32* inOutIdx,
+                            int sniff);
+CYASSL_LOCAL int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx);
+
+
+/* CyaSSL buffer type */
+typedef struct buffer {
+    word32 length;
+    byte*  buffer;
+} 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 CYASSL_SNIFFER
+    #define MTU_EXTRA MAX_MTU * 3 
+#else
+    #define MTU_EXTRA 0
+#endif
+
+
+/* embedded callbacks require large static buffers, make sure on */
+#ifdef CYASSL_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 CYASSL_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
+
+/* CyaSSL 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
+    /* zero length arrays may not be supported */
+    #define STATIC_BUFFER_LEN 1
+#endif
+
+typedef struct {
+    word32 length;       /* total buffer length used */
+    word32 idx;          /* idx to part of length already consumed */
+    byte*  buffer;       /* place holder for static or dynamic buffer */
+    word32 bufferSize;   /* current buffer size */
+    ALIGN16 byte staticBuffer[STATIC_BUFFER_LEN];
+    byte   dynamicFlag;  /* dynamic memory currently in use */
+    byte   offset;       /* alignment offset attempt */
+} bufferStatic;
+
+/* Cipher Suites holder */
+typedef struct Suites {
+    int    setSuites;               /* user set suites from default */
+    byte   suites[MAX_SUITE_SZ];  
+    word16 suiteSz;                 /* suite length in bytes        */
+    byte   hashSigAlgo[HELLO_EXT_SIGALGO_MAX]; /* sig/algo to offer */
+    word16 hashSigAlgoSz;           /* SigAlgo extension length in bytes */
+    byte   hashAlgo;                /* selected hash algorithm */
+    byte   sigAlgo;                 /* selected sig algorithm */
+} Suites;
+
+
+CYASSL_LOCAL
+void InitSuites(Suites*, ProtocolVersion,
+                                     byte, byte, byte, byte, byte, byte, int);
+CYASSL_LOCAL
+int  SetCipherList(Suites*, const char* list);
+
+#ifndef PSK_TYPES_DEFINED
+    typedef unsigned int (*psk_client_callback)(CYASSL*, const char*, char*,
+                          unsigned int, unsigned char*, unsigned int);
+    typedef unsigned int (*psk_server_callback)(CYASSL*, const char*,
+                          unsigned char*, unsigned int);
+#endif /* PSK_TYPES_DEFINED */
+
+
+#ifndef CYASSL_USER_IO
+    /* default IO callbacks */
+    CYASSL_LOCAL
+    int EmbedReceive(CYASSL *ssl, char *buf, int sz, void *ctx);
+    CYASSL_LOCAL 
+    int EmbedSend(CYASSL *ssl, char *buf, int sz, void *ctx);
+
+    #ifdef HAVE_OCSP
+        CYASSL_LOCAL
+        int EmbedOcspLookup(void*, const char*, int, byte*, int, byte**);
+        CYASSL_LOCAL
+        void EmbedOcspRespFree(void*, byte*);
+    #endif
+
+    #ifdef CYASSL_DTLS
+        CYASSL_LOCAL
+        int EmbedReceiveFrom(CYASSL *ssl, char *buf, int sz, void *ctx);
+        CYASSL_LOCAL 
+        int EmbedSendTo(CYASSL *ssl, char *buf, int sz, void *ctx);
+        CYASSL_LOCAL
+        int EmbedGenerateCookie(CYASSL* ssl, byte *buf, int sz, void *ctx);
+        CYASSL_LOCAL
+        int IsUDP(void*);
+    #endif /* CYASSL_DTLS */
+#endif /* CYASSL_USER_IO */
+
+
+/* CyaSSL Cipher type just points back to SSL */
+struct CYASSL_CIPHER {
+    CYASSL* ssl;
+};
+
+
+#ifdef SINGLE_THREADED
+    typedef int CyaSSL_Mutex;
+#else /* MULTI_THREADED */
+    /* FREERTOS comes first to enable use of FreeRTOS Windows simulator only */
+    #ifdef FREERTOS
+        typedef xSemaphoreHandle CyaSSL_Mutex;
+    #elif defined(CYASSL_SAFERTOS)
+        typedef struct CyaSSL_Mutex {
+            signed char mutexBuffer[portQUEUE_OVERHEAD_BYTES];
+            xSemaphoreHandle mutex;
+        } CyaSSL_Mutex;
+    #elif defined(USE_WINDOWS_API)
+        typedef CRITICAL_SECTION CyaSSL_Mutex;
+    #elif defined(CYASSL_PTHREADS)
+        typedef pthread_mutex_t CyaSSL_Mutex;
+    #elif defined(THREADX)
+        typedef TX_MUTEX CyaSSL_Mutex;
+    #elif defined(MICRIUM)
+        typedef OS_MUTEX CyaSSL_Mutex;
+    #elif defined(EBSNET)
+        typedef RTP_MUTEX CyaSSL_Mutex;
+    #elif defined(FREESCALE_MQX)
+        typedef MUTEX_STRUCT CyaSSL_Mutex;
+    #elif defined(CYASSL_MDK_ARM)
+        typedef OS_MUT CyaSSL_Mutex;
+    #else
+        #error Need a mutex type in multithreaded mode
+    #endif /* USE_WINDOWS_API */
+#endif /* SINGLE_THREADED */
+
+CYASSL_LOCAL int InitMutex(CyaSSL_Mutex*);
+CYASSL_LOCAL int FreeMutex(CyaSSL_Mutex*);
+CYASSL_LOCAL int LockMutex(CyaSSL_Mutex*);
+CYASSL_LOCAL int UnLockMutex(CyaSSL_Mutex*);
+
+typedef struct OCSP_Entry OCSP_Entry;
+
+#ifdef SHA_DIGEST_SIZE
+    #define OCSP_DIGEST_SIZE SHA_DIGEST_SIZE
+#else
+    #define OCSP_DIGEST_SIZE 160
+#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         */
+};
+
+
+/* CyaSSL OCSP controller */
+struct CYASSL_OCSP {
+    byte enabled;
+    byte useOverrideUrl;
+    byte useNonce;
+    char overrideUrl[80];
+    OCSP_Entry* ocspList;
+    void* IOCB_OcspCtx;
+    CallbackIOOcsp CBIOOcsp;
+    CallbackIOOcspRespFree CBIOOcspRespFree;
+};
+
+#ifndef MAX_DATE_SIZE
+#define MAX_DATE_SIZE 32
+#endif
+
+typedef struct CRL_Entry CRL_Entry;
+
+#ifdef SHA_DIGEST_SIZE
+    #define CRL_DIGEST_SIZE SHA_DIGEST_SIZE
+#else
+    #define CRL_DIGEST_SIZE 160
+#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 CYASSL_CRL CYASSL_CRL;
+#endif
+
+/* CyaSSL CRL controller */
+struct CYASSL_CRL {
+    CYASSL_CERT_MANAGER* cm;            /* pointer back to cert manager */
+    CRL_Entry*           crlList;       /* our CRL list */
+    CyaSSL_Mutex         crlLock;       /* CRL list lock */
+    CRL_Monitor          monitors[2];   /* PEM and DER possible */
+#ifdef HAVE_CRL_MONITOR
+    pthread_t            tid;           /* monitoring thread */
+#endif
+};
+
+
+#ifdef NO_ASN 
+    typedef struct Signer Signer;
+#endif
+
+
+#ifndef CA_TABLE_SIZE
+    #define CA_TABLE_SIZE 11
+#endif
+
+/* CyaSSL Certificate Manager */
+struct CYASSL_CERT_MANAGER {
+    Signer*         caTable[CA_TABLE_SIZE]; /* the CA signer table */
+    CyaSSL_Mutex    caLock;             /* CA list lock */
+    CallbackCACache caCacheCallback;    /* CA cache addition callback */
+    void*           heap;               /* heap helper */
+    CYASSL_CRL*     crl;                /* CRL checker */
+    byte            crlEnabled;         /* is CRL on ? */
+    byte            crlCheckAll;        /* always leaf, but all ? */
+    CbMissingCRL    cbMissingCRL;       /* notify through cb of missing crl */
+};
+
+CYASSL_LOCAL int CM_SaveCertCache(CYASSL_CERT_MANAGER*, const char*);
+CYASSL_LOCAL int CM_RestoreCertCache(CYASSL_CERT_MANAGER*, const char*);
+CYASSL_LOCAL int CM_MemSaveCertCache(CYASSL_CERT_MANAGER*, void*, int, int*);
+CYASSL_LOCAL int CM_MemRestoreCertCache(CYASSL_CERT_MANAGER*, const void*, int);
+CYASSL_LOCAL int CM_GetCertCacheMemSize(CYASSL_CERT_MANAGER*);
+
+/* CyaSSL Sock Addr */
+struct CYASSL_SOCKADDR {
+    unsigned int sz; /* sockaddr size */
+    void*        sa; /* pointer to the sockaddr_in or sockaddr_in6 */
+};
+
+typedef struct CYASSL_DTLS_CTX {
+    CYASSL_SOCKADDR peer;
+    int fd;
+} CYASSL_DTLS_CTX;
+
+/* RFC 6066 TLS Extensions */
+#ifdef HAVE_TLS_EXTENSIONS
+
+typedef enum {
+    SERVER_NAME_INDICATION =  0,/*
+    MAX_FRAGMENT_LENGTH    =  1,
+    CLIENT_CERTIFICATE_URL =  2,
+    TRUSTED_CA_KEYS        =  3,
+    TRUNCATED_HMAC         =  4,
+    STATUS_REQUEST         =  5,
+    SIGNATURE_ALGORITHMS   = 13,*/
+} TLSX_Type;
+
+typedef struct TLSX {
+    TLSX_Type    type; /* Extension Type  */
+    void*        data; /* Extension Data  */
+    byte         resp; /* IsResponse Flag */
+    struct TLSX* next; /* List Behavior   */
+} TLSX;
+
+CYASSL_LOCAL TLSX* TLSX_Find(TLSX* list, TLSX_Type type);
+CYASSL_LOCAL void TLSX_FreeAll(TLSX* list);
+
+#ifndef NO_CYASSL_CLIENT
+CYASSL_LOCAL word16 TLSX_GetRequestSize(CYASSL* ssl);
+CYASSL_LOCAL word16 TLSX_WriteRequest(CYASSL* ssl, byte* output);
+#endif
+
+#ifndef NO_CYASSL_SERVER
+CYASSL_LOCAL word16 TLSX_GetResponseSize(CYASSL* ssl);
+CYASSL_LOCAL word16 TLSX_WriteResponse(CYASSL* ssl, byte* output);
+#endif
+
+CYASSL_LOCAL int    TLSX_Parse(CYASSL* ssl, byte* input, word16 length,
+                                                byte isRequest, Suites *suites);
+
+/* 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_CYASSL_SERVER
+    byte                       options; /* Behaviour options */
+    byte                       matched; /* Matching result   */
+#endif
+} SNI;
+
+CYASSL_LOCAL int TLSX_UseSNI(TLSX** extensions, byte type, const void* data,
+                                                                   word16 size);
+
+#ifndef NO_CYASSL_SERVER
+CYASSL_LOCAL byte TLSX_SNI_Matched(TLSX* extensions, byte type);
+CYASSL_LOCAL void TLSX_SNI_SetOptions(TLSX* extensions, byte type,
+                                                                  byte options);
+#endif
+
+#endif /* HAVE_SNI */
+
+#endif /* HAVE_TLS_EXTENSIONS */
+
+/* CyaSSL context type */
+struct CYASSL_CTX {
+    CYASSL_METHOD* method;
+    CyaSSL_Mutex   countMutex;    /* reference count mutex */
+    int         refCount;         /* reference count */
+#ifndef NO_CERTS
+    buffer      certificate;
+    buffer      certChain;
+                 /* chain after self, in DER, with leading size for each cert */
+    buffer      privateKey;
+    buffer      serverDH_P;
+    buffer      serverDH_G;
+    CYASSL_CERT_MANAGER* cm;      /* our cert manager, ctx owns SSL will use */
+#endif
+    Suites      suites;
+    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 */
+    CallbackIORecv CBIORecv;
+    CallbackIOSend CBIOSend;
+#ifdef CYASSL_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 */
+#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 */
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+    pem_password_cb passwd_cb;
+    void*            userdata;
+#endif /* OPENSSL_EXTRA */
+#ifdef HAVE_OCSP
+    CYASSL_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 */
+#endif
+};
+
+
+CYASSL_LOCAL
+int InitSSL_Ctx(CYASSL_CTX*, CYASSL_METHOD*);
+CYASSL_LOCAL
+void FreeSSL_Ctx(CYASSL_CTX*);
+CYASSL_LOCAL
+void SSL_CtxResourceFree(CYASSL_CTX*);
+
+CYASSL_LOCAL
+int DeriveTlsKeys(CYASSL* ssl);
+CYASSL_LOCAL
+int ProcessOldClientHello(CYASSL* ssl, const byte* input, word32* inOutIdx,
+                          word32 inSz, word16 sz);
+#ifndef NO_CERTS
+    CYASSL_LOCAL
+    int AddCA(CYASSL_CERT_MANAGER* ctx, buffer der, int type, int verify);
+    CYASSL_LOCAL
+    int AlreadySigner(CYASSL_CERT_MANAGER* cm, byte* hash);
+#endif
+
+/* All cipher suite related info */
+typedef struct CipherSpecs {
+    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;
+    word16 key_size;
+    word16 iv_size;
+    word16 block_size;
+    word16 aead_mac_size;
+} CipherSpecs;
+
+
+void InitCipherSpecs(CipherSpecs* cs);
+
+
+/* Supported Ciphers from page 43  */
+enum BulkCipherAlgorithm { 
+    cipher_null,
+    rc4,
+    rc2,
+    des,
+    triple_des,             /* leading 3 (3des) not valid identifier */
+    des40,
+    idea,
+    aes,
+    aes_gcm,
+    aes_ccm,
+    camellia,
+    hc128,                  /* CyaSSL extensions */
+    rabbit
+};
+
+
+/* Supported Message Authentication Codes from page 43 */
+enum MACAlgorithm { 
+    no_mac,
+    md5_mac,
+    sha_mac,
+    sha224_mac,
+    sha256_mac,
+    sha384_mac,
+    sha512_mac,
+    rmd_mac
+};
+
+
+/* Supported Key Exchange Protocols */
+enum KeyExchangeAlgorithm { 
+    no_kea,
+    rsa_kea, 
+    diffie_hellman_kea, 
+    fortezza_kea,
+    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
+};
+
+
+/* Supprted ECC Named Curves */
+enum EccNamedCurves {
+    secp256r1 = 0x17,         /* default, OpenSSL also calls it prime256v1 */
+    secp384r1 = 0x18,
+    secp521r1 = 0x19,
+
+    secp160r1 = 0x10,
+    secp192r1 = 0x13,        /*           Openssl also call it prime192v1 */
+    secp224r1 = 0x15
+};
+
+
+/* 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
+};
+
+
+enum CipherType { stream, block, aead };
+
+
+/* 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 CYASSL_DTLS
+    word32 dtls_sequence_number;
+    word32 dtls_peer_sequence_number;
+    word32 dtls_expected_peer_sequence_number;
+    word16 dtls_handshake_number;
+    word16 dtls_peer_handshake_number;
+    word16 dtls_expected_peer_handshake_number;
+    word16 dtls_epoch;
+    word16 dtls_peer_epoch;
+    word16 dtls_expected_peer_epoch;
+#endif
+
+    word32 encryptSz;             /* last size of encrypted data   */
+    byte   encryptionOn;          /* true after change cipher spec */
+    byte   decryptedCur;          /* only decrypt current record once */
+} Keys;
+
+
+/* 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_HC128
+    HC128*  hc128;
+#endif
+#ifdef BUILD_RABBIT
+    Rabbit* rabbit;
+#endif
+    byte    setup;       /* have we set it up flag for detection */
+} Ciphers;
+
+
+CYASSL_LOCAL void InitCiphers(CYASSL* ssl);
+CYASSL_LOCAL void FreeCiphers(CYASSL* 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 CYASSL_SHA384
+        byte sha384[SHA384_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;
+
+
+/* CyaSSL X509_CHAIN, for no dynamic memory SESSION_CACHE */
+struct CYASSL_X509_CHAIN {
+    int         count;                    /* total number in chain */
+    x509_buffer certs[MAX_CHAIN_DEPTH];   /* only allow max depth 4 for now */
+};
+
+
+/* CyaSSL session type */
+struct CYASSL_SESSION {
+    byte         sessionID[ID_LEN];             /* id for protocol */
+    byte         masterSecret[SECRET_LEN];      /* stored secret */
+    word32       bornOn;                        /* create time in seconds   */
+    word32       timeout;                       /* timeout in seconds       */
+#ifdef SESSION_CERTS
+    CYASSL_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
+    byte         serverID[SERVER_ID_LEN];       /* for easier client lookup */
+    word16       idLen;                         /* serverID length */
+#endif
+};
+
+
+CYASSL_LOCAL
+CYASSL_SESSION* GetSession(CYASSL*, byte*);
+CYASSL_LOCAL
+int          SetSession(CYASSL*, CYASSL_SESSION*);
+
+typedef void (*hmacfp) (CYASSL*, byte*, const byte*, word32, int, int);
+
+#ifndef NO_CLIENT_CACHE
+    CYASSL_SESSION* GetSessionClient(CYASSL*, 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,
+    CHANGE_CIPHER_SENT,
+    ACCEPT_FINISHED_DONE,
+    ACCEPT_THIRD_REPLY_DONE
+};
+
+
+typedef struct Buffers {
+#ifndef NO_CERTS
+    buffer          certificate;            /* CYASSL_CTX owns, unless we own */
+    buffer          key;                    /* CYASSL_CTX owns, unless we own */
+    buffer          certChain;              /* CYASSL_CTX owns */
+                 /* chain after self, in DER, with leading size for each cert */
+    buffer          serverDH_P;             /* CYASSL_CTX owns, unless we own */
+    buffer          serverDH_G;             /* CYASSL_CTX owns, unless we own */
+    buffer          serverDH_Pub;
+    buffer          serverDH_Priv;
+#endif
+    buffer          domainName;             /* for client check */
+    bufferStatic    inputBuffer;
+    bufferStatic    outputBuffer;
+    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            weOwnKey;              /* SSL own key  flag */
+    byte            weOwnDH;               /* SSL own dh (p,g)  flag */
+#ifdef CYASSL_DTLS
+    CYASSL_DTLS_CTX dtlsCtx;               /* DTLS connection context */
+#endif
+} Buffers;
+
+typedef struct Options {
+    byte            sessionCacheOff;
+    byte            sessionCacheFlushOff;
+    byte            cipherSuite0;           /* first byte, normally 0 */
+    byte            cipherSuite;            /* second byte, actual suite */
+    byte            serverState;
+    byte            clientState;
+    byte            handShakeState;
+    byte            side;               /* client or server end */
+    byte            verifyPeer;
+    byte            verifyNone;
+    byte            failNoCert;
+    byte            downgrade;          /* allow downgrade of versions */
+    byte            sendVerify;         /* false = 0, true = 1, sendBlank = 2 */
+    byte            resuming;
+    byte            haveSessionId;      /* server may not send */
+    byte            tls;                /* using TLS ? */
+    byte            tls1_1;             /* using TLSv1.1+ ? */
+    byte            dtls;               /* using datagrams ? */
+    byte            connReset;          /* has the peer reset */
+    byte            isClosed;           /* if we consider conn closed */
+    byte            closeNotify;        /* we've recieved a close notify */
+    byte            sentNotify;         /* we've sent a close notify */
+    byte            connectState;       /* nonblocking resume */
+    byte            acceptState;        /* nonblocking resume */
+    byte            usingCompression;   /* are we using compression */
+    byte            haveRSA;            /* RSA available */
+    byte            haveDH;             /* server DH parms set by user */
+    byte            haveNTRU;           /* server NTRU  private key loaded */
+    byte            haveECDSAsig;       /* server ECDSA signed cert */
+    byte            haveStaticECC;      /* static server ECC private key */
+    byte            havePeerCert;       /* do we have peer's cert */
+    byte            havePeerVerify;     /* and peer's cert verify */
+    byte            usingPSK_cipher;    /* whether we're using psk as cipher */
+    byte            sendAlertState;     /* nonblocking resume */ 
+    byte            processReply;       /* nonblocking resume */
+    byte            partialWrite;       /* only one msg per write call */
+    byte            quietShutdown;      /* don't send close notify */
+    byte            certOnly;           /* stop once we get cert */
+    byte            groupMessages;      /* group handshake messages */
+    byte            usingNonblock;      /* set when using nonblocking socket */
+    byte            saveArrays;         /* save array Memory for user get keys
+                                           or psk */
+#ifndef NO_PSK
+    byte            havePSK;            /* psk key set by user */
+    psk_client_callback client_psk_cb;
+    psk_server_callback server_psk_cb;
+#endif /* NO_PSK */
+} Options;
+
+typedef struct Arrays {
+    byte            clientRandom[RAN_LEN];
+    byte            serverRandom[RAN_LEN];
+    byte            sessionID[ID_LEN];
+    byte            preMasterSecret[ENCRYPT_LEN];
+    byte            masterSecret[SECRET_LEN];
+#ifdef CYASSL_DTLS
+    byte            cookie[MAX_COOKIE_LEN];
+    byte            cookieSz;
+#endif
+#ifndef NO_PSK
+    char            client_identity[MAX_PSK_ID_LEN];
+    char            server_hint[MAX_PSK_ID_LEN];
+    byte            psk_key[MAX_PSK_KEY_LEN];
+    word32          psk_keySz;          /* acutal size */
+#endif
+    word32          preMasterSz;        /* differs for DH, actual size */
+} Arrays;
+
+#ifndef ASN_NAME_MAX
+#define ASN_NAME_MAX 256
+#endif
+
+struct CYASSL_X509_NAME {
+    char  name[ASN_NAME_MAX];
+    int   sz;
+};
+
+#ifndef EXTERNAL_SERIAL_SIZE
+    #define EXTERNAL_SERIAL_SIZE 32
+#endif
+
+#ifdef NO_ASN 
+    typedef struct DNS_entry DNS_entry;
+#endif
+
+struct CYASSL_X509 {
+    CYASSL_X509_NAME issuer;
+    CYASSL_X509_NAME subject;
+    int              serialSz;
+    byte             serial[EXTERNAL_SERIAL_SIZE];
+    char             subjectCN[ASN_NAME_MAX];        /* common name short cut */
+    buffer           derCert;                        /* may need  */
+    DNS_entry*       altNames;                       /* alt names list */
+    DNS_entry*       altNamesNext;                   /* hint for retrieval */
+    byte             dynamicMemory;                  /* dynamic memory flag */
+};
+
+
+/* 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;
+
+
+/* CyaSSL ssl type */
+struct CYASSL {
+    CYASSL_CTX*     ctx;
+    int             error;
+    ProtocolVersion version;            /* negotiated version */
+    ProtocolVersion chVersion;          /* client hello version */
+    Suites*         suites;             /* only need during handshake */
+    Ciphers         encrypt;
+    Ciphers         decrypt;
+    CipherSpecs     specs;
+    Keys            keys;
+    int             rfd;                /* read  file descriptor */
+    int             wfd;                /* write file descriptor */
+    int             rflags;             /* user read  flags */
+    int             wflags;             /* user write flags */
+    CYASSL_BIO*     biord;              /* socket bio read  to free/close */
+    CYASSL_BIO*     biowr;              /* socket bio write to free/close */
+    void*           IOCB_ReadCtx;
+    void*           IOCB_WriteCtx;
+    RNG*            rng;
+#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
+#ifndef NO_SHA256
+    Sha256          hashSha256;         /* sha256 hash of handshake msgs */
+#endif
+#ifdef CYASSL_SHA384
+    Sha384          hashSha384;         /* sha384 hash of handshake msgs */
+#endif
+    Hashes          verifyHashes;
+    Hashes          certHashes;         /* for cert verify */
+    Buffers         buffers;
+    Options         options;
+    Arrays*         arrays;
+    CYASSL_SESSION  session;
+    VerifyCallback  verifyCallback;      /* cert verification callback */
+    void*           verifyCbCtx;         /* cert verify callback user ctx*/
+#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 */
+    ecc_key*        eccDsaKey;               /* private ECDSA key */
+    word16          eccTempKeySz;            /* in octets 20 - 66 */
+    byte            peerEccKeyPresent;
+    byte            peerEccDsaKeyPresent;
+    byte            eccTempKeyPresent;
+    byte            eccDsaKeyPresent;
+#endif
+    hmacfp          hmac;
+    void*           heap;               /* for user overrides */
+    RecordLayerHeader curRL;
+    word16            curSize;
+    word32          timeout;            /* session timeout */
+    CYASSL_CIPHER   cipher;
+#ifdef HAVE_LIBZ
+    z_stream        c_stream;           /* compression   stream */
+    z_stream        d_stream;           /* decompression stream */
+    byte            didStreamInit;      /* for stream init and end */
+#endif
+#ifdef CYASSL_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 CYASSL_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 KEEP_PEER_CERT
+    CYASSL_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_TLS_EXTENSIONS
+    TLSX* extensions;                  /* RFC 6066 TLS Extensions data */
+#endif
+    CYASSL_ALERT_HISTORY alert_history;
+};
+
+
+CYASSL_LOCAL
+int  InitSSL(CYASSL*, CYASSL_CTX*);
+CYASSL_LOCAL
+void FreeSSL(CYASSL*);
+CYASSL_API void SSL_ResourceFree(CYASSL*);   /* 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 */
+    CYASSL_CTX* ctx;              /* CTX owner */
+} EncryptedInfo;
+
+
+#ifndef NO_CERTS
+    CYASSL_LOCAL int PemToDer(const unsigned char* buff, long sz, int type,
+                              buffer* der, void* heap, EncryptedInfo* info,
+                              int* eccKey);
+
+    CYASSL_LOCAL int ProcessFile(CYASSL_CTX* ctx, const char* fname, int format,
+                                 int type, CYASSL* ssl, int userChain,
+                                CYASSL_CRL* crl);
+#endif
+
+
+#ifdef CYASSL_CALLBACKS
+    CYASSL_LOCAL
+    void InitHandShakeInfo(HandShakeInfo*);
+    CYASSL_LOCAL 
+    void FinishHandShakeInfo(HandShakeInfo*, const CYASSL*);
+    CYASSL_LOCAL 
+    void AddPacketName(const char*, HandShakeInfo*);
+
+    CYASSL_LOCAL
+    void InitTimeoutInfo(TimeoutInfo*);
+    CYASSL_LOCAL 
+    void FreeTimeoutInfo(TimeoutInfo*, void*);
+    CYASSL_LOCAL 
+    void AddPacketInfo(const char*, TimeoutInfo*, const byte*, int, void*);
+    CYASSL_LOCAL 
+    void AddLateName(const char*, TimeoutInfo*);
+    CYASSL_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
+};
+
+
+/* Valid Alert types from page 16/17 */
+enum AlertDescription {
+    close_notify            = 0,
+    unexpected_message      = 10,
+    bad_record_mac          = 20,
+    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,
+    protocol_version        = 70,
+    no_renegotiation        = 100,
+    unrecognized_name       = 112
+};
+
+
+enum AlertLevel { 
+    alert_warning = 1, 
+    alert_fatal = 2
+};
+
+
+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 */
+CYASSL_LOCAL int SendChangeCipher(CYASSL*);
+CYASSL_LOCAL int SendData(CYASSL*, const void*, int);
+CYASSL_LOCAL int SendCertificate(CYASSL*);
+CYASSL_LOCAL int SendCertificateRequest(CYASSL*);
+CYASSL_LOCAL int SendServerKeyExchange(CYASSL*);
+CYASSL_LOCAL int SendBuffered(CYASSL*);
+CYASSL_LOCAL int ReceiveData(CYASSL*, byte*, int, int);
+CYASSL_LOCAL int SendFinished(CYASSL*);
+CYASSL_LOCAL int SendAlert(CYASSL*, int, int);
+CYASSL_LOCAL int ProcessReply(CYASSL*);
+
+CYASSL_LOCAL int SetCipherSpecs(CYASSL*);
+CYASSL_LOCAL int MakeMasterSecret(CYASSL*);
+
+CYASSL_LOCAL int  AddSession(CYASSL*);
+CYASSL_LOCAL int  DeriveKeys(CYASSL* ssl);
+CYASSL_LOCAL int  StoreKeys(CYASSL* ssl, const byte* keyData);
+
+CYASSL_LOCAL int IsTLS(const CYASSL* ssl);
+CYASSL_LOCAL int IsAtLeastTLSv1_2(const CYASSL* ssl);
+
+CYASSL_LOCAL void FreeHandshakeResources(CYASSL* ssl);
+CYASSL_LOCAL void ShrinkInputBuffer(CYASSL* ssl, int forcedFree);
+CYASSL_LOCAL void ShrinkOutputBuffer(CYASSL* ssl);
+#ifndef NO_CERTS
+    CYASSL_LOCAL Signer* GetCA(void* cm, byte* hash);
+    #ifndef NO_SKID
+        CYASSL_LOCAL Signer* GetCAByName(void* cm, byte* hash);
+    #endif
+#endif
+CYASSL_LOCAL void BuildTlsFinished(CYASSL* ssl, Hashes* hashes,
+                                   const byte* sender);
+CYASSL_LOCAL void FreeArrays(CYASSL* ssl, int keep);
+CYASSL_LOCAL  int CheckAvailableSize(CYASSL *ssl, int size);
+CYASSL_LOCAL  int GrowInputBuffer(CYASSL* ssl, int size, int usedLength);
+
+#ifndef NO_TLS
+    CYASSL_LOCAL int  MakeTlsMasterSecret(CYASSL*);
+    CYASSL_LOCAL void TLS_hmac(CYASSL* ssl, byte* digest, const byte* in,
+                               word32 sz, int content, int verify);
+#endif
+
+#ifndef NO_CYASSL_CLIENT
+    CYASSL_LOCAL int SendClientHello(CYASSL*);
+    CYASSL_LOCAL int SendClientKeyExchange(CYASSL*);
+    CYASSL_LOCAL int SendCertificateVerify(CYASSL*);
+#endif /* NO_CYASSL_CLIENT */
+
+#ifndef NO_CYASSL_SERVER
+    CYASSL_LOCAL int SendServerHello(CYASSL*);
+    CYASSL_LOCAL int SendServerHelloDone(CYASSL*);
+    #ifdef CYASSL_DTLS
+        CYASSL_LOCAL int SendHelloVerifyRequest(CYASSL*);
+    #endif
+#endif /* NO_CYASSL_SERVER */
+
+#ifdef CYASSL_DTLS
+    CYASSL_LOCAL int  DtlsPoolInit(CYASSL*);
+    CYASSL_LOCAL int  DtlsPoolSave(CYASSL*, const byte*, int);
+    CYASSL_LOCAL int  DtlsPoolTimeout(CYASSL*);
+    CYASSL_LOCAL int  DtlsPoolSend(CYASSL*);
+    CYASSL_LOCAL void DtlsPoolReset(CYASSL*);
+
+    CYASSL_LOCAL DtlsMsg* DtlsMsgNew(word32, void*);
+    CYASSL_LOCAL void DtlsMsgDelete(DtlsMsg*, void*);
+    CYASSL_LOCAL void DtlsMsgListDelete(DtlsMsg*, void*);
+    CYASSL_LOCAL void DtlsMsgSet(DtlsMsg*, word32, const byte*, byte,
+                                                             word32, word32);
+    CYASSL_LOCAL DtlsMsg* DtlsMsgFind(DtlsMsg*, word32);
+    CYASSL_LOCAL DtlsMsg* DtlsMsgStore(DtlsMsg*, word32, const byte*, word32,
+                                                byte, word32, word32, void*);
+    CYASSL_LOCAL DtlsMsg* DtlsMsgInsert(DtlsMsg*, DtlsMsg*);
+#endif /* CYASSL_DTLS */
+
+#ifndef NO_TLS
+    
+
+#endif /* NO_TLS */
+
+
+CYASSL_LOCAL word32  LowResTimer(void);
+
+CYASSL_LOCAL void InitX509(CYASSL_X509*, int);
+CYASSL_LOCAL void FreeX509(CYASSL_X509*);
+#ifndef NO_CERTS
+    CYASSL_LOCAL int  CopyDecodedToX509(CYASSL_X509*, DecodedCert*);
+#endif
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+#endif /* CyaSSL_INT_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ocsp.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,54 @@
+/* ocsp.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/* CyaSSL OCSP API */
+
+#ifndef CYASSL_OCSP_H
+#define CYASSL_OCSP_H
+
+#ifdef HAVE_OCSP
+
+#include <cyassl/ssl.h>
+#include <cyassl/ctaocrypt/asn.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+typedef struct CYASSL_OCSP CYASSL_OCSP;
+
+CYASSL_LOCAL int  CyaSSL_OCSP_Init(CYASSL_OCSP*);
+CYASSL_LOCAL void CyaSSL_OCSP_Cleanup(CYASSL_OCSP*);
+
+CYASSL_LOCAL int  CyaSSL_OCSP_set_override_url(CYASSL_OCSP*, const char*);
+CYASSL_LOCAL int  CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP*, DecodedCert*);
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+
+#endif /* HAVE_OCSP */
+#endif /* CYASSL_OCSP_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/asn1.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,2 @@
+/* asn1.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/bio.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,23 @@
+/* bio.h for openssl */
+
+
+#ifndef CYASSL_BIO_H_
+#define CYASSL_BIO_H_
+
+#include <cyassl/openssl/ssl.h>
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */ 
+#endif
+
+
+#endif /* CYASSL_BIO_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/bn.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,115 @@
+/* bn.h for openssl */
+
+
+#ifndef CYASSL_BN_H_
+#define CYASSL_BN_H_
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+typedef struct CYASSL_BIGNUM {
+    int   neg;              /* openssh deference */
+    void* internal;         /* our big num */
+} CYASSL_BIGNUM;        
+
+
+typedef struct CYASSL_BN_CTX CYASSL_BN_CTX;
+
+
+CYASSL_API CYASSL_BN_CTX* CyaSSL_BN_CTX_new(void);
+CYASSL_API void           CyaSSL_BN_CTX_init(CYASSL_BN_CTX*);
+CYASSL_API void           CyaSSL_BN_CTX_free(CYASSL_BN_CTX*);
+
+CYASSL_API CYASSL_BIGNUM* CyaSSL_BN_new(void);
+CYASSL_API void           CyaSSL_BN_free(CYASSL_BIGNUM*);
+CYASSL_API void           CyaSSL_BN_clear_free(CYASSL_BIGNUM*);
+
+
+CYASSL_API int CyaSSL_BN_sub(CYASSL_BIGNUM*, const CYASSL_BIGNUM*,
+	                         const CYASSL_BIGNUM*);
+CYASSL_API int CyaSSL_BN_mod(CYASSL_BIGNUM*, const CYASSL_BIGNUM*,
+	                         const CYASSL_BIGNUM*, const CYASSL_BN_CTX*);
+
+CYASSL_API const CYASSL_BIGNUM* CyaSSL_BN_value_one(void);
+
+
+CYASSL_API int CyaSSL_BN_num_bytes(const CYASSL_BIGNUM*);
+CYASSL_API int CyaSSL_BN_num_bits(const CYASSL_BIGNUM*);
+
+CYASSL_API int CyaSSL_BN_is_zero(const CYASSL_BIGNUM*);
+CYASSL_API int CyaSSL_BN_is_one(const CYASSL_BIGNUM*);
+CYASSL_API int CyaSSL_BN_is_odd(const CYASSL_BIGNUM*);
+
+CYASSL_API int CyaSSL_BN_cmp(const CYASSL_BIGNUM*, const CYASSL_BIGNUM*);
+
+CYASSL_API int CyaSSL_BN_bn2bin(const CYASSL_BIGNUM*, unsigned char*);
+CYASSL_API CYASSL_BIGNUM* CyaSSL_BN_bin2bn(const unsigned char*, int len,
+	                            CYASSL_BIGNUM* ret);
+
+CYASSL_API int CyaSSL_mask_bits(CYASSL_BIGNUM*, int n);
+
+CYASSL_API int CyaSSL_BN_rand(CYASSL_BIGNUM*, int bits, int top, int bottom);
+CYASSL_API int CyaSSL_BN_is_bit_set(const CYASSL_BIGNUM*, int n);
+CYASSL_API int CyaSSL_BN_hex2bn(CYASSL_BIGNUM**, const char* str);
+
+CYASSL_API CYASSL_BIGNUM* CyaSSL_BN_dup(const CYASSL_BIGNUM*);
+CYASSL_API CYASSL_BIGNUM* CyaSSL_BN_copy(CYASSL_BIGNUM*, const CYASSL_BIGNUM*);
+
+CYASSL_API int CyaSSL_BN_set_word(CYASSL_BIGNUM*, unsigned long w);
+
+CYASSL_API int   CyaSSL_BN_dec2bn(CYASSL_BIGNUM**, const char* str);
+CYASSL_API char* CyaSSL_BN_bn2dec(const CYASSL_BIGNUM*);
+
+
+typedef CYASSL_BIGNUM BIGNUM;
+typedef CYASSL_BN_CTX BN_CTX;
+
+#define BN_CTX_new        CyaSSL_BN_CTX_new
+#define BN_CTX_init       CyaSSL_BN_CTX_init
+#define BN_CTX_free       CyaSSL_BN_CTX_free
+
+#define BN_new        CyaSSL_BN_new
+#define BN_free       CyaSSL_BN_free
+#define BN_clear_free CyaSSL_BN_clear_free
+
+#define BN_num_bytes CyaSSL_BN_num_bytes
+#define BN_num_bits  CyaSSL_BN_num_bits
+
+#define BN_is_zero  CyaSSL_BN_is_zero
+#define BN_is_one   CyaSSL_BN_is_one
+#define BN_is_odd   CyaSSL_BN_is_odd
+
+#define BN_cmp    CyaSSL_BN_cmp
+
+#define BN_bn2bin  CyaSSL_BN_bn2bin
+#define BN_bin2bn  CyaSSL_BN_bin2bn
+
+#define BN_mod       CyaSSL_BN_mod
+#define BN_sub       CyaSSL_BN_sub
+#define BN_value_one CyaSSL_BN_value_one
+
+#define BN_mask_bits CyaSSL_mask_bits
+
+#define BN_rand       CyaSSL_BN_rand
+#define BN_is_bit_set CyaSSL_BN_is_bit_set
+#define BN_hex2bn     CyaSSL_BN_hex2bn
+
+#define BN_dup  CyaSSL_BN_dup
+#define BN_copy CyaSSL_BN_copy
+
+#define BN_set_word CyaSSL_BN_set_word
+
+#define BN_dec2bn CyaSSL_BN_dec2bn
+#define BN_bn2dec CyaSSL_BN_bn2dec
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */ 
+#endif
+
+
+#endif /* CYASSL__H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/conf.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,2 @@
+/* conf.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/crypto.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,26 @@
+/* crypto.h for openSSL */
+
+#ifndef CYASSL_CRYPTO_H_
+#define CYASSL_CRYPTO_H_
+
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef YASSL_PREFIX
+#include "prefix_crypto.h"
+#endif
+
+
+CYASSL_API const char*   CyaSSLeay_version(int type);
+CYASSL_API unsigned long CyaSSLeay(void);
+
+#define SSLeay_version CyaSSLeay_version
+#define SSLeay CyaSSLeay
+
+
+#define SSLEAY_VERSION 0x0090600fL
+#define SSLEAY_VERSION_NUMBER SSLEAY_VERSION
+
+
+#endif /* header */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/des.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,87 @@
+/* des.h
+ *
+ * Copyright (C) 2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/*  des.h defines mini des openssl compatibility layer 
+ *
+ */
+
+
+#ifndef CYASSL_DES_H_
+#define CYASSL_DES_H_
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef YASSL_PREFIX
+#include "prefix_des.h"
+#endif
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+typedef unsigned char CYASSL_DES_cblock[8];
+typedef /* const */ CYASSL_DES_cblock CYASSL_const_DES_cblock;
+typedef CYASSL_DES_cblock CYASSL_DES_key_schedule;
+
+
+enum {
+    DES_ENCRYPT = 1,
+    DES_DECRYPT = 0
+};
+
+
+CYASSL_API void CyaSSL_DES_set_key_unchecked(CYASSL_const_DES_cblock*,
+                                             CYASSL_DES_key_schedule*);
+CYASSL_API int  CyaSSL_DES_key_sched(CYASSL_const_DES_cblock* key,
+                                     CYASSL_DES_key_schedule* schedule);
+CYASSL_API void CyaSSL_DES_cbc_encrypt(const unsigned char* input,
+                     unsigned char* output, long length,
+                     CYASSL_DES_key_schedule* schedule, CYASSL_DES_cblock* ivec,
+                     int enc);
+CYASSL_API void CyaSSL_DES_ncbc_encrypt(const unsigned char* input,
+                      unsigned char* output, long length,
+                      CYASSL_DES_key_schedule* schedule,
+                      CYASSL_DES_cblock* ivec, int enc);
+
+CYASSL_API void CyaSSL_DES_set_odd_parity(CYASSL_DES_cblock*);
+CYASSL_API void CyaSSL_DES_ecb_encrypt(CYASSL_DES_cblock*, CYASSL_DES_cblock*,
+                                       CYASSL_DES_key_schedule*, int);
+
+
+typedef CYASSL_DES_cblock DES_cblock;
+typedef CYASSL_const_DES_cblock const_DES_cblock;
+typedef CYASSL_DES_key_schedule DES_key_schedule;
+
+#define DES_set_key_unchecked CyaSSL_DES_set_key_unchecked
+#define DES_key_sched CyaSSL_DES_key_sched
+#define DES_cbc_encrypt CyaSSL_DES_cbc_encrypt
+#define DES_ncbc_encrypt CyaSSL_DES_ncbc_encrypt
+#define DES_set_odd_parity CyaSSL_DES_set_odd_parity
+#define DES_ecb_encrypt CyaSSL_DES_ecb_encrypt
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* CYASSL_DES_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/dh.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,52 @@
+/* dh.h for openSSL */
+
+
+#ifndef CYASSL_DH_H_
+#define CYASSL_DH_H_
+
+
+#include <cyassl/openssl/ssl.h>
+#include <cyassl/openssl/bn.h>
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+
+
+typedef struct CYASSL_DH {
+	CYASSL_BIGNUM* p;
+	CYASSL_BIGNUM* g;
+    CYASSL_BIGNUM* pub_key;      /* openssh deference g^x */
+    CYASSL_BIGNUM* priv_key;     /* openssh deference x   */
+    void*          internal;     /* our DH */
+    char           inSet;        /* internal set from external ? */
+    char           exSet;        /* external set from internal ? */
+} CYASSL_DH;
+
+
+CYASSL_API CYASSL_DH* CyaSSL_DH_new(void);
+CYASSL_API void       CyaSSL_DH_free(CYASSL_DH*);
+
+CYASSL_API int CyaSSL_DH_size(CYASSL_DH*);
+CYASSL_API int CyaSSL_DH_generate_key(CYASSL_DH*);
+CYASSL_API int CyaSSL_DH_compute_key(unsigned char* key, CYASSL_BIGNUM* pub,
+                                     CYASSL_DH*);
+
+typedef CYASSL_DH DH;
+
+#define DH_new  CyaSSL_DH_new 
+#define DH_free CyaSSL_DH_free
+
+#define DH_size         CyaSSL_DH_size
+#define DH_generate_key CyaSSL_DH_generate_key
+#define DH_compute_key  CyaSSL_DH_compute_key
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */ 
+#endif
+
+#endif /* header */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/dsa.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,53 @@
+/* dsa.h for openSSL */
+
+
+#ifndef CYASSL_DSA_H_
+#define CYASSL_DSA_H_
+
+
+#include <cyassl/openssl/ssl.h>
+#include <cyassl/openssl/bn.h>
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+
+struct CYASSL_DSA {
+	CYASSL_BIGNUM* p;
+	CYASSL_BIGNUM* q;
+	CYASSL_BIGNUM* g;
+	CYASSL_BIGNUM* pub_key;      /* our y */
+	CYASSL_BIGNUM* priv_key;     /* our x */
+    void*          internal;     /* our Dsa Key */
+    char           inSet;        /* internal set from external ? */
+    char           exSet;        /* external set from internal ? */
+};
+
+
+CYASSL_API CYASSL_DSA* CyaSSL_DSA_new(void);
+CYASSL_API void        CyaSSL_DSA_free(CYASSL_DSA*);
+
+CYASSL_API int CyaSSL_DSA_generate_key(CYASSL_DSA*);
+CYASSL_API int CyaSSL_DSA_generate_parameters_ex(CYASSL_DSA*, int bits,
+                   unsigned char* seed, int seedLen, int* counterRet,
+                   unsigned long* hRet, void* cb);
+
+CYASSL_API int CyaSSL_DSA_LoadDer(CYASSL_DSA*, const unsigned char*, int sz);
+CYASSL_API int CyaSSL_DSA_do_sign(const unsigned char* d, unsigned char* sigRet,
+                                  CYASSL_DSA* dsa);
+
+#define DSA_new CyaSSL_DSA_new
+#define DSA_free CyaSSL_DSA_free
+
+#define DSA_generate_key           CyaSSL_DSA_generate_key
+#define DSA_generate_parameters_ex CyaSSL_DSA_generate_parameters_ex
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */ 
+#endif
+
+#endif /* header */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/ec.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,2 @@
+/* ec.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/ecdsa.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,2 @@
+/* ecdsa.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/engine.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,5 @@
+/* engine.h for libcurl */
+
+#undef HAVE_OPENSSL_ENGINE_H
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/err.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,2 @@
+/* err.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/evp.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,241 @@
+/* evp.h
+ *
+ * Copyright (C) 2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/*  evp.h defines mini evp openssl compatibility layer 
+ *
+ */
+
+
+#ifndef CYASSL_EVP_H_
+#define CYASSL_EVP_H_
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef YASSL_PREFIX
+#include "prefix_evp.h"
+#endif
+
+#include <cyassl/openssl/md5.h>
+#include <cyassl/openssl/sha.h>
+#include <cyassl/openssl/ripemd.h>
+#include <cyassl/openssl/rsa.h>
+#include <cyassl/openssl/dsa.h>
+
+#include <cyassl/ctaocrypt/aes.h>
+#include <cyassl/ctaocrypt/des3.h>
+#include <cyassl/ctaocrypt/arc4.h>
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+typedef char CYASSL_EVP_MD;
+typedef char CYASSL_EVP_CIPHER;
+
+CYASSL_API const CYASSL_EVP_MD* CyaSSL_EVP_md5(void);
+CYASSL_API const CYASSL_EVP_MD* CyaSSL_EVP_sha1(void);
+CYASSL_API const CYASSL_EVP_MD* CyaSSL_EVP_sha256(void);
+CYASSL_API const CYASSL_EVP_MD* CyaSSL_EVP_sha384(void);
+CYASSL_API const CYASSL_EVP_MD* CyaSSL_EVP_sha512(void);
+CYASSL_API const CYASSL_EVP_MD* CyaSSL_EVP_ripemd160(void);
+
+CYASSL_API const CYASSL_EVP_CIPHER* CyaSSL_EVP_aes_128_cbc(void);
+CYASSL_API const CYASSL_EVP_CIPHER* CyaSSL_EVP_aes_192_cbc(void);
+CYASSL_API const CYASSL_EVP_CIPHER* CyaSSL_EVP_aes_256_cbc(void);
+CYASSL_API const CYASSL_EVP_CIPHER* CyaSSL_EVP_aes_128_ctr(void);
+CYASSL_API const CYASSL_EVP_CIPHER* CyaSSL_EVP_aes_192_ctr(void);
+CYASSL_API const CYASSL_EVP_CIPHER* CyaSSL_EVP_aes_256_ctr(void);
+CYASSL_API const CYASSL_EVP_CIPHER* CyaSSL_EVP_des_cbc(void);
+CYASSL_API const CYASSL_EVP_CIPHER* CyaSSL_EVP_des_ede3_cbc(void);
+CYASSL_API const CYASSL_EVP_CIPHER* CyaSSL_EVP_rc4(void);
+CYASSL_API const CYASSL_EVP_CIPHER* CyaSSL_EVP_enc_null(void);
+
+
+typedef union {
+    CYASSL_MD5_CTX    md5;
+    CYASSL_SHA_CTX    sha;
+    CYASSL_SHA256_CTX sha256;
+    #ifdef CYASSL_SHA384
+        CYASSL_SHA384_CTX sha384;
+    #endif
+    #ifdef CYASSL_SHA512
+        CYASSL_SHA512_CTX sha512;
+    #endif
+    #ifdef CYASSL_RIPEMD
+        CYASSL_RIPEMD_CTX ripemd;
+    #endif
+} CYASSL_Hasher;
+
+
+typedef struct CYASSL_EVP_MD_CTX {
+    unsigned char macType;
+    CYASSL_Hasher hash;
+} CYASSL_EVP_MD_CTX;
+
+
+typedef union {
+    Aes  aes;
+#ifndef NO_DES3
+    Des  des;
+    Des3 des3;
+#endif
+    Arc4 arc4;
+} CYASSL_Cipher;
+
+
+enum {
+    AES_128_CBC_TYPE  = 1,
+    AES_192_CBC_TYPE  = 2,
+    AES_256_CBC_TYPE  = 3,
+    AES_128_CTR_TYPE  = 4,
+    AES_192_CTR_TYPE  = 5,
+    AES_256_CTR_TYPE  = 6,
+    DES_CBC_TYPE      = 7,
+    DES_EDE3_CBC_TYPE = 8,
+    ARC4_TYPE         = 9,
+    NULL_CIPHER_TYPE  = 10,
+    EVP_PKEY_RSA      = 11,
+    EVP_PKEY_DSA      = 12,
+    NID_sha1          = 64,
+    NID_md5           =  4
+};
+
+
+typedef struct CYASSL_EVP_CIPHER_CTX {
+    int            keyLen;         /* user may set for variable */
+    unsigned char  enc;            /* if encrypt side, then true */
+    unsigned char  cipherType;
+    unsigned char  iv[AES_BLOCK_SIZE];    /* working iv pointer into cipher */
+    CYASSL_Cipher  cipher;
+} CYASSL_EVP_CIPHER_CTX;
+
+
+CYASSL_API int  CyaSSL_EVP_MD_size(const CYASSL_EVP_MD* md);
+CYASSL_API void CyaSSL_EVP_MD_CTX_init(CYASSL_EVP_MD_CTX* ctx);
+CYASSL_API int  CyaSSL_EVP_MD_CTX_cleanup(CYASSL_EVP_MD_CTX* ctx);
+
+CYASSL_API int CyaSSL_EVP_DigestInit(CYASSL_EVP_MD_CTX* ctx,
+                                     const CYASSL_EVP_MD* type);
+CYASSL_API int CyaSSL_EVP_DigestUpdate(CYASSL_EVP_MD_CTX* ctx, const void* data,
+                                       unsigned long sz);
+CYASSL_API int CyaSSL_EVP_DigestFinal(CYASSL_EVP_MD_CTX* ctx, unsigned char* md,
+                                      unsigned int* s);
+CYASSL_API int CyaSSL_EVP_DigestFinal_ex(CYASSL_EVP_MD_CTX* ctx,
+                                            unsigned char* md, unsigned int* s);
+CYASSL_API int CyaSSL_EVP_BytesToKey(const CYASSL_EVP_CIPHER*,
+                              const CYASSL_EVP_MD*, const unsigned char*,
+                              const unsigned char*, int, int, unsigned char*,
+                              unsigned char*);
+
+CYASSL_API void CyaSSL_EVP_CIPHER_CTX_init(CYASSL_EVP_CIPHER_CTX* ctx);
+CYASSL_API int  CyaSSL_EVP_CIPHER_CTX_cleanup(CYASSL_EVP_CIPHER_CTX* ctx);
+
+CYASSL_API int  CyaSSL_EVP_CIPHER_CTX_iv_length(const CYASSL_EVP_CIPHER_CTX*);
+
+
+CYASSL_API int  CyaSSL_EVP_CipherInit(CYASSL_EVP_CIPHER_CTX* ctx,
+                                    const CYASSL_EVP_CIPHER* type,
+                                    unsigned char* key, unsigned char* iv,
+                                    int enc);
+CYASSL_API int  CyaSSL_EVP_CIPHER_CTX_key_length(CYASSL_EVP_CIPHER_CTX* ctx);
+CYASSL_API int  CyaSSL_EVP_CIPHER_CTX_set_key_length(CYASSL_EVP_CIPHER_CTX* ctx,
+                                                     int keylen);
+CYASSL_API int  CyaSSL_EVP_Cipher(CYASSL_EVP_CIPHER_CTX* ctx,
+                          unsigned char* dst, unsigned char* src,
+                          unsigned int len);
+
+CYASSL_API const CYASSL_EVP_MD* CyaSSL_EVP_get_digestbynid(int);
+
+CYASSL_API CYASSL_RSA* CyaSSL_EVP_PKEY_get1_RSA(CYASSL_EVP_PKEY*);
+CYASSL_API CYASSL_DSA* CyaSSL_EVP_PKEY_get1_DSA(CYASSL_EVP_PKEY*);
+
+/* these next ones don't need real OpenSSL type, for OpenSSH compat only */
+CYASSL_API void* CyaSSL_EVP_X_STATE(const CYASSL_EVP_CIPHER_CTX* ctx);
+CYASSL_API int   CyaSSL_EVP_X_STATE_LEN(const CYASSL_EVP_CIPHER_CTX* ctx);
+
+CYASSL_API void  CyaSSL_3des_iv(CYASSL_EVP_CIPHER_CTX* ctx, int doset,
+                                unsigned char* iv, int len);
+CYASSL_API void  CyaSSL_aes_ctr_iv(CYASSL_EVP_CIPHER_CTX* ctx, int doset,
+                                unsigned char* iv, int len);
+
+CYASSL_API int  CyaSSL_StoreExternalIV(CYASSL_EVP_CIPHER_CTX* ctx);
+CYASSL_API int  CyaSSL_SetInternalIV(CYASSL_EVP_CIPHER_CTX* ctx);
+
+
+/* end OpenSSH compat */
+
+typedef CYASSL_EVP_MD         EVP_MD;
+typedef CYASSL_EVP_CIPHER     EVP_CIPHER;
+typedef CYASSL_EVP_MD_CTX     EVP_MD_CTX;
+typedef CYASSL_EVP_CIPHER_CTX EVP_CIPHER_CTX;
+
+#define EVP_md5       CyaSSL_EVP_md5
+#define EVP_sha1      CyaSSL_EVP_sha1
+#define EVP_sha256    CyaSSL_EVP_sha256
+#define EVP_sha384    CyaSSL_EVP_sha384
+#define EVP_sha512    CyaSSL_EVP_sha512
+#define EVP_ripemd160 CyaSSL_EVP_ripemd160
+
+#define EVP_aes_128_cbc  CyaSSL_EVP_aes_128_cbc
+#define EVP_aes_192_cbc  CyaSSL_EVP_aes_192_cbc
+#define EVP_aes_256_cbc  CyaSSL_EVP_aes_256_cbc
+#define EVP_aes_128_ctr  CyaSSL_EVP_aes_128_ctr
+#define EVP_aes_192_ctr  CyaSSL_EVP_aes_192_ctr
+#define EVP_aes_256_ctr  CyaSSL_EVP_aes_256_ctr
+#define EVP_des_cbc      CyaSSL_EVP_des_cbc
+#define EVP_des_ede3_cbc CyaSSL_EVP_des_ede3_cbc
+#define EVP_rc4          CyaSSL_EVP_rc4
+#define EVP_enc_null     CyaSSL_EVP_enc_null
+
+#define EVP_MD_size        CyaSSL_EVP_MD_size
+#define EVP_MD_CTX_init    CyaSSL_EVP_MD_CTX_init
+#define EVP_MD_CTX_cleanup CyaSSL_EVP_MD_CTX_cleanup
+#define EVP_DigestInit     CyaSSL_EVP_DigestInit
+#define EVP_DigestUpdate   CyaSSL_EVP_DigestUpdate
+#define EVP_DigestFinal    CyaSSL_EVP_DigestFinal
+#define EVP_DigestFinal_ex CyaSSL_EVP_DigestFinal_ex
+#define EVP_BytesToKey     CyaSSL_EVP_BytesToKey
+
+#define EVP_CIPHER_CTX_init           CyaSSL_EVP_CIPHER_CTX_init
+#define EVP_CIPHER_CTX_cleanup        CyaSSL_EVP_CIPHER_CTX_cleanup
+#define EVP_CIPHER_CTX_iv_length      CyaSSL_EVP_CIPHER_CTX_iv_length
+#define EVP_CIPHER_CTX_key_length     CyaSSL_EVP_CIPHER_CTX_key_length
+#define EVP_CIPHER_CTX_set_key_length CyaSSL_EVP_CIPHER_CTX_set_key_length
+#define EVP_CipherInit                CyaSSL_EVP_CipherInit
+#define EVP_Cipher                    CyaSSL_EVP_Cipher
+
+#define EVP_get_digestbynid           CyaSSL_EVP_get_digestbynid
+
+#define EVP_PKEY_get1_RSA   CyaSSL_EVP_PKEY_get1_RSA
+#define EVP_PKEY_get1_DSA   CyaSSL_EVP_PKEY_get1_DSA
+
+#ifndef EVP_MAX_MD_SIZE
+    #define EVP_MAX_MD_SIZE   64     /* sha512 */
+#endif
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* CYASSL_EVP_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/hmac.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,81 @@
+/* hmac.h
+ *
+ * Copyright (C) 2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/*  hmac.h defines mini hamc openssl compatibility layer 
+ *
+ */
+
+
+#ifndef CYASSL_HMAC_H_
+#define CYASSL_HMAC_H_
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef YASSL_PREFIX
+#include "prefix_hmac.h"
+#endif
+
+#include <cyassl/openssl/evp.h>
+#include <cyassl/ctaocrypt/hmac.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+CYASSL_API unsigned char* CyaSSL_HMAC(const CYASSL_EVP_MD* evp_md,
+                               const void* key, int key_len,
+                               const unsigned char* d, int n, unsigned char* md,
+                               unsigned int* md_len);
+
+
+typedef struct CYASSL_HMAC_CTX {
+    Hmac hmac;
+    int  type;
+} CYASSL_HMAC_CTX;
+
+
+CYASSL_API void CyaSSL_HMAC_Init(CYASSL_HMAC_CTX* ctx, const void* key,
+                                 int keylen, const EVP_MD* type);
+CYASSL_API void CyaSSL_HMAC_Update(CYASSL_HMAC_CTX* ctx,
+                                   const unsigned char* data, int len);
+CYASSL_API void CyaSSL_HMAC_Final(CYASSL_HMAC_CTX* ctx, unsigned char* hash,
+                                  unsigned int* len);
+CYASSL_API void CyaSSL_HMAC_cleanup(CYASSL_HMAC_CTX* ctx);
+
+
+typedef struct CYASSL_HMAC_CTX HMAC_CTX;
+
+#define HMAC(a,b,c,d,e,f,g) CyaSSL_HMAC((a),(b),(c),(d),(e),(f),(g))
+
+#define HMAC_Init    CyaSSL_HMAC_Init
+#define HMAC_Update  CyaSSL_HMAC_Update
+#define HMAC_Final   CyaSSL_HMAC_Final
+#define HMAC_cleanup CyaSSL_HMAC_cleanup
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* CYASSL_HMAC_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/lhash.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,2 @@
+/* lhash.h for openSSL */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/md4.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,1 @@
+/* md4.h for libcurl */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/md5.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,39 @@
+/* md5.h for openssl */
+
+
+#ifndef CYASSL_MD5_H_
+#define CYASSL_MD5_H_
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef YASSL_PREFIX
+#include "prefix_md5.h"
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+typedef struct CYASSL_MD5_CTX {
+    int holder[24];   /* big enough to hold ctaocrypt md5, but check on init */
+} CYASSL_MD5_CTX;
+
+CYASSL_API void CyaSSL_MD5_Init(CYASSL_MD5_CTX*);
+CYASSL_API void CyaSSL_MD5_Update(CYASSL_MD5_CTX*, const void*, unsigned long);
+CYASSL_API void CyaSSL_MD5_Final(unsigned char*, CYASSL_MD5_CTX*);
+
+
+typedef CYASSL_MD5_CTX MD5_CTX;
+
+#define MD5_Init CyaSSL_MD5_Init
+#define MD5_Update CyaSSL_MD5_Update
+#define MD5_Final CyaSSL_MD5_Final
+
+#ifdef __cplusplus
+    }  /* extern "C" */ 
+#endif
+
+
+#endif /* CYASSL_MD5_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/ocsp.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,1 @@
+/* ocsp.h for libcurl */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/opensslconf.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,8 @@
+/* opensslconf.h for openSSL */
+
+
+#ifndef OPENSSL_THREADS
+    #define OPENSSL_THREADS
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/opensslv.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,12 @@
+/* opensslv.h compatibility */
+
+#ifndef CYASSL_OPENSSLV_H_
+#define CYASSL_OPENSSLV_H_
+
+
+/* api version compatibility */
+#define OPENSSL_VERSION_NUMBER 0x0090410fL
+
+
+#endif /* header */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/ossl_typ.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,2 @@
+/* ossl_typ.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/pem.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,41 @@
+/* pem.h for openssl */
+
+
+#ifndef CYASSL_PEM_H_
+#define CYASSL_PEM_H_
+
+#include <cyassl/openssl/evp.h>
+#include <cyassl/openssl/bio.h>
+#include <cyassl/openssl/rsa.h>
+#include <cyassl/openssl/dsa.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+CYASSL_API int CyaSSL_PEM_write_bio_RSAPrivateKey(CYASSL_BIO* bio, RSA* rsa,
+	                                  const EVP_CIPHER* cipher,
+	                                  unsigned char* passwd, int len,
+	                                  pem_password_cb cb, void* arg);
+
+CYASSL_API int CyaSSL_PEM_write_bio_DSAPrivateKey(CYASSL_BIO* bio, DSA* rsa,
+	                                  const EVP_CIPHER* cipher,
+	                                  unsigned char* passwd, int len,
+	                                  pem_password_cb cb, void* arg);
+
+CYASSL_API CYASSL_EVP_PKEY* CyaSSL_PEM_read_bio_PrivateKey(CYASSL_BIO* bio,
+                        CYASSL_EVP_PKEY**, pem_password_cb cb, void* arg); 
+
+#define PEM_write_bio_RSAPrivateKey CyaSSL_PEM_write_bio_RSAPrivateKey
+#define PEM_write_bio_DSAPrivateKey CyaSSL_PEM_write_bio_DSAPrivateKey
+#define PEM_read_bio_PrivateKey     CyaSSL_PEM_read_bio_PrivateKey
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */ 
+#endif
+
+
+#endif /* CYASSL_PEM_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/pkcs12.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,2 @@
+/* pkcs12.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/rand.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,4 @@
+/* rand.h for openSSL */
+
+#include <cyassl/openssl/ssl.h>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/ripemd.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,37 @@
+/* ripemd.h for openssl */
+
+
+#ifndef CYASSL_RIPEMD_H_
+#define CYASSL_RIPEMD_H_
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+typedef struct CYASSL_RIPEMD_CTX {
+    int holder[32];   /* big enough to hold ctaocrypt, but check on init */
+} CYASSL_RIPEMD_CTX;
+
+CYASSL_API void CyaSSL_RIPEMD_Init(CYASSL_RIPEMD_CTX*);
+CYASSL_API void CyaSSL_RIPEMD_Update(CYASSL_RIPEMD_CTX*, const void*,
+                                     unsigned long);
+CYASSL_API void CyaSSL_RIPEMD_Final(unsigned char*, CYASSL_RIPEMD_CTX*);
+
+
+typedef CYASSL_RIPEMD_CTX RIPEMD_CTX;
+
+#define RIPEMD_Init   CyaSSL_RIPEMD_Init
+#define RIPEMD_Update CyaSSL_RIPEMD_Update
+#define RIPEMD_Final  CyaSSL_RIPEMD_Final
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */ 
+#endif
+
+
+#endif /* CYASSL_MD5_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/rsa.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,75 @@
+/* rsa.h for openSSL */
+
+
+#ifndef CYASSL_RSA_H_
+#define CYASSL_RSA_H_
+
+#include <cyassl/openssl/ssl.h>
+#include <cyassl/openssl/bn.h>
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+enum  { 
+	RSA_PKCS1_PADDING = 1
+ };
+
+struct CYASSL_RSA {
+	CYASSL_BIGNUM* n;
+	CYASSL_BIGNUM* e;
+	CYASSL_BIGNUM* d;
+	CYASSL_BIGNUM* p;
+	CYASSL_BIGNUM* q;
+	CYASSL_BIGNUM* dmp1;      /* dP */
+	CYASSL_BIGNUM* dmq1;      /* dQ */
+	CYASSL_BIGNUM* iqmp;      /* u */
+    void*          internal;  /* our RSA */
+    char           inSet;     /* internal set from external ? */
+    char           exSet;     /* external set from internal ? */
+};
+
+
+CYASSL_API CYASSL_RSA* CyaSSL_RSA_new(void);
+CYASSL_API void        CyaSSL_RSA_free(CYASSL_RSA*);
+
+CYASSL_API int CyaSSL_RSA_generate_key_ex(CYASSL_RSA*, int bits, CYASSL_BIGNUM*,
+                                          void* cb);
+
+CYASSL_API int CyaSSL_RSA_blinding_on(CYASSL_RSA*, CYASSL_BN_CTX*);
+CYASSL_API int CyaSSL_RSA_public_encrypt(int len, unsigned char* fr,
+	                               unsigned char* to, CYASSL_RSA*, int padding);
+CYASSL_API int CyaSSL_RSA_private_decrypt(int len, unsigned char* fr,
+	                               unsigned char* to, CYASSL_RSA*, int padding);
+
+CYASSL_API int CyaSSL_RSA_size(const CYASSL_RSA*);
+CYASSL_API int CyaSSL_RSA_sign(int type, const unsigned char* m,
+                               unsigned int mLen, unsigned char* sigRet,
+                               unsigned int* sigLen, CYASSL_RSA*);
+CYASSL_API int CyaSSL_RSA_public_decrypt(int flen, unsigned char* from,
+                                  unsigned char* to, CYASSL_RSA*, int padding);
+CYASSL_API int CyaSSL_RSA_GenAdd(CYASSL_RSA*);
+CYASSL_API int CyaSSL_RSA_LoadDer(CYASSL_RSA*, const unsigned char*, int sz);
+
+
+#define RSA_new  CyaSSL_RSA_new
+#define RSA_free CyaSSL_RSA_free
+
+#define RSA_generate_key_ex CyaSSL_RSA_generate_key_ex
+
+#define RSA_blinding_on     CyaSSL_RSA_blinding_on
+#define RSA_public_encrypt  CyaSSL_RSA_public_encrypt
+#define RSA_private_decrypt CyaSSL_RSA_private_decrypt
+
+#define RSA_size           CyaSSL_RSA_size
+#define RSA_sign           CyaSSL_RSA_sign
+#define RSA_public_decrypt CyaSSL_RSA_public_decrypt
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */ 
+#endif
+
+#endif /* header */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/sha.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,125 @@
+/* sha.h for openssl */
+
+
+#ifndef CYASSL_SHA_H_
+#define CYASSL_SHA_H_
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef YASSL_PREFIX
+#include "prefix_sha.h"
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+typedef struct CYASSL_SHA_CTX {
+    int holder[24];   /* big enough to hold ctaocrypt sha, but check on init */
+} CYASSL_SHA_CTX;
+
+CYASSL_API void CyaSSL_SHA_Init(CYASSL_SHA_CTX*);
+CYASSL_API void CyaSSL_SHA_Update(CYASSL_SHA_CTX*, const void*, unsigned long);
+CYASSL_API void CyaSSL_SHA_Final(unsigned char*, CYASSL_SHA_CTX*);
+
+/* SHA1 points to above, shouldn't use SHA0 ever */
+CYASSL_API void CyaSSL_SHA1_Init(CYASSL_SHA_CTX*);
+CYASSL_API void CyaSSL_SHA1_Update(CYASSL_SHA_CTX*, const void*, unsigned long);
+CYASSL_API void CyaSSL_SHA1_Final(unsigned char*, CYASSL_SHA_CTX*);
+
+enum {
+    SHA_DIGEST_LENGTH = 20
+};
+
+
+typedef CYASSL_SHA_CTX SHA_CTX;
+
+#define SHA_Init CyaSSL_SHA_Init
+#define SHA_Update CyaSSL_SHA_Update
+#define SHA_Final CyaSSL_SHA_Final
+
+#define SHA1_Init CyaSSL_SHA1_Init
+#define SHA1_Update CyaSSL_SHA1_Update
+#define SHA1_Final CyaSSL_SHA1_Final
+
+
+typedef struct CYASSL_SHA256_CTX {
+    int holder[28];   /* big enough to hold ctaocrypt sha, but check on init */
+} CYASSL_SHA256_CTX;
+
+CYASSL_API void CyaSSL_SHA256_Init(CYASSL_SHA256_CTX*);
+CYASSL_API void CyaSSL_SHA256_Update(CYASSL_SHA256_CTX*, const void*,
+	                                 unsigned long);
+CYASSL_API void CyaSSL_SHA256_Final(unsigned char*, CYASSL_SHA256_CTX*);
+
+enum {
+    SHA256_DIGEST_LENGTH = 32 
+};
+
+
+typedef CYASSL_SHA256_CTX SHA256_CTX;
+
+#define SHA256_Init   CyaSSL_SHA256_Init
+#define SHA256_Update CyaSSL_SHA256_Update
+#define SHA256_Final  CyaSSL_SHA256_Final
+
+
+#ifdef CYASSL_SHA384
+
+typedef struct CYASSL_SHA384_CTX {
+    long long holder[32];   /* big enough, but check on init */
+} CYASSL_SHA384_CTX;
+
+CYASSL_API void CyaSSL_SHA384_Init(CYASSL_SHA384_CTX*);
+CYASSL_API void CyaSSL_SHA384_Update(CYASSL_SHA384_CTX*, const void*,
+	                                 unsigned long);
+CYASSL_API void CyaSSL_SHA384_Final(unsigned char*, CYASSL_SHA384_CTX*);
+
+enum {
+    SHA384_DIGEST_LENGTH = 48 
+};
+
+
+typedef CYASSL_SHA384_CTX SHA384_CTX;
+
+#define SHA384_Init   CyaSSL_SHA384_Init
+#define SHA384_Update CyaSSL_SHA384_Update
+#define SHA384_Final  CyaSSL_SHA384_Final
+
+#endif /* CYASSL_SHA384 */
+
+#ifdef CYASSL_SHA512
+
+typedef struct CYASSL_SHA512_CTX {
+    long long holder[36];   /* big enough, but check on init */
+} CYASSL_SHA512_CTX;
+
+CYASSL_API void CyaSSL_SHA512_Init(CYASSL_SHA512_CTX*);
+CYASSL_API void CyaSSL_SHA512_Update(CYASSL_SHA512_CTX*, const void*,
+	                                 unsigned long);
+CYASSL_API void CyaSSL_SHA512_Final(unsigned char*, CYASSL_SHA512_CTX*);
+
+enum {
+    SHA512_DIGEST_LENGTH = 64 
+};
+
+
+typedef CYASSL_SHA512_CTX SHA512_CTX;
+
+#define SHA512_Init   CyaSSL_SHA512_Init
+#define SHA512_Update CyaSSL_SHA512_Update
+#define SHA512_Final  CyaSSL_SHA512_Final
+
+#endif /* CYASSL_SHA512 */
+
+
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */ 
+#endif
+
+
+#endif /* CYASSL_SHA_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/ssl.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,380 @@
+/* ssl.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/*  ssl.h defines openssl compatibility layer 
+ *
+ */
+
+
+#ifndef CYASSL_OPENSSL_H_
+#define CYASSL_OPENSSL_H_
+
+#include <cyassl/ssl.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#ifdef _WIN32
+    /* wincrypt.h clashes */
+    #undef X509_NAME
+#endif
+
+
+typedef CYASSL          SSL;          
+typedef CYASSL_SESSION  SSL_SESSION;
+typedef CYASSL_METHOD   SSL_METHOD;
+typedef CYASSL_CTX      SSL_CTX;
+
+typedef CYASSL_X509       X509;
+typedef CYASSL_X509_NAME  X509_NAME;
+typedef CYASSL_X509_CHAIN X509_CHAIN;
+
+
+/* redeclare guard */
+#define CYASSL_TYPES_DEFINED
+
+
+typedef CYASSL_EVP_PKEY       EVP_PKEY;
+typedef CYASSL_RSA            RSA;
+typedef CYASSL_DSA            DSA;
+typedef CYASSL_BIO            BIO;
+typedef CYASSL_BIO_METHOD     BIO_METHOD;
+typedef CYASSL_CIPHER         SSL_CIPHER;
+typedef CYASSL_X509_LOOKUP    X509_LOOKUP;
+typedef CYASSL_X509_LOOKUP_METHOD X509_LOOKUP_METHOD;
+typedef CYASSL_X509_CRL       X509_CRL;
+typedef CYASSL_X509_EXTENSION X509_EXTENSION;
+typedef CYASSL_ASN1_TIME      ASN1_TIME;
+typedef CYASSL_ASN1_INTEGER   ASN1_INTEGER;
+typedef CYASSL_ASN1_OBJECT    ASN1_OBJECT;
+typedef CYASSL_ASN1_STRING    ASN1_STRING;
+typedef CYASSL_dynlock_value  CRYPTO_dynlock_value;
+
+#define ASN1_UTCTIME CYASSL_ASN1_TIME
+
+typedef CYASSL_MD4_CTX        MD4_CTX;
+typedef CYASSL_COMP_METHOD    COMP_METHOD;
+typedef CYASSL_X509_STORE     X509_STORE;
+typedef CYASSL_X509_REVOKED   X509_REVOKED;
+typedef CYASSL_X509_OBJECT    X509_OBJECT;
+typedef CYASSL_X509_STORE_CTX X509_STORE_CTX;
+
+
+#define SSLv3_server_method CyaSSLv3_server_method
+#define SSLv3_client_method CyaSSLv3_client_method
+#define TLSv1_server_method CyaTLSv1_server_method
+#define TLSv1_client_method CyaTLSv1_client_method
+#define TLSv1_1_server_method CyaTLSv1_1_server_method
+#define TLSv1_1_client_method CyaTLSv1_1_client_method
+#define TLSv1_2_server_method CyaTLSv1_2_server_method
+#define TLSv1_2_client_method CyaTLSv1_2_client_method
+
+#ifdef CYASSL_DTLS
+    #define DTLSv1_client_method CyaDTLSv1_client_method
+    #define DTLSv1_server_method CyaDTLSv1_server_method
+    #define DTLSv1_2_client_method CyaDTLSv1_2_client_method
+    #define DTLSv1_2_server_method CyaDTLSv1_2_server_method
+#endif
+
+
+#ifndef NO_FILESYSTEM
+    #define SSL_CTX_use_certificate_file CyaSSL_CTX_use_certificate_file
+    #define SSL_CTX_use_PrivateKey_file CyaSSL_CTX_use_PrivateKey_file
+    #define SSL_CTX_load_verify_locations CyaSSL_CTX_load_verify_locations
+    #define SSL_CTX_use_certificate_chain_file CyaSSL_CTX_use_certificate_chain_file
+    #define SSL_CTX_use_RSAPrivateKey_file CyaSSL_CTX_use_RSAPrivateKey_file
+    
+    #define SSL_use_certificate_file CyaSSL_use_certificate_file
+    #define SSL_use_PrivateKey_file CyaSSL_use_PrivateKey_file
+    #define SSL_use_certificate_chain_file CyaSSL_use_certificate_chain_file
+    #define SSL_use_RSAPrivateKey_file CyaSSL_use_RSAPrivateKey_file
+#endif
+
+#define SSL_CTX_new CyaSSL_CTX_new
+#define SSL_new     CyaSSL_new
+#define SSL_set_fd  CyaSSL_set_fd
+#define SSL_get_fd  CyaSSL_get_fd
+#define SSL_connect CyaSSL_connect
+
+#define SSL_write    CyaSSL_write
+#define SSL_read     CyaSSL_read
+#define SSL_peek     CyaSSL_peek
+#define SSL_accept   CyaSSL_accept
+#define SSL_CTX_free CyaSSL_CTX_free
+#define SSL_free     CyaSSL_free
+#define SSL_shutdown CyaSSL_shutdown
+
+#define SSL_CTX_set_quiet_shutdown CyaSSL_CTX_set_quiet_shutdown
+#define SSL_set_quiet_shutdown CyaSSL_set_quiet_shutdown
+#define SSL_get_error CyaSSL_get_error
+#define SSL_set_session CyaSSL_set_session
+#define SSL_get_session CyaSSL_get_session
+#define SSL_flush_sessions CyaSSL_flush_sessions
+
+#define SSL_CTX_set_verify CyaSSL_CTX_set_verify
+#define SSL_set_verify CyaSSL_set_verify
+#define SSL_pending CyaSSL_pending
+#define SSL_load_error_strings CyaSSL_load_error_strings
+#define SSL_library_init CyaSSL_library_init
+#define SSL_CTX_set_session_cache_mode CyaSSL_CTX_set_session_cache_mode 
+#define SSL_CTX_set_cipher_list CyaSSL_CTX_set_cipher_list
+#define SSL_set_cipher_list     CyaSSL_set_cipher_list
+
+#define ERR_error_string CyaSSL_ERR_error_string
+#define ERR_error_string_n CyaSSL_ERR_error_string_n
+
+#define SSL_set_ex_data CyaSSL_set_ex_data
+#define SSL_get_shutdown CyaSSL_get_shutdown
+#define SSL_set_rfd CyaSSL_set_rfd 
+#define SSL_set_wfd CyaSSL_set_wfd 
+#define SSL_set_shutdown CyaSSL_set_shutdown 
+#define SSL_set_session_id_context CyaSSL_set_session_id_context
+#define SSL_set_connect_state CyaSSL_set_connect_state
+#define SSL_set_accept_state CyaSSL_set_accept_state
+#define SSL_session_reused CyaSSL_session_reused
+#define SSL_SESSION_free CyaSSL_SESSION_free
+#define SSL_is_init_finished CyaSSL_is_init_finished
+
+#define SSL_get_version CyaSSL_get_version
+#define SSL_get_current_cipher CyaSSL_get_current_cipher
+#define SSL_get_cipher CyaSSL_get_cipher
+#define SSL_CIPHER_description CyaSSL_CIPHER_description
+#define SSL_CIPHER_get_name CyaSSL_CIPHER_get_name
+#define SSL_get1_session CyaSSL_get1_session
+
+#define SSL_get_keyblock_size CyaSSL_get_keyblock_size
+#define SSL_get_keys          CyaSSL_get_keys
+
+#define X509_free CyaSSL_X509_free
+#define OPENSSL_free CyaSSL_OPENSSL_free
+
+#define OCSP_parse_url CyaSSL_OCSP_parse_url
+#define SSLv23_client_method CyaSSLv23_client_method
+#define SSLv2_client_method CyaSSLv2_client_method
+#define SSLv2_server_method CyaSSLv2_server_method
+
+#define MD4_Init CyaSSL_MD4_Init
+#define MD4_Update  CyaSSL_MD4_Update  
+#define MD4_Final CyaSSL_MD4_Final
+
+#define BIO_new CyaSSL_BIO_new
+#define BIO_free CyaSSL_BIO_free
+#define BIO_free_all CyaSSL_BIO_free_all
+#define BIO_read CyaSSL_BIO_read
+#define BIO_write CyaSSL_BIO_write
+#define BIO_push CyaSSL_BIO_push
+#define BIO_pop CyaSSL_BIO_pop
+#define BIO_flush CyaSSL_BIO_flush
+#define BIO_pending CyaSSL_BIO_pending
+
+#define BIO_get_mem_data CyaSSL_BIO_get_mem_data
+#define BIO_new_mem_buf  CyaSSL_BIO_new_mem_buf
+
+#define BIO_f_buffer CyaSSL_BIO_f_buffer
+#define BIO_set_write_buffer_size CyaSSL_BIO_set_write_buffer_size
+#define BIO_f_ssl CyaSSL_BIO_f_ssl
+#define BIO_new_socket CyaSSL_BIO_new_socket
+#define SSL_set_bio CyaSSL_set_bio
+#define BIO_eof CyaSSL_BIO_eof
+#define BIO_set_ss CyaSSL_BIO_set_ss
+
+#define BIO_s_mem CyaSSL_BIO_s_mem
+#define BIO_f_base64 CyaSSL_BIO_f_base64
+#define BIO_set_flags CyaSSL_BIO_set_flags
+
+#define OpenSSL_add_all_algorithms CyaSSL_add_all_algorithms
+#define SSLeay_add_ssl_algorithms CyaSSL_add_all_algorithms
+#define SSLeay_add_all_algorithms CyaSSL_add_all_algorithms
+
+#define RAND_screen CyaSSL_RAND_screen
+#define RAND_file_name CyaSSL_RAND_file_name
+#define RAND_write_file CyaSSL_RAND_write_file
+#define RAND_load_file CyaSSL_RAND_load_file
+#define RAND_egd CyaSSL_RAND_egd
+#define RAND_seed CyaSSL_RAND_seed
+#define RAND_add  CyaSSL_RAND_add
+
+#define COMP_zlib CyaSSL_COMP_zlib
+#define COMP_rle CyaSSL_COMP_rle
+#define SSL_COMP_add_compression_method CyaSSL_COMP_add_compression_method
+
+#define SSL_get_ex_new_index CyaSSL_get_ex_new_index
+
+#define CRYPTO_set_id_callback CyaSSL_set_id_callback
+#define CRYPTO_set_locking_callback CyaSSL_set_locking_callback
+#define CRYPTO_set_dynlock_create_callback CyaSSL_set_dynlock_create_callback
+#define CRYPTO_set_dynlock_lock_callback CyaSSL_set_dynlock_lock_callback
+#define CRYPTO_set_dynlock_destroy_callback CyaSSL_set_dynlock_destroy_callback
+#define CRYPTO_num_locks CyaSSL_num_locks
+
+#define X509_STORE_CTX_get_current_cert CyaSSL_X509_STORE_CTX_get_current_cert
+#define X509_STORE_CTX_get_error CyaSSL_X509_STORE_CTX_get_error
+#define X509_STORE_CTX_get_error_depth CyaSSL_X509_STORE_CTX_get_error_depth
+
+#define X509_NAME_oneline CyaSSL_X509_NAME_oneline
+#define X509_get_issuer_name CyaSSL_X509_get_issuer_name
+#define X509_get_subject_name CyaSSL_X509_get_subject_name
+#define X509_verify_cert_error_string CyaSSL_X509_verify_cert_error_string
+
+#define X509_LOOKUP_add_dir CyaSSL_X509_LOOKUP_add_dir
+#define X509_LOOKUP_load_file CyaSSL_X509_LOOKUP_load_file
+#define X509_LOOKUP_hash_dir CyaSSL_X509_LOOKUP_hash_dir
+#define X509_LOOKUP_file CyaSSL_X509_LOOKUP_file
+
+#define X509_STORE_add_lookup CyaSSL_X509_STORE_add_lookup
+#define X509_STORE_new CyaSSL_X509_STORE_new
+#define X509_STORE_get_by_subject CyaSSL_X509_STORE_get_by_subject
+#define X509_STORE_CTX_init CyaSSL_X509_STORE_CTX_init
+#define X509_STORE_CTX_cleanup CyaSSL_X509_STORE_CTX_cleanup
+
+#define X509_CRL_get_lastUpdate CyaSSL_X509_CRL_get_lastUpdate
+#define X509_CRL_get_nextUpdate CyaSSL_X509_CRL_get_nextUpdate
+
+#define X509_get_pubkey CyaSSL_X509_get_pubkey
+#define X509_CRL_verify CyaSSL_X509_CRL_verify
+#define X509_STORE_CTX_set_error CyaSSL_X509_STORE_CTX_set_error
+#define X509_OBJECT_free_contents CyaSSL_X509_OBJECT_free_contents
+#define EVP_PKEY_free CyaSSL_EVP_PKEY_free
+#define X509_cmp_current_time CyaSSL_X509_cmp_current_time
+#define sk_X509_REVOKED_num CyaSSL_sk_X509_REVOKED_num
+#define X509_CRL_get_REVOKED CyaSSL_X509_CRL_get_REVOKED
+#define sk_X509_REVOKED_value CyaSSL_sk_X509_REVOKED_value 
+
+#define X509_get_serialNumber CyaSSL_X509_get_serialNumber
+
+#define ASN1_TIME_pr CyaSSL_ASN1_TIME_pr
+
+#define ASN1_INTEGER_cmp CyaSSL_ASN1_INTEGER_cmp
+#define ASN1_INTEGER_get CyaSSL_ASN1_INTEGER_get
+
+#define SSL_load_client_CA_file CyaSSL_load_client_CA_file
+
+#define SSL_CTX_set_client_CA_list CyaSSL_CTX_set_client_CA_list
+#define X509_STORE_CTX_get_ex_data CyaSSL_X509_STORE_CTX_get_ex_data 
+#define SSL_get_ex_data_X509_STORE_CTX_idx CyaSSL_get_ex_data_X509_STORE_CTX_idx
+#define SSL_get_ex_data CyaSSL_get_ex_data
+
+#define SSL_CTX_set_default_passwd_cb_userdata CyaSSL_CTX_set_default_passwd_cb_userdata
+#define SSL_CTX_set_default_passwd_cb CyaSSL_CTX_set_default_passwd_cb
+
+#define SSL_CTX_set_timeout CyaSSL_CTX_set_timeout
+#define SSL_CTX_set_info_callback CyaSSL_CTX_set_info_callback
+
+#define ERR_peek_error CyaSSL_ERR_peek_error
+#define ERR_GET_REASON CyaSSL_ERR_GET_REASON
+
+#define SSL_alert_type_string CyaSSL_alert_type_string
+#define SSL_alert_desc_string CyaSSL_alert_desc_string
+#define SSL_state_string CyaSSL_state_string
+
+#define RSA_free CyaSSL_RSA_free
+#define RSA_generate_key CyaSSL_RSA_generate_key
+#define SSL_CTX_set_tmp_rsa_callback CyaSSL_CTX_set_tmp_rsa_callback
+
+#define PEM_def_callback CyaSSL_PEM_def_callback
+
+#define SSL_CTX_sess_accept CyaSSL_CTX_sess_accept
+#define SSL_CTX_sess_connect CyaSSL_CTX_sess_connect
+#define SSL_CTX_sess_accept_good CyaSSL_CTX_sess_accept_good
+#define SSL_CTX_sess_connect_good CyaSSL_CTX_sess_connect_good
+#define SSL_CTX_sess_accept_renegotiate CyaSSL_CTX_sess_accept_renegotiate
+#define SSL_CTX_sess_connect_renegotiate CyaSSL_CTX_sess_connect_renegotiate
+#define SSL_CTX_sess_hits CyaSSL_CTX_sess_hits
+#define SSL_CTX_sess_cb_hits CyaSSL_CTX_sess_cb_hits
+#define SSL_CTX_sess_cache_full CyaSSL_CTX_sess_cache_full
+#define SSL_CTX_sess_misses CyaSSL_CTX_sess_misses
+#define SSL_CTX_sess_timeouts CyaSSL_CTX_sess_timeouts
+#define SSL_CTX_sess_number CyaSSL_CTX_sess_number
+#define SSL_CTX_sess_get_cache_size CyaSSL_CTX_sess_get_cache_size
+
+
+#define SSL_DEFAULT_CIPHER_LIST CYASSL_DEFAULT_CIPHER_LIST
+#define RSA_F4 CYASSL_RSA_F4
+
+#define SSL_CTX_set_psk_client_callback CyaSSL_CTX_set_psk_client_callback
+#define SSL_set_psk_client_callback CyaSSL_set_psk_client_callback
+
+#define SSL_get_psk_identity_hint CyaSSL_get_psk_identity_hint
+#define SSL_get_psk_identity CyaSSL_get_psk_identity
+
+#define SSL_CTX_use_psk_identity_hint CyaSSL_CTX_use_psk_identity_hint
+#define SSL_use_psk_identity_hint CyaSSL_use_psk_identity_hint
+
+#define SSL_CTX_set_psk_server_callback CyaSSL_CTX_set_psk_server_callback
+#define SSL_set_psk_server_callback CyaSSL_set_psk_server_callback
+
+#define ERR_get_error_line_data CyaSSL_ERR_get_error_line_data
+
+#define ERR_get_error CyaSSL_ERR_get_error
+#define ERR_clear_error CyaSSL_ERR_clear_error
+
+#define RAND_status CyaSSL_RAND_status
+#define RAND_bytes CyaSSL_RAND_bytes
+#define SSLv23_server_method CyaSSLv23_server_method
+#define SSL_CTX_set_options CyaSSL_CTX_set_options 
+#define SSL_CTX_check_private_key CyaSSL_CTX_check_private_key
+
+#define ERR_free_strings CyaSSL_ERR_free_strings
+#define ERR_remove_state CyaSSL_ERR_remove_state
+#define EVP_cleanup CyaSSL_EVP_cleanup
+
+#define CRYPTO_cleanup_all_ex_data CyaSSL_cleanup_all_ex_data
+#define SSL_CTX_set_mode CyaSSL_CTX_set_mode
+#define SSL_CTX_get_mode CyaSSL_CTX_get_mode
+#define SSL_CTX_set_default_read_ahead CyaSSL_CTX_set_default_read_ahead
+
+#define SSL_CTX_sess_set_cache_size CyaSSL_CTX_sess_set_cache_size
+#define SSL_CTX_set_default_verify_paths CyaSSL_CTX_set_default_verify_paths
+
+#define SSL_CTX_set_session_id_context CyaSSL_CTX_set_session_id_context
+#define SSL_get_peer_certificate CyaSSL_get_peer_certificate
+
+#define SSL_want_read CyaSSL_want_read
+#define SSL_want_write CyaSSL_want_write
+
+#define BIO_prf CyaSSL_BIO_prf
+#define ASN1_UTCTIME_pr CyaSSL_ASN1_UTCTIME_pr
+
+#define sk_num CyaSSL_sk_num
+#define sk_value CyaSSL_sk_value
+
+#define SSL_CTX_get_ex_data CyaSSL_CTX_get_ex_data
+#define SSL_CTX_set_ex_data CyaSSL_CTX_set_ex_data
+#define SSL_CTX_sess_set_get_cb CyaSSL_CTX_sess_set_get_cb
+#define SSL_CTX_sess_set_new_cb CyaSSL_CTX_sess_set_new_cb
+#define SSL_CTX_sess_set_remove_cb CyaSSL_CTX_sess_set_remove_cb
+
+#define i2d_SSL_SESSION CyaSSL_i2d_SSL_SESSION
+#define d2i_SSL_SESSION CyaSSL_d2i_SSL_SESSION
+#define SSL_SESSION_get_timeout CyaSSL_SESSION_get_timeout
+#define SSL_SESSION_get_time CyaSSL_SESSION_get_time
+#define SSL_CTX_get_ex_new_index CyaSSL_CTX_get_ex_new_index
+
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* CyaSSL_openssl_h__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/stack.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,2 @@
+/* stack.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/ui.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,2 @@
+/* ui.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/x509.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,3 @@
+/* x509.h for openssl */
+
+#include <cyassl/openssl/ssl.h>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/x509v3.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,2 @@
+/* x509v3.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/options.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,34 @@
+/* options.h.in
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/* default blank options for autoconf */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/sniffer.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,74 @@
+/* sniffer.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CYASSL_SNIFFER_H
+#define CYASSL_SNIFFER_H
+
+#include <cyassl/ctaocrypt/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
+
+
+CYASSL_API 
+SSL_SNIFFER_API int ssl_SetPrivateKey(const char* address, int port,
+                                      const char* keyFile, int keyType,
+                                      const char* password, char* error);
+
+CYASSL_API 
+SSL_SNIFFER_API int ssl_DecodePacket(const unsigned char* packet, int length,
+                                     unsigned char* data, char* error);
+
+CYASSL_API 
+SSL_SNIFFER_API int ssl_Trace(const char* traceFile, char* error);
+        
+        
+CYASSL_API void ssl_InitSniffer(void);
+        
+CYASSL_API void ssl_FreeSniffer(void);
+
+        
+/* ssl_SetPrivateKey keyTypes */
+enum {
+    FILETYPE_PEM = 1,
+    FILETYPE_DER = 2,
+};
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+#endif /* CyaSSL_SNIFFER_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/sniffer_error.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,109 @@
+/* sniffer_error.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifndef CYASSL_SNIFFER_ERROR_H
+#define CYASSL_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
+
+/* !!!! also add to msgTable in sniffer.c and .rc file !!!! */
+
+
+#endif /* CyaSSL_SNIFFER_ERROR_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ssl.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,997 @@
+/* ssl.h
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/* CyaSSL API */
+
+#ifndef CYASSL_SSL_H
+#define CYASSL_SSL_H
+
+
+/* for users not using preprocessor flags*/
+#include <cyassl/ctaocrypt/settings.h>
+#include <cyassl/version.h>
+
+
+#ifndef NO_FILESYSTEM
+    #ifdef FREESCALE_MQX
+        #include <fio.h>
+    #else
+        #include <stdio.h>   /* ERR_printf */
+    #endif
+#endif
+
+#ifdef YASSL_PREFIX
+    #include "prefix_ssl.h"
+#endif
+
+#ifdef LIBCYASSL_VERSION_STRING
+    #define CYASSL_VERSION LIBCYASSL_VERSION_STRING
+#endif
+
+#ifdef _WIN32
+    /* wincrypt.h clashes */
+    #undef OCSP_REQUEST
+    #undef OCSP_RESPONSE
+#endif
+
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+typedef struct CYASSL          CYASSL;          
+typedef struct CYASSL_SESSION  CYASSL_SESSION;
+typedef struct CYASSL_METHOD   CYASSL_METHOD;
+typedef struct CYASSL_CTX      CYASSL_CTX;
+
+typedef struct CYASSL_X509       CYASSL_X509;
+typedef struct CYASSL_X509_NAME  CYASSL_X509_NAME;
+typedef struct CYASSL_X509_CHAIN CYASSL_X509_CHAIN;
+
+typedef struct CYASSL_CERT_MANAGER CYASSL_CERT_MANAGER;
+typedef struct CYASSL_SOCKADDR     CYASSL_SOCKADDR;
+
+/* redeclare guard */
+#define CYASSL_TYPES_DEFINED
+
+
+typedef struct CYASSL_RSA            CYASSL_RSA;
+typedef struct CYASSL_DSA            CYASSL_DSA;
+typedef struct CYASSL_CIPHER         CYASSL_CIPHER;
+typedef struct CYASSL_X509_LOOKUP    CYASSL_X509_LOOKUP;
+typedef struct CYASSL_X509_LOOKUP_METHOD CYASSL_X509_LOOKUP_METHOD;
+typedef struct CYASSL_X509_CRL       CYASSL_X509_CRL;
+typedef struct CYASSL_BIO            CYASSL_BIO;
+typedef struct CYASSL_BIO_METHOD     CYASSL_BIO_METHOD;
+typedef struct CYASSL_X509_EXTENSION CYASSL_X509_EXTENSION;
+typedef struct CYASSL_ASN1_TIME      CYASSL_ASN1_TIME;
+typedef struct CYASSL_ASN1_INTEGER   CYASSL_ASN1_INTEGER;
+typedef struct CYASSL_ASN1_OBJECT    CYASSL_ASN1_OBJECT;
+typedef struct CYASSL_ASN1_STRING    CYASSL_ASN1_STRING;
+typedef struct CYASSL_dynlock_value  CYASSL_dynlock_value;
+
+#define CYASSL_ASN1_UTCTIME CYASSL_ASN1_TIME
+
+typedef struct CYASSL_EVP_PKEY {
+    int type;         /* openssh dereference */
+    int save_type;    /* openssh dereference */
+} CYASSL_EVP_PKEY;
+
+typedef struct CYASSL_MD4_CTX {
+    int buffer[32];      /* big enough to hold, check size in Init */
+} CYASSL_MD4_CTX;
+
+
+typedef struct CYASSL_COMP_METHOD {
+    int type;            /* stunnel dereference */
+} CYASSL_COMP_METHOD;
+
+
+typedef struct CYASSL_X509_STORE {
+    int cache;          /* stunnel dereference */
+} CYASSL_X509_STORE;
+
+typedef struct CYASSL_ALERT {
+    int code;
+    int level;
+} CYASSL_ALERT;
+
+typedef struct CYASSL_ALERT_HISTORY {
+    CYASSL_ALERT last_rx;
+    CYASSL_ALERT last_tx;
+} CYASSL_ALERT_HISTORY;
+
+typedef struct CYASSL_X509_REVOKED {
+    CYASSL_ASN1_INTEGER* serialNumber;          /* stunnel dereference */
+} CYASSL_X509_REVOKED;
+
+
+typedef struct CYASSL_X509_OBJECT {
+    union {
+        char* ptr;
+        CYASSL_X509_CRL* crl;           /* stunnel dereference */
+    } data;
+} CYASSL_X509_OBJECT;
+
+
+typedef struct CYASSL_X509_STORE_CTX {
+    CYASSL_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 */ 
+} CYASSL_X509_STORE_CTX;
+
+
+CYASSL_API CYASSL_METHOD *CyaSSLv3_server_method(void);
+CYASSL_API CYASSL_METHOD *CyaSSLv3_client_method(void);
+CYASSL_API CYASSL_METHOD *CyaTLSv1_server_method(void);  
+CYASSL_API CYASSL_METHOD *CyaTLSv1_client_method(void);
+CYASSL_API CYASSL_METHOD *CyaTLSv1_1_server_method(void);  
+CYASSL_API CYASSL_METHOD *CyaTLSv1_1_client_method(void);
+CYASSL_API CYASSL_METHOD *CyaTLSv1_2_server_method(void);  
+CYASSL_API CYASSL_METHOD *CyaTLSv1_2_client_method(void);
+
+#ifdef CYASSL_DTLS
+    CYASSL_API CYASSL_METHOD *CyaDTLSv1_client_method(void);
+    CYASSL_API CYASSL_METHOD *CyaDTLSv1_server_method(void);
+    CYASSL_API CYASSL_METHOD *CyaDTLSv1_2_client_method(void);
+    CYASSL_API CYASSL_METHOD *CyaDTLSv1_2_server_method(void);
+#endif
+
+#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
+
+CYASSL_API int CyaSSL_CTX_use_certificate_file(CYASSL_CTX*, const char*, int);
+CYASSL_API int CyaSSL_CTX_use_PrivateKey_file(CYASSL_CTX*, const char*, int);
+CYASSL_API int CyaSSL_CTX_load_verify_locations(CYASSL_CTX*, const char*,
+                                                const char*);
+CYASSL_API int CyaSSL_CTX_use_certificate_chain_file(CYASSL_CTX *,
+                                                     const char *file);
+CYASSL_API int CyaSSL_CTX_use_RSAPrivateKey_file(CYASSL_CTX*, const char*, int);
+
+CYASSL_API int CyaSSL_use_certificate_file(CYASSL*, const char*, int);
+CYASSL_API int CyaSSL_use_PrivateKey_file(CYASSL*, const char*, int);
+CYASSL_API int CyaSSL_use_certificate_chain_file(CYASSL*, const char *file);
+CYASSL_API int CyaSSL_use_RSAPrivateKey_file(CYASSL*, const char*, int);
+
+#ifdef CYASSL_DER_LOAD
+    CYASSL_API int CyaSSL_CTX_der_load_verify_locations(CYASSL_CTX*,
+                                                    const char*, int);
+#endif
+
+#ifdef HAVE_NTRU
+    CYASSL_API int CyaSSL_CTX_use_NTRUPrivateKey_file(CYASSL_CTX*, const char*);
+    /* load NTRU private key blob */
+#endif
+
+CYASSL_API int CyaSSL_PemCertToDer(const char*, unsigned char*, int);
+
+#endif /* !NO_FILESYSTEM && !NO_CERTS */
+
+CYASSL_API CYASSL_CTX* CyaSSL_CTX_new(CYASSL_METHOD*);
+CYASSL_API CYASSL* CyaSSL_new(CYASSL_CTX*);
+CYASSL_API int  CyaSSL_set_fd (CYASSL*, int);
+CYASSL_API int  CyaSSL_get_fd(const CYASSL*);
+CYASSL_API void CyaSSL_set_using_nonblock(CYASSL*, int);
+CYASSL_API int  CyaSSL_get_using_nonblock(CYASSL*);
+CYASSL_API int  CyaSSL_connect(CYASSL*);     /* please see note at top of README
+                                             if you get an error from connect */
+CYASSL_API int  CyaSSL_write(CYASSL*, const void*, int);
+CYASSL_API int  CyaSSL_read(CYASSL*, void*, int);
+CYASSL_API int  CyaSSL_peek(CYASSL*, void*, int);
+CYASSL_API int  CyaSSL_accept(CYASSL*);
+CYASSL_API void CyaSSL_CTX_free(CYASSL_CTX*);
+CYASSL_API void CyaSSL_free(CYASSL*);
+CYASSL_API int  CyaSSL_shutdown(CYASSL*);
+CYASSL_API int  CyaSSL_send(CYASSL*, const void*, int sz, int flags);
+CYASSL_API int  CyaSSL_recv(CYASSL*, void*, int sz, int flags);
+
+CYASSL_API void CyaSSL_CTX_set_quiet_shutdown(CYASSL_CTX*, int);
+CYASSL_API void CyaSSL_set_quiet_shutdown(CYASSL*, int);
+
+CYASSL_API int  CyaSSL_get_error(CYASSL*, int);
+CYASSL_API int  CyaSSL_get_alert_history(CYASSL*, CYASSL_ALERT_HISTORY *);
+
+CYASSL_API int        CyaSSL_set_session(CYASSL* ssl,CYASSL_SESSION* session);
+CYASSL_API CYASSL_SESSION* CyaSSL_get_session(CYASSL* ssl);
+CYASSL_API void       CyaSSL_flush_sessions(CYASSL_CTX *ctx, long tm);
+CYASSL_API int        CyaSSL_SetServerID(CYASSL* ssl, const unsigned char*, 
+                                         int, int);
+
+typedef int (*VerifyCallback)(int, CYASSL_X509_STORE_CTX*);
+typedef int (*pem_password_cb)(char*, int, int, void*);
+
+CYASSL_API void CyaSSL_CTX_set_verify(CYASSL_CTX*, int, 
+                                      VerifyCallback verify_callback);
+CYASSL_API void CyaSSL_set_verify(CYASSL*, int, VerifyCallback verify_callback);
+CYASSL_API void CyaSSL_SetCertCbCtx(CYASSL*, void*);
+
+CYASSL_API int  CyaSSL_pending(CYASSL*);
+
+CYASSL_API void CyaSSL_load_error_strings(void);
+CYASSL_API int  CyaSSL_library_init(void);
+CYASSL_API long CyaSSL_CTX_set_session_cache_mode(CYASSL_CTX*, long);
+
+/* session cache persistence */
+CYASSL_API int  CyaSSL_save_session_cache(const char*);
+CYASSL_API int  CyaSSL_restore_session_cache(const char*);
+CYASSL_API int  CyaSSL_memsave_session_cache(void*, int);
+CYASSL_API int  CyaSSL_memrestore_session_cache(const void*, int);
+CYASSL_API int  CyaSSL_get_session_cache_memsize(void);
+
+/* certificate cache persistence, uses ctx since certs are per ctx */
+CYASSL_API int  CyaSSL_CTX_save_cert_cache(CYASSL_CTX*, const char*);
+CYASSL_API int  CyaSSL_CTX_restore_cert_cache(CYASSL_CTX*, const char*);
+CYASSL_API int  CyaSSL_CTX_memsave_cert_cache(CYASSL_CTX*, void*, int, int*);
+CYASSL_API int  CyaSSL_CTX_memrestore_cert_cache(CYASSL_CTX*, const void*, int);
+CYASSL_API int  CyaSSL_CTX_get_cert_cache_memsize(CYASSL_CTX*);
+
+/* only supports full name from cipher_name[] delimited by : */
+CYASSL_API int  CyaSSL_CTX_set_cipher_list(CYASSL_CTX*, const char*);
+CYASSL_API int  CyaSSL_set_cipher_list(CYASSL*, const char*);
+
+/* Nonblocking DTLS helper functions */
+CYASSL_API int  CyaSSL_dtls_get_current_timeout(CYASSL* ssl);
+CYASSL_API int  CyaSSL_dtls_set_timeout_init(CYASSL* ssl, int);
+CYASSL_API int  CyaSSL_dtls_set_timeout_max(CYASSL* ssl, int);
+CYASSL_API int  CyaSSL_dtls_got_timeout(CYASSL* ssl);
+CYASSL_API int  CyaSSL_dtls(CYASSL* ssl);
+
+CYASSL_API int  CyaSSL_dtls_set_peer(CYASSL*, void*, unsigned int);
+CYASSL_API int  CyaSSL_dtls_get_peer(CYASSL*, void*, unsigned int*);
+
+CYASSL_API int   CyaSSL_ERR_GET_REASON(int err);
+CYASSL_API char* CyaSSL_ERR_error_string(unsigned long,char*);
+CYASSL_API void  CyaSSL_ERR_error_string_n(unsigned long e, char* buf,
+                                           unsigned long sz);
+
+/* extras */
+
+#define STACK_OF(x) x
+
+CYASSL_API int  CyaSSL_set_ex_data(CYASSL*, int, void*);
+CYASSL_API int  CyaSSL_get_shutdown(const CYASSL*);
+CYASSL_API int  CyaSSL_set_rfd(CYASSL*, int);
+CYASSL_API int  CyaSSL_set_wfd(CYASSL*, int);
+CYASSL_API void CyaSSL_set_shutdown(CYASSL*, int);
+CYASSL_API int  CyaSSL_set_session_id_context(CYASSL*, const unsigned char*,
+                                           unsigned int);
+CYASSL_API void CyaSSL_set_connect_state(CYASSL*);
+CYASSL_API void CyaSSL_set_accept_state(CYASSL*);
+CYASSL_API int  CyaSSL_session_reused(CYASSL*);
+CYASSL_API void CyaSSL_SESSION_free(CYASSL_SESSION* session);
+CYASSL_API int  CyaSSL_is_init_finished(CYASSL*);
+
+CYASSL_API const char*  CyaSSL_get_version(CYASSL*);
+CYASSL_API int  CyaSSL_get_current_cipher_suite(CYASSL* ssl);
+CYASSL_API CYASSL_CIPHER*  CyaSSL_get_current_cipher(CYASSL*);
+CYASSL_API char*        CyaSSL_CIPHER_description(CYASSL_CIPHER*, char*, int);
+CYASSL_API const char*  CyaSSL_CIPHER_get_name(const CYASSL_CIPHER* cipher);
+CYASSL_API const char*  CyaSSL_get_cipher(CYASSL*);
+CYASSL_API CYASSL_SESSION* CyaSSL_get1_session(CYASSL* ssl);
+                           /* what's ref count */
+
+CYASSL_API void CyaSSL_X509_free(CYASSL_X509*);
+CYASSL_API void CyaSSL_OPENSSL_free(void*);
+
+CYASSL_API int CyaSSL_OCSP_parse_url(char* url, char** host, char** port,
+                                     char** path, int* ssl);
+
+CYASSL_API CYASSL_METHOD* CyaSSLv23_client_method(void);
+CYASSL_API CYASSL_METHOD* CyaSSLv2_client_method(void);
+CYASSL_API CYASSL_METHOD* CyaSSLv2_server_method(void);
+
+CYASSL_API void CyaSSL_MD4_Init(CYASSL_MD4_CTX*);
+CYASSL_API void CyaSSL_MD4_Update(CYASSL_MD4_CTX*, const void*, unsigned long);
+CYASSL_API void CyaSSL_MD4_Final(unsigned char*, CYASSL_MD4_CTX*);
+
+
+CYASSL_API CYASSL_BIO* CyaSSL_BIO_new(CYASSL_BIO_METHOD*);
+CYASSL_API int  CyaSSL_BIO_free(CYASSL_BIO*);
+CYASSL_API int  CyaSSL_BIO_free_all(CYASSL_BIO*);
+CYASSL_API int  CyaSSL_BIO_read(CYASSL_BIO*, void*, int);
+CYASSL_API int  CyaSSL_BIO_write(CYASSL_BIO*, const void*, int);
+CYASSL_API CYASSL_BIO* CyaSSL_BIO_push(CYASSL_BIO*, CYASSL_BIO* append);
+CYASSL_API CYASSL_BIO* CyaSSL_BIO_pop(CYASSL_BIO*);
+CYASSL_API int  CyaSSL_BIO_flush(CYASSL_BIO*);
+CYASSL_API int  CyaSSL_BIO_pending(CYASSL_BIO*);
+
+CYASSL_API CYASSL_BIO_METHOD* CyaSSL_BIO_f_buffer(void);
+CYASSL_API long CyaSSL_BIO_set_write_buffer_size(CYASSL_BIO*, long size);
+CYASSL_API CYASSL_BIO_METHOD* CyaSSL_BIO_f_ssl(void);
+CYASSL_API CYASSL_BIO*        CyaSSL_BIO_new_socket(int sfd, int flag);
+CYASSL_API int         CyaSSL_BIO_eof(CYASSL_BIO*);
+
+CYASSL_API CYASSL_BIO_METHOD* CyaSSL_BIO_s_mem(void);
+CYASSL_API CYASSL_BIO_METHOD* CyaSSL_BIO_f_base64(void);
+CYASSL_API void CyaSSL_BIO_set_flags(CYASSL_BIO*, int);
+
+CYASSL_API int CyaSSL_BIO_get_mem_data(CYASSL_BIO* bio,const unsigned char** p);
+CYASSL_API CYASSL_BIO* CyaSSL_BIO_new_mem_buf(void* buf, int len);
+
+
+CYASSL_API long        CyaSSL_BIO_set_ssl(CYASSL_BIO*, CYASSL*, int flag);
+CYASSL_API void        CyaSSL_set_bio(CYASSL*, CYASSL_BIO* rd, CYASSL_BIO* wr);
+
+CYASSL_API int  CyaSSL_add_all_algorithms(void);
+
+CYASSL_API void        CyaSSL_RAND_screen(void);
+CYASSL_API const char* CyaSSL_RAND_file_name(char*, unsigned long);
+CYASSL_API int         CyaSSL_RAND_write_file(const char*);
+CYASSL_API int         CyaSSL_RAND_load_file(const char*, long);
+CYASSL_API int         CyaSSL_RAND_egd(const char*);
+CYASSL_API int         CyaSSL_RAND_seed(const void*, int);
+CYASSL_API void        CyaSSL_RAND_add(const void*, int, double);
+
+CYASSL_API CYASSL_COMP_METHOD* CyaSSL_COMP_zlib(void);
+CYASSL_API CYASSL_COMP_METHOD* CyaSSL_COMP_rle(void);
+CYASSL_API int CyaSSL_COMP_add_compression_method(int, void*);
+
+CYASSL_API int CyaSSL_get_ex_new_index(long, void*, void*, void*, void*);
+
+CYASSL_API void CyaSSL_set_id_callback(unsigned long (*f)(void));
+CYASSL_API void CyaSSL_set_locking_callback(void (*f)(int, int, const char*,
+                                                      int));
+CYASSL_API void CyaSSL_set_dynlock_create_callback(CYASSL_dynlock_value* (*f)
+                                                   (const char*, int));
+CYASSL_API void CyaSSL_set_dynlock_lock_callback(void (*f)(int,
+                                      CYASSL_dynlock_value*, const char*, int));
+CYASSL_API void CyaSSL_set_dynlock_destroy_callback(void (*f)
+                                     (CYASSL_dynlock_value*, const char*, int));
+CYASSL_API int  CyaSSL_num_locks(void);
+
+CYASSL_API CYASSL_X509* CyaSSL_X509_STORE_CTX_get_current_cert(
+                                                        CYASSL_X509_STORE_CTX*);
+CYASSL_API int   CyaSSL_X509_STORE_CTX_get_error(CYASSL_X509_STORE_CTX*);
+CYASSL_API int   CyaSSL_X509_STORE_CTX_get_error_depth(CYASSL_X509_STORE_CTX*);
+
+CYASSL_API char*       CyaSSL_X509_NAME_oneline(CYASSL_X509_NAME*, char*, int);
+CYASSL_API CYASSL_X509_NAME*  CyaSSL_X509_get_issuer_name(CYASSL_X509*);
+CYASSL_API CYASSL_X509_NAME*  CyaSSL_X509_get_subject_name(CYASSL_X509*);
+CYASSL_API const char* CyaSSL_X509_verify_cert_error_string(long);
+
+CYASSL_API int CyaSSL_X509_LOOKUP_add_dir(CYASSL_X509_LOOKUP*,const char*,long);
+CYASSL_API int CyaSSL_X509_LOOKUP_load_file(CYASSL_X509_LOOKUP*, const char*,
+                                            long);
+CYASSL_API CYASSL_X509_LOOKUP_METHOD* CyaSSL_X509_LOOKUP_hash_dir(void);
+CYASSL_API CYASSL_X509_LOOKUP_METHOD* CyaSSL_X509_LOOKUP_file(void);
+
+CYASSL_API CYASSL_X509_LOOKUP* CyaSSL_X509_STORE_add_lookup(CYASSL_X509_STORE*,
+                                                    CYASSL_X509_LOOKUP_METHOD*);
+CYASSL_API CYASSL_X509_STORE*  CyaSSL_X509_STORE_new(void);
+CYASSL_API int          CyaSSL_X509_STORE_get_by_subject(CYASSL_X509_STORE_CTX*,
+                                   int, CYASSL_X509_NAME*, CYASSL_X509_OBJECT*);
+CYASSL_API int  CyaSSL_X509_STORE_CTX_init(CYASSL_X509_STORE_CTX*,
+                      CYASSL_X509_STORE*, CYASSL_X509*, STACK_OF(CYASSL_X509)*);
+CYASSL_API void CyaSSL_X509_STORE_CTX_cleanup(CYASSL_X509_STORE_CTX*);
+
+CYASSL_API CYASSL_ASN1_TIME* CyaSSL_X509_CRL_get_lastUpdate(CYASSL_X509_CRL*);
+CYASSL_API CYASSL_ASN1_TIME* CyaSSL_X509_CRL_get_nextUpdate(CYASSL_X509_CRL*);
+
+CYASSL_API CYASSL_EVP_PKEY* CyaSSL_X509_get_pubkey(CYASSL_X509*);
+CYASSL_API int       CyaSSL_X509_CRL_verify(CYASSL_X509_CRL*, CYASSL_EVP_PKEY*);
+CYASSL_API void      CyaSSL_X509_STORE_CTX_set_error(CYASSL_X509_STORE_CTX*,
+                                                     int);
+CYASSL_API void      CyaSSL_X509_OBJECT_free_contents(CYASSL_X509_OBJECT*);
+CYASSL_API void      CyaSSL_EVP_PKEY_free(CYASSL_EVP_PKEY*);
+CYASSL_API int       CyaSSL_X509_cmp_current_time(const CYASSL_ASN1_TIME*);
+CYASSL_API int       CyaSSL_sk_X509_REVOKED_num(CYASSL_X509_REVOKED*);
+
+CYASSL_API CYASSL_X509_REVOKED* CyaSSL_X509_CRL_get_REVOKED(CYASSL_X509_CRL*);
+CYASSL_API CYASSL_X509_REVOKED* CyaSSL_sk_X509_REVOKED_value(
+                                                      CYASSL_X509_REVOKED*,int);
+CYASSL_API CYASSL_ASN1_INTEGER* CyaSSL_X509_get_serialNumber(CYASSL_X509*);
+
+CYASSL_API int CyaSSL_ASN1_TIME_print(CYASSL_BIO*, const CYASSL_ASN1_TIME*);
+
+CYASSL_API int  CyaSSL_ASN1_INTEGER_cmp(const CYASSL_ASN1_INTEGER*,
+                                       const CYASSL_ASN1_INTEGER*);
+CYASSL_API long CyaSSL_ASN1_INTEGER_get(const CYASSL_ASN1_INTEGER*);
+
+CYASSL_API STACK_OF(CYASSL_X509_NAME)* CyaSSL_load_client_CA_file(const char*);
+
+CYASSL_API void  CyaSSL_CTX_set_client_CA_list(CYASSL_CTX*,
+                                               STACK_OF(CYASSL_X509_NAME)*);
+CYASSL_API void* CyaSSL_X509_STORE_CTX_get_ex_data(CYASSL_X509_STORE_CTX*, int);
+CYASSL_API int   CyaSSL_get_ex_data_X509_STORE_CTX_idx(void);
+CYASSL_API void* CyaSSL_get_ex_data(const CYASSL*, int);
+
+CYASSL_API void CyaSSL_CTX_set_default_passwd_cb_userdata(CYASSL_CTX*,
+                                                          void* userdata);
+CYASSL_API void CyaSSL_CTX_set_default_passwd_cb(CYASSL_CTX*, pem_password_cb);
+
+
+CYASSL_API void CyaSSL_CTX_set_info_callback(CYASSL_CTX*, void (*)(void));
+
+CYASSL_API unsigned long CyaSSL_ERR_peek_error(void);
+CYASSL_API int           CyaSSL_GET_REASON(int);
+
+CYASSL_API char* CyaSSL_alert_type_string_long(int);
+CYASSL_API char* CyaSSL_alert_desc_string_long(int);
+CYASSL_API char* CyaSSL_state_string_long(CYASSL*);
+
+CYASSL_API CYASSL_RSA* CyaSSL_RSA_generate_key(int, unsigned long,
+                                               void(*)(int, int, void*), void*);
+CYASSL_API void CyaSSL_CTX_set_tmp_rsa_callback(CYASSL_CTX*,
+                                             CYASSL_RSA*(*)(CYASSL*, int, int));
+
+CYASSL_API int CyaSSL_PEM_def_callback(char*, int num, int w, void* key);
+
+CYASSL_API long CyaSSL_CTX_sess_accept(CYASSL_CTX*);
+CYASSL_API long CyaSSL_CTX_sess_connect(CYASSL_CTX*);
+CYASSL_API long CyaSSL_CTX_sess_accept_good(CYASSL_CTX*);
+CYASSL_API long CyaSSL_CTX_sess_connect_good(CYASSL_CTX*);
+CYASSL_API long CyaSSL_CTX_sess_accept_renegotiate(CYASSL_CTX*);
+CYASSL_API long CyaSSL_CTX_sess_connect_renegotiate(CYASSL_CTX*);
+CYASSL_API long CyaSSL_CTX_sess_hits(CYASSL_CTX*);
+CYASSL_API long CyaSSL_CTX_sess_cb_hits(CYASSL_CTX*);
+CYASSL_API long CyaSSL_CTX_sess_cache_full(CYASSL_CTX*);
+CYASSL_API long CyaSSL_CTX_sess_misses(CYASSL_CTX*);
+CYASSL_API long CyaSSL_CTX_sess_timeouts(CYASSL_CTX*);
+CYASSL_API long CyaSSL_CTX_sess_number(CYASSL_CTX*);
+CYASSL_API long CyaSSL_CTX_sess_get_cache_size(CYASSL_CTX*);
+
+#define CYASSL_DEFAULT_CIPHER_LIST ""   /* default all */
+#define CYASSL_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,
+
+    CYASSL_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 */
+
+#ifndef NO_FILESYSTEM
+/* CyaSSL extension, provide last error from SSL_get_error
+   since not using thread storage error queue */
+CYASSL_API void  CyaSSL_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_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)(CYASSL*, const char*, char*,
+                                    unsigned int, unsigned char*, unsigned int);
+    CYASSL_API void CyaSSL_CTX_set_psk_client_callback(CYASSL_CTX*,
+                                                    psk_client_callback);
+    CYASSL_API void CyaSSL_set_psk_client_callback(CYASSL*,psk_client_callback);
+
+    CYASSL_API const char* CyaSSL_get_psk_identity_hint(const CYASSL*);
+    CYASSL_API const char* CyaSSL_get_psk_identity(const CYASSL*);
+
+    CYASSL_API int CyaSSL_CTX_use_psk_identity_hint(CYASSL_CTX*, const char*);
+    CYASSL_API int CyaSSL_use_psk_identity_hint(CYASSL*, const char*);
+
+    typedef unsigned int (*psk_server_callback)(CYASSL*, const char*,
+                          unsigned char*, unsigned int);
+    CYASSL_API void CyaSSL_CTX_set_psk_server_callback(CYASSL_CTX*,
+                                                    psk_server_callback);
+    CYASSL_API void CyaSSL_set_psk_server_callback(CYASSL*,psk_server_callback);
+
+    #define PSK_TYPES_DEFINED
+#endif /* NO_PSK */
+
+
+/* extra begins */
+
+enum {  /* ERR Constants */
+    ERR_TXT_STRING = 1
+};
+
+CYASSL_API unsigned long CyaSSL_ERR_get_error_line_data(const char**, int*,
+                                                 const char**, int *);
+
+CYASSL_API unsigned long CyaSSL_ERR_get_error(void);
+CYASSL_API void          CyaSSL_ERR_clear_error(void);
+
+
+CYASSL_API int  CyaSSL_RAND_status(void);
+CYASSL_API int  CyaSSL_RAND_bytes(unsigned char* buf, int num);
+CYASSL_API CYASSL_METHOD *CyaSSLv23_server_method(void);
+CYASSL_API long CyaSSL_CTX_set_options(CYASSL_CTX*, long);
+#ifndef NO_CERTS
+  CYASSL_API int  CyaSSL_CTX_check_private_key(CYASSL_CTX*);
+#endif /* !NO_CERTS */
+
+CYASSL_API void CyaSSL_ERR_free_strings(void);
+CYASSL_API void CyaSSL_ERR_remove_state(unsigned long);
+CYASSL_API void CyaSSL_EVP_cleanup(void);
+
+CYASSL_API void CyaSSL_cleanup_all_ex_data(void);
+CYASSL_API long CyaSSL_CTX_set_mode(CYASSL_CTX* ctx, long mode);
+CYASSL_API long CyaSSL_CTX_get_mode(CYASSL_CTX* ctx);
+CYASSL_API void CyaSSL_CTX_set_default_read_ahead(CYASSL_CTX* ctx, int m);
+
+CYASSL_API long CyaSSL_CTX_sess_set_cache_size(CYASSL_CTX*, long);
+
+CYASSL_API int  CyaSSL_CTX_set_default_verify_paths(CYASSL_CTX*);
+CYASSL_API int  CyaSSL_CTX_set_session_id_context(CYASSL_CTX*,
+                                            const unsigned char*, unsigned int);
+CYASSL_API CYASSL_X509* CyaSSL_get_peer_certificate(CYASSL* ssl);
+
+CYASSL_API int CyaSSL_want_read(CYASSL*);
+CYASSL_API int CyaSSL_want_write(CYASSL*);
+
+CYASSL_API int CyaSSL_BIO_printf(CYASSL_BIO*, const char*, ...);
+CYASSL_API int CyaSSL_ASN1_UTCTIME_print(CYASSL_BIO*,
+                                         const CYASSL_ASN1_UTCTIME*);
+CYASSL_API int   CyaSSL_sk_num(CYASSL_X509_REVOKED*);
+CYASSL_API void* CyaSSL_sk_value(CYASSL_X509_REVOKED*, int);
+
+/* stunnel 4.28 needs */
+CYASSL_API void* CyaSSL_CTX_get_ex_data(const CYASSL_CTX*, int);
+CYASSL_API int   CyaSSL_CTX_set_ex_data(CYASSL_CTX*, int, void*);
+CYASSL_API void  CyaSSL_CTX_sess_set_get_cb(CYASSL_CTX*,
+                       CYASSL_SESSION*(*f)(CYASSL*, unsigned char*, int, int*));
+CYASSL_API void  CyaSSL_CTX_sess_set_new_cb(CYASSL_CTX*,
+                                            int (*f)(CYASSL*, CYASSL_SESSION*));
+CYASSL_API void  CyaSSL_CTX_sess_set_remove_cb(CYASSL_CTX*,
+                                       void (*f)(CYASSL_CTX*, CYASSL_SESSION*));
+
+CYASSL_API int          CyaSSL_i2d_SSL_SESSION(CYASSL_SESSION*,unsigned char**);
+CYASSL_API CYASSL_SESSION* CyaSSL_d2i_SSL_SESSION(CYASSL_SESSION**,
+                                                   const unsigned char**, long);
+
+CYASSL_API long CyaSSL_SESSION_get_timeout(const CYASSL_SESSION*);
+CYASSL_API long CyaSSL_SESSION_get_time(const CYASSL_SESSION*);
+CYASSL_API int  CyaSSL_CTX_get_ex_new_index(long, void*, void*, void*, void*);
+
+/* extra ends */
+
+
+/* CyaSSL extensions */
+
+/* call before SSL_connect, if verifying will add name check to
+   date check and signature check */
+CYASSL_API int CyaSSL_check_domain_name(CYASSL* ssl, const char* dn);
+
+/* need to call once to load library (session cache) */
+CYASSL_API int CyaSSL_Init(void);
+/* call when done to cleanup/free session cache mutex / resources  */
+CYASSL_API int CyaSSL_Cleanup(void);
+
+/* turn logging on, only if compiled in */
+CYASSL_API int  CyaSSL_Debugging_ON(void);
+/* turn logging off */
+CYASSL_API void CyaSSL_Debugging_OFF(void);
+
+/* do accept or connect depedning on side */
+CYASSL_API int CyaSSL_negotiate(CYASSL* ssl);
+/* turn on CyaSSL data compression */
+CYASSL_API int CyaSSL_set_compression(CYASSL* ssl);
+
+CYASSL_API int CyaSSL_set_timeout(CYASSL*, unsigned int);
+CYASSL_API int CyaSSL_CTX_set_timeout(CYASSL_CTX*, unsigned int);
+
+/* get CyaSSL peer X509_CHAIN */
+CYASSL_API CYASSL_X509_CHAIN* CyaSSL_get_peer_chain(CYASSL* ssl);
+/* peer chain count */
+CYASSL_API int  CyaSSL_get_chain_count(CYASSL_X509_CHAIN* chain);
+/* index cert length */
+CYASSL_API int  CyaSSL_get_chain_length(CYASSL_X509_CHAIN*, int idx);
+/* index cert */
+CYASSL_API unsigned char* CyaSSL_get_chain_cert(CYASSL_X509_CHAIN*, int idx);
+/* index cert in X509 */
+CYASSL_API CYASSL_X509* CyaSSL_get_chain_X509(CYASSL_X509_CHAIN*, int idx);
+/* free X509 */
+CYASSL_API void CyaSSL_FreeX509(CYASSL_X509*);
+/* get index cert in PEM */
+CYASSL_API int  CyaSSL_get_chain_cert_pem(CYASSL_X509_CHAIN*, int idx,
+                                unsigned char* buffer, int inLen, int* outLen);
+CYASSL_API const unsigned char* CyaSSL_get_sessionID(const CYASSL_SESSION* s);
+CYASSL_API int  CyaSSL_X509_get_serial_number(CYASSL_X509*,unsigned char*,int*);
+CYASSL_API char*  CyaSSL_X509_get_subjectCN(CYASSL_X509*);
+CYASSL_API const unsigned char* CyaSSL_X509_get_der(CYASSL_X509*, int*);
+
+CYASSL_API int CyaSSL_cmp_peer_cert_to_file(CYASSL*, const char*);
+
+CYASSL_API char* CyaSSL_X509_get_next_altname(CYASSL_X509*);
+
+/* connect enough to get peer cert */
+CYASSL_API int  CyaSSL_connect_cert(CYASSL* ssl);
+
+/* XXX This should be #ifndef NO_DH */
+#ifndef NO_CERTS
+/* server Diffie-Hellman parameters */
+CYASSL_API int  CyaSSL_SetTmpDH(CYASSL*, const unsigned char* p, int pSz,
+                                const unsigned char* g, int gSz);
+CYASSL_API int  CyaSSL_SetTmpDH_buffer(CYASSL*, const unsigned char* b, long sz,
+                                       int format);
+CYASSL_API int  CyaSSL_SetTmpEC_DHE_Sz(CYASSL*, unsigned short);
+#ifndef NO_FILESYSTEM
+    CYASSL_API int  CyaSSL_SetTmpDH_file(CYASSL*, const char* f, int format);
+#endif
+
+/* server ctx Diffie-Hellman parameters */
+CYASSL_API int  CyaSSL_CTX_SetTmpDH(CYASSL_CTX*, const unsigned char* p,
+                                    int pSz, const unsigned char* g, int gSz);
+CYASSL_API int  CyaSSL_CTX_SetTmpDH_buffer(CYASSL_CTX*, const unsigned char* b,
+                                           long sz, int format);
+CYASSL_API int  CyaSSL_CTX_SetTmpEC_DHE_Sz(CYASSL_CTX*, unsigned short);
+
+#ifndef NO_FILESYSTEM
+    CYASSL_API int  CyaSSL_CTX_SetTmpDH_file(CYASSL_CTX*, const char* f,
+                                             int format);
+#endif
+#endif
+
+/* keyblock size in bytes or -1 */
+/* need to call CyaSSL_KeepArrays before handshake to save keys */
+CYASSL_API int CyaSSL_get_keyblock_size(CYASSL*);
+CYASSL_API int CyaSSL_get_keys(CYASSL*,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. */
+CYASSL_API int CyaSSL_make_eap_keys(CYASSL*, 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(CYASSL_MDK_ARM)
+            #include <sys/uio.h>
+        #endif
+        /* allow writev style writing */
+        CYASSL_API int CyaSSL_writev(CYASSL* ssl, const struct iovec* iov,
+                                     int iovcnt);
+    #endif
+#endif
+
+
+#ifndef NO_CERTS
+    /* SSL_CTX versions */
+    CYASSL_API int CyaSSL_CTX_UnloadCAs(CYASSL_CTX*);
+    CYASSL_API int CyaSSL_CTX_load_verify_buffer(CYASSL_CTX*, 
+                                               const unsigned char*, long, int);
+    CYASSL_API int CyaSSL_CTX_use_certificate_buffer(CYASSL_CTX*,
+                                               const unsigned char*, long, int);
+    CYASSL_API int CyaSSL_CTX_use_PrivateKey_buffer(CYASSL_CTX*,
+                                               const unsigned char*, long, int);
+    CYASSL_API int CyaSSL_CTX_use_certificate_chain_buffer(CYASSL_CTX*, 
+                                                    const unsigned char*, long);
+
+    /* SSL versions */
+    CYASSL_API int CyaSSL_use_certificate_buffer(CYASSL*, const unsigned char*,
+                                               long, int);
+    CYASSL_API int CyaSSL_use_PrivateKey_buffer(CYASSL*, const unsigned char*,
+                                               long, int);
+    CYASSL_API int CyaSSL_use_certificate_chain_buffer(CYASSL*, 
+                                               const unsigned char*, long);
+#endif
+
+CYASSL_API int CyaSSL_CTX_set_group_messages(CYASSL_CTX*);
+CYASSL_API int CyaSSL_set_group_messages(CYASSL*);
+
+/* I/O callbacks */
+typedef int (*CallbackIORecv)(CYASSL *ssl, char *buf, int sz, void *ctx);
+typedef int (*CallbackIOSend)(CYASSL *ssl, char *buf, int sz, void *ctx);
+
+CYASSL_API void CyaSSL_SetIORecv(CYASSL_CTX*, CallbackIORecv);
+CYASSL_API void CyaSSL_SetIOSend(CYASSL_CTX*, CallbackIOSend);
+
+CYASSL_API void CyaSSL_SetIOReadCtx( CYASSL* ssl, void *ctx);
+CYASSL_API void CyaSSL_SetIOWriteCtx(CYASSL* ssl, void *ctx);
+
+CYASSL_API void CyaSSL_SetIOReadFlags( CYASSL* ssl, int flags);
+CYASSL_API void CyaSSL_SetIOWriteFlags(CYASSL* ssl, int flags);
+
+typedef int (*CallbackGenCookie)(CYASSL* ssl, unsigned char* buf, int sz,
+                                 void* ctx);
+CYASSL_API void CyaSSL_CTX_SetGenCookie(CYASSL_CTX*, CallbackGenCookie);
+CYASSL_API void CyaSSL_SetCookieCtx(CYASSL* ssl, void *ctx);
+
+typedef int (*CallbackIOOcsp)(void*, const char*, int,
+                                         unsigned char*, int, unsigned char**);
+typedef void (*CallbackIOOcspRespFree)(void*,unsigned char*); 
+#ifdef HAVE_OCSP 
+CYASSL_API void CyaSSL_SetIOOcsp(CYASSL_CTX *ocsp, CallbackIOOcsp cb);
+CYASSL_API void CyaSSL_SetIOOcspRespFree(CYASSL_CTX *ocsp,
+                                                    CallbackIOOcspRespFree cb);
+CYASSL_API void CyaSSL_SetIOOcspCtx(CYASSL_CTX *ocsp, void *octx);
+#endif
+
+/* I/O Callback default errors */
+enum IOerrors {
+    CYASSL_CBIO_ERR_GENERAL    = -1,     /* general unexpected err */
+    CYASSL_CBIO_ERR_WANT_READ  = -2,     /* need to call read  again */
+    CYASSL_CBIO_ERR_WANT_WRITE = -2,     /* need to call write again */
+    CYASSL_CBIO_ERR_CONN_RST   = -3,     /* connection reset */
+    CYASSL_CBIO_ERR_ISR        = -4,     /* interrupt */
+    CYASSL_CBIO_ERR_CONN_CLOSE = -5,     /* connection closed or epipe */
+    CYASSL_CBIO_ERR_TIMEOUT    = -6      /* socket timeout */
+};
+
+
+/* CA cache callbacks */
+enum {
+    CYASSL_SSLV3    = 0,
+    CYASSL_TLSV1    = 1,
+    CYASSL_TLSV1_1  = 2,
+    CYASSL_TLSV1_2  = 3,
+    CYASSL_USER_CA  = 1,          /* user added as trusted */
+    CYASSL_CHAIN_CA = 2           /* added to cache from trusted chain */
+};
+
+CYASSL_API int CyaSSL_GetObjectSize(void);  /* object size based on build */
+CYASSL_API int CyaSSL_SetVersion(CYASSL* ssl, int version);
+CYASSL_API int CyaSSL_KeyPemToDer(const unsigned char*, int sz, unsigned char*,
+                                  int, const char*);
+
+typedef void (*CallbackCACache)(unsigned char* der, int sz, int type);
+typedef void (*CbMissingCRL)(const char* url);
+
+
+#ifndef NO_CERTS
+	CYASSL_API void CyaSSL_CTX_SetCACb(CYASSL_CTX*, CallbackCACache);
+
+    CYASSL_API CYASSL_CERT_MANAGER* CyaSSL_CertManagerNew(void);
+    CYASSL_API void CyaSSL_CertManagerFree(CYASSL_CERT_MANAGER*);
+
+    CYASSL_API int CyaSSL_CertManagerLoadCA(CYASSL_CERT_MANAGER*, const char* f,
+                                                                 const char* d);
+    CYASSL_API int CyaSSL_CertManagerUnloadCAs(CYASSL_CERT_MANAGER* cm);
+    CYASSL_API int CyaSSL_CertManagerVerify(CYASSL_CERT_MANAGER*, const char* f,
+                                                                    int format);
+    CYASSL_API int CyaSSL_CertManagerVerifyBuffer(CYASSL_CERT_MANAGER* cm,
+                                const unsigned char* buff, long sz, int format);
+    CYASSL_API int CyaSSL_CertManagerCheckCRL(CYASSL_CERT_MANAGER*,
+                                                        unsigned char*, int sz);
+    CYASSL_API int CyaSSL_CertManagerEnableCRL(CYASSL_CERT_MANAGER*,
+                                                                   int options);
+    CYASSL_API int CyaSSL_CertManagerDisableCRL(CYASSL_CERT_MANAGER*);
+    CYASSL_API int CyaSSL_CertManagerLoadCRL(CYASSL_CERT_MANAGER*, const char*,
+                                                                      int, int);
+    CYASSL_API int CyaSSL_CertManagerSetCRL_Cb(CYASSL_CERT_MANAGER*,
+                                                                  CbMissingCRL);
+
+    CYASSL_API int CyaSSL_EnableCRL(CYASSL* ssl, int options);
+    CYASSL_API int CyaSSL_DisableCRL(CYASSL* ssl);
+    CYASSL_API int CyaSSL_LoadCRL(CYASSL*, const char*, int, int);
+    CYASSL_API int CyaSSL_SetCRL_Cb(CYASSL*, CbMissingCRL);
+
+    CYASSL_API int CyaSSL_CTX_EnableCRL(CYASSL_CTX* ctx, int options);
+    CYASSL_API int CyaSSL_CTX_DisableCRL(CYASSL_CTX* ctx);
+    CYASSL_API int CyaSSL_CTX_LoadCRL(CYASSL_CTX*, const char*, int, int);
+    CYASSL_API int CyaSSL_CTX_SetCRL_Cb(CYASSL_CTX*, CbMissingCRL);
+#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 */
+CYASSL_API void CyaSSL_KeepArrays(CYASSL*);
+CYASSL_API void CyaSSL_FreeArrays(CYASSL*);
+
+
+/* cavium additions */
+CYASSL_API int CyaSSL_UseCavium(CYASSL*, int devId);
+CYASSL_API int CyaSSL_CTX_UseCavium(CYASSL_CTX*, int devId);
+
+/* tls extensions */
+#ifdef HAVE_SNI
+/* SNI types */
+enum {
+    CYASSL_SNI_HOST_NAME = 0
+};
+
+CYASSL_API int CyaSSL_UseSNI(CYASSL* ssl, unsigned char type, const void* data,
+                                                           unsigned short size);
+CYASSL_API int CyaSSL_CTX_UseSNI(CYASSL_CTX* ctx, unsigned char type,
+                                         const void* data, unsigned short size);
+
+#ifndef NO_CYASSL_SERVER
+/* SNI options */
+enum {
+    CYASSL_SNI_CONTINUE_ON_MISMATCH = 0x01, /* do not abort on mismatch flag */
+    CYASSL_SNI_ANSWER_ON_MISMATCH   = 0x02  /* fake match on mismatch flag */
+};
+
+CYASSL_API unsigned char CyaSSL_SNI_Matched(CYASSL* ssl, unsigned char type);
+
+CYASSL_API void CyaSSL_SNI_SetOptions(CYASSL* ssl, unsigned char type,
+                                                         unsigned char options);
+CYASSL_API void CyaSSL_CTX_SNI_SetOptions(CYASSL_CTX* ctx, unsigned char type,
+                                                         unsigned char options);
+#endif
+#endif
+
+#define CYASSL_CRL_MONITOR   0x01   /* monitor this dir flag */
+#define CYASSL_CRL_START_MON 0x02   /* start monitoring flag */
+
+#ifdef CYASSL_CALLBACKS
+
+/* used internally by CyaSSL while OpenSSL types aren't */
+#include <cyassl/callbacks.h>
+
+typedef int (*HandShakeCallBack)(HandShakeInfo*);
+typedef int (*TimeoutCallBack)(TimeoutInfo*);
+
+/* CyaSSL connect extension allowing HandShakeCallBack and/or TimeoutCallBack
+   for diagnostics */
+CYASSL_API int CyaSSL_connect_ex(CYASSL*, HandShakeCallBack, TimeoutCallBack,
+                                 Timeval);
+CYASSL_API int CyaSSL_accept_ex(CYASSL*, HandShakeCallBack, TimeoutCallBack,
+                                Timeval);
+
+#endif /* CYASSL_CALLBACKS */
+
+
+CYASSL_API long CyaSSL_CTX_OCSP_set_options(CYASSL_CTX*, long);
+CYASSL_API int  CyaSSL_CTX_OCSP_set_override_url(CYASSL_CTX*, const char*);
+
+/* OCSP Options */
+#define CYASSL_OCSP_ENABLE       0x0001 /* Enable OCSP lookups */
+#define CYASSL_OCSP_URL_OVERRIDE 0x0002 /* Use the override URL instead of URL
+                                         * in certificate */
+#define CYASSL_OCSP_NO_NONCE     0x0004 /* Disables the request nonce. */
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+
+#endif /* CYASSL_SSL_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/test.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,1303 @@
+/* test.h */
+
+#ifndef CyaSSL_TEST_H
+#define CyaSSL_TEST_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <ctype.h>
+#include <cyassl/ssl.h>
+#include <cyassl/ctaocrypt/types.h>
+
+#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(CYASSL_MDK_ARM)
+    #include <string.h>
+#else
+    #include <string.h>
+    #include <sys/types.h>
+#ifndef CYASSL_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(CYASSL_MDK_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(CYASSL_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 CYASSL_THREAD
+#else
+    #if defined(_POSIX_THREADS) && !defined(__MINGW32__)
+        typedef void*         THREAD_RETURN;
+        typedef pthread_t     THREAD_TYPE;
+        #define CYASSL_THREAD
+        #define INFINITE -1
+        #define WAIT_OBJECT_0 0L
+    #elif defined(CYASSL_MDK_ARM)
+        typedef unsigned int  THREAD_RETURN;
+        typedef int           THREAD_TYPE;
+        #define CYASSL_THREAD
+    #else
+        typedef unsigned int  THREAD_RETURN;
+        typedef intptr_t      THREAD_TYPE;
+        #define CYASSL_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)
+
+/* all certs relative to CyaSSL 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 {
+    int ready;              /* predicate */
+    int 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 struct func_args {
+    int    argc;
+    char** argv;
+    int    return_code;
+    tcp_ready* signal;
+} func_args;
+
+void wait_tcp_ready(func_args*);
+
+typedef THREAD_RETURN CYASSL_THREAD THREAD_FUNC(void*);
+
+void start_thread(THREAD_FUNC, func_args*, THREAD_TYPE*);
+void join_thread(THREAD_TYPE);
+
+/* yaSSL */
+#ifndef TEST_IPV6
+    static const char* const yasslIP   = "127.0.0.1";
+#else
+    static const char* const yasslIP   = "::1";
+#endif
+static const word16      yasslPort = 11111;
+
+static INLINE void err_sys(const char* msg)
+{
+    printf("yassl error: %s\n", msg);
+    #ifndef CYASSL_MDK_SHELL
+    if (msg)
+        exit(EXIT_FAILURE);
+    #endif
+}
+
+
+#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;
+}
+
+
+#ifdef OPENSSL_EXTRA
+
+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(CYASSL_X509* x509, const char* hdr)
+{
+    char* altName;
+    char* issuer  = CyaSSL_X509_NAME_oneline(
+                                       CyaSSL_X509_get_issuer_name(x509), 0, 0);
+    char* subject = CyaSSL_X509_NAME_oneline(
+                                      CyaSSL_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 = CyaSSL_X509_get_next_altname(x509)) != NULL)
+        printf(" altname = %s\n", altName);
+
+    ret = CyaSSL_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(CYASSL* ssl)
+{
+
+    CYASSL_CIPHER* cipher;
+#ifdef KEEP_PEER_CERT
+    CYASSL_X509* peer = CyaSSL_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", CyaSSL_get_version(ssl));
+
+    cipher = CyaSSL_get_current_cipher(ssl);
+    printf("SSL cipher suite is %s\n", CyaSSL_CIPHER_get_name(cipher));
+
+#if defined(SESSION_CERTS) && defined(SHOW_CERTS)
+    {
+        CYASSL_X509_CHAIN* chain = CyaSSL_get_peer_chain(ssl);
+        int                count = CyaSSL_get_chain_count(chain);
+        int i;
+
+        for (i = 0; i < count; i++) {
+            int length;
+            unsigned char buffer[3072];
+            CYASSL_X509* chainX509;
+
+            CyaSSL_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 = CyaSSL_get_chain_X509(chain, i);
+            if (chainX509)
+                ShowX509(chainX509, "session cert info:");
+            else
+                printf("get_chain_X509 failed\n");
+            CyaSSL_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 CYASSL_MDK_ARM
+            int err;
+            struct hostent* entry = gethostbyname(peer, &err);
+        #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(CYASSL_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");
+#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(CYASSL_MDK_ARM)
+    /* 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(CYASSL_MDK_ARM)
+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;
+}
+#endif /* !CYASSL_MDK_ARM */
+
+
+static INLINE void tcp_listen(SOCKET_T* sockfd, int* 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 : yasslIP), *port, udp);
+    tcp_socket(sockfd, udp);
+
+#if !defined(USE_WINDOWS_API) && !defined(CYASSL_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)
+        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, int port, func_args* args)
+{
+    SOCKADDR_IN_T addr;
+
+    (void)args;
+    build_addr(&addr, (useAnyAddr ? INADDR_ANY : yasslIP), port, 1);
+    tcp_socket(sockfd, 1);
+
+
+#if !defined(USE_WINDOWS_API) && !defined(CYASSL_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)
+        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);
+    }
+#endif
+
+    *clientfd = udp_read_connect(*sockfd);
+}
+
+static INLINE void tcp_accept(SOCKET_T* sockfd, SOCKET_T* clientfd,
+                              func_args* args, int port, int useAnyAddr,
+                              int udp)
+{
+    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);
+    }
+#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(CYASSL_MDK_ARM)
+         /* 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(CYASSL* 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(CYASSL* 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;
+    }
+
+#else
+
+#if !defined(CYASSL_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 {
+        CYASSL_CA   = 1,
+        CYASSL_CERT = 2,
+        CYASSL_KEY  = 3
+    };
+
+    static INLINE void load_buffer(CYASSL_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 CyaSSL home directory if not");
+        fseek(file, 0, SEEK_END);
+        sz = ftell(file);
+        rewind(file);
+        fread(buff, sizeof(buff), 1, file);
+  
+        if (type == CYASSL_CA) {
+            if (CyaSSL_CTX_load_verify_buffer(ctx, buff, sz, SSL_FILETYPE_PEM)
+                                              != SSL_SUCCESS)
+                err_sys("can't load buffer ca file");
+        }
+        else if (type == CYASSL_CERT) {
+            if (CyaSSL_CTX_use_certificate_buffer(ctx, buff, sz,
+                        SSL_FILETYPE_PEM) != SSL_SUCCESS)
+                err_sys("can't load buffer cert file");
+        }
+        else if (type == CYASSL_KEY) {
+            if (CyaSSL_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, CYASSL_X509_STORE_CTX* store)
+{
+    char buffer[80];
+
+#ifdef OPENSSL_EXTRA
+    CYASSL_X509* peer;
+#endif
+
+    printf("In verification callback, error = %d, %s\n", store->error,
+                                 CyaSSL_ERR_error_string(store->error, buffer));
+#ifdef OPENSSL_EXTRA
+    peer = store->current_cert;
+    if (peer) {
+        char* issuer  = CyaSSL_X509_NAME_oneline(
+                                       CyaSSL_X509_get_issuer_name(peer), 0, 0);
+        char* subject = CyaSSL_X509_NAME_oneline(
+                                      CyaSSL_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 */
+
+
+#ifdef HAVE_CRL
+
+static INLINE void CRL_CallBack(const char* url)
+{
+    printf("CRL callback url = %s\n", url);
+}
+
+#endif
+
+#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);
+}
+
+
+static INLINE void SetDH(CYASSL* 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,
+    };
+
+    CyaSSL_SetTmpDH(ssl, p, sizeof(p), g, sizeof(g));
+}
+
+static INLINE void SetDHCtx(CYASSL_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,
+    };
+
+    CyaSSL_CTX_SetTmpDH(ctx, p, sizeof(p), g, sizeof(g));
+}
+
+#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(CYASSL_MDK_ARM)
+    /* KEIL-RL File System does not support relative directry */
+#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_CYASSL_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(CYASSL_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*)((byte*)ptr - sizeof(memoryTrack));
+
+#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*)((byte*)ptr - sizeof(memoryTrack));
+
+            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 (CyaSSL_SetAllocators(TrackMalloc, TrackFree, TrackRealloc) != 0)
+            err_sys("CyaSSL 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_CYASSL_MEMORY */
+
+
+#ifdef HAVE_STACK_SIZE
+
+typedef THREAD_RETURN CYASSL_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, 0xee, 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] != 0xee) {
+            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 */
+
+
+#if defined(__hpux__) || defined(__MINGW32__)
+
+/* 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__ */
+
+#endif /* CyaSSL_TEST_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/version.h	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,35 @@
+/* cyassl_version.h.in
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LIBCYASSL_VERSION_STRING "2.7.0"
+#define LIBCYASSL_VERSION_HEX 0x02007000
+
+#ifdef __cplusplus
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/internal.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,10365 @@
+/* internal.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#include <cyassl/internal.h>
+#include <cyassl/ctaoerror.h>
+#include <cyassl/ctaocrypt/asn.h>
+
+#ifdef HAVE_LIBZ
+    #include "zlib.h"
+#endif
+
+#ifdef HAVE_NTRU
+    #include "crypto_ntru.h"
+#endif
+
+#if defined(DEBUG_CYASSL) || defined(SHOW_SECRETS)
+    #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
+
+
+#if defined(OPENSSL_EXTRA) && defined(NO_DH)
+    #error OPENSSL_EXTRA needs DH, please remove NO_DH
+#endif
+
+#if defined(CYASSL_CALLBACKS) && !defined(LARGE_STATIC_BUFFERS)
+    #error \
+CYASSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS
+#endif
+
+
+#ifndef NO_CYASSL_CLIENT
+    static int DoHelloVerifyRequest(CYASSL* ssl, const byte* input, word32*);
+    static int DoServerHello(CYASSL* ssl, const byte* input, word32*, word32);
+    static int DoServerKeyExchange(CYASSL* ssl, const byte* input, word32*);
+    #ifndef NO_CERTS
+        static int DoCertificateRequest(CYASSL* ssl, const byte* input,word32*);
+    #endif
+#endif
+
+
+#ifndef NO_CYASSL_SERVER
+    static int DoClientHello(CYASSL* ssl, const byte* input, word32*, word32,
+                             word32);
+    static int DoClientKeyExchange(CYASSL* ssl, byte* input, word32*, word32);
+    #if !defined(NO_RSA) || defined(HAVE_ECC)
+        static int DoCertificateVerify(CYASSL* ssl, byte*, word32*, word32);
+    #endif
+#endif
+
+typedef enum {
+    doProcessInit = 0,
+#ifndef NO_CYASSL_SERVER
+    runProcessOldClientHello,
+#endif
+    getRecordLayerHeader,
+    getData,
+    runProcessingOneMessage
+} processReply;
+
+#ifndef NO_OLD_TLS
+static void Hmac(CYASSL* ssl, byte* digest, const byte* in, word32 sz,
+                 int content, int verify);
+
+#endif
+
+#ifndef NO_CERTS
+static void BuildCertHashes(CYASSL* ssl, Hashes* hashes);
+#endif
+
+static void PickHashSigAlgo(CYASSL* ssl,
+                                const byte* hashSigAlgo, word32 hashSigAlgoSz);
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+int IsTLS(const CYASSL* ssl)
+{
+    if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_MINOR)
+        return 1;
+
+    return 0;
+}
+
+
+int IsAtLeastTLSv1_2(const CYASSL* 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) {
+        int ret = InitRng(&rng);
+        if (ret == 0)
+            return 1;
+        else
+            return 0;
+    }
+
+    if (out == NULL)
+        return 0;
+
+    if (cmd == GET_BYTE_OF_ENTROPY) {
+        RNG_GenerateBlock(&rng, out, 1);
+        return 1;
+    }
+
+    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 CYASSL_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 /* CYASSL_DTLS */
+
+
+/* convert 16 bit integer to opaque */
+static INLINE void c16toa(word16 u16, byte* c)
+{
+    c[0] = (u16 >> 8) & 0xff;
+    c[1] =  u16 & 0xff;
+}
+
+
+/* convert 32 bit integer to opaque */
+static INLINE void c32toa(word32 u32, byte* c)
+{
+    c[0] = (u32 >> 24) & 0xff;
+    c[1] = (u32 >> 16) & 0xff;
+    c[2] = (u32 >>  8) & 0xff;
+    c[3] =  u32 & 0xff;
+}
+
+
+/* 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 = (c[0] << 8) | (c[1]);
+}
+
+
+#ifdef CYASSL_DTLS
+
+/* 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 /* CYASSL_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(CYASSL* 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(CYASSL* ssl)
+    {
+        if (ssl->didStreamInit) {
+            deflateEnd(&ssl->c_stream);
+            inflateEnd(&ssl->d_stream);
+        }
+    }
+
+
+    /* compress in to out, return out size or error */
+    static int myCompress(CYASSL* 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(CYASSL* 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(CYASSL_METHOD* method, ProtocolVersion pv)
+{
+    method->version    = pv;
+    method->side       = CLIENT_END;
+    method->downgrade  = 0;
+}
+
+
+/* Initialze SSL context, return 0 on success */
+int InitSSL_Ctx(CYASSL_CTX* ctx, CYASSL_METHOD* method)
+{
+    ctx->method = method;
+    ctx->refCount = 1;          /* so either CTX_free or SSL_free can release */
+#ifndef NO_CERTS
+    ctx->certificate.buffer = 0;
+    ctx->certChain.buffer   = 0;
+    ctx->privateKey.buffer  = 0;
+    ctx->serverDH_P.buffer  = 0;
+    ctx->serverDH_G.buffer  = 0;
+#endif
+    ctx->haveDH             = 0;
+    ctx->haveNTRU           = 0;    /* start off */
+    ctx->haveECDSAsig       = 0;    /* start off */
+    ctx->haveStaticECC      = 0;    /* start off */
+    ctx->heap               = ctx;  /* defaults to self */
+#ifndef NO_PSK
+    ctx->havePSK            = 0;
+    ctx->server_hint[0]     = 0;
+    ctx->client_psk_cb      = 0;
+    ctx->server_psk_cb      = 0;
+#endif /* NO_PSK */
+#ifdef HAVE_ECC
+    ctx->eccTempKeySz       = ECDHE_SIZE;   
+#endif
+
+#ifdef OPENSSL_EXTRA
+    ctx->passwd_cb   = 0;
+    ctx->userdata    = 0;
+#endif /* OPENSSL_EXTRA */
+
+    ctx->timeout = DEFAULT_TIMEOUT;
+
+#ifndef CYASSL_USER_IO
+    ctx->CBIORecv = EmbedReceive;
+    ctx->CBIOSend = EmbedSend;
+    #ifdef CYASSL_DTLS
+        if (method->version.major == DTLS_MAJOR) {
+            ctx->CBIORecv   = EmbedReceiveFrom;
+            ctx->CBIOSend   = EmbedSendTo;
+            ctx->CBIOCookie = EmbedGenerateCookie;
+        }
+    #endif
+#else
+    /* user will set */
+    ctx->CBIORecv   = NULL;
+    ctx->CBIOSend   = NULL;
+    #ifdef CYASSL_DTLS
+        ctx->CBIOCookie = NULL;
+    #endif
+#endif
+    ctx->partialWrite   = 0;
+    ctx->verifyCallback = 0;
+
+#ifndef NO_CERTS
+    ctx->cm = CyaSSL_CertManagerNew();
+#endif
+#ifdef HAVE_NTRU
+    if (method->side == CLIENT_END)
+        ctx->haveNTRU = 1;           /* always on cliet side */
+                                     /* server can turn on by loading key */
+#endif
+#ifdef HAVE_ECC
+    if (method->side == CLIENT_END) {
+        ctx->haveECDSAsig  = 1;        /* always on cliet side */
+        ctx->haveStaticECC = 1;        /* server can turn on by loading key */
+    }
+#endif
+    ctx->suites.setSuites = 0;  /* user hasn't set yet */
+    /* remove DH later if server didn't set, add psk later */
+    InitSuites(&ctx->suites, method->version, TRUE, FALSE, TRUE, ctx->haveNTRU,
+               ctx->haveECDSAsig, ctx->haveStaticECC, method->side);  
+    ctx->verifyPeer = 0;
+    ctx->verifyNone = 0;
+    ctx->failNoCert = 0;
+    ctx->sessionCacheOff      = 0;  /* initially on */
+    ctx->sessionCacheFlushOff = 0;  /* initially on */
+    ctx->sendVerify = 0;
+    ctx->quietShutdown = 0;
+    ctx->groupMessages = 0;
+#ifdef HAVE_OCSP
+    CyaSSL_OCSP_Init(&ctx->ocsp);
+#endif
+#ifdef HAVE_CAVIUM
+    ctx->devId = NO_CAVIUM_DEVICE; 
+#endif
+#ifdef HAVE_TLS_EXTENSIONS
+    ctx->extensions = NULL;
+#endif
+
+    if (InitMutex(&ctx->countMutex) < 0) {
+        CYASSL_MSG("Mutex error on CTX init");
+        return BAD_MUTEX_ERROR;
+    } 
+#ifndef NO_CERTS
+    if (ctx->cm == NULL) {
+        CYASSL_MSG("Bad Cert Manager New");
+        return BAD_CERT_MANAGER_ERROR;
+    }
+#endif
+    return 0;
+}
+
+
+/* In case contexts are held in array and don't want to free actual ctx */
+void SSL_CtxResourceFree(CYASSL_CTX* ctx)
+{
+    XFREE(ctx->method, ctx->heap, DYNAMIC_TYPE_METHOD);
+
+#ifndef NO_CERTS
+    XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_DH);
+    XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_DH);
+    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);
+    CyaSSL_CertManagerFree(ctx->cm);
+#endif
+#ifdef HAVE_OCSP
+    CyaSSL_OCSP_Cleanup(&ctx->ocsp);
+#endif
+#ifdef HAVE_TLS_EXTENSIONS
+    TLSX_FreeAll(ctx->extensions);
+#endif
+}
+
+
+void FreeSSL_Ctx(CYASSL_CTX* ctx)
+{
+    int doFree = 0;
+
+    if (LockMutex(&ctx->countMutex) != 0) {
+        CYASSL_MSG("Couldn't lock count mutex");
+        return;
+    }
+    ctx->refCount--;
+    if (ctx->refCount == 0)
+        doFree = 1;
+    UnLockMutex(&ctx->countMutex);
+
+    if (doFree) {
+        CYASSL_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;
+        CYASSL_MSG("CTX ref count not 0 yet, no free");
+    }
+}
+
+
+/* Set cipher pointers to null */
+void InitCiphers(CYASSL* 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
+    ssl->encrypt.setup = 0;
+    ssl->decrypt.setup = 0;
+}
+
+
+/* Free ciphers */
+void FreeCiphers(CYASSL* ssl)
+{
+    (void)ssl;
+#ifdef BUILD_ARC4
+    #ifdef HAVE_CAVIUM
+    if (ssl->devId != NO_CAVIUM_DEVICE) {
+        Arc4FreeCavium(ssl->encrypt.arc4);
+        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) {
+        Des3_FreeCavium(ssl->encrypt.des3);
+        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) {
+        AesFreeCavium(ssl->encrypt.aes);
+        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 BUILD_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
+}
+
+
+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;
+}
+
+
+void InitSuites(Suites* suites, ProtocolVersion pv, byte haveRSA, byte havePSK,
+                byte haveDH, byte haveNTRU, byte haveECDSAsig,
+                byte 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) {
+        CYASSL_MSG("InitSuites pointer error");
+        return; 
+    }
+
+    if (suites->setSuites)
+        return;      /* trust user settings, don't override */
+
+    if (side == SERVER_END && haveStaticECC)
+        haveRSA = 0;   /* can't do RSA with ECDSA key */
+
+    if (side == SERVER_END && haveECDSAsig) {
+        haveRSAsig = 0;     /* can't have RSA sig if signed by ECDSA */
+        (void)haveRSAsig;   /* non ecc builds won't read */
+    }
+
+#ifdef CYASSL_DTLS
+    if (pv.major == DTLS_MAJOR) {
+        tls    = 1;
+        tls1_2 = pv.minor <= DTLSv1_2_MINOR;
+    }
+#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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_GCM_SHA256
+    if (tls1_2 && haveRSA) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_RSA_WITH_AES_128_GCM_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_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_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_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_CBC_MD5
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_HC_128_CBC_MD5;
+    }
+#endif
+    
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_HC_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_RABBIT_CBC_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;
+
+    {
+        idx = 0;
+        
+        if (haveECDSAsig) {
+            #ifdef CYASSL_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 CYASSL_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
+        }
+
+        suites->hashSigAlgoSz = idx;
+    }
+}
+
+
+#ifndef NO_CERTS
+
+/* Initialize CyaSSL X509 type */
+void InitX509(CYASSL_X509* x509, int dynamicFlag)
+{
+    x509->derCert.buffer = NULL;
+    x509->altNames       = NULL;
+    x509->altNamesNext   = NULL;
+    x509->dynamicMemory  = (byte)dynamicFlag;
+}
+
+
+/* Free CyaSSL X509 type */
+void FreeX509(CYASSL_X509* x509)
+{
+    if (x509 == NULL)
+        return;
+
+    XFREE(x509->derCert.buffer, NULL, DYNAMIC_TYPE_CERT);
+    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(CYASSL* ssl, CYASSL_CTX* ctx)
+{
+    int  ret;
+    byte haveRSA = 0;
+    byte havePSK = 0;
+
+    ssl->ctx     = ctx; /* only for passing to calls, options could change */
+    ssl->version = ctx->method->version;
+    ssl->suites  = NULL;
+
+#ifdef HAVE_LIBZ
+    ssl->didStreamInit = 0;
+#endif
+#ifndef NO_RSA
+    haveRSA = 1;
+#endif
+   
+#ifndef NO_CERTS
+    ssl->buffers.certificate.buffer   = 0;
+    ssl->buffers.key.buffer           = 0;
+    ssl->buffers.certChain.buffer     = 0;
+#endif
+    ssl->buffers.inputBuffer.length   = 0;
+    ssl->buffers.inputBuffer.idx      = 0;
+    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.outputBuffer.length  = 0;
+    ssl->buffers.outputBuffer.idx     = 0;
+    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;
+    ssl->buffers.domainName.buffer    = 0;
+#ifndef NO_CERTS
+    ssl->buffers.serverDH_P.buffer    = 0;
+    ssl->buffers.serverDH_G.buffer    = 0;
+    ssl->buffers.serverDH_Pub.buffer  = 0;
+    ssl->buffers.serverDH_Priv.buffer = 0;
+#endif
+    ssl->buffers.clearOutputBuffer.buffer  = 0;
+    ssl->buffers.clearOutputBuffer.length  = 0;
+    ssl->buffers.prevSent                  = 0;
+    ssl->buffers.plainSz                   = 0;
+
+#ifdef KEEP_PEER_CERT
+    InitX509(&ssl->peerCert, 0);
+#endif
+
+#ifdef HAVE_ECC
+    ssl->eccTempKeySz = ctx->eccTempKeySz;
+    ssl->peerEccKeyPresent = 0;
+    ssl->peerEccDsaKeyPresent = 0;
+    ssl->eccDsaKeyPresent = 0;
+    ssl->eccTempKeyPresent = 0;
+    ssl->peerEccKey = NULL;
+    ssl->peerEccDsaKey = NULL;
+    ssl->eccDsaKey = NULL;
+    ssl->eccTempKey = NULL;
+#endif
+
+    ssl->timeout = ctx->timeout;
+    ssl->rfd = -1;   /* set to invalid descriptor */
+    ssl->wfd = -1;
+    ssl->rflags = 0;    /* no user flags yet */
+    ssl->wflags = 0;    /* no user flags yet */
+    ssl->biord = 0;
+    ssl->biowr = 0;
+
+    ssl->IOCB_ReadCtx  = &ssl->rfd;  /* prevent invalid pointer access if not */
+    ssl->IOCB_WriteCtx = &ssl->wfd;  /* correctly set */
+#ifdef CYASSL_DTLS
+    ssl->IOCB_CookieCtx = NULL;      /* we don't use for default cb */
+    ssl->dtls_expected_rx = MAX_MTU;
+#endif
+
+#ifndef NO_OLD_TLS
+#ifndef NO_MD5
+    InitMd5(&ssl->hashMd5);
+#endif
+#ifndef NO_SHA
+    InitSha(&ssl->hashSha);
+#endif
+#endif
+#ifndef NO_SHA256
+    InitSha256(&ssl->hashSha256);
+#endif
+#ifdef CYASSL_SHA384
+    InitSha384(&ssl->hashSha384);
+#endif
+#ifndef NO_RSA
+    ssl->peerRsaKey = NULL;
+    ssl->peerRsaKeyPresent = 0;
+#endif
+    ssl->verifyCallback    = ctx->verifyCallback;
+    ssl->verifyCbCtx       = NULL;
+    ssl->options.side      = ctx->method->side;
+    ssl->options.downgrade = ctx->method->downgrade;
+    ssl->error = 0;
+    ssl->options.connReset = 0;
+    ssl->options.isClosed  = 0;
+    ssl->options.closeNotify  = 0;
+    ssl->options.sentNotify   = 0;
+    ssl->options.usingCompression = 0;
+    if (ssl->options.side == SERVER_END)
+        ssl->options.haveDH = ctx->haveDH;
+    else
+        ssl->options.haveDH = 0;
+    ssl->options.haveNTRU      = ctx->haveNTRU;
+    ssl->options.haveECDSAsig  = ctx->haveECDSAsig;
+    ssl->options.haveStaticECC = ctx->haveStaticECC;
+    ssl->options.havePeerCert    = 0; 
+    ssl->options.havePeerVerify  = 0;
+    ssl->options.usingPSK_cipher = 0;
+    ssl->options.sendAlertState = 0;
+#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 */
+
+    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;
+
+#ifdef CYASSL_DTLS
+    ssl->keys.dtls_sequence_number      = 0;
+    ssl->keys.dtls_peer_sequence_number = 0;
+    ssl->keys.dtls_expected_peer_sequence_number = 0;
+    ssl->keys.dtls_handshake_number     = 0;
+    ssl->keys.dtls_expected_peer_handshake_number = 0;
+    ssl->keys.dtls_epoch                = 0;
+    ssl->keys.dtls_peer_epoch           = 0;
+    ssl->keys.dtls_expected_peer_epoch  = 0;
+    ssl->dtls_timeout_init              = DTLS_TIMEOUT_INIT;
+    ssl->dtls_timeout_max               = DTLS_TIMEOUT_MAX;
+    ssl->dtls_timeout                   = ssl->dtls_timeout_init;
+    ssl->dtls_pool                      = NULL;
+    ssl->dtls_msg_list                  = NULL;
+#endif
+    ssl->keys.encryptSz    = 0;
+    ssl->keys.encryptionOn = 0;     /* initially off */
+    ssl->keys.decryptedCur = 0;     /* initially off */
+    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;
+    
+    ssl->options.resuming = 0;
+    ssl->options.haveSessionId = 0;
+    #ifndef NO_OLD_TLS
+        ssl->hmac = Hmac;         /* default to SSLv3 */
+    #else
+        ssl->hmac = TLS_hmac;
+    #endif
+    ssl->heap = ctx->heap;    /* defaults to self */
+    ssl->options.tls    = 0;
+    ssl->options.tls1_1 = 0;
+    ssl->options.dtls = ssl->version.major == DTLS_MAJOR;
+    ssl->options.partialWrite  = ctx->partialWrite;
+    ssl->options.quietShutdown = ctx->quietShutdown;
+    ssl->options.certOnly = 0;
+    ssl->options.groupMessages = ctx->groupMessages;
+    ssl->options.usingNonblock = 0;
+    ssl->options.saveArrays = 0;
+
+#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;
+    if (ssl->options.side == SERVER_END) {
+        ssl->buffers.serverDH_P = ctx->serverDH_P;
+        ssl->buffers.serverDH_G = ctx->serverDH_G;
+    }
+#endif
+    ssl->buffers.weOwnCert = 0;
+    ssl->buffers.weOwnKey  = 0;
+    ssl->buffers.weOwnDH   = 0;
+
+#ifdef CYASSL_DTLS
+    ssl->buffers.dtlsCtx.fd = -1;
+    ssl->buffers.dtlsCtx.peer.sa = NULL;
+    ssl->buffers.dtlsCtx.peer.sz = 0;
+#endif
+
+#ifdef KEEP_PEER_CERT
+    ssl->peerCert.issuer.sz    = 0;
+    ssl->peerCert.subject.sz   = 0;
+#endif
+  
+#ifdef SESSION_CERTS
+    ssl->session.chain.count = 0;
+#endif
+
+#ifndef NO_CLIENT_CACHE
+    ssl->session.idLen = 0;
+#endif
+
+    ssl->cipher.ssl = ssl;
+
+#ifdef FORTRESS
+    ssl->ex_data[0] = 0;
+    ssl->ex_data[1] = 0;
+    ssl->ex_data[2] = 0;
+#endif
+
+#ifdef CYASSL_CALLBACKS
+    ssl->hsInfoOn = 0;
+    ssl->toInfoOn = 0;
+#endif
+
+#ifdef HAVE_CAVIUM
+    ssl->devId = ctx->devId; 
+#endif
+
+#ifdef HAVE_TLS_EXTENSIONS
+    ssl->extensions = NULL;
+#endif
+
+    ssl->rng    = NULL;
+    ssl->arrays = NULL;
+
+    /* 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 */
+
+    /* increment CTX reference count */
+    if (LockMutex(&ctx->countMutex) != 0) {
+        CYASSL_MSG("Couldn't lock CTX count mutex");
+        return BAD_MUTEX_ERROR;
+    }
+    ctx->refCount++;
+    UnLockMutex(&ctx->countMutex);
+
+    /* arrays */
+    ssl->arrays = (Arrays*)XMALLOC(sizeof(Arrays), ssl->heap,
+                                   DYNAMIC_TYPE_ARRAYS);
+    if (ssl->arrays == NULL) {
+        CYASSL_MSG("Arrays Memory error");
+        return MEMORY_E;
+    }
+
+#ifndef NO_PSK
+    ssl->arrays->client_identity[0] = 0;
+    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';
+    }
+    else
+        ssl->arrays->server_hint[0] = 0;
+#endif /* NO_PSK */
+
+#ifdef CYASSL_DTLS
+    ssl->arrays->cookieSz = 0;
+#endif
+
+    /* RNG */
+    ssl->rng = (RNG*)XMALLOC(sizeof(RNG), ssl->heap, DYNAMIC_TYPE_RNG);
+    if (ssl->rng == NULL) {
+        CYASSL_MSG("RNG Memory error");
+        return MEMORY_E;
+    }
+
+    if ( (ret = InitRng(ssl->rng)) != 0) {
+        CYASSL_MSG("RNG Init error");
+        return ret;
+    }
+
+    /* suites */
+    ssl->suites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap,
+                                   DYNAMIC_TYPE_SUITES);
+    if (ssl->suites == NULL) {
+        CYASSL_MSG("Suites Memory error");
+        return MEMORY_E;
+    }
+    *ssl->suites = ctx->suites;
+
+    /* peer key */
+#ifndef NO_RSA
+    ssl->peerRsaKey = (RsaKey*)XMALLOC(sizeof(RsaKey), ssl->heap,
+                                       DYNAMIC_TYPE_RSA);
+    if (ssl->peerRsaKey == NULL) {
+        CYASSL_MSG("PeerRsaKey Memory error");
+        return MEMORY_E;
+    }
+    InitRsaKey(ssl->peerRsaKey, ctx->heap);
+#endif
+#ifndef NO_CERTS
+    /* make sure server has cert and key unless using PSK */
+    if (ssl->options.side == SERVER_END && !havePSK)
+        if (!ssl->buffers.certificate.buffer || !ssl->buffers.key.buffer) {
+            CYASSL_MSG("Server missing certificate and/or private key"); 
+            return NO_PRIVATE_KEY;
+        }
+#endif
+#ifdef HAVE_ECC
+    ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key),
+                                                   ctx->heap, DYNAMIC_TYPE_ECC);
+    if (ssl->peerEccKey == NULL) {
+        CYASSL_MSG("PeerEccKey Memory error");
+        return MEMORY_E;
+    }
+    ssl->peerEccDsaKey = (ecc_key*)XMALLOC(sizeof(ecc_key),
+                                                   ctx->heap, DYNAMIC_TYPE_ECC);
+    if (ssl->peerEccDsaKey == NULL) {
+        CYASSL_MSG("PeerEccDsaKey Memory error");
+        return MEMORY_E;
+    }
+    ssl->eccDsaKey = (ecc_key*)XMALLOC(sizeof(ecc_key),
+                                                   ctx->heap, DYNAMIC_TYPE_ECC);
+    if (ssl->eccDsaKey == NULL) {
+        CYASSL_MSG("EccDsaKey Memory error");
+        return MEMORY_E;
+    }
+    ssl->eccTempKey = (ecc_key*)XMALLOC(sizeof(ecc_key),
+                                                   ctx->heap, DYNAMIC_TYPE_ECC);
+    if (ssl->eccTempKey == NULL) {
+        CYASSL_MSG("EccTempKey Memory error");
+        return MEMORY_E;
+    }
+    ecc_init(ssl->peerEccKey);
+    ecc_init(ssl->peerEccDsaKey);
+    ecc_init(ssl->eccDsaKey);
+    ecc_init(ssl->eccTempKey);
+#endif
+
+    /* make sure server has DH parms, and add PSK if there, add NTRU too */
+    if (ssl->options.side == 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(CYASSL* ssl, int keep)
+{
+    if (ssl->arrays && keep) {
+        /* keeps session id for user retrieval */
+        XMEMCPY(ssl->session.sessionID, ssl->arrays->sessionID, ID_LEN);
+    }
+    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(CYASSL* ssl)
+{
+    FreeCiphers(ssl);
+    FreeArrays(ssl, 0);
+    XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG);
+    XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES);
+    XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN);
+
+#ifndef NO_CERTS
+    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 == CLIENT_END) {
+        XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+        XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+    }
+
+    /* CYASSL_CTX always owns certChain */
+    if (ssl->buffers.weOwnCert)
+        XFREE(ssl->buffers.certificate.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) {
+        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 CYASSL_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)
+    CyaSSL_BIO_free(ssl->biord);
+    if (ssl->biord != ssl->biowr)        /* in case same as write */
+        CyaSSL_BIO_free(ssl->biowr);
+#endif
+#ifdef HAVE_LIBZ
+    FreeStreams(ssl);
+#endif
+#ifdef HAVE_ECC
+    if (ssl->peerEccKey) {
+        if (ssl->peerEccKeyPresent)
+            ecc_free(ssl->peerEccKey);
+        XFREE(ssl->peerEccKey, ssl->heap, DYNAMIC_TYPE_ECC);
+    }
+    if (ssl->peerEccDsaKey) {
+        if (ssl->peerEccDsaKeyPresent)
+            ecc_free(ssl->peerEccDsaKey);
+        XFREE(ssl->peerEccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC);
+    }
+    if (ssl->eccTempKey) {
+        if (ssl->eccTempKeyPresent)
+            ecc_free(ssl->eccTempKey);
+        XFREE(ssl->eccTempKey, ssl->heap, DYNAMIC_TYPE_ECC);
+    }
+    if (ssl->eccDsaKey) {
+        if (ssl->eccDsaKeyPresent)
+            ecc_free(ssl->eccDsaKey);
+        XFREE(ssl->eccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC);
+    }
+#endif
+#ifdef HAVE_TLS_EXTENSIONS
+    TLSX_FreeAll(ssl->extensions);
+#endif
+}
+
+
+/* Free any handshake resources no longer needed */
+void FreeHandshakeResources(CYASSL* ssl)
+{
+    /* input buffer */
+    if (ssl->buffers.inputBuffer.dynamicFlag)
+        ShrinkInputBuffer(ssl, NO_FORCED_FREE);
+
+    /* suites */
+    XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES);
+    ssl->suites = NULL;
+
+    /* RNG */
+    if (ssl->specs.cipher_type == stream || ssl->options.tls1_1 == 0) {
+        XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG);
+        ssl->rng = NULL;
+    }
+
+#ifdef CYASSL_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)
+        FreeArrays(ssl, 1);
+
+#ifndef NO_RSA
+    /* peerRsaKey */
+    if (ssl->peerRsaKey) {
+        FreeRsaKey(ssl->peerRsaKey);
+        XFREE(ssl->peerRsaKey, ssl->heap, DYNAMIC_TYPE_RSA);
+        ssl->peerRsaKey = NULL;
+    }
+#endif
+
+#ifdef HAVE_ECC
+    if (ssl->peerEccKey)
+    {
+        if (ssl->peerEccKeyPresent) {
+            ecc_free(ssl->peerEccKey);
+            ssl->peerEccKeyPresent = 0;
+        }
+        XFREE(ssl->peerEccKey, ssl->heap, DYNAMIC_TYPE_ECC);
+        ssl->peerEccKey = NULL;
+    }
+    if (ssl->peerEccDsaKey)
+    {
+        if (ssl->peerEccDsaKeyPresent) {
+            ecc_free(ssl->peerEccDsaKey);
+            ssl->peerEccDsaKeyPresent = 0;
+        }
+        XFREE(ssl->peerEccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC);
+        ssl->peerEccDsaKey = NULL;
+    }
+    if (ssl->eccTempKey)
+    {
+        if (ssl->eccTempKeyPresent) {
+            ecc_free(ssl->eccTempKey);
+            ssl->eccTempKeyPresent = 0;
+        }
+        XFREE(ssl->eccTempKey, ssl->heap, DYNAMIC_TYPE_ECC);
+        ssl->eccTempKey = NULL;
+    }
+    if (ssl->eccDsaKey)
+    {
+        if (ssl->eccDsaKeyPresent) {
+            ecc_free(ssl->eccDsaKey);
+            ssl->eccDsaKeyPresent = 0;
+        }
+        XFREE(ssl->eccDsaKey, ssl->heap, DYNAMIC_TYPE_ECC);
+        ssl->eccDsaKey = NULL;
+    }
+#endif
+}
+
+
+void FreeSSL(CYASSL* ssl)
+{
+    FreeSSL_Ctx(ssl->ctx);  /* will decrement and free underyling CTX if 0 */
+    SSL_ResourceFree(ssl);
+    XFREE(ssl, ssl->heap, DYNAMIC_TYPE_SSL);
+}
+
+
+#ifdef CYASSL_DTLS
+
+int DtlsPoolInit(CYASSL* ssl)
+{
+    if (ssl->dtls_pool == NULL) {
+        DtlsPool *pool = (DtlsPool*)XMALLOC(sizeof(DtlsPool),
+                                             ssl->heap, DYNAMIC_TYPE_DTLS_POOL);
+        if (pool == NULL) {
+            CYASSL_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(CYASSL* 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_OUT_BUFFER);
+        if (pBuf->buffer == NULL) {
+            CYASSL_MSG("DTLS Buffer Memory error");
+            return MEMORY_ERROR;
+        }
+        XMEMCPY(pBuf->buffer, src, sz);
+        pBuf->length = (word32)sz;
+        pool->used++;
+    }
+    return 0;
+}
+
+
+void DtlsPoolReset(CYASSL* 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_OUT_BUFFER);
+            pBuf->buffer = NULL;
+            pBuf->length = 0;
+        }
+        pool->used = 0;
+    }
+    ssl->dtls_timeout = ssl->dtls_timeout_init;
+}
+
+
+int DtlsPoolTimeout(CYASSL* ssl)
+{
+    int result = -1;
+    if (ssl->dtls_timeout <  ssl->dtls_timeout_max) {
+        ssl->dtls_timeout *= DTLS_TIMEOUT_MULTIPLIER;
+        result = 0;
+    }
+    return result;
+}
+
+
+int DtlsPoolSend(CYASSL* 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) {
+        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 as well as the message data. */
+        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);
+            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 /* CYASSL_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 CYASSL_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 /* CYASSL_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)
+
+    word32 LowResTimer(void)
+    {
+        return (word32) SYS_TICK_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
+#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 void HashOutput(CYASSL* ssl, const byte* output, int sz, int ivSz)
+{
+    const byte* adj = output + RECORD_HEADER_SZ + ivSz;
+    sz -= RECORD_HEADER_SZ;
+    
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        adj += DTLS_RECORD_EXTRA;
+        sz  -= DTLS_RECORD_EXTRA;
+    }
+#endif
+#ifndef NO_OLD_TLS
+#ifndef NO_SHA
+    ShaUpdate(&ssl->hashSha, adj, sz);
+#endif
+#ifndef NO_MD5
+    Md5Update(&ssl->hashMd5, adj, sz);
+#endif
+#endif
+
+    if (IsAtLeastTLSv1_2(ssl)) {
+#ifndef NO_SHA256
+        Sha256Update(&ssl->hashSha256, adj, sz);
+#endif
+#ifdef CYASSL_SHA384
+        Sha384Update(&ssl->hashSha384, adj, sz);
+#endif
+    }
+}
+
+
+/* add input to md5 and sha handshake hashes, include handshake header */
+static void HashInput(CYASSL* ssl, const byte* input, int sz)
+{
+    const byte* adj = input - HANDSHAKE_HEADER_SZ;
+    sz += HANDSHAKE_HEADER_SZ;
+    
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        adj -= DTLS_HANDSHAKE_EXTRA;
+        sz  += DTLS_HANDSHAKE_EXTRA;
+    }
+#endif
+
+#ifndef NO_OLD_TLS
+#ifndef NO_SHA
+    ShaUpdate(&ssl->hashSha, adj, sz);
+#endif
+#ifndef NO_MD5
+    Md5Update(&ssl->hashMd5, adj, sz);
+#endif
+#endif
+
+    if (IsAtLeastTLSv1_2(ssl)) {
+#ifndef NO_SHA256
+        Sha256Update(&ssl->hashSha256, adj, sz);
+#endif
+#ifdef CYASSL_SHA384
+        Sha384Update(&ssl->hashSha384, adj, sz);
+#endif
+    }
+}
+
+
+/* add record layer header for message */
+static void AddRecordHeader(byte* output, word32 length, byte type, CYASSL* 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 CYASSL_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,
+                               CYASSL* ssl)
+{
+    HandShakeHeader* hs;
+    (void)ssl;
+ 
+    /* handshake header */
+    hs = (HandShakeHeader*)output;
+    hs->type = type;
+    c32to24(length, hs->length);         /* type and length same for each */
+#ifdef CYASSL_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, CYASSL* ssl)
+{
+    if (!ssl->options.dtls) {
+        AddRecordHeader(output, length + HANDSHAKE_HEADER_SZ, handshake, ssl);
+        AddHandShakeHeader(output + RECORD_HEADER_SZ, length, type, ssl);
+    }
+#ifdef CYASSL_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(CYASSL* ssl, byte* buf, word32 sz)
+{
+    int recvd;
+
+    if (ssl->ctx->CBIORecv == NULL) {
+        CYASSL_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 CYASSL_CBIO_ERR_GENERAL:        /* general/unknown error */
+                return -1;
+
+            case CYASSL_CBIO_ERR_WANT_READ:      /* want read, would block */
+                return WANT_READ;
+
+            case CYASSL_CBIO_ERR_CONN_RST:       /* connection reset */
+                #ifdef USE_WINDOWS_API
+                if (ssl->options.dtls) {
+                    goto retry;
+                }
+                #endif
+                ssl->options.connReset = 1;
+                return -1;
+
+            case CYASSL_CBIO_ERR_ISR:            /* interrupt */
+                /* see if we got our timeout */
+                #ifdef CYASSL_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);
+                            CYASSL_MSG("Got our timeout"); 
+                            return WANT_READ;
+                        }
+                    }
+                #endif
+                goto retry;
+
+            case CYASSL_CBIO_ERR_CONN_CLOSE:     /* peer closed connection */
+                ssl->options.isClosed = 1;
+                return -1;
+
+            case CYASSL_CBIO_ERR_TIMEOUT:
+#ifdef CYASSL_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(CYASSL* ssl)
+{
+    CYASSL_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(CYASSL* ssl, int forcedFree)
+{
+    int usedLength = ssl->buffers.inputBuffer.length -
+                     ssl->buffers.inputBuffer.idx;
+    if (!forcedFree && usedLength > STATIC_BUFFER_LEN)
+        return;
+
+    CYASSL_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(CYASSL* ssl)
+{
+    if (ssl->ctx->CBIOSend == NULL) {
+        CYASSL_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 CYASSL_CBIO_ERR_WANT_WRITE:        /* would block */
+                    return WANT_WRITE;
+
+                case CYASSL_CBIO_ERR_CONN_RST:          /* connection reset */
+                    ssl->options.connReset = 1;
+                    break;
+
+                case CYASSL_CBIO_ERR_ISR:               /* interrupt */
+                    /* see if we got our timeout */
+                    #ifdef CYASSL_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);
+                                CYASSL_MSG("Got our timeout"); 
+                                return WANT_WRITE;
+                            }
+                        }
+                    #endif
+                    continue;
+
+                case CYASSL_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;
+        }
+
+        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(CYASSL* ssl, int size)
+{
+    byte* tmp;
+    byte  hdrSz = ssl->options.dtls ? DTLS_RECORD_HEADER_SZ :
+                                      RECORD_HEADER_SZ; 
+    byte  align = CYASSL_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);
+    CYASSL_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(CYASSL* ssl, int size, int usedLength)
+{
+    byte* tmp;
+    byte  hdrSz = DTLS_RECORD_HEADER_SZ;
+    byte  align = ssl->options.dtls ? CYASSL_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);
+    CYASSL_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(CYASSL *ssl, int size)
+{
+    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(CYASSL* ssl, const byte* input, word32* inOutIdx,
+                           RecordLayerHeader* rh, word16 *size)
+{
+    if (!ssl->options.dtls) {
+        XMEMCPY(rh, input + *inOutIdx, RECORD_HEADER_SZ);
+        *inOutIdx += RECORD_HEADER_SZ;
+        ato16(rh->length, size);
+    }
+    else {
+#ifdef CYASSL_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_peer_epoch);
+        *inOutIdx += 4; /* advance past epoch, skip first 2 seq bytes for now */
+        ato32(input + *inOutIdx, &ssl->keys.dtls_peer_sequence_number);
+        *inOutIdx += 4;  /* advance past rest of seq */
+        ato16(input + *inOutIdx, size);
+        *inOutIdx += LENGTH_SZ;
+#endif
+    }
+
+    /* catch version mismatch */
+    if (rh->pvMajor != ssl->version.major || rh->pvMinor != ssl->version.minor){
+        if (ssl->options.side == SERVER_END &&
+            ssl->options.acceptState == ACCEPT_BEGIN)
+            CYASSL_MSG("Client attempting to connect with different version"); 
+        else if (ssl->options.side == CLIENT_END && ssl->options.downgrade &&
+                 ssl->options.connectState < FIRST_REPLY_DONE)
+            CYASSL_MSG("Server attempting to accept with different version"); 
+        else {
+            CYASSL_MSG("SSL version error"); 
+            return VERSION_ERROR;              /* only use requested version */
+        }
+    }
+#if 0
+    /* Instead of this, check the datagram against the sliding window of
+     * received datagram goodness. */
+#ifdef CYASSL_DTLS
+    /* If DTLS, check the sequence number against expected. If out of
+     * order, drop the record. Allows newer records in and resets the
+     * expected to the next record. */
+    if (ssl->options.dtls) {
+        if ((ssl->keys.dtls_expected_peer_epoch ==
+                                        ssl->keys.dtls_peer_epoch) &&
+                (ssl->keys.dtls_peer_sequence_number >=
+                                ssl->keys.dtls_expected_peer_sequence_number)) {
+            ssl->keys.dtls_expected_peer_sequence_number =
+                            ssl->keys.dtls_peer_sequence_number + 1;
+        }
+        else {
+            return SEQUENCE_ERROR;
+        }
+    }
+#endif
+#endif
+    /* record layer length check */
+    if (*size > (MAX_RECORD_SIZE + MAX_COMP_EXTRA + MAX_MSG_EXTRA))
+        return LENGTH_ERROR;
+
+    /* verify record type here as well */
+    switch ((enum ContentType)rh->type) {
+        case handshake:
+        case change_cipher_spec:
+        case application_data:
+        case alert:
+            break;
+        case no_type:
+        default:
+            CYASSL_MSG("Unknown Record Type"); 
+            return UNKNOWN_RECORD_TYPE;
+    }
+
+    /* haven't decrypted this record yet */
+    ssl->keys.decryptedCur = 0;
+
+    return 0;
+}
+
+
+static int GetHandShakeHeader(CYASSL* ssl, const byte* input, word32* inOutIdx,
+                              byte *type, word32 *size)
+{
+    const byte *ptr = input + *inOutIdx;
+    (void)ssl;
+    *inOutIdx += HANDSHAKE_HEADER_SZ;
+    
+    *type = ptr[0];
+    c24to32(&ptr[1], size);
+
+    return 0;
+}
+
+
+#ifdef CYASSL_DTLS
+static int GetDtlsHandShakeHeader(CYASSL* ssl, const byte* input,
+                                    word32* inOutIdx, byte *type, word32 *size,
+                                    word32 *fragOffset, word32 *fragSz)
+{
+    word32 idx = *inOutIdx;
+
+    *inOutIdx += HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA;
+    
+    *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 */
+static void BuildMD5(CYASSL* ssl, Hashes* hashes, const byte* sender)
+{
+    byte md5_result[MD5_DIGEST_SIZE];
+
+    /* make md5 inner */    
+    Md5Update(&ssl->hashMd5, sender, SIZEOF_SENDER);
+    Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN);
+    Md5Update(&ssl->hashMd5, PAD1, PAD_MD5);
+    Md5Final(&ssl->hashMd5, md5_result);
+
+    /* make md5 outer */
+    Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN);
+    Md5Update(&ssl->hashMd5, PAD2, PAD_MD5);
+    Md5Update(&ssl->hashMd5, md5_result, MD5_DIGEST_SIZE);
+
+    Md5Final(&ssl->hashMd5, hashes->md5);
+}
+
+
+/* calculate SHA hash for finished */
+static void BuildSHA(CYASSL* ssl, Hashes* hashes, const byte* sender)
+{
+    byte sha_result[SHA_DIGEST_SIZE];
+
+    /* make sha inner */
+    ShaUpdate(&ssl->hashSha, sender, SIZEOF_SENDER);
+    ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN);
+    ShaUpdate(&ssl->hashSha, PAD1, PAD_SHA);
+    ShaFinal(&ssl->hashSha, sha_result);
+
+    /* make sha outer */
+    ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN);
+    ShaUpdate(&ssl->hashSha, PAD2, PAD_SHA);
+    ShaUpdate(&ssl->hashSha, sha_result, SHA_DIGEST_SIZE);
+
+    ShaFinal(&ssl->hashSha, hashes->sha);
+}
+#endif
+
+
+static void BuildFinished(CYASSL* ssl, Hashes* hashes, const byte* sender)
+{
+    /* store current states, building requires get_digest which resets state */
+#ifndef NO_OLD_TLS
+#ifndef NO_MD5
+    Md5 md5 = ssl->hashMd5;
+#endif
+#ifndef NO_SHA
+    Sha sha = ssl->hashSha;
+#endif
+#endif
+#ifndef NO_SHA256
+    Sha256 sha256 = ssl->hashSha256;
+#endif
+#ifdef CYASSL_SHA384
+    Sha384 sha384 = ssl->hashSha384;
+#endif
+
+#ifndef NO_TLS
+    if (ssl->options.tls) {
+        BuildTlsFinished(ssl, hashes, sender);
+    }
+#endif
+#ifndef NO_OLD_TLS
+    if (!ssl->options.tls) {
+        BuildMD5(ssl, hashes, sender);
+        BuildSHA(ssl, hashes, sender);
+    }
+#endif
+    
+    /* restore */
+#ifndef NO_OLD_TLS
+    #ifndef NO_MD5
+        ssl->hashMd5 = md5;
+    #endif
+    #ifndef NO_SHA
+    ssl->hashSha = sha;
+    #endif
+#endif
+    if (IsAtLeastTLSv1_2(ssl)) {
+    #ifndef NO_SHA256
+        ssl->hashSha256 = sha256;
+    #endif
+    #ifdef CYASSL_SHA384
+        ssl->hashSha384 = sha384;
+    #endif
+    }
+}
+
+
+#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)(*pattern++))) {
+        if (p == '*') {
+            while (--len > 0 && (p = (char)(*pattern++)) == '*')
+                ;
+
+            if (len == 0)
+                p = '\0';
+
+            while ( (s = (char)(*str)) != '\0') {
+                if (s == p)
+                    break;
+                if (s == '.')
+                    return 0;
+                str++;
+            }
+        }
+        else {
+            if (p != (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;
+
+    CYASSL_MSG("Checking AltNames");
+
+    if (dCert)
+        altName = dCert->altNames;
+
+    while (altName) {
+        CYASSL_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(CYASSL_X509* x509, DecodedCert* dCert)
+{
+    int ret = 0;
+
+    if (x509 == NULL || dCert == NULL)
+        return BAD_FUNC_ARG;
+
+    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;
+
+    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;
+
+    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';
+
+    /* 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->altNames    = NULL;     /* takes ownership */
+    x509->altNamesNext = x509->altNames;  /* index hint */
+
+    return ret;
+}
+
+#endif /* KEEP_PEER_CERT || SESSION_CERTS */
+
+
+static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx)
+{
+    word32 listSz, i = *inOutIdx;
+    int    ret = 0;
+    int    anyError = 0;
+    int    totalCerts = 0;    /* number of certs in certs buffer */
+    int    count;
+    char   domain[ASN_NAME_MAX];
+    buffer certs[MAX_CHAIN_DEPTH];
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("Certificate", &ssl->timeoutInfo);
+    #endif
+    c24to32(&input[i], &listSz);
+    i += CERT_HEADER_SZ;
+
+    CYASSL_MSG("Loading peer's cert chain");
+    /* first put cert chain into buffer so can verify top down
+       we're sent bottom up */
+    while (listSz) {
+        /* cert size */
+        word32 certSz;
+
+        if (totalCerts >= MAX_CHAIN_DEPTH)
+            return MAX_CHAIN_ERROR;
+
+        c24to32(&input[i], &certSz);
+        i += CERT_HEADER_SZ;
+       
+        if (listSz > MAX_RECORD_SIZE || certSz > MAX_RECORD_SIZE)
+            return BUFFER_E;
+
+        certs[totalCerts].length = certSz;
+        certs[totalCerts].buffer = input + i;
+
+#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 + i, certSz);
+            ssl->session.chain.count++;
+        } else {
+            CYASSL_MSG("Couldn't store chain cert for session");
+        }
+#endif
+
+        i += certSz;
+        listSz -= certSz + CERT_HEADER_SZ;
+
+        totalCerts++;
+        CYASSL_MSG("    Put another cert into chain");
+    }
+
+    count = totalCerts;
+
+    /* verify up to peer's first */
+    while (count > 1) {
+        buffer myCert = certs[count - 1];
+        DecodedCert dCert;
+        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) {
+            CYASSL_MSG("Chain cert is not a CA, not adding as one");
+        }
+        else if (ret == 0 && ssl->options.verifyNone) {
+            CYASSL_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);
+            CYASSL_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, CYASSL_CHAIN_CA,
+                        ssl->ctx->verifyPeer);
+            if (ret == 1) ret = 0;   /* SSL_SUCCESS for external */
+        }
+        else if (ret != 0) {
+            CYASSL_MSG("Failed to verify CA from chain");
+        }
+        else {
+            CYASSL_MSG("Verified CA from chain and already had it");
+        }
+
+#ifdef HAVE_CRL
+        if (ret == 0 && ssl->ctx->cm->crlEnabled && ssl->ctx->cm->crlCheckAll) {
+            CYASSL_MSG("Doing Non Leaf CRL check");
+            ret = CheckCertCRL(ssl->ctx->cm->crl, &dCert);
+
+            if (ret != 0) {
+                CYASSL_MSG("\tCRL check not ok");
+            }
+        }
+#endif /* 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];
+        DecodedCert dCert;
+        int         fatal = 0;
+
+        CYASSL_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) {
+            CYASSL_MSG("Verified Peer's cert");
+            fatal = 0;
+        }
+        else if (ret == ASN_PARSE_E) {
+            CYASSL_MSG("Got Peer cert ASN PARSE ERROR, fatal");
+            fatal = 1;
+        }
+        else {
+            CYASSL_MSG("Failed to verify Peer's cert");
+            if (ssl->verifyCallback) {
+                CYASSL_MSG("\tCallback override available, will continue");
+                fatal = 0;
+            }
+            else {
+                CYASSL_MSG("\tNo callback override available, fatal");
+                fatal = 1;
+            }
+        }
+
+#ifdef HAVE_OCSP
+        if (fatal == 0) {
+            ret = CyaSSL_OCSP_Lookup_Cert(&ssl->ctx->ocsp, &dCert);
+            if (ret != 0) {
+                CYASSL_MSG("\tOCSP Lookup not ok");
+                fatal = 0;
+            }
+        }
+#endif
+
+#ifdef HAVE_CRL
+        if (fatal == 0 && ssl->ctx->cm->crlEnabled) {
+            int doCrlLookup = 1;
+
+            #ifdef HAVE_OCSP
+            if (ssl->ctx->ocsp.enabled) {
+                doCrlLookup = (ret == OCSP_CERT_UNKNOWN);
+            }
+            #endif /* HAVE_OCSP */
+
+            if (doCrlLookup) {
+                CYASSL_MSG("Doing Leaf CRL check");
+                ret = CheckCertCRL(ssl->ctx->cm->crl, &dCert);
+    
+                if (ret != 0) {
+                    CYASSL_MSG("\tCRL check not ok");
+                    fatal = 0;
+                }
+            }
+        }
+
+#endif /* 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    
+
+        if (fatal) {
+            FreeDecodedCert(&dCert);
+            ssl->error = ret;
+            return ret;
+        }
+        ssl->options.havePeerCert = 1;
+
+        /* 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) {
+                CYASSL_MSG("DomainName match on common name failed");
+                if (CheckAltNames(&dCert,
+                                 (char*)ssl->buffers.domainName.buffer) == 0 ) {
+                    CYASSL_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;
+                    if (RsaPublicKeyDecode(dCert.publicKey, &idx,
+                                      ssl->peerRsaKey, dCert.pubKeySize) != 0) {
+                        ret = PEER_KEY_ERROR;
+                    }
+                    else
+                        ssl->peerRsaKeyPresent = 1;
+                }
+                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 (ecc_import_x963(dCert.publicKey, dCert.pubKeySize,
+                                        ssl->peerEccDsaKey) != 0) {
+                        ret = PEER_KEY_ERROR;
+                    }
+                    else
+                        ssl->peerEccDsaKeyPresent = 1;
+                }
+                break;
+        #endif /* HAVE_ECC */
+            default:
+                break;
+        }
+
+        FreeDecodedCert(&dCert);
+    }
+    
+    if (anyError != 0 && ret == 0)
+        ret = anyError;
+
+    if (ret == 0 && ssl->options.side == CLIENT_END)
+        ssl->options.serverState = SERVER_CERT_COMPLETE;
+
+    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;
+                CYASSL_X509_STORE_CTX store;
+
+                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) {
+                    CYASSL_MSG("Verify callback overriding error!"); 
+                    ret = 0;
+                }
+                #ifdef SESSION_CERTS
+                if (store.discardSessionCerts) {
+                    CYASSL_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 FORTRESS
+    else {
+        if (ssl->verifyCallback) {
+            int ok;
+            CYASSL_X509_STORE_CTX store;
+
+            store.error = ret;
+            store.error_depth = totalCerts;
+            store.discardSessionCerts = 0;
+            store.domain = domain;
+            store.userCtx = ssl->verifyCbCtx;
+            store.current_cert = &ssl->peerCert;
+            store.ex_data = ssl;
+
+            ok = ssl->verifyCallback(1, &store);
+            if (!ok) {
+                CYASSL_MSG("Verify callback overriding valid certificate!");
+                ret = -1;
+                SendAlert(ssl, alert_fatal, bad_certificate);
+                ssl->options.isClosed = 1;
+            }
+            #ifdef SESSION_CERTS
+            if (store.discardSessionCerts) {
+                CYASSL_MSG("Verify callback requested discard sess certs");
+                ssl->session.chain.count = 0;
+            }
+            #endif
+        }
+    }
+#endif
+
+    *inOutIdx = i;
+    return ret;
+}
+
+#endif /* !NO_CERTS */
+
+
+static int DoHelloRequest(CYASSL* ssl, const byte* input, word32* inOutIdx)
+{
+    if (ssl->keys.encryptionOn) {
+        const byte* mac;
+        int         padSz = ssl->keys.encryptSz - HANDSHAKE_HEADER_SZ - 
+                            ssl->specs.hash_size;
+        byte        verify[SHA256_DIGEST_SIZE];
+       
+        ssl->hmac(ssl, verify, input + *inOutIdx - HANDSHAKE_HEADER_SZ,
+                  HANDSHAKE_HEADER_SZ, handshake, 1);
+        /* read mac and fill */
+        mac = input + *inOutIdx;
+        *inOutIdx += ssl->specs.hash_size;
+
+        if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
+            padSz -= ssl->specs.block_size;
+
+        *inOutIdx += padSz;
+
+        /* verify */
+        if (XMEMCMP(mac, verify, ssl->specs.hash_size) != 0) {
+            CYASSL_MSG("    hello_request verify mac error");
+            return VERIFY_MAC_ERROR;
+        }
+    }
+
+    if (ssl->options.side == SERVER_END) {
+        SendAlert(ssl, alert_fatal, unexpected_message); /* try */
+        return FATAL_ERROR;
+    }
+    else
+        return SendAlert(ssl, alert_warning, no_renegotiation);
+}
+
+
+int DoFinished(CYASSL* ssl, const byte* input, word32* inOutIdx, int sniff)
+{
+    int    finishedSz = ssl->options.tls ? TLS_FINISHED_SZ : FINISHED_SZ;
+    int    headerSz = HANDSHAKE_HEADER_SZ;
+    word32 macSz = finishedSz + HANDSHAKE_HEADER_SZ,
+           idx = *inOutIdx,
+           padSz = ssl->keys.encryptSz - HANDSHAKE_HEADER_SZ - finishedSz -
+                   ssl->specs.hash_size;
+    const byte* mac;
+
+    #ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            headerSz += DTLS_HANDSHAKE_EXTRA;
+            macSz    += DTLS_HANDSHAKE_EXTRA;
+            padSz    -= DTLS_HANDSHAKE_EXTRA;
+        }
+    #endif
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo);
+    #endif
+    if (sniff == NO_SNIFF) {
+        if (XMEMCMP(input + idx, &ssl->verifyHashes, finishedSz) != 0) {
+            CYASSL_MSG("Verify finished error on hashes");
+            return VERIFY_FINISHED_ERROR;
+        }
+    }
+
+    if (ssl->specs.cipher_type != aead) {
+        byte verifyMAC[MAX_DIGEST_SIZE];
+        ssl->hmac(ssl, verifyMAC, input + idx - headerSz, macSz,
+             handshake, 1);
+        idx += finishedSz;
+
+        /* read mac and fill */
+        mac = input + idx;
+        idx += ssl->specs.hash_size;
+
+        if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
+            padSz -= ssl->specs.block_size;
+
+        idx += padSz;
+
+        /* verify mac */
+        if (XMEMCMP(mac, verifyMAC, ssl->specs.hash_size) != 0) {
+            CYASSL_MSG("Verify finished error on mac");
+            return VERIFY_MAC_ERROR;
+        }
+    }
+    else {
+        idx += (finishedSz + ssl->specs.aead_mac_size);
+    }
+
+    if (ssl->options.side == CLIENT_END) {
+        ssl->options.serverState = SERVER_FINISHED_COMPLETE;
+        if (!ssl->options.resuming) {
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+#ifdef CYASSL_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;
+#ifdef CYASSL_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
+        }
+    }
+
+    *inOutIdx = idx;
+    return 0;
+}
+
+
+static int DoHandShakeMsgType(CYASSL* ssl, byte* input, word32* inOutIdx,
+                          byte type, word32 size, word32 totalSz)
+{
+    int ret = 0;
+    (void)totalSz;
+
+    CYASSL_ENTER("DoHandShakeMsgType");
+
+    HashInput(ssl, input + *inOutIdx, size);
+#ifdef CYASSL_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){
+        CYASSL_MSG("HandShake message after handshake complete");
+        SendAlert(ssl, alert_fatal, unexpected_message);
+        return OUT_OF_ORDER_E;
+    }
+
+    if (ssl->options.side == CLIENT_END && ssl->options.dtls == 0 &&
+               ssl->options.serverState == NULL_STATE && type != server_hello) {
+        CYASSL_MSG("First server message not server hello");
+        SendAlert(ssl, alert_fatal, unexpected_message);
+        return OUT_OF_ORDER_E;
+    }
+
+    if (ssl->options.side == CLIENT_END && ssl->options.dtls &&
+            type == server_hello_done &&
+            ssl->options.serverState < SERVER_HELLO_COMPLETE) {
+        CYASSL_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 == SERVER_END &&
+               ssl->options.clientState == NULL_STATE && type != client_hello) {
+        CYASSL_MSG("First client message not client hello");
+        SendAlert(ssl, alert_fatal, unexpected_message);
+        return OUT_OF_ORDER_E;
+    }
+
+
+    switch (type) {
+
+    case hello_request:
+        CYASSL_MSG("processing hello request");
+        ret = DoHelloRequest(ssl, input, inOutIdx);
+        break;
+
+#ifndef NO_CYASSL_CLIENT
+    case hello_verify_request:
+        CYASSL_MSG("processing hello verify request");
+        ret = DoHelloVerifyRequest(ssl, input,inOutIdx);
+        break;
+            
+    case server_hello:
+        CYASSL_MSG("processing server hello");
+        ret = DoServerHello(ssl, input, inOutIdx, size);
+        break;
+
+#ifndef NO_CERTS
+    case certificate_request:
+        CYASSL_MSG("processing certificate request");
+        ret = DoCertificateRequest(ssl, input, inOutIdx);
+        break;
+#endif
+
+    case server_key_exchange:
+        CYASSL_MSG("processing server key exchange");
+        ret = DoServerKeyExchange(ssl, input, inOutIdx);
+        break;
+#endif
+
+#ifndef NO_CERTS
+    case certificate:
+        CYASSL_MSG("processing certificate");
+        ret =  DoCertificate(ssl, input, inOutIdx);
+        break;
+#endif
+
+    case server_hello_done:
+        CYASSL_MSG("processing server hello done");
+        #ifdef CYASSL_CALLBACKS
+            if (ssl->hsInfoOn) 
+                AddPacketName("ServerHelloDone", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("ServerHelloDone", &ssl->timeoutInfo);
+        #endif
+        ssl->options.serverState = SERVER_HELLODONE_COMPLETE;
+        break;
+
+    case finished:
+        CYASSL_MSG("processing finished");
+        ret = DoFinished(ssl, input, inOutIdx, NO_SNIFF);
+        break;
+
+#ifndef NO_CYASSL_SERVER
+    case client_hello:
+        CYASSL_MSG("processing client hello");
+        ret = DoClientHello(ssl, input, inOutIdx, totalSz, size);
+        break;
+
+    case client_key_exchange:
+        CYASSL_MSG("processing client key exchange");
+        ret = DoClientKeyExchange(ssl, input, inOutIdx, totalSz);
+        break;
+
+#if !defined(NO_RSA) || defined(HAVE_ECC)
+    case certificate_verify:
+        CYASSL_MSG("processing certificate verify");
+        ret = DoCertificateVerify(ssl, input, inOutIdx, totalSz);
+        break;
+#endif /* !NO_RSA || HAVE_ECC */
+
+#endif /* !NO_CYASSL_SERVER */
+
+    default:
+        CYASSL_MSG("Unknown handshake message type");
+        ret = UNKNOWN_HANDSHAKE_TYPE;
+    }
+
+    CYASSL_LEAVE("DoHandShakeMsgType()", ret);
+    return ret;
+}
+
+
+static int DoHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx,
+                          word32 totalSz)
+{
+    byte type;
+    word32 size;
+    int ret = 0;
+
+    CYASSL_ENTER("DoHandShakeMsg()");
+
+    if (GetHandShakeHeader(ssl, input, inOutIdx, &type, &size) != 0)
+        return PARSE_ERROR;
+
+    if (*inOutIdx + size > totalSz)
+        return INCOMPLETE_DATA;
+
+    ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz);
+
+    CYASSL_LEAVE("DoHandShakeMsg()", ret);
+    return ret;
+}
+
+
+#ifdef CYASSL_DTLS
+static int DtlsMsgDrain(CYASSL* ssl)
+{
+    DtlsMsg* item = ssl->dtls_msg_list;
+    int ret = 0;
+    word32 idx = 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) {
+        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(CYASSL* ssl, byte* input, word32* inOutIdx,
+                          word32 totalSz)
+{
+    byte type;
+    word32 size;
+    word32 fragOffset, fragSz;
+    int ret = 0;
+
+    CYASSL_ENTER("DoDtlsHandShakeMsg()");
+    if (GetDtlsHandShakeHeader(ssl, input, inOutIdx, &type,
+                                            &size, &fragOffset, &fragSz) != 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->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);
+    }
+
+    CYASSL_LEAVE("DoDtlsHandShakeMsg()", ret);
+    return ret;
+}
+#endif
+
+
+static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify)
+{
+    if (verify)
+        return ssl->keys.peer_sequence_number++; 
+    else
+        return ssl->keys.sequence_number++; 
+}
+
+
+#ifdef HAVE_AEAD
+static INLINE void AeadIncrementExpIV(CYASSL* ssl)
+{
+    int i;
+    for (i = AEAD_EXP_IV_SZ-1; i >= 0; i--) {
+        if (++ssl->keys.aead_exp_IV[i]) return;
+    }
+}
+#endif
+
+
+static INLINE int Encrypt(CYASSL* ssl, byte* out, const byte* input, word32 sz)
+{
+    (void)out;
+    (void)input;
+    (void)sz;
+
+    if (ssl->encrypt.setup == 0) {
+        CYASSL_MSG("Encrypt ciphers not setup");
+        return ENCRYPT_ERROR;
+    }
+
+    switch (ssl->specs.bulk_cipher_algorithm) {
+        #ifdef BUILD_ARC4
+            case rc4:
+                Arc4Process(ssl->encrypt.arc4, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_DES3
+            case triple_des:
+                Des3_CbcEncrypt(ssl->encrypt.des3, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_AES
+            case aes:
+                return AesCbcEncrypt(ssl->encrypt.aes, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_AESGCM
+            case aes_gcm:
+                {
+                    byte additional[AES_BLOCK_SIZE];
+                    byte nonce[AEAD_NONCE_SZ];
+                    const byte* additionalSrc = input - 5;
+
+                    XMEMSET(additional, 0, AES_BLOCK_SIZE);
+
+                    /* 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 CYASSL_DTLS
+                        if (ssl->options.dtls)
+                            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);
+                    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);
+                    AeadIncrementExpIV(ssl);
+                    XMEMSET(nonce, 0, AEAD_NONCE_SZ);
+                }
+                break;
+        #endif
+
+        #ifdef HAVE_AESCCM
+            case aes_ccm:
+                {
+                    byte additional[AES_BLOCK_SIZE];
+                    byte nonce[AEAD_NONCE_SZ];
+                    const byte* additionalSrc = input - 5;
+
+                    XMEMSET(additional, 0, AES_BLOCK_SIZE);
+
+                    /* 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 CYASSL_DTLS
+                        if (ssl->options.dtls)
+                            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);
+                    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);
+                    XMEMSET(nonce, 0, AEAD_NONCE_SZ);
+                }
+                break;
+        #endif
+
+        #ifdef HAVE_CAMELLIA
+            case camellia:
+                CamelliaCbcEncrypt(ssl->encrypt.cam, out, input, sz);
+                break;
+        #endif
+
+        #ifdef HAVE_HC128
+            case hc128:
+                return Hc128_Process(ssl->encrypt.hc128, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_RABBIT
+            case rabbit:
+                return RabbitProcess(ssl->encrypt.rabbit, out, input, sz);
+                break;
+        #endif
+
+        #ifdef HAVE_NULL_CIPHER
+            case cipher_null:
+                if (input != out) {
+                    XMEMMOVE(out, input, sz);
+                }
+                break;
+        #endif
+
+            default:
+                CYASSL_MSG("CyaSSL Encrypt programming error");
+                return ENCRYPT_ERROR;
+    }
+
+    return 0;
+}
+
+
+static INLINE int Decrypt(CYASSL* ssl, byte* plain, const byte* input,
+                           word32 sz)
+{
+    (void)plain;
+    (void)input;
+    (void)sz;
+
+    if (ssl->decrypt.setup == 0) {
+        CYASSL_MSG("Decrypt ciphers not setup");
+        return DECRYPT_ERROR;
+    }
+
+    switch (ssl->specs.bulk_cipher_algorithm) {
+        #ifdef BUILD_ARC4
+            case rc4:
+                Arc4Process(ssl->decrypt.arc4, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_DES3
+            case triple_des:
+                Des3_CbcDecrypt(ssl->decrypt.des3, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_AES
+            case aes:
+                return AesCbcDecrypt(ssl->decrypt.aes, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_AESGCM
+            case aes_gcm:
+            {
+                byte additional[AES_BLOCK_SIZE];
+                byte nonce[AEAD_NONCE_SZ];
+
+                XMEMSET(additional, 0, AES_BLOCK_SIZE);
+
+                /* sequence number field is 64-bits, we only use 32-bits */
+                c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET);
+                
+                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 (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);
+                    XMEMSET(nonce, 0, AEAD_NONCE_SZ);
+                    return VERIFY_MAC_ERROR;
+                }
+                XMEMSET(nonce, 0, AEAD_NONCE_SZ);
+                break;
+            }
+        #endif
+
+        #ifdef HAVE_AESCCM
+            case aes_ccm:
+            {
+                byte additional[AES_BLOCK_SIZE];
+                byte nonce[AEAD_NONCE_SZ];
+
+                XMEMSET(additional, 0, AES_BLOCK_SIZE);
+
+                /* sequence number field is 64-bits, we only use 32-bits */
+                c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET);
+                
+                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 (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);
+                    XMEMSET(nonce, 0, AEAD_NONCE_SZ);
+                    return VERIFY_MAC_ERROR;
+                }
+                XMEMSET(nonce, 0, AEAD_NONCE_SZ);
+                break;
+            }
+        #endif
+
+        #ifdef HAVE_CAMELLIA
+            case camellia:
+                CamelliaCbcDecrypt(ssl->decrypt.cam, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef HAVE_HC128
+            case hc128:
+                return Hc128_Process(ssl->decrypt.hc128, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_RABBIT
+            case rabbit:
+                return RabbitProcess(ssl->decrypt.rabbit, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef HAVE_NULL_CIPHER
+            case cipher_null:
+                if (input != plain) {
+                    XMEMMOVE(plain, input, sz);
+                }
+                break;
+        #endif
+                
+            default:
+                CYASSL_MSG("CyaSSL Decrypt programming error");
+                return DECRYPT_ERROR;
+    }
+    return 0;
+}
+
+
+/* check cipher text size for sanity */
+static int SanityCheckCipherText(CYASSL* ssl, word32 encryptSz)
+{
+    word32 minLength = 0;
+
+    if (ssl->specs.cipher_type == block) {
+        if (encryptSz % ssl->specs.block_size) {
+            CYASSL_MSG("Block ciphertext not block size");
+            return SANITY_CIPHER_E;
+        }
+        minLength = ssl->specs.hash_size + 1;  /* 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 == stream) {
+        minLength = ssl->specs.hash_size;
+    }
+    else if (ssl->specs.cipher_type == aead) {
+        minLength = ssl->specs.block_size; /* explicit IV + implicit IV + CTR */
+    }
+
+    if (encryptSz < minLength) {
+        CYASSL_MSG("Ciphertext not minimum size");
+        return SANITY_CIPHER_E;
+    }
+
+    return 0;
+}
+
+
+/* decrypt input message in place */
+static int DecryptMessage(CYASSL* ssl, byte* input, word32 sz, word32* idx)
+{
+    int decryptResult;
+    int sanityResult = SanityCheckCipherText(ssl, sz);
+
+    if (sanityResult != 0)
+        return sanityResult;
+
+    decryptResult = Decrypt(ssl, input, input, sz);
+
+    if (decryptResult == 0)
+    {
+        ssl->keys.encryptSz    = sz;
+        ssl->keys.decryptedCur = 1;
+
+        if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
+            *idx += ssl->specs.block_size;  /* go past TLSv1.1 IV */
+        if (ssl->specs.cipher_type == aead)
+            *idx += AEAD_EXP_IV_SZ;
+    }
+
+    return decryptResult;
+}
+
+
+#ifndef NO_OLD_TLS
+
+static INLINE void Md5Rounds(int rounds, const byte* data, int sz)
+{
+    Md5 md5;
+    int i;
+
+    InitMd5(&md5);
+
+    for (i = 0; i < rounds; i++)
+        Md5Update(&md5, data, sz);
+}
+
+
+
+static INLINE void ShaRounds(int rounds, const byte* data, int sz)
+{
+    Sha sha;
+    int i;
+
+    InitSha(&sha);
+
+    for (i = 0; i < rounds; i++)
+        ShaUpdate(&sha, data, sz);
+}
+#endif
+
+
+#ifndef NO_SHA256
+
+static INLINE void Sha256Rounds(int rounds, const byte* data, int sz)
+{
+    Sha256 sha256;
+    int i;
+
+    InitSha256(&sha256);
+
+    for (i = 0; i < rounds; i++)
+        Sha256Update(&sha256, data, sz);
+}
+
+#endif
+
+
+#ifdef CYASSL_SHA384
+
+static INLINE void Sha384Rounds(int rounds, const byte* data, int sz)
+{
+    Sha384 sha384;
+    int i;
+
+    InitSha384(&sha384);
+
+    for (i = 0; i < rounds; i++)
+        Sha384Update(&sha384, data, sz);
+}
+
+#endif
+
+
+#ifdef CYASSL_SHA512
+
+static INLINE void Sha512Rounds(int rounds, const byte* data, int sz)
+{
+    Sha512 sha512;
+    int i;
+
+    InitSha512(&sha512);
+
+    for (i = 0; i < rounds; i++)
+        Sha512Update(&sha512, data, sz);
+}
+
+#endif
+
+
+#ifdef CYASSL_RIPEMD
+
+static INLINE void RmdRounds(int rounds, const byte* data, int sz)
+{
+    RipeMd ripemd;
+    int i;
+
+    InitRipeMd(&ripemd);
+
+    for (i = 0; i < rounds; i++)
+        RipeMdUpdate(&ripemd, data, sz);
+}
+
+#endif
+
+
+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 CYASSL_SHA384
+        case sha384_mac :
+            Sha384Rounds(rounds, data, sz);
+            break;
+#endif
+
+#ifdef CYASSL_SHA512
+        case sha512_mac :
+            Sha512Rounds(rounds, data, sz);
+            break;
+#endif
+
+#ifdef CYASSL_RIPEMD 
+        case rmd_mac :
+            RmdRounds(rounds, data, sz);
+            break;
+#endif
+
+        default:
+            CYASSL_MSG("Bad round type");
+            break;
+    }
+}
+
+
+/* do number of compression rounds on dummy data */
+static INLINE void CompressRounds(CYASSL* ssl, int rounds, const byte* dummy)
+{
+    if (rounds)
+        DoRounds(ssl->specs.mac_algorithm, rounds, dummy, COMPRESS_LOWER);
+}
+
+
+/* check all length bytes for equality, return 0 on success */
+static int ConstantCompare(const byte* a, const byte* b, int length)
+{
+    int i;
+    int good = 0;
+    int bad  = 0;
+
+    for (i = 0; i < length; i++) {
+        if (a[i] == b[i])
+            good++;
+        else
+            bad++;
+    }
+
+    if (good == length)
+        return 0;
+    else
+        return 0 - bad;  /* compare failed */
+}
+
+
+/* check all length bytes for the pad value, return 0 on success */
+static int PadCheck(const byte* input, byte pad, int length)
+{
+    int i;
+    int good = 0;
+    int bad  = 0;
+
+    for (i = 0; i < length; i++) {
+        if (input[i] == pad)
+            good++;
+        else
+            bad++;
+    }
+
+    if (good == length)
+        return 0;
+    else
+        return 0 - bad;  /* pad check failed */
+}
+
+
+/* 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(CYASSL* ssl, const byte* input, int padLen, int t,
+                           int pLen)
+{
+    byte verify[MAX_DIGEST_SIZE];
+    byte dummy[MAX_PAD_SIZE];
+
+    XMEMSET(dummy, 1, sizeof(dummy));
+
+    if ( (t + padLen + 1) > pLen) {
+        CYASSL_MSG("Plain Len not long enough for pad/mac");
+        PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE);
+        ssl->hmac(ssl, verify, input, pLen - t, application_data, 1);
+        ConstantCompare(verify, input + pLen - t, t);
+
+        return VERIFY_MAC_ERROR;
+    }
+
+    if (PadCheck(input + pLen - (padLen + 1), (byte)padLen, padLen + 1) != 0) {
+        CYASSL_MSG("PadCheck failed");
+        PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1);
+        ssl->hmac(ssl, verify, input, pLen - t, application_data, 1);
+        ConstantCompare(verify, input + pLen - t, t);
+
+        return VERIFY_MAC_ERROR;
+    }
+
+    PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1);
+    ssl->hmac(ssl, verify, input, pLen - padLen - 1 - t, application_data, 1);
+
+    CompressRounds(ssl, GetRounds(pLen, padLen, t), dummy);
+
+    if (ConstantCompare(verify, input + (pLen - padLen - 1 - t), t) != 0) {
+        CYASSL_MSG("Verify MAC compare failed");
+        return VERIFY_MAC_ERROR;
+    }
+
+    return 0;
+}
+
+
+int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx)
+{
+    word32 msgSz   = ssl->keys.encryptSz;
+    word32 pad     = 0, 
+           padByte = 0,
+           idx     = *inOutIdx,
+           digestSz = ssl->specs.hash_size;
+    int    dataSz, ret;
+    int    ivExtra = 0;
+    byte*  rawData = input + idx;  /* keep current  for hmac */
+#ifdef HAVE_LIBZ
+    byte   decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
+#endif
+    byte   verify[MAX_DIGEST_SIZE];
+
+    if (ssl->options.handShakeState != HANDSHAKE_DONE) {
+        CYASSL_MSG("Received App data before handshake complete");
+        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;
+        pad = *(input + idx + msgSz - ivExtra - 1);
+        padByte = 1;
+
+        if (ssl->options.tls) {
+            ret = TimingPadVerify(ssl, input + idx, pad, digestSz,
+                                  msgSz - ivExtra);
+            if (ret != 0)
+                return ret;
+        }
+        else {  /* sslv3, some implementations have bad padding */
+            ssl->hmac(ssl, verify, rawData, msgSz - digestSz - pad - 1,
+                      application_data, 1);
+            if (ConstantCompare(verify, rawData + msgSz - digestSz - pad - 1,
+                                digestSz) != 0)
+                return VERIFY_MAC_ERROR;
+        }
+    }
+    else if (ssl->specs.cipher_type == stream) {
+        ssl->hmac(ssl, verify, rawData, msgSz - digestSz, application_data, 1);
+        if (ConstantCompare(verify, rawData + msgSz - digestSz, digestSz) != 0){
+            return VERIFY_MAC_ERROR;
+        }
+    }
+    else if (ssl->specs.cipher_type == aead) {
+        ivExtra = AEAD_EXP_IV_SZ;
+        digestSz = ssl->specs.aead_mac_size;
+    }
+
+    dataSz = msgSz - ivExtra - digestSz - pad - padByte;
+    if (dataSz < 0) {
+        CYASSL_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 += digestSz;
+    idx += pad;
+    if (padByte)
+        idx++;
+
+#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(CYASSL* ssl, byte* input, word32* inOutIdx, int* type)
+{
+    byte level;
+    byte code;
+
+    #ifdef CYASSL_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
+    level = input[(*inOutIdx)++];
+    code  = (int)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 */
+    }
+
+    CYASSL_MSG("Got alert");
+    if (*type == close_notify) {
+        CYASSL_MSG("    close notify");
+        ssl->options.closeNotify = 1;
+    }
+    CYASSL_ERROR(*type);
+
+    if (ssl->keys.encryptionOn) {
+        if (ssl->specs.cipher_type != aead) {
+            int     aSz = ALERT_SIZE;
+            const byte* mac;
+            byte    verify[MAX_DIGEST_SIZE];
+            int     padSz = ssl->keys.encryptSz - aSz - ssl->specs.hash_size;
+
+            ssl->hmac(ssl, verify, input + *inOutIdx - aSz, aSz, alert, 1);
+    
+            /* read mac and fill */
+            mac = input + *inOutIdx;
+            *inOutIdx += (ssl->specs.hash_size + padSz);
+    
+            /* verify */
+            if (XMEMCMP(mac, verify, ssl->specs.hash_size) != 0) {
+                CYASSL_MSG("    alert verify mac error");
+                return VERIFY_MAC_ERROR;
+            }
+        }
+        else {
+            *inOutIdx += ssl->specs.aead_mac_size;
+        }
+    }
+
+    return level;
+}
+
+static int GetInputData(CYASSL *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 CYASSL_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;
+}
+
+/* process input requests, return 0 is done, 1 is call again to complete, and
+   negative number is error */
+int ProcessReply(CYASSL* ssl)
+{
+    int    ret = 0, type, readSz;
+    word32 startIdx = 0;
+#ifndef NO_CYASSL_SERVER
+    byte   b0, b1;
+#endif
+#ifdef CYASSL_DTLS
+    int    used;
+#endif
+
+    for (;;) {
+        switch ((processReply)ssl->options.processReply) {
+
+        /* in the CYASSL_SERVER case, get the first byte for detecting 
+         * old client hello */
+        case doProcessInit:
+            
+            readSz = RECORD_HEADER_SZ;
+            
+            #ifdef CYASSL_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 CYASSL_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
+            }
+
+#ifndef NO_CYASSL_SERVER
+
+            /* see if sending SSLv2 client hello */
+            if ( ssl->options.side == SERVER_END &&
+                 ssl->options.clientState == NULL_STATE &&
+                 ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx]
+                         != handshake) {
+                ssl->options.processReply = runProcessOldClientHello;
+
+                /* 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 = ((b0 & 0x7f) << 8) | b1;
+            }
+            else {
+                ssl->options.processReply = getRecordLayerHeader;
+                continue;
+            }
+
+        /* in the CYASSL_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 CYASSL_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  /* CYASSL_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  /* NO_CYASSL_SERVER */
+
+        /* get the record layer header */
+        case getRecordLayerHeader:
+
+            ret = GetRecordHeader(ssl, ssl->buffers.inputBuffer.buffer,
+                                       &ssl->buffers.inputBuffer.idx,
+                                       &ssl->curRL, &ssl->curSize);
+#ifdef CYASSL_DTLS
+            if (ssl->options.dtls && ret == SEQUENCE_ERROR) {
+                /* This message is out of order. If we are handshaking, save
+                 *it for later. Otherwise go ahead and process it. */
+                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 CYASSL_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:
+
+            if (ssl->keys.encryptionOn && ssl->keys.decryptedCur == 0) {
+                ret = DecryptMessage(ssl, ssl->buffers.inputBuffer.buffer + 
+                                     ssl->buffers.inputBuffer.idx,
+                                     ssl->curSize,
+                                     &ssl->buffers.inputBuffer.idx);
+                if (ret < 0) {
+                    CYASSL_ERROR(ret);
+                    return DECRYPT_ERROR;
+                }
+            }
+
+            CYASSL_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 CYASSL_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:
+                    CYASSL_MSG("got CHANGE CIPHER SPEC");
+                    #ifdef CYASSL_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
+
+                    if (ssl->curSize != 1) {
+                        CYASSL_MSG("Malicious or corrupted ChangeCipher msg");
+                        return LENGTH_ERROR;
+                    }
+                    #ifndef NO_CERTS
+                        if (ssl->options.side == SERVER_END &&
+                                 ssl->options.verifyPeer &&
+                                 ssl->options.havePeerCert)
+                            if (!ssl->options.havePeerVerify) {
+                                CYASSL_MSG("client didn't send cert verify");
+                                return NO_PEER_VERIFY;
+                            }
+                    #endif
+
+
+                    ssl->buffers.inputBuffer.idx++;
+                    ssl->keys.encryptionOn = 1;
+
+                    #ifdef CYASSL_DTLS
+                        if (ssl->options.dtls) {
+                            DtlsPoolReset(ssl);
+                            ssl->keys.dtls_expected_peer_epoch++;
+                            ssl->keys.dtls_expected_peer_sequence_number = 0;
+                        }
+                    #endif
+
+                    #ifdef HAVE_LIBZ
+                        if (ssl->options.usingCompression)
+                            if ( (ret = InitStreams(ssl)) != 0)
+                                return ret;
+                    #endif
+                    if (ssl->options.resuming && ssl->options.side ==
+                                                                    CLIENT_END)
+                        BuildFinished(ssl, &ssl->verifyHashes, server);
+                    else if (!ssl->options.resuming && ssl->options.side ==
+                                                                    SERVER_END)
+                        BuildFinished(ssl, &ssl->verifyHashes, client);
+                    break;
+
+                case application_data:
+                    CYASSL_MSG("got app DATA");
+                    if ((ret = DoApplicationData(ssl,
+                                                ssl->buffers.inputBuffer.buffer,
+                                               &ssl->buffers.inputBuffer.idx))
+                                                                         != 0) {
+                        CYASSL_ERROR(ret);
+                        return ret;
+                    }
+                    break;
+
+                case alert:
+                    CYASSL_MSG("got ALERT!");
+                    if (DoAlert(ssl, ssl->buffers.inputBuffer.buffer,
+                           &ssl->buffers.inputBuffer.idx, &type) == alert_fatal)
+                        return FATAL_ERROR;
+
+                    /* 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:
+                    CYASSL_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) {
+                CYASSL_MSG("More messages in record");
+                #ifdef CYASSL_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;
+                continue;
+            }
+            /* more records */
+            else {
+                CYASSL_MSG("More records in input");
+                ssl->options.processReply = doProcessInit;
+                continue;
+            }
+        default:
+            CYASSL_MSG("Bad process input state, programming error");
+            return INPUT_CASE_ERROR;
+        }
+    }
+}
+
+
+int SendChangeCipher(CYASSL* ssl)
+{
+    byte              *output;
+    int                sendSz = RECORD_HEADER_SZ + ENUM_LEN;
+    int                idx    = RECORD_HEADER_SZ;
+    int                ret;
+
+    #ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            sendSz += DTLS_RECORD_EXTRA;
+            idx    += DTLS_RECORD_EXTRA;
+        }
+    #endif
+
+    /* 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 */
+
+    #ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                return ret;
+        }
+    #endif
+    #ifdef CYASSL_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 CYASSL_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);
+}
+
+
+static INLINE const byte* GetMacSecret(CYASSL* ssl, int verify)
+{
+    if ( (ssl->options.side == CLIENT_END && !verify) ||
+         (ssl->options.side == SERVER_END &&  verify) )
+        return ssl->keys.client_write_MAC_secret;
+    else
+        return ssl->keys.server_write_MAC_secret;
+}
+
+#ifndef NO_OLD_TLS
+static void Hmac(CYASSL* 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;
+
+    Md5 md5;
+    Sha sha;
+
+    /* data */
+    byte seq[SEQ_SZ];
+    byte conLen[ENUM_LEN + LENGTH_SZ];     /* content & length */
+    const byte* macSecret = GetMacSecret(ssl, verify);
+    
+    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) {
+        InitMd5(&md5);
+        /* inner */
+        Md5Update(&md5, macSecret, digestSz);
+        Md5Update(&md5, PAD1, padSz);
+        Md5Update(&md5, seq, SEQ_SZ);
+        Md5Update(&md5, conLen, sizeof(conLen));
+        /* in buffer */
+        Md5Update(&md5, in, sz);
+        Md5Final(&md5, result);
+        /* outer */
+        Md5Update(&md5, macSecret, digestSz);
+        Md5Update(&md5, PAD2, padSz);
+        Md5Update(&md5, result, digestSz);
+        Md5Final(&md5, digest);        
+    }
+    else {
+        InitSha(&sha);
+        /* inner */
+        ShaUpdate(&sha, macSecret, digestSz);
+        ShaUpdate(&sha, PAD1, padSz);
+        ShaUpdate(&sha, seq, SEQ_SZ);
+        ShaUpdate(&sha, conLen, sizeof(conLen));
+        /* in buffer */
+        ShaUpdate(&sha, in, sz);
+        ShaFinal(&sha, result);
+        /* outer */
+        ShaUpdate(&sha, macSecret, digestSz);
+        ShaUpdate(&sha, PAD2, padSz);
+        ShaUpdate(&sha, result, digestSz);
+        ShaFinal(&sha, digest);        
+    }
+}
+
+#ifndef NO_CERTS
+static void BuildMD5_CertVerify(CYASSL* ssl, byte* digest)
+{
+    byte md5_result[MD5_DIGEST_SIZE];
+
+    /* make md5 inner */
+    Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN);
+    Md5Update(&ssl->hashMd5, PAD1, PAD_MD5);
+    Md5Final(&ssl->hashMd5, md5_result);
+
+    /* make md5 outer */
+    Md5Update(&ssl->hashMd5, ssl->arrays->masterSecret, SECRET_LEN);
+    Md5Update(&ssl->hashMd5, PAD2, PAD_MD5);
+    Md5Update(&ssl->hashMd5, md5_result, MD5_DIGEST_SIZE);
+
+    Md5Final(&ssl->hashMd5, digest);
+}
+
+
+static void BuildSHA_CertVerify(CYASSL* ssl, byte* digest)
+{
+    byte sha_result[SHA_DIGEST_SIZE];
+    
+    /* make sha inner */
+    ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN);
+    ShaUpdate(&ssl->hashSha, PAD1, PAD_SHA);
+    ShaFinal(&ssl->hashSha, sha_result);
+
+    /* make sha outer */
+    ShaUpdate(&ssl->hashSha, ssl->arrays->masterSecret, SECRET_LEN);
+    ShaUpdate(&ssl->hashSha, PAD2, PAD_SHA);
+    ShaUpdate(&ssl->hashSha, sha_result, SHA_DIGEST_SIZE);
+
+    ShaFinal(&ssl->hashSha, digest);
+}
+#endif /* NO_CERTS */
+#endif /* NO_OLD_TLS */
+
+
+#ifndef NO_CERTS
+
+static void BuildCertHashes(CYASSL* ssl, Hashes* hashes)
+{
+    /* store current states, building requires get_digest which resets state */
+    #ifndef NO_OLD_TLS
+    Md5 md5 = ssl->hashMd5;
+    Sha sha = ssl->hashSha;
+    #endif
+    #ifndef NO_SHA256
+        Sha256 sha256 = ssl->hashSha256;
+    #endif
+    #ifdef CYASSL_SHA384
+        Sha384 sha384 = ssl->hashSha384;
+    #endif
+    
+    if (ssl->options.tls) {
+#if ! defined( NO_OLD_TLS )
+        Md5Final(&ssl->hashMd5, hashes->md5);
+        ShaFinal(&ssl->hashSha, hashes->sha);
+#endif
+        if (IsAtLeastTLSv1_2(ssl)) {
+            #ifndef NO_SHA256
+                Sha256Final(&ssl->hashSha256, hashes->sha256);
+            #endif
+            #ifdef CYASSL_SHA384
+                Sha384Final(&ssl->hashSha384, hashes->sha384);
+            #endif
+        }
+    }
+#if ! defined( NO_OLD_TLS )
+    else {
+        BuildMD5_CertVerify(ssl, hashes->md5);
+        BuildSHA_CertVerify(ssl, hashes->sha);
+    }
+    
+    /* restore */
+    ssl->hashMd5 = md5;
+    ssl->hashSha = sha;
+#endif
+    if (IsAtLeastTLSv1_2(ssl)) {
+        #ifndef NO_SHA256
+            ssl->hashSha256 = sha256;
+        #endif
+        #ifdef CYASSL_SHA384
+            ssl->hashSha384 = sha384;
+        #endif
+    }
+}
+
+#endif /* CYASSL_LEANPSK */
+
+/* Build SSL Message, encrypted */
+static int BuildMessage(CYASSL* ssl, byte* output, const byte* input, int inSz,
+                        int type)
+{
+    word32 digestSz = ssl->specs.hash_size;
+    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;
+
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        sz       += DTLS_RECORD_EXTRA;
+        idx      += DTLS_RECORD_EXTRA; 
+        headerSz += DTLS_RECORD_EXTRA;
+    }
+#endif
+
+    if (ssl->specs.cipher_type == block) {
+        word32 blockSz = ssl->specs.block_size;
+        if (ssl->options.tls1_1) {
+            ivSz = blockSz;
+            sz  += ivSz;
+            RNG_GenerateBlock(ssl->rng, iv, ivSz);
+        }
+        sz += 1;       /* pad byte */
+        pad = (sz - headerSz) % blockSz;
+        pad = blockSz - pad;
+        sz += pad;
+    }
+
+#ifdef HAVE_AEAD
+    if (ssl->specs.cipher_type == aead) {
+        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
+    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) {
+        HashOutput(ssl, output, headerSz + inSz, ivSz);
+    }
+
+    if (ssl->specs.cipher_type != aead) {
+        ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, type, 0);
+        idx += digestSz;
+    }
+
+    if (ssl->specs.cipher_type == block)
+        for (i = 0; i <= pad; i++)
+            output[idx++] = (byte)pad; /* pad byte gets pad value too */
+
+    if ( (ret = Encrypt(ssl, output + headerSz, output + headerSz, size)) != 0)
+        return ret;
+
+    return sz;
+}
+
+
+int SendFinished(CYASSL* 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;
+
+    #ifdef CYASSL_DTLS
+        word32 sequence_number = ssl->keys.dtls_sequence_number;
+        word16 epoch           = ssl->keys.dtls_epoch;
+    #endif
+
+
+    /* check for available size */
+    if ((ret = CheckAvailableSize(ssl, sizeof(input) + MAX_MSG_EXTRA)) != 0)
+        return ret;
+
+    #ifdef CYASSL_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];
+    BuildFinished(ssl, hashes, ssl->options.side == CLIENT_END ? client :
+                  server);
+
+    sendSz = BuildMessage(ssl, output, input, headerSz + finishedSz, handshake);
+
+    #ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        ssl->keys.dtls_epoch = epoch;
+        ssl->keys.dtls_sequence_number = sequence_number;
+    }
+    #endif
+
+    if (sendSz < 0)
+        return BUILD_MSG_ERROR;
+
+    if (!ssl->options.resuming) {
+#ifndef NO_SESSION_CACHE
+        AddSession(ssl);    /* just try */
+#endif
+        if (ssl->options.side == CLIENT_END) {
+            BuildFinished(ssl, &ssl->verifyHashes, server);
+        }
+        else {
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+            #ifdef CYASSL_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 == CLIENT_END) {
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+            #ifdef CYASSL_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 {
+            BuildFinished(ssl, &ssl->verifyHashes, client);
+        }
+    }
+    #ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                return ret;
+        }
+    #endif
+
+    #ifdef CYASSL_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(CYASSL* 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) 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 CYASSL_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, 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);
+            /* if add more to output adjust i
+               i += ssl->buffers.certChain.length; */
+        }
+    }
+    #ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                return ret;
+        }
+    #endif
+    HashOutput(ssl, output, sendSz, 0);
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz,
+                           ssl->heap);
+    #endif
+
+    if (ssl->options.side == 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(CYASSL* ssl)
+{
+    byte   *output;
+    int    ret;
+    int    sendSz;
+    word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+    
+    int  typeTotal = 1;  /* only rsa 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) return 0;  /* not needed */
+
+    sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz;
+
+    #ifdef CYASSL_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 */
+    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 CYASSL_DTLS
+        if (ssl->options.dtls) {
+            if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                return ret;
+        }
+    #endif
+    HashOutput(ssl, output, sendSz, 0);
+
+    #ifdef CYASSL_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(CYASSL* ssl, const void* data, int sz)
+{
+    int sent = 0,  /* plainText size */
+        sendSz,
+        ret;
+
+    if (ssl->error == WANT_WRITE)
+        ssl->error = 0;
+
+    if (ssl->options.handShakeState != HANDSHAKE_DONE) {
+        int err;
+        CYASSL_MSG("handshake not complete, trying to finish");
+        if ( (err = CyaSSL_negotiate(ssl)) != SSL_SUCCESS) 
+            return  err;
+    }
+
+    /* last time system socket output buffer was full, try again to send */
+    if (ssl->buffers.outputBuffer.length > 0) {
+        CYASSL_MSG("output buffer was full, trying to send again");
+        if ( (ssl->error = SendBuffered(ssl)) < 0) {
+            CYASSL_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;
+            CYASSL_MSG("sent write buffered data");
+        }
+    }
+
+    for (;;) {
+        int   len = min(sz - sent, OUTPUT_RECORD_SIZE);
+        byte* out;
+        byte* sendBuffer = (byte*)data + sent;  /* may switch on comp */
+        int   buffSz = len;                       /* may switch on comp */
+#ifdef HAVE_LIBZ
+        byte  comp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
+#endif
+
+        if (sent == sz) break;
+
+#ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            len    = min(len, MAX_UDP_SIZE);
+            buffSz = len;
+        }
+#endif
+
+        /* check for available size */
+        if ((ret = CheckAvailableSize(ssl, len + COMP_EXTRA +
+                                      MAX_MSG_EXTRA)) != 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, sendBuffer, buffSz,
+                              application_data);
+
+        ssl->buffers.outputBuffer.length += sendSz;
+
+        if ( (ret = SendBuffered(ssl)) < 0) {
+            CYASSL_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) {
+            CYASSL_MSG("Paritial Write on, only sending one record");
+            break;
+        }
+    }
+ 
+    return sent;
+}
+
+/* process input data */
+int ReceiveData(CYASSL* ssl, byte* output, int sz, int peek)
+{
+    int size;
+
+    CYASSL_ENTER("ReceiveData()");
+
+    if (ssl->error == WANT_READ)
+        ssl->error = 0;
+
+    if (ssl->options.handShakeState != HANDSHAKE_DONE) {
+        int err;
+        CYASSL_MSG("Handshake not complete, trying to finish");
+        if ( (err = CyaSSL_negotiate(ssl)) != SSL_SUCCESS)
+            return  err;
+    }
+
+    while (ssl->buffers.clearOutputBuffer.length == 0)
+        if ( (ssl->error = ProcessReply(ssl)) < 0) {
+            CYASSL_ERROR(ssl->error);
+            if (ssl->error == ZERO_RETURN) {
+                CYASSL_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) {
+                    CYASSL_MSG("Peer reset or closed, connection done");
+                    return 0;     /* peer reset or closed */
+                }
+            }
+            return ssl->error;
+        }
+
+    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);
+
+    CYASSL_LEAVE("ReceiveData()", size);
+    return size;
+}
+
+
+/* send alert message */
+int SendAlert(CYASSL* ssl, int severity, int type)
+{
+    byte input[ALERT_SIZE];
+    byte *output;
+    int  sendSz;
+    int  ret;
+    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 CYASSL_DTLS
+        if (ssl->options.dtls)
+           dtlsExtra = DTLS_RECORD_EXTRA; 
+   #endif
+
+    /* check for available size */
+    if ((ret = CheckAvailableSize(ssl,
+                                  ALERT_SIZE + MAX_MSG_EXTRA + dtlsExtra)) != 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.handShakeState == HANDSHAKE_DONE)
+        sendSz = BuildMessage(ssl, output, input, ALERT_SIZE, alert);
+    else {
+
+        AddRecordHeader(output, ALERT_SIZE, alert, ssl);
+        output += RECORD_HEADER_SZ;
+        #ifdef CYASSL_DTLS
+            if (ssl->options.dtls)
+                output += DTLS_RECORD_EXTRA;
+        #endif
+        XMEMCPY(output, input, ALERT_SIZE);
+
+        sendSz = RECORD_HEADER_SZ + ALERT_SIZE;
+        #ifdef CYASSL_DTLS
+            if (ssl->options.dtls)
+                sendSz += DTLS_RECORD_EXTRA;
+        #endif
+    }
+
+    #ifdef CYASSL_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);
+}
+
+
+
+void SetErrorString(int error, char* str)
+{
+    const int max = MAX_ERROR_SZ;  /* shorthand */
+
+#ifdef NO_ERROR_STRINGS
+
+    (void)error;
+    XSTRNCPY(str, "no support for error strings built in", max);
+
+#else
+
+    /* pass to CTaoCrypt */
+    if (error < MAX_CODE_E && error > MIN_CODE_E) {
+        CTaoCryptErrorString(error, str);
+        return;
+    }
+
+    switch (error) {
+
+    case UNSUPPORTED_SUITE :
+        XSTRNCPY(str, "unsupported cipher suite", max);
+        break;
+
+    case INPUT_CASE_ERROR :
+        XSTRNCPY(str, "input state error", max);
+        break;
+
+    case PREFIX_ERROR :
+        XSTRNCPY(str, "bad index to key rounds", max);
+        break;
+
+    case MEMORY_ERROR :
+        XSTRNCPY(str, "out of memory", max);
+        break;
+
+    case VERIFY_FINISHED_ERROR :
+        XSTRNCPY(str, "verify problem on finished", max);
+        break;
+
+    case VERIFY_MAC_ERROR :
+        XSTRNCPY(str, "verify mac problem", max);
+        break;
+
+    case PARSE_ERROR :
+        XSTRNCPY(str, "parse error on header", max);
+        break;
+
+    case SIDE_ERROR :
+        XSTRNCPY(str, "wrong client/server type", max);
+        break;
+
+    case NO_PEER_CERT :
+        XSTRNCPY(str, "peer didn't send cert", max);
+        break;
+
+    case UNKNOWN_HANDSHAKE_TYPE :
+        XSTRNCPY(str, "weird handshake type", max);
+        break;
+
+    case SOCKET_ERROR_E :
+        XSTRNCPY(str, "error state on socket", max);
+        break;
+
+    case SOCKET_NODATA :
+        XSTRNCPY(str, "expected data, not there", max);
+        break;
+
+    case INCOMPLETE_DATA :
+        XSTRNCPY(str, "don't have enough data to complete task", max);
+        break;
+
+    case UNKNOWN_RECORD_TYPE :
+        XSTRNCPY(str, "unknown type in record hdr", max);
+        break;
+
+    case DECRYPT_ERROR :
+        XSTRNCPY(str, "error during decryption", max);
+        break;
+
+    case FATAL_ERROR :
+        XSTRNCPY(str, "revcd alert fatal error", max);
+        break;
+
+    case ENCRYPT_ERROR :
+        XSTRNCPY(str, "error during encryption", max);
+        break;
+
+    case FREAD_ERROR :
+        XSTRNCPY(str, "fread problem", max);
+        break;
+
+    case NO_PEER_KEY :
+        XSTRNCPY(str, "need peer's key", max);
+        break;
+
+    case NO_PRIVATE_KEY :
+        XSTRNCPY(str, "need the private key", max);
+        break;
+
+    case NO_DH_PARAMS :
+        XSTRNCPY(str, "server missing DH params", max);
+        break;
+
+    case RSA_PRIVATE_ERROR :
+        XSTRNCPY(str, "error during rsa priv op", max);
+        break;
+
+    case MATCH_SUITE_ERROR :
+        XSTRNCPY(str, "can't match cipher suite", max);
+        break;
+
+    case BUILD_MSG_ERROR :
+        XSTRNCPY(str, "build message failure", max);
+        break;
+
+    case BAD_HELLO :
+        XSTRNCPY(str, "client hello malformed", max);
+        break;
+
+    case DOMAIN_NAME_MISMATCH :
+        XSTRNCPY(str, "peer subject name mismatch", max);
+        break;
+
+    case WANT_READ :
+    case SSL_ERROR_WANT_READ :
+        XSTRNCPY(str, "non-blocking socket wants data to be read", max);
+        break;
+
+    case NOT_READY_ERROR :
+        XSTRNCPY(str, "handshake layer not ready yet, complete first", max);
+        break;
+
+    case PMS_VERSION_ERROR :
+        XSTRNCPY(str, "premaster secret version mismatch error", max);
+        break;
+
+    case VERSION_ERROR :
+        XSTRNCPY(str, "record layer version error", max);
+        break;
+
+    case WANT_WRITE :
+    case SSL_ERROR_WANT_WRITE :
+        XSTRNCPY(str, "non-blocking socket write buffer full", max);
+        break;
+
+    case BUFFER_ERROR :
+        XSTRNCPY(str, "malformed buffer input error", max);
+        break;
+
+    case VERIFY_CERT_ERROR :
+        XSTRNCPY(str, "verify problem on certificate", max);
+        break;
+
+    case VERIFY_SIGN_ERROR :
+        XSTRNCPY(str, "verify problem based on signature", max);
+        break;
+
+    case CLIENT_ID_ERROR :
+        XSTRNCPY(str, "psk client identity error", max);
+        break;
+
+    case SERVER_HINT_ERROR:
+        XSTRNCPY(str, "psk server hint error", max);
+        break;
+
+    case PSK_KEY_ERROR:
+        XSTRNCPY(str, "psk key callback error", max);
+        break;
+
+    case NTRU_KEY_ERROR:
+        XSTRNCPY(str, "NTRU key error", max);
+        break;
+
+    case NTRU_DRBG_ERROR:
+        XSTRNCPY(str, "NTRU drbg error", max);
+        break;
+
+    case NTRU_ENCRYPT_ERROR:
+        XSTRNCPY(str, "NTRU encrypt error", max);
+        break;
+
+    case NTRU_DECRYPT_ERROR:
+        XSTRNCPY(str, "NTRU decrypt error", max);
+        break;
+
+    case ZLIB_INIT_ERROR:
+        XSTRNCPY(str, "zlib init error", max);
+        break;
+
+    case ZLIB_COMPRESS_ERROR:
+        XSTRNCPY(str, "zlib compress error", max);
+        break;
+
+    case ZLIB_DECOMPRESS_ERROR:
+        XSTRNCPY(str, "zlib decompress error", max);
+        break;
+
+    case GETTIME_ERROR:
+        XSTRNCPY(str, "gettimeofday() error", max);
+        break;
+
+    case GETITIMER_ERROR:
+        XSTRNCPY(str, "getitimer() error", max);
+        break;
+
+    case SIGACT_ERROR:
+        XSTRNCPY(str, "sigaction() error", max);
+        break;
+
+    case SETITIMER_ERROR:
+        XSTRNCPY(str, "setitimer() error", max);
+        break;
+
+    case LENGTH_ERROR:
+        XSTRNCPY(str, "record layer length error", max);
+        break;
+
+    case PEER_KEY_ERROR:
+        XSTRNCPY(str, "cant decode peer key", max);
+        break;
+
+    case ZERO_RETURN:
+    case SSL_ERROR_ZERO_RETURN:
+        XSTRNCPY(str, "peer sent close notify alert", max);
+        break;
+
+    case ECC_CURVETYPE_ERROR:
+        XSTRNCPY(str, "Bad ECC Curve Type or unsupported", max);
+        break;
+
+    case ECC_CURVE_ERROR:
+        XSTRNCPY(str, "Bad ECC Curve or unsupported", max);
+        break;
+
+    case ECC_PEERKEY_ERROR:
+        XSTRNCPY(str, "Bad ECC Peer Key", max);
+        break;
+
+    case ECC_MAKEKEY_ERROR:
+        XSTRNCPY(str, "ECC Make Key failure", max);
+        break;
+
+    case ECC_EXPORT_ERROR:
+        XSTRNCPY(str, "ECC Export Key failure", max);
+        break;
+
+    case ECC_SHARED_ERROR:
+        XSTRNCPY(str, "ECC DHE shared failure", max);
+        break;
+
+    case BAD_MUTEX_ERROR:
+        XSTRNCPY(str, "Bad mutex, operation failed", max);
+        break;
+
+    case NOT_CA_ERROR:
+        XSTRNCPY(str, "Not a CA by basic constraint error", max);
+        break;
+
+    case BAD_PATH_ERROR:
+        XSTRNCPY(str, "Bad path for opendir error", max);
+        break;
+
+    case BAD_CERT_MANAGER_ERROR:
+        XSTRNCPY(str, "Bad Cert Manager error", max);
+        break;
+
+    case OCSP_CERT_REVOKED:
+        XSTRNCPY(str, "OCSP Cert revoked", max);
+        break;
+
+    case CRL_CERT_REVOKED:
+        XSTRNCPY(str, "CRL Cert revoked", max);
+        break;
+
+    case CRL_MISSING:
+        XSTRNCPY(str, "CRL missing, not loaded", max);
+        break;
+
+    case MONITOR_RUNNING_E:
+        XSTRNCPY(str, "CRL monitor already running", max);
+        break;
+
+    case THREAD_CREATE_E:
+        XSTRNCPY(str, "Thread creation problem", max);
+        break;
+
+    case OCSP_NEED_URL:
+        XSTRNCPY(str, "OCSP need URL", max);
+        break;
+
+    case OCSP_CERT_UNKNOWN:
+        XSTRNCPY(str, "OCSP Cert unknown", max);
+        break;
+
+    case OCSP_LOOKUP_FAIL:
+        XSTRNCPY(str, "OCSP Responder lookup fail", max);
+        break;
+
+    case MAX_CHAIN_ERROR:
+        XSTRNCPY(str, "Maximum Chain Depth Exceeded", max);
+        break;
+
+    case COOKIE_ERROR:
+        XSTRNCPY(str, "DTLS Cookie Error", max);
+        break;
+
+    case SEQUENCE_ERROR:
+        XSTRNCPY(str, "DTLS Sequence Error", max);
+        break;
+
+    case SUITES_ERROR:
+        XSTRNCPY(str, "Suites Pointer Error", max);
+        break;
+
+    case SSL_NO_PEM_HEADER:
+        XSTRNCPY(str, "No PEM Header Error", max);
+        break;
+
+    case OUT_OF_ORDER_E:
+        XSTRNCPY(str, "Out of order message, fatal", max);
+        break;
+
+    case BAD_KEA_TYPE_E:
+        XSTRNCPY(str, "Bad KEA type found", max);
+        break;
+
+    case SANITY_CIPHER_E:
+        XSTRNCPY(str, "Sanity check on ciphertext failed", max);
+        break;
+
+    case RECV_OVERFLOW_E:
+        XSTRNCPY(str, "Receive callback returned more than requested", max);
+        break;
+
+    case GEN_COOKIE_E:
+        XSTRNCPY(str, "Generate Cookie Error", max);
+        break;
+
+    case NO_PEER_VERIFY:
+        XSTRNCPY(str, "Need peer certificate verify Error", max);
+        break;
+
+    case FWRITE_ERROR:
+        XSTRNCPY(str, "fwrite Error", max);
+        break;
+
+    case CACHE_MATCH_ERROR:
+        XSTRNCPY(str, "Cache restore header match Error", max);
+        break;
+
+    case UNKNOWN_SNI_HOST_NAME_E:
+        XSTRNCPY(str, "Unrecognized host name Error", max);
+        break;
+
+    default :
+        XSTRNCPY(str, "unknown error number", max);
+    }
+
+#endif /* NO_ERROR_STRINGS */
+}
+
+
+
+/* be sure to add to cipher_name_idx too !!!! */
+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_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_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_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_CBC_MD5
+    "HC128-MD5",
+#endif
+    
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA
+    "HC128-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_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
+
+};
+
+
+
+/* cipher suite number that matches above name table */
+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_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_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_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_CBC_MD5
+    TLS_RSA_WITH_HC_128_CBC_MD5,    
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA
+    TLS_RSA_WITH_HC_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA
+    TLS_RSA_WITH_RABBIT_CBC_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
+};
+
+
+/* return true if set, else false */
+/* only supports full name from cipher_name[] delimited by : */
+int SetCipherList(Suites* s, const char* list)
+{
+    int  ret = 0, i;
+    char name[MAX_SUITE_NAME];
+
+    char  needle[] = ":";
+    char* haystack = (char*)list;
+    char* prev;
+
+    const int suiteSz = sizeof(cipher_names) / sizeof(cipher_names[0]);
+    int idx = 0;
+    int haveRSA = 0, haveECDSA = 0;
+
+    if (s == NULL) {
+        CYASSL_MSG("SetCipherList suite pointer error");
+        return 0;    
+    }
+
+    if (!list)
+        return 0;
+    
+    if (*list == 0) return 1;   /* CyaSSL default */
+
+    if (XSTRNCMP(haystack, "ALL", 3) == 0) return 1;  /* CyaSSL defualt */
+
+    for(;;) {
+        word32 len;
+        prev = haystack;
+        haystack = XSTRSTR(haystack, needle);
+
+        if (!haystack)    /* last cipher */
+            len = min(sizeof(name), (word32)XSTRLEN(prev));
+        else
+            len = min(sizeof(name), (word32)(haystack - prev));
+
+        XSTRNCPY(name, prev, len);
+        name[(len == sizeof(name)) ? len - 1 : len] = 0;
+
+        for (i = 0; i < suiteSz; i++)
+            if (XSTRNCMP(name, cipher_names[i], sizeof(name)) == 0) {
+                if (XSTRSTR(name, "EC") || XSTRSTR(name, "CCM"))
+                    s->suites[idx++] = ECC_BYTE;  /* ECC suite */
+                else
+                    s->suites[idx++] = 0x00;      /* normal */
+                s->suites[idx++] = (byte)cipher_name_idx[i];
+
+                /* The suites are either ECDSA, RSA, or PSK. The RSA suites
+                 * don't necessarily have RSA in the name. */
+                if ((haveECDSA == 0) && XSTRSTR(name, "ECDSA")) {
+                    haveECDSA = 1;
+                }
+                else if ((haveRSA == 0) && (XSTRSTR(name, "PSK") == NULL)) {
+                    haveRSA = 1;
+                }
+
+                if (!ret) ret = 1;   /* found at least one */
+                break;
+            }
+        if (!haystack) break;
+        haystack++;
+    }
+
+    if (ret) {
+        s->setSuites = 1;
+        s->suiteSz   = (word16)idx;
+
+        idx = 0;
+        
+        if (haveECDSA) {
+            #ifdef CYASSL_SHA384
+                s->hashSigAlgo[idx++] = sha384_mac;
+                s->hashSigAlgo[idx++] = ecc_dsa_sa_algo;
+            #endif
+            #ifndef NO_SHA256
+                s->hashSigAlgo[idx++] = sha256_mac;
+                s->hashSigAlgo[idx++] = ecc_dsa_sa_algo;
+            #endif
+            s->hashSigAlgo[idx++] = sha_mac;
+            s->hashSigAlgo[idx++] = ecc_dsa_sa_algo;
+        }
+
+        if (haveRSA) {
+            #ifdef CYASSL_SHA384
+                s->hashSigAlgo[idx++] = sha384_mac;
+                s->hashSigAlgo[idx++] = rsa_sa_algo;
+            #endif
+            #ifndef NO_SHA256
+                s->hashSigAlgo[idx++] = sha256_mac;
+                s->hashSigAlgo[idx++] = rsa_sa_algo;
+            #endif
+            s->hashSigAlgo[idx++] = sha_mac;
+            s->hashSigAlgo[idx++] = rsa_sa_algo;
+        }
+
+        s->hashSigAlgoSz = (word16)idx;
+    }
+
+    return ret;
+}
+
+
+static void PickHashSigAlgo(CYASSL* ssl,
+                             const byte* hashSigAlgo, word32 hashSigAlgoSz)
+{
+    word32 i;
+
+    ssl->suites->sigAlgo = ssl->specs.sig_algo;
+    ssl->suites->hashAlgo = sha_mac;
+
+    for (i = 0; i < 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 CYASSL_SHA384
+            else if (hashSigAlgo[i] == sha384_mac) {
+                ssl->suites->hashAlgo = sha384_mac;
+                break;
+            }
+            #endif
+        }
+    }
+}
+
+
+#ifdef CYASSL_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 CYASSL* 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 /* CYASSL_CALLBACKS */
+
+
+
+/* client only parts */
+#ifndef NO_CYASSL_CLIENT
+
+    int SendClientHello(CYASSL* ssl)
+    {
+        byte              *output;
+        word32             length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        int                sendSz;
+        int                idSz = ssl->options.resuming ? ID_LEN : 0;
+        int                ret;
+
+        if (ssl->suites == NULL) {
+            CYASSL_MSG("Bad suites pointer in SendClientHello");
+            return SUITES_ERROR;
+        } 
+
+        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 CYASSL_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
+
+        /* 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) {
+            RNG_GenerateBlock(ssl->rng, output + idx, RAN_LEN);
+            
+                /* store random */
+            XMEMCPY(ssl->arrays->clientRandom, output + idx, RAN_LEN);
+        } else {
+#ifdef CYASSL_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, ID_LEN);
+            idx += ID_LEN;
+        }
+        
+            /* then DTLS cookie */
+#ifdef CYASSL_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
+
+        #ifdef CYASSL_DTLS
+            if (ssl->options.dtls) {
+                if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                    return ret;
+            }
+        #endif
+        HashOutput(ssl, output, sendSz, 0);
+
+        ssl->options.clientState = CLIENT_HELLO_COMPLETE;
+
+#ifdef CYASSL_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(CYASSL* ssl, const byte* input,
+                                    word32* inOutIdx)
+    {
+        ProtocolVersion pv;
+        byte            cookieSz;
+        
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("HelloVerifyRequest",
+                                         &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("HelloVerifyRequest", &ssl->timeoutInfo);
+#endif
+#ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            DtlsPoolReset(ssl);
+        }
+#endif
+        XMEMCPY(&pv, input + *inOutIdx, sizeof(pv));
+        *inOutIdx += (word32)sizeof(pv);
+        
+        cookieSz = input[(*inOutIdx)++];
+        
+        if (cookieSz) {
+#ifdef CYASSL_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 int DoServerHello(CYASSL* ssl, const byte* input, word32* inOutIdx,
+                             word32 helloSz)
+    {
+        byte b;
+        byte compression;
+        ProtocolVersion pv;
+        word32 i = *inOutIdx;
+        word32 begin = i;
+
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo);
+#endif
+        XMEMCPY(&pv, input + i, sizeof(pv));
+        i += (word32)sizeof(pv);
+        if (pv.minor > ssl->version.minor) {
+            CYASSL_MSG("Server using higher version, fatal error");
+            return VERSION_ERROR;
+        }
+        else if (pv.minor < ssl->version.minor) {
+            CYASSL_MSG("server using lower version");
+            if (!ssl->options.downgrade) {
+                CYASSL_MSG("    no downgrade allowed, fatal error");
+                return VERSION_ERROR;
+            }
+            else if (pv.minor == SSLv3_MINOR) {
+                /* turn off tls */
+                CYASSL_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+ */
+                CYASSL_MSG("    downgrading to TLSv1");
+                ssl->options.tls1_1 = 0;
+                ssl->version.minor  = TLSv1_MINOR;
+            }
+            else if (pv.minor == TLSv1_1_MINOR) {
+                CYASSL_MSG("    downgrading to TLSv1.1");
+                ssl->version.minor  = TLSv1_1_MINOR;
+            }
+        }
+        XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN);
+        i += RAN_LEN;
+        b = input[i++];
+        if (b) {
+            XMEMCPY(ssl->arrays->sessionID, input + i, min(b, ID_LEN));
+            i += b;
+            ssl->options.haveSessionId = 1;
+        }
+        ssl->options.cipherSuite0 = input[i++];
+        ssl->options.cipherSuite  = input[i++];  
+        compression = input[i++];
+
+        if (compression != ZLIB_COMPRESSION && ssl->options.usingCompression) {
+            CYASSL_MSG("Server refused compression, turning off"); 
+            ssl->options.usingCompression = 0;  /* turn off if server refused */
+        }
+
+        *inOutIdx = i;
+        if ( (i - begin) < helloSz) {
+#ifdef HAVE_TLS_EXTENSIONS
+            if (IsTLS(ssl)) {
+                int ret = 0;
+                word16 totalExtSz;
+                Suites clSuites; /* just for compatibility right now */
+
+                ato16(&input[i], &totalExtSz);
+                i += LENGTH_SZ;
+                if (totalExtSz > helloSz + begin - i)
+                    return INCOMPLETE_DATA;
+
+                if ((ret = TLSX_Parse(ssl, (byte *) input + i,
+                                                     totalExtSz, 0, &clSuites)))
+                    return ret;
+
+                i += totalExtSz;
+                *inOutIdx = i;
+            }
+            else
+#endif
+                *inOutIdx = begin + helloSz;  /* skip extensions */
+        }
+
+        ssl->options.serverState = SERVER_HELLO_COMPLETE;
+
+        if (ssl->options.resuming) {
+            if (ssl->options.haveSessionId && XMEMCMP(ssl->arrays->sessionID,
+                                         ssl->session.sessionID, ID_LEN) == 0) {
+                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 {
+                    CYASSL_MSG("Unsupported cipher suite, DoServerHello");
+                    return UNSUPPORTED_SUITE;
+                }
+            }
+            else {
+                CYASSL_MSG("Server denied resumption attempt"); 
+                ssl->options.resuming = 0; /* server denied resumption try */
+            }
+        }
+        #ifdef CYASSL_DTLS
+            if (ssl->options.dtls) {
+                DtlsPoolReset(ssl);
+            }
+        #endif
+        return SetCipherSpecs(ssl);
+    }
+
+
+#ifndef NO_CERTS
+    /* just read in and ignore for now TODO: */
+    static int DoCertificateRequest(CYASSL* ssl, const byte* input, word32*
+                                    inOutIdx)
+    {
+        word16 len;
+       
+        #ifdef CYASSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("CertificateRequest", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("CertificateRequest", &ssl->timeoutInfo);
+        #endif
+        len = input[(*inOutIdx)++];
+
+        /* types, read in here */
+        *inOutIdx += len;
+
+        if (IsAtLeastTLSv1_2(ssl)) {
+            /* hash sig format */
+            ato16(&input[*inOutIdx], &len);
+            *inOutIdx += LENGTH_SZ;
+            PickHashSigAlgo(ssl, &input[*inOutIdx], len);
+            *inOutIdx += len;
+        }
+
+        /* authorities */
+        ato16(&input[*inOutIdx], &len);
+        *inOutIdx += LENGTH_SZ;
+        while (len) {
+            word16 dnSz;
+       
+            ato16(&input[*inOutIdx], &dnSz);
+            *inOutIdx += (REQUEST_HEADER + dnSz);
+            len -= dnSz + REQUEST_HEADER;
+        }
+
+        /* 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 (IsAtLeastTLSv1_2(ssl))
+            ssl->options.sendVerify = SEND_BLANK_CERT;
+
+        return 0;
+    }
+#endif /* !NO_CERTS */
+
+
+    static int DoServerKeyExchange(CYASSL* ssl, const byte* input,
+                                   word32* inOutIdx)
+    {
+    #if defined(OPENSSL_EXTRA) || defined(HAVE_ECC)
+        word16 length    = 0;
+        word16 sigLen    = 0;
+        word16 verifySz  = (word16)*inOutIdx;  /* keep start idx */
+        byte*  signature = 0;
+    #endif 
+
+        (void)ssl;
+        (void)input;
+        (void)inOutIdx;
+
+    #ifdef CYASSL_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) {
+            word16 pskLen = 0;
+            ato16(&input[*inOutIdx], &pskLen);
+            *inOutIdx += LENGTH_SZ;
+            XMEMCPY(ssl->arrays->server_hint, &input[*inOutIdx],
+                   min(pskLen, MAX_PSK_ID_LEN));
+            if (pskLen < MAX_PSK_ID_LEN)
+                ssl->arrays->server_hint[pskLen] = 0;
+            else
+                ssl->arrays->server_hint[MAX_PSK_ID_LEN - 1] = 0;
+            *inOutIdx += pskLen;
+
+            return 0;
+        }
+    #endif
+    #ifdef OPENSSL_EXTRA
+        if (ssl->specs.kea == diffie_hellman_kea)
+        {
+        /* p */
+        ato16(&input[*inOutIdx], &length);
+        *inOutIdx += LENGTH_SZ;
+
+        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;
+
+        /* g */
+        ato16(&input[*inOutIdx], &length);
+        *inOutIdx += LENGTH_SZ;
+
+        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 */
+        ato16(&input[*inOutIdx], &length);
+        *inOutIdx += LENGTH_SZ;
+
+        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 /* OPENSSL_EXTRA */
+
+    #ifdef HAVE_ECC
+        if (ssl->specs.kea == ecc_diffie_hellman_kea)
+        {
+        byte b = input[*inOutIdx];
+        *inOutIdx += 1;
+
+        if (b != named_curve)
+            return ECC_CURVETYPE_ERROR;
+
+        *inOutIdx += 1;   /* curve type, eat leading 0 */
+        b = input[*inOutIdx];
+        *inOutIdx += 1;
+
+        if (b != secp256r1 && b != secp384r1 && b != secp521r1 && b !=
+                 secp160r1 && b != secp192r1 && b != secp224r1)
+            return ECC_CURVE_ERROR;
+
+        length = input[*inOutIdx];
+        *inOutIdx += 1;
+
+        if (ecc_import_x963(&input[*inOutIdx], length, ssl->peerEccKey) != 0)
+            return ECC_PEERKEY_ERROR;
+
+        *inOutIdx += length;
+        ssl->peerEccKeyPresent = 1;
+        }
+    #endif /* HAVE_ECC */
+
+    #if defined(OPENSSL_EXTRA) || defined(HAVE_ECC)
+    {
+#ifndef NO_OLD_TLS
+        Md5    md5;
+        Sha    sha;
+#endif
+        byte   hash[FINISHED_SZ];
+        #ifndef NO_SHA256
+            Sha256 sha256;
+            byte hash256[SHA256_DIGEST_SIZE];
+        #endif
+        #ifdef CYASSL_SHA384
+            Sha384 sha384;
+            byte hash384[SHA384_DIGEST_SIZE];
+        #endif
+        byte   messageVerify[MAX_DH_SZ];
+        byte   hashAlgo = sha_mac;
+        byte   sigAlgo = ssl->specs.sig_algo;
+
+        /* adjust from start idx */
+        verifySz = (word16)(*inOutIdx - verifySz);
+
+        /* save message for hash verify */
+        if (verifySz > sizeof(messageVerify))
+            return BUFFER_ERROR;
+        XMEMCPY(messageVerify, &input[*inOutIdx - verifySz], verifySz);
+
+        if (IsAtLeastTLSv1_2(ssl)) {
+            hashAlgo = input[*inOutIdx];
+            *inOutIdx += 1;
+            sigAlgo = input[*inOutIdx];
+            *inOutIdx += 1;
+        }
+
+        /* signature */
+        ato16(&input[*inOutIdx], &length);
+        *inOutIdx += LENGTH_SZ;
+
+        signature = (byte*)&input[*inOutIdx];
+        *inOutIdx += length;
+        sigLen = length;
+
+        /* verify signature */
+#ifndef NO_OLD_TLS
+        /* md5 */
+        InitMd5(&md5);
+        Md5Update(&md5, ssl->arrays->clientRandom, RAN_LEN);
+        Md5Update(&md5, ssl->arrays->serverRandom, RAN_LEN);
+        Md5Update(&md5, messageVerify, verifySz);
+        Md5Final(&md5, hash);
+
+        /* sha */
+        InitSha(&sha);
+        ShaUpdate(&sha, ssl->arrays->clientRandom, RAN_LEN);
+        ShaUpdate(&sha, ssl->arrays->serverRandom, RAN_LEN);
+        ShaUpdate(&sha, messageVerify, verifySz);
+        ShaFinal(&sha, &hash[MD5_DIGEST_SIZE]);
+#endif
+        #ifndef NO_SHA256
+            InitSha256(&sha256);
+            Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN);
+            Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN);
+            Sha256Update(&sha256, messageVerify, verifySz);
+            Sha256Final(&sha256, hash256);
+        #endif
+
+        #ifdef CYASSL_SHA384
+            InitSha384(&sha384);
+            Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN);
+            Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN);
+            Sha384Update(&sha384, messageVerify, verifySz);
+            Sha384Final(&sha384, hash384);
+        #endif
+#ifndef NO_RSA
+        /* rsa */
+        if (sigAlgo == rsa_sa_algo)
+        {
+            int   ret;
+            byte* out;
+
+            if (!ssl->peerRsaKeyPresent)
+                return NO_PEER_KEY;
+
+            ret = RsaSSL_VerifyInline(signature, sigLen,&out, ssl->peerRsaKey);
+
+            if (IsAtLeastTLSv1_2(ssl)) {
+                byte   encodedSig[MAX_ENCODED_SIG_SZ];
+                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
+
+                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 CYASSL_SHA384
+                        digest   = hash384;
+                        typeH    = SHA384h;
+                        digestSz = SHA384_DIGEST_SIZE;
+                    #endif
+                }
+
+                encSigSz = EncodeSignature(encodedSig, digest, digestSz, typeH);
+
+                if (encSigSz != (word32)ret || XMEMCMP(out, encodedSig,
+                                        min(encSigSz, MAX_ENCODED_SIG_SZ)) != 0)
+                    return VERIFY_SIGN_ERROR;
+            }
+            else { 
+                if (ret != sizeof(hash) || XMEMCMP(out, hash,sizeof(hash)) != 0)
+                    return VERIFY_SIGN_ERROR;
+            }
+        } else
+#endif
+#ifdef HAVE_ECC
+        /* ecdsa */
+        if (sigAlgo == ecc_dsa_sa_algo) {
+            int verify = 0, ret;
+#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
+            if (!ssl->peerEccDsaKeyPresent)
+                return NO_PEER_KEY;
+
+            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 CYASSL_SHA384
+                        digest   = hash384;
+                        digestSz = SHA384_DIGEST_SIZE;
+                    #endif
+                }
+            }
+
+            ret = ecc_verify_hash(signature, sigLen, digest, digestSz,
+                                  &verify, ssl->peerEccDsaKey);
+            if (ret != 0 || verify == 0)
+                return VERIFY_SIGN_ERROR;
+        }
+        else
+#endif /* HAVE_ECC */
+            return ALGO_ID_E;
+
+        ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
+
+        return 0;
+
+    }
+#else  /* HAVE_OPENSSL or HAVE_ECC */
+        return NOT_COMPILED_IN;  /* not supported by build */
+#endif /* HAVE_OPENSSL or HAVE_ECC */
+    }
+
+
+    int SendClientKeyExchange(CYASSL* ssl)
+    {
+        byte   encSecret[MAX_ENCRYPT_SZ];
+        word32 encSz = 0;
+        word32 idx = 0;
+        int    ret = 0;
+
+        switch (ssl->specs.kea) {
+        #ifndef NO_RSA
+            case rsa_kea:
+                RNG_GenerateBlock(ssl->rng, ssl->arrays->preMasterSecret,
+                                  SECRET_LEN);
+                ssl->arrays->preMasterSecret[0] = ssl->chVersion.major;
+                ssl->arrays->preMasterSecret[1] = ssl->chVersion.minor;
+                ssl->arrays->preMasterSz = SECRET_LEN;
+
+                if (ssl->peerRsaKeyPresent == 0)
+                    return NO_PEER_KEY;
+
+                ret = RsaPublicEncrypt(ssl->arrays->preMasterSecret, SECRET_LEN,
+                                 encSecret, sizeof(encSecret), ssl->peerRsaKey,
+                                 ssl->rng);
+                if (ret > 0) {
+                    encSz = ret;
+                    ret = 0;   /* set success to 0 */
+                }
+                break;
+        #endif
+        #ifdef OPENSSL_EXTRA
+            case diffie_hellman_kea:
+                {
+                    buffer  serverP   = ssl->buffers.serverDH_P;
+                    buffer  serverG   = ssl->buffers.serverDH_G;
+                    buffer  serverPub = ssl->buffers.serverDH_Pub;
+                    byte    priv[ENCRYPT_LEN];
+                    word32  privSz = 0;
+                    DhKey   key;
+
+                    if (serverP.buffer == 0 || serverG.buffer == 0 ||
+                                               serverPub.buffer == 0)
+                        return NO_PEER_KEY;
+
+                    InitDhKey(&key);
+                    ret = DhSetKey(&key, serverP.buffer, serverP.length,
+                                   serverG.buffer, serverG.length);
+                    if (ret == 0)
+                        /* for DH, encSecret is Yc, agree is pre-master */
+                        ret = DhGenerateKeyPair(&key, ssl->rng, priv, &privSz,
+                                                encSecret, &encSz);
+                    if (ret == 0)
+                        ret = DhAgree(&key, ssl->arrays->preMasterSecret,
+                                      &ssl->arrays->preMasterSz, priv, privSz,
+                                      serverPub.buffer, serverPub.length);
+                    FreeDhKey(&key);
+                }
+                break;
+        #endif /* OPENSSL_EXTRA */
+        #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)
+                        return PSK_KEY_ERROR;
+                    encSz = (word32)XSTRLEN(ssl->arrays->client_identity);
+                    if (encSz > MAX_PSK_ID_LEN) 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;
+                    XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz);
+                    ssl->arrays->psk_keySz = 0; /* No further need */
+                }
+                break;
+        #endif /* NO_PSK */
+        #ifdef HAVE_NTRU
+            case ntru_kea:
+                {
+                    word32 rc;
+                    word16 cipherLen = sizeof(encSecret);
+                    DRBG_HANDLE drbg;
+                    static uint8_t const cyasslStr[] = {
+                        'C', 'y', 'a', 'S', 'S', 'L', ' ', 'N', 'T', 'R', 'U'
+                    };
+
+                    RNG_GenerateBlock(ssl->rng, ssl->arrays->preMasterSecret,
+                                      SECRET_LEN);
+                    ssl->arrays->preMasterSz = SECRET_LEN;
+
+                    if (ssl->peerNtruKeyPresent == 0)
+                        return NO_PEER_KEY;
+
+                    rc = crypto_drbg_instantiate(MAX_NTRU_BITS, cyasslStr,
+                                                  sizeof(cyasslStr), GetEntropy,
+                                                  &drbg);
+                    if (rc != DRBG_OK)
+                        return NTRU_DRBG_ERROR; 
+
+                    rc = crypto_ntru_encrypt(drbg, ssl->peerNtruKeyLen,
+                                             ssl->peerNtruKey,
+                                             ssl->arrays->preMasterSz,
+                                             ssl->arrays->preMasterSecret,
+                                             &cipherLen, encSecret);
+                    crypto_drbg_uninstantiate(drbg);
+                    if (rc != NTRU_OK)
+                        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 = &myKey;
+                    word32   size = sizeof(encSecret);
+
+                    if (ssl->specs.static_ecdh) {
+                        /* TODO: EccDsa is really fixed Ecc change naming */
+                        if (!ssl->peerEccDsaKeyPresent || !ssl->peerEccDsaKey->dp)
+                            return NO_PEER_KEY;
+                        peerKey = ssl->peerEccDsaKey;
+                    }
+                    else {
+                        if (!ssl->peerEccKeyPresent || !ssl->peerEccKey->dp)
+                            return NO_PEER_KEY;
+                        peerKey = ssl->peerEccKey;
+                    }
+
+                    ecc_init(&myKey);
+                    ret = ecc_make_key(ssl->rng, peerKey->dp->size, &myKey);
+                    if (ret != 0)
+                        return ECC_MAKEKEY_ERROR;
+
+                    /* precede export with 1 byte length */
+                    ret = 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  = ecc_shared_secret(&myKey, peerKey,
+                                                 ssl->arrays->preMasterSecret, &size);
+                        if (ret != 0)
+                            ret = ECC_SHARED_ERROR;
+                    }
+
+                    ssl->arrays->preMasterSz = size;
+                    ecc_free(&myKey);
+                }
+                break;
+        #endif /* HAVE_ECC */
+            default:
+                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)  /* always off */
+                tlsSz = 0;
+
+            sendSz = encSz + tlsSz + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+            idx    = HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls) {
+                    sendSz += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA;
+                    idx    += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_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, encSz + tlsSz, client_key_exchange, ssl);
+
+            if (tlsSz) {
+                c16toa((word16)encSz, &output[idx]);
+                idx += 2;
+            }
+            XMEMCPY(output + idx, encSecret, encSz);
+            /* if add more to output, adjust idx
+            idx += encSz; */
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls) {
+                    if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                        return ret;
+                }
+            #endif
+            HashOutput(ssl, output, sendSz, 0);
+
+            #ifdef CYASSL_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);
+        }
+    
+        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 */
+        XMEMSET(ssl->arrays->preMasterSecret, 0, ssl->arrays->preMasterSz);
+        ssl->arrays->preMasterSz = 0;
+
+        return ret;
+    }
+
+#ifndef NO_CERTS
+    int SendCertificateVerify(CYASSL* ssl)
+    {
+        byte              *output;
+        int                sendSz = 0, length, ret;
+        word32             idx = 0;
+        word32             sigOutSz = 0;
+#ifndef NO_RSA
+        RsaKey             key;
+#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 */
+
+        /* check for available size */
+        if ((ret = CheckAvailableSize(ssl, MAX_CERT_VERIFY_SZ)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.length;
+
+        BuildCertHashes(ssl, &ssl->certHashes);
+
+#ifdef HAVE_ECC
+        ecc_init(&eccKey);
+#endif
+#ifndef NO_RSA
+        InitRsaKey(&key, ssl->heap);
+        ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &key,
+                                  ssl->buffers.key.length);
+        if (ret == 0)
+            sigOutSz = RsaEncryptSize(&key);
+        else 
+#endif
+        {
+    #ifdef HAVE_ECC
+            CYASSL_MSG("Trying ECC client cert, RSA didn't work");
+           
+            idx = 0; 
+            ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &eccKey,
+                                      ssl->buffers.key.length);
+            if (ret == 0) {
+                CYASSL_MSG("Using ECC client cert");
+                usingEcc = 1;
+                sigOutSz = MAX_ENCODED_SIG_SZ; 
+            }
+            else {
+                CYASSL_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->certHashes.md5;
+#else
+            byte*  signBuffer = NULL;
+#endif
+            word32 signSz = FINISHED_SZ;
+            byte   encodedSig[MAX_ENCODED_SIG_SZ];
+            word32 extraSz = 0;  /* tls 1.2 hash/sig */
+
+            (void)encodedSig;
+            (void)signSz;
+            (void)signBuffer;
+
+            #ifdef CYASSL_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;
+#ifndef NO_OLD_TLS
+                /* old tls default */
+                digestSz = SHA_DIGEST_SIZE;
+                digest   = ssl->certHashes.sha;
+#else
+                /* new tls default */
+                digestSz = SHA256_DIGEST_SIZE;
+                digest   = ssl->certHashes.sha256;
+#endif
+
+                if (IsAtLeastTLSv1_2(ssl)) {
+                    if (ssl->suites->hashAlgo == sha_mac) {
+                        #ifndef NO_SHA
+                            digest = ssl->certHashes.sha;
+                            digestSz = SHA_DIGEST_SIZE;
+                        #endif
+                    }
+                    else if (ssl->suites->hashAlgo == sha256_mac) {
+                        #ifndef NO_SHA256
+                            digest = ssl->certHashes.sha256;
+                            digestSz = SHA256_DIGEST_SIZE;
+                        #endif
+                    }
+                    else if (ssl->suites->hashAlgo == sha384_mac) {
+                        #ifdef CYASSL_SHA384
+                            digest = ssl->certHashes.sha384;
+                            digestSz = SHA384_DIGEST_SIZE;
+                        #endif
+                    }
+                }
+
+                ret = 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 {
+                if (IsAtLeastTLSv1_2(ssl)) {
+#ifndef NO_OLD_TLS
+                    byte* digest = ssl->certHashes.sha;
+                    int   digestSz = SHA_DIGEST_SIZE;
+                    int   typeH = SHAh;
+#else
+                    byte* digest = ssl->certHashes.sha256;
+                    int   digestSz = SHA256_DIGEST_SIZE;
+                    int   typeH = SHA256h;
+#endif
+
+                    if (ssl->suites->hashAlgo == sha_mac) {
+                        #ifndef NO_SHA
+                            digest = ssl->certHashes.sha;
+                            typeH    = SHAh;
+                            digestSz = SHA_DIGEST_SIZE;
+                        #endif
+                    }
+                    else if (ssl->suites->hashAlgo == sha256_mac) {
+                        #ifndef NO_SHA256
+                            digest = ssl->certHashes.sha256;
+                            typeH    = SHA256h;
+                            digestSz = SHA256_DIGEST_SIZE;
+                        #endif
+                    }
+                    else if (ssl->suites->hashAlgo == sha384_mac) {
+                        #ifdef CYASSL_SHA384
+                            digest = ssl->certHashes.sha384;
+                            typeH    = SHA384h;
+                            digestSz = SHA384_DIGEST_SIZE;
+                        #endif
+                    }
+
+                    signSz = EncodeSignature(encodedSig, digest,digestSz,typeH);
+                    signBuffer = encodedSig;
+                }
+
+                c16toa((word16)length, verify + extraSz); /* prepend hdr */
+                ret = RsaSSL_Sign(signBuffer, signSz, verify + extraSz +
+                                  VERIFY_HEADER, ENCRYPT_LEN, &key, ssl->rng);
+
+                if (ret > 0)
+                    ret = 0;  /* RSA reset */
+            }
+#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 CYASSL_DTLS
+                    if (ssl->options.dtls) {
+                        sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                        if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                            return ret;
+                    }
+                #endif
+                HashOutput(ssl, output, sendSz, 0);
+            }
+        }
+#ifndef NO_RSA
+        FreeRsaKey(&key);
+#endif
+#ifdef HAVE_ECC
+        ecc_free(&eccKey);
+#endif
+
+        if (ret == 0) {
+            #ifdef CYASSL_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 */
+
+
+#endif /* NO_CYASSL_CLIENT */
+
+
+#ifndef NO_CYASSL_SERVER
+
+    int SendServerHello(CYASSL* ssl)
+    {
+        byte              *output;
+        word32             length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        int                sendSz;
+        int                ret;
+
+        length = VERSION_SZ + RAN_LEN
+               + ID_LEN + ENUM_LEN                 
+               + SUITE_LEN 
+               + ENUM_LEN;
+
+#ifdef HAVE_TLS_EXTENSIONS
+        length += TLSX_GetResponseSize(ssl);
+#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 CYASSL_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)         
+            RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, RAN_LEN);
+        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++] = ID_LEN;
+        if (!ssl->options.resuming)
+            RNG_GenerateBlock(ssl->rng, ssl->arrays->sessionID, ID_LEN);
+        XMEMCPY(output + idx, ssl->arrays->sessionID, ID_LEN);
+        idx += ID_LEN;
+
+            /* 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
+        if (IsTLS(ssl))
+            TLSX_WriteResponse(ssl, output + idx);
+#endif
+            
+        ssl->buffers.outputBuffer.length += sendSz;
+        #ifdef CYASSL_DTLS
+            if (ssl->options.dtls) {
+                if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                    return ret;
+            }
+        #endif
+        HashOutput(ssl, output, sendSz, 0);
+
+        #ifdef CYASSL_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) {
+            case 20:
+                return secp160r1;
+                break;
+            case 24:
+                return secp192r1;
+                break;
+            case 28:
+                return secp224r1;
+                break;
+            case 32:
+                return secp256r1;
+                break;
+            case 48:
+                return secp384r1;
+                break;
+            case 66:
+                return secp521r1;
+                break;
+            default:
+                return 0;
+        }        
+    }
+
+#endif /* HAVE_ECC */
+
+
+    int SendServerKeyExchange(CYASSL* ssl)
+    {
+        int ret = 0;
+        (void)ssl;
+
+        #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 CYASSL_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);
+
+            HashOutput(ssl, output, sendSz, 0);
+
+            #ifdef CYASSL_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 */
+
+        #ifdef HAVE_ECC
+        if (ssl->specs.kea == ecc_diffie_hellman_kea)
+        {
+            byte    *output;
+            word32   length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+            int      sendSz;
+            byte     exportBuf[MAX_EXPORT_ECC_SZ];
+            word32   expSz = sizeof(exportBuf);
+            word32   sigSz;
+            word32   preSigSz, preSigIdx;
+#ifndef NO_RSA
+            RsaKey   rsaKey;
+#endif
+            ecc_key  dsaKey;
+
+            if (ssl->specs.static_ecdh) {
+                CYASSL_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 */
+            CYASSL_MSG("Using ephemeral ECDH");
+            if (ecc_export_x963(ssl->eccTempKey, exportBuf, &expSz) != 0)
+                return ECC_EXPORT_ERROR;
+            length += expSz;
+
+            preSigSz  = length;
+            preSigIdx = idx;
+
+#ifndef NO_RSA
+            InitRsaKey(&rsaKey, ssl->heap);
+#endif
+            ecc_init(&dsaKey);
+
+            /* sig length */
+            length += LENGTH_SZ;
+
+            if (!ssl->buffers.key.buffer) {
+#ifndef NO_RSA
+                FreeRsaKey(&rsaKey);
+#endif
+                ecc_free(&dsaKey);
+                return NO_PRIVATE_KEY;
+            }
+
+#ifndef NO_RSA
+            if (ssl->specs.sig_algo == rsa_sa_algo) {
+                /* rsa sig size */
+                word32 i = 0;
+                ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &i,
+                                          &rsaKey, ssl->buffers.key.length);
+                if (ret != 0) return ret;
+                sigSz = RsaEncryptSize(&rsaKey); 
+            } else 
+#endif
+            if (ssl->specs.sig_algo == ecc_dsa_sa_algo) {
+                /* ecdsa sig size */
+                word32 i = 0;
+                ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &i,
+                                          &dsaKey, ssl->buffers.key.length);
+                if (ret != 0) return ret;
+                sigSz = ecc_sig_size(&dsaKey) + 2;  /* worst case estimate */
+            }
+            else {
+#ifndef NO_RSA
+                FreeRsaKey(&rsaKey);
+#endif
+                ecc_free(&dsaKey);
+                return ALGO_ID_E;  /* unsupported type */
+            }
+            length += sigSz;
+
+            if (IsAtLeastTLSv1_2(ssl))
+                length += HASH_SIG_SIZE;
+
+            sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+            #ifdef CYASSL_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
+                FreeRsaKey(&rsaKey);
+#endif
+                ecc_free(&dsaKey); 
+                return ret;
+            } 
+
+            /* 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(ecc_size(ssl->eccTempKey)); 
+            output[idx++] = (byte)expSz;
+            XMEMCPY(output + idx, exportBuf, expSz);
+            idx += expSz;
+            if (IsAtLeastTLSv1_2(ssl)) {
+                output[idx++] = ssl->suites->hashAlgo;
+                output[idx++] = ssl->suites->sigAlgo;
+            }
+
+            /* Signtaure length will be written later, when we're sure what it
+               is */
+
+            /* do signature */
+            {
+#ifndef NO_OLD_TLS
+                Md5    md5;
+                Sha    sha;
+#endif
+                byte   hash[FINISHED_SZ];
+                #ifndef NO_SHA256
+                    Sha256 sha256;
+                    byte hash256[SHA256_DIGEST_SIZE];
+                #endif
+                #ifdef CYASSL_SHA384
+                    Sha384 sha384;
+                    byte hash384[SHA384_DIGEST_SIZE];
+                #endif
+
+#ifndef NO_OLD_TLS
+                /* md5 */
+                InitMd5(&md5);
+                Md5Update(&md5, ssl->arrays->clientRandom, RAN_LEN);
+                Md5Update(&md5, ssl->arrays->serverRandom, RAN_LEN);
+                Md5Update(&md5, output + preSigIdx, preSigSz);
+                Md5Final(&md5, hash);
+
+                /* sha */
+                InitSha(&sha);
+                ShaUpdate(&sha, ssl->arrays->clientRandom, RAN_LEN);
+                ShaUpdate(&sha, ssl->arrays->serverRandom, RAN_LEN);
+                ShaUpdate(&sha, output + preSigIdx, preSigSz);
+                ShaFinal(&sha, &hash[MD5_DIGEST_SIZE]);
+#endif
+
+                #ifndef NO_SHA256
+                    InitSha256(&sha256);
+                    Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN);
+                    Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN);
+                    Sha256Update(&sha256, output + preSigIdx, preSigSz);
+                    Sha256Final(&sha256, hash256);
+                #endif
+
+                #ifdef CYASSL_SHA384
+                    InitSha384(&sha384);
+                    Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN);
+                    Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN);
+                    Sha384Update(&sha384, output + preSigIdx, preSigSz);
+                    Sha384Final(&sha384, hash384);
+                #endif
+#ifndef NO_RSA
+                if (ssl->suites->sigAlgo == rsa_sa_algo) {
+                    byte*  signBuffer = hash;
+                    word32 signSz    = sizeof(hash);
+                    byte   encodedSig[MAX_ENCODED_SIG_SZ];
+                    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 CYASSL_SHA384
+                                digest   = hash384;
+                                typeH    = SHA384h;
+                                digestSz = SHA384_DIGEST_SIZE;
+                            #endif
+                        }
+
+                        signSz = EncodeSignature(encodedSig, digest, digestSz,
+                                                 typeH);
+                        signBuffer = encodedSig;
+                    }
+                    /* write sig size here */
+                    c16toa((word16)sigSz, output + idx);
+                    idx += LENGTH_SZ;
+
+                    ret = RsaSSL_Sign(signBuffer, signSz, output + idx, sigSz,
+                                      &rsaKey, ssl->rng);
+                    FreeRsaKey(&rsaKey);
+                    ecc_free(&dsaKey);
+                    if (ret > 0)
+                        ret = 0;  /* reset on success */
+                    else
+                        return ret;
+                } 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;
+
+                    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 CYASSL_SHA384
+                                digest   = hash384;
+                                digestSz = SHA384_DIGEST_SIZE;
+                            #endif
+                        }
+                    }
+
+                    ret = ecc_sign_hash(digest, digestSz,
+                              output + LENGTH_SZ + idx, &sz, ssl->rng, &dsaKey);
+#ifndef NO_RSA
+                    FreeRsaKey(&rsaKey);
+#endif
+                    ecc_free(&dsaKey);
+                    if (ret < 0) return ret;
+
+                    /* 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;
+                }
+            }
+
+            AddHeaders(output, length, server_key_exchange, ssl);
+            HashOutput(ssl, output, sendSz, 0);
+
+            #ifdef CYASSL_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 /* HAVE_ECC */
+
+        #ifdef OPENSSL_EXTRA 
+        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;
+            } 
+
+            InitDhKey(&dhKey);
+            ret = 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 = DhGenerateKeyPair(&dhKey, ssl->rng,
+                                         ssl->buffers.serverDH_Priv.buffer,
+                                        &ssl->buffers.serverDH_Priv.length,
+                                         ssl->buffers.serverDH_Pub.buffer,
+                                        &ssl->buffers.serverDH_Pub.length);
+            FreeDhKey(&dhKey);
+
+            InitRsaKey(&rsaKey, ssl->heap);
+            if (ret == 0) {
+                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;
+
+                /* sig length */
+                length += LENGTH_SZ;
+
+                if (!ssl->buffers.key.buffer)
+                    return NO_PRIVATE_KEY;
+
+                ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &i, &rsaKey,
+                                          ssl->buffers.key.length);
+                if (ret == 0) {
+                    sigSz = RsaEncryptSize(&rsaKey);
+                    length += sigSz;
+                }
+            }
+            if (ret != 0) {
+                FreeRsaKey(&rsaKey);
+                return ret;
+            }
+                                         
+            if (IsAtLeastTLSv1_2(ssl))
+                length += HASH_SIG_SIZE;
+
+            sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+            #ifdef CYASSL_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) {
+                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;
+
+            /* Add signature */
+            if (IsAtLeastTLSv1_2(ssl)) {
+                output[idx++] = ssl->suites->hashAlgo;
+                output[idx++] = ssl->suites->sigAlgo; 
+            }
+            /*    size */
+            c16toa((word16)sigSz, output + idx);
+            idx += LENGTH_SZ;
+
+            /* do signature */
+            {
+#ifndef NO_OLD_TLS
+                Md5    md5;
+                Sha    sha;
+#endif
+                byte   hash[FINISHED_SZ];
+                #ifndef NO_SHA256
+                    Sha256 sha256;
+                    byte hash256[SHA256_DIGEST_SIZE];
+                #endif
+                #ifdef CYASSL_SHA384
+                    Sha384 sha384;
+                    byte hash384[SHA384_DIGEST_SIZE];
+                #endif
+
+#ifndef NO_OLD_TLS
+                /* md5 */
+                InitMd5(&md5);
+                Md5Update(&md5, ssl->arrays->clientRandom, RAN_LEN);
+                Md5Update(&md5, ssl->arrays->serverRandom, RAN_LEN);
+                Md5Update(&md5, output + preSigIdx, preSigSz);
+                Md5Final(&md5, hash);
+
+                /* sha */
+                InitSha(&sha);
+                ShaUpdate(&sha, ssl->arrays->clientRandom, RAN_LEN);
+                ShaUpdate(&sha, ssl->arrays->serverRandom, RAN_LEN);
+                ShaUpdate(&sha, output + preSigIdx, preSigSz);
+                ShaFinal(&sha, &hash[MD5_DIGEST_SIZE]);
+#endif
+
+                #ifndef NO_SHA256
+                    InitSha256(&sha256);
+                    Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN);
+                    Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN);
+                    Sha256Update(&sha256, output + preSigIdx, preSigSz);
+                    Sha256Final(&sha256, hash256);
+                #endif
+
+                #ifdef CYASSL_SHA384
+                    InitSha384(&sha384);
+                    Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN);
+                    Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN);
+                    Sha384Update(&sha384, output + preSigIdx, preSigSz);
+                    Sha384Final(&sha384, hash384);
+                #endif
+#ifndef NO_RSA
+                if (ssl->suites->sigAlgo == rsa_sa_algo) {
+                    byte*  signBuffer = hash;
+                    word32 signSz    = sizeof(hash);
+                    byte   encodedSig[MAX_ENCODED_SIG_SZ];
+                    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 CYASSL_SHA384
+                                digest   = hash384;
+                                typeH    = SHA384h;
+                                digestSz = SHA384_DIGEST_SIZE;
+                            #endif
+                        }
+
+                        signSz = EncodeSignature(encodedSig, digest, digestSz,
+                                                 typeH);
+                        signBuffer = encodedSig;
+                    }
+                    ret = RsaSSL_Sign(signBuffer, signSz, output + idx, sigSz,
+                                      &rsaKey, ssl->rng);
+                    FreeRsaKey(&rsaKey);
+                    if (ret <= 0)
+                        return ret;
+                }
+#endif
+            }
+
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls) {
+                    if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                        return ret;
+                }
+            #endif
+            HashOutput(ssl, output, sendSz, 0);
+
+            #ifdef CYASSL_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 /* OPENSSL_EXTRA */
+
+        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)
+    {
+        /* 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_3DES
+        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_3DES
+        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;
+
+        default:
+            CYASSL_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_CBC_SHA256 :
+            if (requirement == REQUIRES_PSK)
+                return 1;
+            break;
+
+        case TLS_PSK_WITH_AES_128_CBC_SHA :
+            if (requirement == REQUIRES_PSK)
+                return 1;
+            break;
+
+        case TLS_PSK_WITH_AES_256_CBC_SHA :
+            if (requirement == REQUIRES_PSK)
+                return 1;
+            break;
+
+        case TLS_PSK_WITH_NULL_SHA256 :
+            if (requirement == REQUIRES_PSK)
+                return 1;
+            break;
+
+        case TLS_PSK_WITH_NULL_SHA :
+            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_CBC_MD5 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+                
+        case TLS_RSA_WITH_HC_128_CBC_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_RABBIT_CBC_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
+
+        default:
+            CYASSL_MSG("Unsupported cipher suite, CipherRequires");
+            return 0;
+        }  /* switch */
+        }  /* if ECC / Normal suites else */
+
+        return 0;
+    }
+
+
+
+
+
+    /* Make sure cert/key are valid for this suite, true on success */
+    static int VerifySuite(CYASSL* ssl, word16 idx)
+    {
+        int  haveRSA = !ssl->options.haveStaticECC;
+        int  havePSK = 0;
+        byte first;
+        byte second;
+
+        CYASSL_ENTER("VerifySuite");
+
+        if (ssl->suites == NULL) {
+            CYASSL_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)) {
+            CYASSL_MSG("Requires RSA");
+            if (haveRSA == 0) {
+                CYASSL_MSG("Don't have RSA");
+                return 0;
+            }
+        }
+
+        if (CipherRequires(first, second, REQUIRES_DHE)) {
+            CYASSL_MSG("Requires DHE");
+            if (ssl->options.haveDH == 0) {
+                CYASSL_MSG("Don't have DHE");
+                return 0;
+            }
+        }
+
+        if (CipherRequires(first, second, REQUIRES_ECC_DSA)) {
+            CYASSL_MSG("Requires ECCDSA");
+            if (ssl->options.haveECDSAsig == 0) {
+                CYASSL_MSG("Don't have ECCDSA");
+                return 0;
+            }
+        }
+
+        if (CipherRequires(first, second, REQUIRES_ECC_STATIC)) {
+            CYASSL_MSG("Requires static ECC");
+            if (ssl->options.haveStaticECC == 0) {
+                CYASSL_MSG("Don't have static ECC");
+                return 0;
+            }
+        }
+
+        if (CipherRequires(first, second, REQUIRES_PSK)) {
+            CYASSL_MSG("Requires PSK");
+            if (havePSK == 0) {
+                CYASSL_MSG("Don't have PSK");
+                return 0;
+            }
+        }
+
+        if (CipherRequires(first, second, REQUIRES_NTRU)) {
+            CYASSL_MSG("Requires NTRU");
+            if (ssl->options.haveNTRU == 0) {
+                CYASSL_MSG("Don't have NTRU");
+                return 0;
+            }
+        }
+
+        if (CipherRequires(first, second, REQUIRES_RSA_SIG)) {
+            CYASSL_MSG("Requires RSA Signature");
+            if (ssl->options.side == SERVER_END && ssl->options.haveECDSAsig == 1) {
+                CYASSL_MSG("Don't have RSA Signature");
+                return 0;
+            }
+        }
+
+        /* ECCDHE is always supported if ECC on */
+
+        return 1;
+    }
+
+
+    static int MatchSuite(CYASSL* ssl, Suites* peerSuites)
+    {
+        word16 i, j;
+
+        CYASSL_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 (VerifySuite(ssl, i)) {
+                        int result;
+                        CYASSL_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 {
+                        CYASSL_MSG("Could not verify suite validity, continue");
+                    }
+                }
+
+        return MATCH_SUITE_ERROR;
+    }
+
+
+    /* process old style client hello, deprecate? */
+    int ProcessOldClientHello(CYASSL* 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;
+        CYASSL_MSG("Got old format client hello");
+#ifdef CYASSL_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
+        Md5Update(&ssl->hashMd5, input + idx, sz);
+#endif
+#ifndef NO_SHA
+        ShaUpdate(&ssl->hashSha, input + idx, sz);
+#endif
+#endif
+#ifndef NO_SHA256
+    if (IsAtLeastTLSv1_2(ssl))
+        Sha256Update(&ssl->hashSha256, input + idx, sz);
+#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) {
+                CYASSL_MSG("Client trying to connect with lesser version"); 
+                return VERSION_ERROR;
+            }
+            if (pv.minor == SSLv3_MINOR) {
+                /* turn off tls */
+                CYASSL_MSG("    downgrading to SSLv3");
+                ssl->options.tls    = 0;
+                ssl->options.tls1_1 = 0;
+                ssl->version.minor  = SSLv3_MINOR;
+            }
+            else if (pv.minor == TLSv1_MINOR) {
+                CYASSL_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) {
+                CYASSL_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;
+
+        /* 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);
+            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; 
+            CYASSL_SESSION* session = GetSession(ssl,ssl->arrays->masterSecret);
+            if (!session) {
+                CYASSL_MSG("Session lookup for resume failed");
+                ssl->options.resuming = 0;
+            } else {
+                if (MatchSuite(ssl, &clSuites) < 0) {
+                    CYASSL_MSG("Unsupported cipher suite, OldClientHello");
+                    return UNSUPPORTED_SUITE;
+                }
+                #ifdef SESSION_CERTS
+                    ssl->session = *session; /* restore session certs. */
+                #endif
+                RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, RAN_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.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+
+                return ret;
+            }
+        }
+
+        return MatchSuite(ssl, &clSuites);
+    }
+
+
+    static int DoClientHello(CYASSL* ssl, const byte* input, word32* inOutIdx,
+                             word32 totalSz, word32 helloSz)
+    {
+        byte b;
+        ProtocolVersion pv;
+        Suites          clSuites;
+        word32 i = *inOutIdx;
+        word32 begin = i;
+
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo);
+#endif
+        /* make sure can read up to session */
+        if (i + sizeof(pv) + RAN_LEN + ENUM_LEN > totalSz)
+            return INCOMPLETE_DATA;
+
+        XMEMCPY(&pv, input + i, sizeof(pv));
+        ssl->chVersion = pv;   /* store */
+        i += (word32)sizeof(pv);
+        if (ssl->version.minor > pv.minor) {
+            byte haveRSA = 0;
+            byte havePSK = 0;
+            if (!ssl->options.downgrade) {
+                CYASSL_MSG("Client trying to connect with lesser version"); 
+                return VERSION_ERROR;
+            }
+            if (pv.minor == SSLv3_MINOR) {
+                /* turn off tls */
+                CYASSL_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+ */
+                CYASSL_MSG("    downgrading to TLSv1");
+                ssl->options.tls1_1 = 0;
+                ssl->version.minor  = TLSv1_MINOR;
+            }
+            else if (pv.minor == TLSv1_1_MINOR) {
+                CYASSL_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) {
+            if (i + ID_LEN > totalSz)
+                return INCOMPLETE_DATA;
+            XMEMCPY(ssl->arrays->sessionID, input + i, ID_LEN);
+            i += b;
+            ssl->options.resuming= 1; /* client wants to resume */
+            CYASSL_MSG("Client wants to resume session");
+        }
+        
+        #ifdef CYASSL_DTLS
+            /* cookie */
+            if (ssl->options.dtls) {
+                b = input[i++];
+                if (b) {
+                    byte cookie[MAX_COOKIE_LEN];
+
+                    if (b > MAX_COOKIE_LEN)
+                        return BUFFER_ERROR;
+                    if (i + b > totalSz)
+                        return INCOMPLETE_DATA;
+                    if (ssl->ctx->CBIOCookie == NULL) {
+                        CYASSL_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
+
+        if (i + LENGTH_SZ > totalSz)
+            return INCOMPLETE_DATA;
+        /* suites */
+        ato16(&input[i], &clSuites.suiteSz);
+        i += 2;
+
+        /* suites and comp len */
+        if (i + clSuites.suiteSz + ENUM_LEN > totalSz)
+            return INCOMPLETE_DATA;
+        if (clSuites.suiteSz > MAX_SUITE_SZ)
+            return BUFFER_ERROR;
+        XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz);
+        i += clSuites.suiteSz;
+        clSuites.hashSigAlgoSz = 0;
+
+        b = input[i++];  /* comp len */
+        if (i + b > totalSz)
+            return INCOMPLETE_DATA;
+
+        if (ssl->options.usingCompression) {
+            int match = 0;
+            while (b--) {
+                byte comp = input[i++];
+                if (comp == ZLIB_COMPRESSION)
+                    match = 1;
+            }
+            if (!match) {
+                CYASSL_MSG("Not matching compression, turning off"); 
+                ssl->options.usingCompression = 0;  /* turn off */
+            }
+        }
+        else
+            i += b;  /* ignore, since we're not on */
+
+        *inOutIdx = i;
+        if ( (i - begin) < helloSz) {
+#ifdef HAVE_TLS_EXTENSIONS
+            if (IsTLS(ssl)) {
+                int ret = 0;
+#else
+            if (IsAtLeastTLSv1_2(ssl)) {
+#endif
+                /* Process the hello extension. Skip unsupported. */
+                word16 totalExtSz;
+
+                ato16(&input[i], &totalExtSz);
+                i += LENGTH_SZ;
+                if (totalExtSz > helloSz + begin - i)
+                    return INCOMPLETE_DATA;
+
+#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;
+                   
+                    ato16(&input[i], &extId);
+                    i += LENGTH_SZ;
+                    ato16(&input[i], &extSz);
+                    i += EXT_ID_SZ;
+                    if (extSz > totalExtSz - LENGTH_SZ - EXT_ID_SZ)
+                        return INCOMPLETE_DATA;
+
+                    if (extId == HELLO_EXT_SIG_ALGO) {
+                        ato16(&input[i], &clSuites.hashSigAlgoSz);
+                        i += LENGTH_SZ;
+                        if (clSuites.hashSigAlgoSz > extSz - LENGTH_SZ)
+                            return INCOMPLETE_DATA;
+
+                        XMEMCPY(clSuites.hashSigAlgo, &input[i],
+                            min(clSuites.hashSigAlgoSz, HELLO_EXT_SIGALGO_MAX));
+                        i += clSuites.hashSigAlgoSz;
+                    }
+                    else
+                        i += extSz;
+
+                    totalExtSz -= LENGTH_SZ + EXT_ID_SZ + 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;            
+            CYASSL_SESSION* session = GetSession(ssl,ssl->arrays->masterSecret);
+            if (!session) {
+                CYASSL_MSG("Session lookup for resume failed");
+                ssl->options.resuming = 0;
+            } else {
+                if (MatchSuite(ssl, &clSuites) < 0) {
+                    CYASSL_MSG("Unsupported cipher suite, ClientHello");
+                    return UNSUPPORTED_SUITE;
+                }
+                #ifdef SESSION_CERTS
+                    ssl->session = *session; /* restore session certs. */
+                #endif
+                RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, RAN_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.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+
+                return ret;
+            }
+        }
+        return MatchSuite(ssl, &clSuites);
+    }
+
+#if !defined(NO_RSA) || defined(HAVE_ECC)
+    static int DoCertificateVerify(CYASSL* ssl, byte* input, word32* inOutsz,
+                                   word32 totalSz)
+    {
+        word16      sz = 0;
+        word32      i = *inOutsz;
+        int         ret = VERIFY_CERT_ERROR;   /* start in error state */
+        byte*       sig;
+        byte        hashAlgo = sha_mac;
+        byte        sigAlgo = anonymous_sa_algo;
+
+        #ifdef CYASSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("CertificateVerify", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("CertificateVerify", &ssl->timeoutInfo);
+        #endif
+        if ( (i + VERIFY_HEADER) > totalSz)
+            return INCOMPLETE_DATA;
+
+        if (IsAtLeastTLSv1_2(ssl)) {
+            hashAlgo = input[i++];
+            sigAlgo = input[i++];
+        }
+        ato16(&input[i], &sz);
+        i += VERIFY_HEADER;
+
+        if ( (i + sz) > totalSz)
+            return INCOMPLETE_DATA;
+
+        if (sz > ENCRYPT_LEN)
+            return BUFFER_ERROR;
+
+        sig = &input[i];
+        *inOutsz = i + sz;
+
+        /* RSA */
+#ifndef NO_RSA
+        if (ssl->peerRsaKeyPresent != 0) {
+            byte* out;
+            int   outLen;
+
+            CYASSL_MSG("Doing RSA peer cert verify");
+
+            outLen = RsaSSL_VerifyInline(sig, sz, &out, ssl->peerRsaKey);
+
+            if (IsAtLeastTLSv1_2(ssl)) {
+                byte   encodedSig[MAX_ENCODED_SIG_SZ];
+                word32 sigSz;
+                byte*  digest = ssl->certHashes.sha;
+                int    typeH = SHAh;
+                int    digestSz = SHA_DIGEST_SIZE;
+
+                if (sigAlgo != rsa_sa_algo) {
+                    CYASSL_MSG("Oops, peer sent RSA key but not in verify");
+                }
+
+                if (hashAlgo == sha256_mac) {
+                    #ifndef NO_SHA256
+                        digest = ssl->certHashes.sha256;
+                        typeH    = SHA256h;
+                        digestSz = SHA256_DIGEST_SIZE;
+                    #endif
+                }
+                else if (hashAlgo == sha384_mac) {
+                    #ifdef CYASSL_SHA384
+                        digest = ssl->certHashes.sha384;
+                        typeH    = SHA384h;
+                        digestSz = SHA384_DIGEST_SIZE;
+                    #endif
+                }
+
+                sigSz = EncodeSignature(encodedSig, digest, digestSz, typeH);
+
+                if (outLen == (int)sigSz && XMEMCMP(out, encodedSig,
+                                           min(sigSz, MAX_ENCODED_SIG_SZ)) == 0)
+                    ret = 0;  /* verified */
+            }
+            else {
+                if (outLen == FINISHED_SZ && XMEMCMP(out,
+                                &ssl->certHashes, FINISHED_SZ) == 0)
+                    ret = 0;  /* verified */
+            }
+        }
+#endif
+#ifdef HAVE_ECC
+        if (ssl->peerEccDsaKeyPresent) {
+            int verify =  0;
+            int err    = -1;
+            byte* digest = ssl->certHashes.sha;
+            word32 digestSz = SHA_DIGEST_SIZE;
+
+            CYASSL_MSG("Doing ECC peer cert verify");
+
+            if (IsAtLeastTLSv1_2(ssl)) {
+                if (sigAlgo != ecc_dsa_sa_algo) {
+                    CYASSL_MSG("Oops, peer sent ECC key but not in verify");
+                }
+                if (hashAlgo == sha256_mac) {
+                    #ifndef NO_SHA256
+                        digest = ssl->certHashes.sha256;
+                        digestSz = SHA256_DIGEST_SIZE;
+                    #endif
+                }
+                else if (hashAlgo == sha384_mac) {
+                    #ifdef CYASSL_SHA384
+                        digest = ssl->certHashes.sha384;
+                        digestSz = SHA384_DIGEST_SIZE;
+                    #endif
+                }
+            }
+            err = ecc_verify_hash(sig, sz, digest, digestSz,
+                                  &verify, ssl->peerEccDsaKey);
+
+            if (err == 0 && verify == 1)
+               ret = 0;   /* verified */ 
+        }
+#endif
+        if (ret == 0)
+            ssl->options.havePeerVerify = 1;
+          
+        return ret;
+    }
+#endif /* !NO_RSA || HAVE_ECC */
+
+    int SendServerHelloDone(CYASSL* ssl)
+    {
+        byte              *output;
+        int                sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        int                ret;
+
+        #ifdef CYASSL_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 CYASSL_DTLS
+            if (ssl->options.dtls) {
+                if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
+                    return 0;
+            }
+        #endif
+        HashOutput(ssl, output, sendSz, 0);
+#ifdef CYASSL_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 CYASSL_DTLS
+    int SendHelloVerifyRequest(CYASSL* 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) {
+            CYASSL_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;
+
+        HashOutput(ssl, output, sendSz, 0);
+#ifdef CYASSL_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(CYASSL* ssl, byte* input,
+                                   word32* inOutIdx, word32 totalSz)
+    {
+        int    ret = 0;
+        word32 length = 0;
+        byte*  out = NULL;
+
+        (void)length; /* shut up compiler warnings */
+        (void)out;
+        (void)input;
+        (void)inOutIdx;
+        (void)totalSz;
+
+        if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) {
+            CYASSL_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) {
+                    CYASSL_MSG("client didn't present peer cert");
+                    return NO_PEER_CERT;
+                }
+        #endif
+
+        #ifdef CYASSL_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*  tmp = 0;
+
+                InitRsaKey(&key, ssl->heap);
+
+                if (ssl->buffers.key.buffer)
+                    ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx,
+                                             &key, ssl->buffers.key.length);
+                else
+                    return NO_PRIVATE_KEY;
+
+                if (ret == 0) {
+                    length = RsaEncryptSize(&key);
+                    ssl->arrays->preMasterSz = SECRET_LEN;
+
+                    if (ssl->options.tls) {
+                        word16 check;
+                        ato16(input + *inOutIdx, &check);
+                        if ((word32)check != length) {
+                            CYASSL_MSG("RSA explicit size doesn't match");
+                            FreeRsaKey(&key);
+                            return RSA_PRIVATE_ERROR;
+                        }
+                        (*inOutIdx) += 2;
+                    }
+                    tmp = input + *inOutIdx;
+                    *inOutIdx += length;
+
+                    if (*inOutIdx > totalSz) {
+                        CYASSL_MSG("RSA message too big");
+                        FreeRsaKey(&key);
+                        return INCOMPLETE_DATA;
+                    }
+
+                    if (RsaPrivateDecryptInline(tmp, length, &out, &key) ==
+                                                                   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;
+                }
+
+                FreeRsaKey(&key);
+            }
+            break;
+        #endif
+        #ifndef NO_PSK
+            case psk_kea:
+            {
+                byte* pms = ssl->arrays->preMasterSecret;
+                word16 ci_sz;
+
+                ato16(&input[*inOutIdx], &ci_sz);
+                *inOutIdx += LENGTH_SZ;
+                if (ci_sz > MAX_PSK_ID_LEN) return CLIENT_ID_ERROR;
+
+                XMEMCPY(ssl->arrays->client_identity, &input[*inOutIdx], ci_sz);
+                *inOutIdx += ci_sz;
+                if (ci_sz < MAX_PSK_ID_LEN)
+                    ssl->arrays->client_identity[ci_sz] = 0;
+                else
+                    ssl->arrays->client_identity[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 += 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;
+
+                ret = MakeMasterSecret(ssl);
+                /* No further need for PSK */
+                XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz);
+                ssl->arrays->psk_keySz = 0;
+            }
+            break;
+        #endif /* NO_PSK */
+        #ifdef HAVE_NTRU
+            case ntru_kea:
+            {
+                word32 rc;
+                word16 cipherLen;
+                word16 plainLen = sizeof(ssl->arrays->preMasterSecret);
+                byte*  tmp;
+
+                if (!ssl->buffers.key.buffer)
+                    return NO_PRIVATE_KEY;
+
+                ato16(&input[*inOutIdx], &cipherLen);
+                *inOutIdx += LENGTH_SZ;
+                if (cipherLen > MAX_NTRU_ENCRYPT_SZ)
+                    return NTRU_KEY_ERROR;
+
+                tmp = input + *inOutIdx;
+                rc = crypto_ntru_decrypt((word16)ssl->buffers.key.length,
+                            ssl->buffers.key.buffer, cipherLen, tmp, &plainLen,
+                            ssl->arrays->preMasterSecret);
+
+                if (rc != NTRU_OK || 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:
+            {
+                word32 size;
+                word32 bLength = input[*inOutIdx];  /* one byte length */
+                *inOutIdx += 1;
+
+                ret = ecc_import_x963(&input[*inOutIdx],
+                                                      bLength, ssl->peerEccKey);
+                if (ret != 0)
+                    return ECC_PEERKEY_ERROR;
+                *inOutIdx += bLength;
+                ssl->peerEccKeyPresent = 1;
+
+                size = sizeof(ssl->arrays->preMasterSecret);
+                if (ssl->specs.static_ecdh) {
+                    ecc_key staticKey;
+                    word32 i = 0;
+
+                    ecc_init(&staticKey);
+                    ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &i,
+                                           &staticKey, ssl->buffers.key.length);
+                    if (ret == 0)
+                        ret = ecc_shared_secret(&staticKey, ssl->peerEccKey,
+                                           ssl->arrays->preMasterSecret, &size);
+                    ecc_free(&staticKey);
+                }
+                else 
+                    ret = ecc_shared_secret(ssl->eccTempKey, ssl->peerEccKey,
+                                        ssl->arrays->preMasterSecret, &size);
+                if (ret != 0)
+                    return ECC_SHARED_ERROR;
+                ssl->arrays->preMasterSz = size;
+                ret = MakeMasterSecret(ssl);
+            }
+            break;
+        #endif /* HAVE_ECC */
+        #ifdef OPENSSL_EXTRA 
+            case diffie_hellman_kea:
+            {
+                byte*  clientPub;
+                word16 clientPubSz;
+                DhKey  dhKey;
+
+                ato16(&input[*inOutIdx], &clientPubSz);
+                *inOutIdx += LENGTH_SZ;
+
+                clientPub = &input[*inOutIdx];
+                *inOutIdx += clientPubSz;
+
+                InitDhKey(&dhKey);
+                ret = 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 = DhAgree(&dhKey, ssl->arrays->preMasterSecret,
+                                         &ssl->arrays->preMasterSz,
+                                          ssl->buffers.serverDH_Priv.buffer,
+                                          ssl->buffers.serverDH_Priv.length,
+                                          clientPub, clientPubSz);
+                FreeDhKey(&dhKey);
+                if (ret == 0)
+                    ret = MakeMasterSecret(ssl);
+            }
+            break;
+        #endif /* OPENSSL_EXTRA */
+            default:
+            {
+                CYASSL_MSG("Bad kea type");
+                ret = BAD_KEA_TYPE_E; 
+            }
+            break;
+        }
+        /* No further need for PMS */
+        XMEMSET(ssl->arrays->preMasterSecret, 0, ssl->arrays->preMasterSz);
+        ssl->arrays->preMasterSz = 0;
+
+        if (ret == 0) {
+            ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+            #ifndef NO_CERTS
+                if (ssl->options.verifyPeer)
+                    BuildCertHashes(ssl, &ssl->certHashes);
+            #endif
+        }
+
+        return ret;
+    }
+
+#endif /* NO_CYASSL_SERVER */
+
+
+#ifdef SINGLE_THREADED
+
+int InitMutex(CyaSSL_Mutex* m)
+{
+    (void)m;
+    return 0;
+}
+
+
+int FreeMutex(CyaSSL_Mutex *m)
+{
+    (void)m;
+    return 0;
+}
+
+
+int LockMutex(CyaSSL_Mutex *m)
+{
+    (void)m;
+    return 0;
+}
+
+
+int UnLockMutex(CyaSSL_Mutex *m)
+{
+    (void)m;
+    return 0;
+}
+
+#else /* MULTI_THREAD */
+
+    #if defined(FREERTOS)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            int iReturn;
+
+            *m = ( CyaSSL_Mutex ) xSemaphoreCreateMutex();
+            if( *m != NULL )
+                iReturn = 0;
+            else
+                iReturn = BAD_MUTEX_ERROR;
+
+            return iReturn;
+        }
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            vSemaphoreDelete( *m );
+            return 0;
+        }
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            /* Assume an infinite block, or should there be zero block? */
+            xSemaphoreTake( *m, portMAX_DELAY );
+            return 0;
+        }
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            xSemaphoreGive( *m );
+            return 0;
+        }
+
+    #elif defined(CYASSL_SAFERTOS)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            vSemaphoreCreateBinary(m->mutexBuffer, m->mutex);
+            if (m->mutex == NULL)
+                return BAD_MUTEX_ERROR;
+
+            return 0;
+        }
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            (void)m;
+            return 0;
+        }
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            /* Assume an infinite block */
+            xSemaphoreTake(m->mutex, portMAX_DELAY);
+            return 0;
+        }
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            xSemaphoreGive(m->mutex);
+            return 0;
+        }
+
+
+    #elif defined(USE_WINDOWS_API)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            InitializeCriticalSection(m);
+            return 0;
+        }
+
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            DeleteCriticalSection(m);
+            return 0;
+        }
+
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            EnterCriticalSection(m);
+            return 0;
+        }
+
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            LeaveCriticalSection(m);
+            return 0;
+        }
+
+    #elif defined(CYASSL_PTHREADS)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            if (pthread_mutex_init(m, 0) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_ERROR;
+        }
+
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            if (pthread_mutex_destroy(m) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_ERROR;
+        }
+
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            if (pthread_mutex_lock(m) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_ERROR;
+        }
+
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            if (pthread_mutex_unlock(m) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_ERROR;
+        }
+
+    #elif defined(THREADX)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            if (tx_mutex_create(m, "CyaSSL Mutex", TX_NO_INHERIT) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_ERROR;
+        }
+
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            if (tx_mutex_delete(m) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_ERROR;
+        }
+
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            if (tx_mutex_get(m, TX_WAIT_FOREVER) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_ERROR;
+        }
+
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            if (tx_mutex_put(m) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_ERROR;
+        }
+
+    #elif defined(MICRIUM)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_MutexCreate(m) == 0)
+                    return 0;
+                else
+                    return BAD_MUTEX_ERROR;
+            #else
+                return 0;
+            #endif
+        }
+
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_FreeMutex(m) == 0)
+                    return 0;
+                else
+                    return BAD_MUTEX_ERROR;
+            #else
+                return 0;
+            #endif
+        }
+
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_LockMutex(m) == 0)
+                    return 0;
+                else
+                    return BAD_MUTEX_ERROR;
+            #else
+                return 0;
+            #endif
+        }
+
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_UnLockMutex(m) == 0)
+                    return 0;
+                else
+                    return BAD_MUTEX_ERROR;
+            #else
+                return 0;
+            #endif
+
+        }
+
+    #elif defined(EBSNET)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            if (rtp_sig_mutex_alloc(m, "CyaSSL Mutex") == -1)
+                return BAD_MUTEX_ERROR;
+            else
+                return 0;
+        }
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            rtp_sig_mutex_free(*m);
+            return 0;
+        }
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            if (rtp_sig_mutex_claim_timed(*m, RTIP_INF) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_ERROR;
+        }
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            rtp_sig_mutex_release(*m);
+            return 0;
+        }
+
+    #elif defined(FREESCALE_MQX)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            if (_mutex_init(m, NULL) == MQX_EOK)
+                return 0;
+            else
+                return BAD_MUTEX_ERROR;
+        }
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            if (_mutex_destroy(m) == MQX_EOK)
+                return 0;
+            else
+                return BAD_MUTEX_ERROR;
+        }
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            if (_mutex_lock(m) == MQX_EOK)
+                return 0;
+            else
+                return BAD_MUTEX_ERROR;
+        }
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            if (_mutex_unlock(m) == MQX_EOK)
+                return 0;
+            else
+                return BAD_MUTEX_ERROR;
+        }
+        
+    #elif defined(CYASSL_MDK_ARM)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            os_mut_init (m); 
+            return 0;
+        }
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            return(0) ;
+        }
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            os_mut_wait (m, 0xffff);
+            return(0) ;
+        }
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            os_mut_release (m);
+            return 0;
+        }
+    #endif /* USE_WINDOWS_API */
+#endif /* SINGLE_THREADED */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/io.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,849 @@
+/* io.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include "bsd_socket.h"
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef _WIN32_WCE
+    /* On WinCE winsock2.h must be included before windows.h for socket stuff */
+    #include <winsock2.h>
+#endif
+
+#include <cyassl/internal.h>
+#include <cyassl/ctaoerror.h>
+
+/* if user writes own I/O callbacks they can define CYASSL_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 CYASSL_USER_IO
+
+#ifdef HAVE_LIBZ
+    #include "zlib.h"
+#endif
+
+#ifndef USE_WINDOWS_API
+    #ifdef CYASSL_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(CYASSL_MDK_ARM)
+        #include <rtl.h>
+        #undef RNG
+        #include "CYASSL_MDK_ARM.h"
+        #undef RNG
+        #define RNG CyaSSL_RNG 
+        /* for avoiding name conflict in "stm32f2xx.h" */
+        static int errno;
+    #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))
+            #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
+#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(CYASSL_MDK_ARM)
+    #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
+#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(CYASSL_LWIP)
+    #define SEND_FUNCTION lwip_send
+    #define RECV_FUNCTION lwip_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(CYASSL *ssl, char *buf, int sz, void *ctx)
+{
+    int recvd;
+    int err;
+    int sd = *(int*)ctx;
+
+#ifdef CYASSL_DTLS
+    {
+        int dtls_timeout = CyaSSL_dtls_get_current_timeout(ssl);
+        if (CyaSSL_dtls(ssl)
+                     && !CyaSSL_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) {
+                CYASSL_MSG("setsockopt rcvtimeo failed");
+            }
+        }
+    }
+#endif
+
+    recvd = (int)RECV_FUNCTION(sd, buf, sz, ssl->rflags);
+
+    recvd = TranslateReturnCode(recvd, sd);
+
+    if (recvd < 0) {
+        err = LastError();
+        CYASSL_MSG("Embed Receive error");
+
+        if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
+            if (!CyaSSL_dtls(ssl) || CyaSSL_get_using_nonblock(ssl)) {
+                CYASSL_MSG("    Would block");
+                return CYASSL_CBIO_ERR_WANT_READ;
+            }
+            else {
+                CYASSL_MSG("    Socket timeout");
+                return CYASSL_CBIO_ERR_TIMEOUT;
+            }
+        }
+        else if (err == SOCKET_ECONNRESET) {
+            CYASSL_MSG("    Connection reset");
+            return CYASSL_CBIO_ERR_CONN_RST;
+        }
+        else if (err == SOCKET_EINTR) {
+            CYASSL_MSG("    Socket interrupted");
+            return CYASSL_CBIO_ERR_ISR;
+        }
+        else if (err == SOCKET_ECONNREFUSED) {
+            CYASSL_MSG("    Connection refused");
+            return CYASSL_CBIO_ERR_WANT_READ;
+        }
+        else if (err == SOCKET_ECONNABORTED) {
+            CYASSL_MSG("    Connection aborted");
+            return CYASSL_CBIO_ERR_CONN_CLOSE;
+        }
+        else {
+            CYASSL_MSG("    General error");
+            return CYASSL_CBIO_ERR_GENERAL;
+        }
+    }
+    else if (recvd == 0) {
+        CYASSL_MSG("Embed receive connection closed");
+        return CYASSL_CBIO_ERR_CONN_CLOSE;
+    }
+
+    return recvd;
+}
+
+/* The send embedded callback
+ *  return : nb bytes sent, or error
+ */
+int EmbedSend(CYASSL* 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();
+        CYASSL_MSG("Embed Send error");
+
+        if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
+            CYASSL_MSG("    Would Block");
+            return CYASSL_CBIO_ERR_WANT_WRITE;
+        }
+        else if (err == SOCKET_ECONNRESET) {
+            CYASSL_MSG("    Connection reset");
+            return CYASSL_CBIO_ERR_CONN_RST;
+        }
+        else if (err == SOCKET_EINTR) {
+            CYASSL_MSG("    Socket interrupted");
+            return CYASSL_CBIO_ERR_ISR;
+        }
+        else if (err == SOCKET_EPIPE) {
+            CYASSL_MSG("    Socket EPIPE");
+            return CYASSL_CBIO_ERR_CONN_CLOSE;
+        }
+        else {
+            CYASSL_MSG("    General error");
+            return CYASSL_CBIO_ERR_GENERAL;
+        }
+    }
+ 
+    return sent;
+}
+
+
+#ifdef CYASSL_DTLS
+
+#include <cyassl/ctaocrypt/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(CYASSL *ssl, char *buf, int sz, void *ctx)
+{
+    CYASSL_DTLS_CTX* dtlsCtx = (CYASSL_DTLS_CTX*)ctx;
+    int recvd;
+    int err;
+    int sd = dtlsCtx->fd;
+    int dtls_timeout = CyaSSL_dtls_get_current_timeout(ssl);
+    struct sockaddr_in peer;
+    XSOCKLENT peerSz = sizeof(peer);
+
+    CYASSL_ENTER("EmbedReceiveFrom()");
+
+    if (!CyaSSL_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) {
+                CYASSL_MSG("setsockopt rcvtimeo failed");
+        }
+    }
+    
+    recvd = (int)RECVFROM_FUNCTION(sd, buf, sz, ssl->rflags,
+                                  (struct sockaddr*)&peer, &peerSz);
+    printf("Received %d bytes",recvd); 
+    recvd = TranslateReturnCode(recvd, sd);
+
+    if (recvd < 0) {
+        err = LastError();
+        CYASSL_MSG("Embed Receive From error");
+
+        if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
+            if (CyaSSL_get_using_nonblock(ssl)) {
+                CYASSL_MSG("    Would block");
+                return CYASSL_CBIO_ERR_WANT_READ;
+            }
+            else {
+                CYASSL_MSG("    Socket timeout");
+                return CYASSL_CBIO_ERR_TIMEOUT;
+            }
+        }
+        else if (err == SOCKET_ECONNRESET) {
+            CYASSL_MSG("    Connection reset");
+            return CYASSL_CBIO_ERR_CONN_RST;
+        }
+        else if (err == SOCKET_EINTR) {
+            CYASSL_MSG("    Socket interrupted");
+            return CYASSL_CBIO_ERR_ISR;
+        }
+        else if (err == SOCKET_ECONNREFUSED) {
+            CYASSL_MSG("    Connection refused");
+            return CYASSL_CBIO_ERR_WANT_READ;
+        }
+        else {
+            CYASSL_MSG("    General error");
+            return CYASSL_CBIO_ERR_GENERAL;
+        }
+    }
+    else {
+        if (dtlsCtx->peer.sz > 0
+                && peerSz != (XSOCKLENT)dtlsCtx->peer.sz
+                && memcmp(&peer, dtlsCtx->peer.sa, peerSz) != 0) {
+            CYASSL_MSG("    Ignored packet from invalid peer");
+            return CYASSL_CBIO_ERR_WANT_READ;
+        }
+    }
+
+    return recvd;
+}
+
+
+/* The send embedded callback
+ *  return : nb bytes sent, or error
+ */
+int EmbedSendTo(CYASSL* ssl, char *buf, int sz, void *ctx)
+{
+    CYASSL_DTLS_CTX* dtlsCtx = (CYASSL_DTLS_CTX*)ctx;
+    int sd = dtlsCtx->fd;
+    int sent;
+    int len = sz;
+    int err;
+
+    CYASSL_ENTER("EmbedSendTo()");
+
+    sent = (int)SENDTO_FUNCTION(sd, &buf[sz - len], len, ssl->wflags,
+                                dtlsCtx->peer.sa, dtlsCtx->peer.sz);
+    if (sent < 0) {
+        err = LastError();
+        CYASSL_MSG("Embed Send To error");
+
+        if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
+            CYASSL_MSG("    Would Block");
+            return CYASSL_CBIO_ERR_WANT_WRITE;
+        }
+        else if (err == SOCKET_ECONNRESET) {
+            CYASSL_MSG("    Connection reset");
+            return CYASSL_CBIO_ERR_CONN_RST;
+        }
+        else if (err == SOCKET_EINTR) {
+            CYASSL_MSG("    Socket interrupted");
+            return CYASSL_CBIO_ERR_ISR;
+        }
+        else if (err == SOCKET_EPIPE) {
+            CYASSL_MSG("    Socket EPIPE");
+            return CYASSL_CBIO_ERR_CONN_CLOSE;
+        }
+        else {
+            CYASSL_MSG("    General error");
+            return CYASSL_CBIO_ERR_GENERAL;
+        }
+    }
+ 
+    return sent;
+}
+
+
+/* The DTLS Generate Cookie callback
+ *  return : number of bytes copied into buf, or error
+ */
+int EmbedGenerateCookie(CYASSL* ssl, byte *buf, int sz, void *ctx)
+{
+    int sd = ssl->wfd;
+    struct sockaddr_in peer;
+    XSOCKLENT peerSz = sizeof(peer);
+    byte cookieSrc[sizeof(struct in_addr) + sizeof(int)];
+    int cookieSrcSz = 0;
+    Sha sha;
+
+    (void)ctx;
+
+    if (getpeername(sd, (struct sockaddr*)&peer, &peerSz) != 0) {
+        CYASSL_MSG("getpeername failed in EmbedGenerateCookie");
+        return GEN_COOKIE_E;
+    }
+    
+    if (peer.sin_family == AF_INET) {
+        struct sockaddr_in *s = (struct sockaddr_in*)&peer;
+
+        cookieSrcSz = sizeof(struct in_addr) + sizeof(s->sin_port);
+        XMEMCPY(cookieSrc, &s->sin_port, sizeof(s->sin_port));
+        XMEMCPY(cookieSrc + sizeof(s->sin_port),
+                                     &s->sin_addr, sizeof(struct in_addr));
+    }
+
+    InitSha(&sha);
+    ShaUpdate(&sha, cookieSrc, cookieSrcSz);
+
+    if (sz < SHA_DIGEST_SIZE) {
+        byte digest[SHA_DIGEST_SIZE];
+        ShaFinal(&sha, digest);
+        XMEMCPY(buf, digest, sz);
+        return sz;
+    }
+
+    ShaFinal(&sha, buf);
+
+    return SHA_DIGEST_SIZE;
+}
+
+#endif /* CYASSL_DTLS */
+
+#ifdef HAVE_OCSP
+
+#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
+
+
+static INLINE int tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port)
+{
+    SOCKADDR_IN_T addr;
+    const char* host = ip;
+
+    /* peer could be in human readable form */
+    if (ip != INADDR_ANY && isalpha(ip[0])) {
+        struct hostent* entry = gethostbyname(ip);
+
+        if (entry) {
+            struct sockaddr_in tmp;
+            XMEMSET(&tmp, 0, sizeof(struct sockaddr_in));
+            XMEMCPY(&tmp.sin_addr.s_addr, entry->h_addr_list[0],
+                   entry->h_length);
+            host = inet_ntoa(tmp.sin_addr);
+        }
+        else {
+            CYASSL_MSG("no addr entry for OCSP responder");
+            return -1;
+        }
+    }
+
+    *sockfd = socket(AF_INET_V, SOCK_STREAM, 0);
+    if (*sockfd < 0) {
+        CYASSL_MSG("bad socket fd, out of fds?");
+        return -1;
+    }
+    XMEMSET(&addr, 0, sizeof(SOCKADDR_IN_T));
+
+    addr.sin_family = AF_INET_V;
+    addr.sin_port = htons(port);
+    if (host == INADDR_ANY)
+        addr.sin_addr.s_addr = INADDR_ANY;
+    else
+        addr.sin_addr.s_addr = inet_addr(host);
+
+    if (connect(*sockfd, (const struct sockaddr*)&addr, sizeof(addr)) != 0) {
+        CYASSL_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)
+{
+    return snprintf((char*)buf, bufSize,
+        "POST %s HTTP/1.1\r\n"
+        "Host: %s\r\n"
+        "Content-Length: %d\r\n"
+        "Content-Type: application/ocsp-request\r\n"
+        "\r\n", 
+        path, domainName, ocspReqSz);
+}
+
+
+static int decode_http_response(byte* httpBuf, int httpBufSz, byte** dst)
+{
+    int idx = 0;
+    int stop = 0;
+    int len = 0;
+    byte* contentType = NULL;
+    byte* contentLength = NULL;
+    char* buf = (char*)httpBuf; /* kludge so I'm not constantly casting */
+
+    if (XSTRNCASECMP(buf, "HTTP/1", 6) != 0)
+        return 0;
+    
+    idx = 9; /* sets to the first byte after "HTTP/1.X ", which should be the
+              * HTTP result code */
+
+     if (XSTRNCASECMP(&buf[idx], "200 OK", 6) != 0)
+        return 0;
+    
+    idx += 8;
+
+    while (idx < httpBufSz && !stop) {
+        if (buf[idx] == '\r' && buf[idx+1] == '\n') {
+            stop = 1;
+            idx += 2;
+        }
+        else {
+            if (contentType == NULL &&
+                           XSTRNCASECMP(&buf[idx], "Content-Type:", 13) == 0) {
+                idx += 13;
+                if (buf[idx] == ' ') idx++;
+                if (XSTRNCASECMP(&buf[idx],
+                                       "application/ocsp-response", 25) != 0) {
+                    return 0;
+                }
+                idx += 27;
+            }
+            else if (contentLength == NULL &&
+                         XSTRNCASECMP(&buf[idx], "Content-Length:", 15) == 0) {
+                idx += 15;
+                if (buf[idx] == ' ') idx++;
+                while (buf[idx] >= '0' && buf[idx] <= '9' && idx < httpBufSz) {
+                    len = (len * 10) + (buf[idx] - '0');
+                    idx++;
+                }
+                idx += 2; /* skip the crlf */
+            }
+            else {
+                /* Advance idx past the next \r\n */
+                char* end = XSTRSTR(&buf[idx], "\r\n");
+                idx = (int)(end - buf + 2);
+            }
+        }
+    }
+    
+    if (len > 0) {
+        *dst = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_IN_BUFFER);
+        XMEMCPY(*dst, httpBuf + idx, len);
+    }
+
+    return len;
+}
+
+
+static int decode_url(const char* url, int urlSz,
+    char* outName, char* outPath, int* 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/" */
+            if (XSTRNCMP(url, "http://", 7) == 0) {
+                cur = 7;
+            } else cur = 0;
+    
+            i = 0;
+            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;
+                i = 0;
+                cur++;
+                while (cur < urlSz && url[cur] != 0 && url[cur] != '/' &&
+                        i < 6) {
+                    port[i++] = url[cur++];
+                }
+    
+                *outPort = 0;
+                for (j = 0; j < i; j++) {
+                    if (port[j] < '0' || port[j] > '9') return -1;
+                    *outPort = (*outPort * 10) + (port[j] - '0');
+                }
+            }
+            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;
+}
+
+
+#define SCRATCH_BUFFER_SIZE 2048
+
+int EmbedOcspLookup(void* ctx, const char* url, int urlSz,
+                        byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf)
+{
+    char domainName[80], path[80];
+    int port, httpBufSz, sfd = -1;
+    int ocspRespSz = 0;
+    byte* httpBuf = NULL;
+
+    (void)ctx;
+
+    if (ocspReqBuf == NULL || ocspReqSz == 0) {
+        CYASSL_MSG("OCSP request is required for lookup");
+        return -1;
+    }
+
+    if (ocspRespBuf == NULL) {
+        CYASSL_MSG("Cannot save OCSP response");
+        return -1;
+    }
+
+    if (decode_url(url, urlSz, domainName, path, &port) < 0) {
+        CYASSL_MSG("Unable to decode OCSP URL");
+        return -1;
+    }
+    
+    httpBufSz = SCRATCH_BUFFER_SIZE;
+    httpBuf = (byte*)XMALLOC(httpBufSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
+
+    if (httpBuf == NULL) {
+        CYASSL_MSG("Unable to create OCSP response buffer");
+        return -1;
+    }
+    *ocspRespBuf = httpBuf;
+
+    httpBufSz = build_http_request(domainName, path, ocspReqSz,
+                                                        httpBuf, httpBufSz);
+
+    if ((tcp_connect(&sfd, domainName, port) == 0) && (sfd > 0)) {
+        int written;
+        written = (int)send(sfd, httpBuf, httpBufSz, 0);
+        if (written == httpBufSz) {
+            written = (int)send(sfd, ocspReqBuf, ocspReqSz, 0);
+            if (written == ocspReqSz) {
+                httpBufSz = (int)recv(sfd, httpBuf, SCRATCH_BUFFER_SIZE, 0);
+                if (httpBufSz > 0) {
+                    ocspRespSz = decode_http_response(httpBuf, httpBufSz,
+                        ocspRespBuf);
+                }
+            }
+        }
+        close(sfd);
+        if (ocspRespSz == 0) {
+            CYASSL_MSG("OCSP response was not OK, no OCSP response");
+            return -1;
+        }
+    } else {
+        CYASSL_MSG("OCSP Responder connection failed");
+        close(sfd);
+        return -1;
+    }
+
+    return ocspRespSz;
+}
+
+
+void EmbedOcspRespFree(void* ctx, byte *resp)
+{
+    (void)ctx;
+
+    if (resp)
+        XFREE(resp, NULL, DYNAMIC_TYPE_IN_BUFFER);
+}
+
+
+#endif
+
+#endif /* CYASSL_USER_IO */
+
+CYASSL_API void CyaSSL_SetIORecv(CYASSL_CTX *ctx, CallbackIORecv CBIORecv)
+{
+    ctx->CBIORecv = CBIORecv;
+}
+
+
+CYASSL_API void CyaSSL_SetIOSend(CYASSL_CTX *ctx, CallbackIOSend CBIOSend)
+{
+    ctx->CBIOSend = CBIOSend;
+}
+
+
+CYASSL_API void CyaSSL_SetIOReadCtx(CYASSL* ssl, void *rctx)
+{
+	ssl->IOCB_ReadCtx = rctx;
+}
+
+
+CYASSL_API void CyaSSL_SetIOWriteCtx(CYASSL* ssl, void *wctx)
+{
+	ssl->IOCB_WriteCtx = wctx;
+}
+
+
+CYASSL_API void CyaSSL_SetIOReadFlags(CYASSL* ssl, int flags)
+{
+    ssl->rflags = flags; 
+}
+
+
+CYASSL_API void CyaSSL_SetIOWriteFlags(CYASSL* ssl, int flags)
+{
+    ssl->wflags = flags;
+}
+
+
+#ifdef CYASSL_DTLS
+
+CYASSL_API void CyaSSL_CTX_SetGenCookie(CYASSL_CTX* ctx, CallbackGenCookie cb)
+{
+    ctx->CBIOCookie = cb;
+}
+
+
+CYASSL_API void CyaSSL_SetCookieCtx(CYASSL* ssl, void *ctx)
+{
+	ssl->IOCB_CookieCtx = ctx;
+}
+
+#endif /* CYASSL_DTLS */
+
+
+#ifdef HAVE_OCSP
+
+CYASSL_API void CyaSSL_SetIOOcsp(CYASSL_CTX* ctx, CallbackIOOcsp cb)
+{
+    ctx->ocsp.CBIOOcsp = cb;
+}
+
+CYASSL_API void CyaSSL_SetIOOcspRespFree(CYASSL_CTX* ctx,
+                                                     CallbackIOOcspRespFree cb)
+{
+    ctx->ocsp.CBIOOcspRespFree = cb;
+}
+
+CYASSL_API void CyaSSL_SetIOOcspCtx(CYASSL_CTX* ctx, void *octx)
+{
+    ctx->ocsp.IOCB_OcspCtx = octx;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/keys.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,1908 @@
+/* keys.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#include <cyassl/internal.h>
+#include <cyassl/ctaoerror.h>
+#ifdef SHOW_SECRETS
+    #ifdef FREESCALE_MQX
+        #include <fio.h>
+    #else
+        #include <stdio.h>
+    #endif
+#endif
+
+
+int SetCipherSpecs(CYASSL* ssl)
+{
+    /* 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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
+
+    default:
+        CYASSL_MSG("Unsupported cipher suite, SetCipherSpecs ECC");
+        return UNSUPPORTED_SUITE;
+    }   /* switch */
+    }   /* if     */
+    if (ssl->options.cipherSuite0 != ECC_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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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_CBC_SHA256
+    case TLS_PSK_WITH_AES_128_CBC_SHA256 :
+        ssl->specs.bulk_cipher_algorithm = 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_128_CBC_SHA
+    case TLS_PSK_WITH_AES_128_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = 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 = 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 = 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_SHA
+    case TLS_PSK_WITH_NULL_SHA :
+        ssl->specs.bulk_cipher_algorithm = 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_RSA_WITH_AES_128_CBC_SHA256
+    case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 :
+        ssl->specs.bulk_cipher_algorithm = 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 = 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 = 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 = 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_CBC_MD5
+    case TLS_RSA_WITH_HC_128_CBC_MD5 :
+        ssl->specs.bulk_cipher_algorithm = 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_CBC_SHA
+        case TLS_RSA_WITH_HC_128_CBC_SHA :
+            ssl->specs.bulk_cipher_algorithm = 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_RABBIT_CBC_SHA
+    case TLS_RSA_WITH_RABBIT_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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
+
+    default:
+        CYASSL_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 CYASSL_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:
+        CYASSL_MSG("Set Prefix error, bad input");
+        return 0; 
+    }
+    return 1;
+}
+#endif
+
+
+static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs,
+                   byte side, void* heap, int devId)
+{
+#ifdef BUILD_ARC4
+    word32 sz = specs->key_size;
+    if (specs->bulk_cipher_algorithm == rc4) {
+        if (enc->arc4 == NULL)
+            enc->arc4 = (Arc4*)XMALLOC(sizeof(Arc4), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc->arc4 == NULL)
+            return MEMORY_E;
+        if (dec->arc4 == NULL)
+            dec->arc4 = (Arc4*)XMALLOC(sizeof(Arc4), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec->arc4 == NULL)
+            return MEMORY_E;
+#ifdef HAVE_CAVIUM
+        if (devId != NO_CAVIUM_DEVICE) {
+            if (Arc4InitCavium(enc->arc4, devId) != 0) {
+                CYASSL_MSG("Arc4InitCavium failed in SetKeys");
+                return CAVIUM_INIT_E;
+            }
+            if (Arc4InitCavium(dec->arc4, devId) != 0) {
+                CYASSL_MSG("Arc4InitCavium failed in SetKeys");
+                return CAVIUM_INIT_E;
+            }
+        }
+#endif
+        if (side == CLIENT_END) {
+            Arc4SetKey(enc->arc4, keys->client_write_key, sz);
+            Arc4SetKey(dec->arc4, keys->server_write_key, sz);
+        }
+        else {
+            Arc4SetKey(enc->arc4, keys->server_write_key, sz);
+            Arc4SetKey(dec->arc4, keys->client_write_key, sz);
+        }
+        enc->setup = 1;
+        dec->setup = 1;
+    }
+#endif
+    
+#ifdef HAVE_HC128
+    if (specs->bulk_cipher_algorithm == hc128) {
+        int hcRet;
+        if (enc->hc128 == NULL)
+            enc->hc128 =
+                      (HC128*)XMALLOC(sizeof(HC128), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc->hc128 == NULL)
+            return MEMORY_E;
+        if (dec->hc128 == NULL)
+            dec->hc128 =
+                      (HC128*)XMALLOC(sizeof(HC128), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec->hc128 == NULL)
+            return MEMORY_E;
+        if (side == CLIENT_END) {
+            hcRet = Hc128_SetKey(enc->hc128, keys->client_write_key,
+                                 keys->client_write_IV);
+            if (hcRet != 0) return hcRet;
+            hcRet = Hc128_SetKey(dec->hc128, keys->server_write_key,
+                                  keys->server_write_IV);
+            if (hcRet != 0) return hcRet;
+        }
+        else {
+            hcRet = Hc128_SetKey(enc->hc128, keys->server_write_key,
+                                  keys->server_write_IV);
+            if (hcRet != 0) return hcRet;
+            hcRet = Hc128_SetKey(dec->hc128, keys->client_write_key,
+                                  keys->client_write_IV);
+            if (hcRet != 0) return hcRet;
+        }
+        enc->setup = 1;
+        dec->setup = 1;
+    }
+#endif
+    
+#ifdef BUILD_RABBIT
+    if (specs->bulk_cipher_algorithm == rabbit) {
+        int rabRet;
+        if (enc->rabbit == NULL)
+            enc->rabbit =
+                    (Rabbit*)XMALLOC(sizeof(Rabbit), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc->rabbit == NULL)
+            return MEMORY_E;
+        if (dec->rabbit == NULL)
+            dec->rabbit =
+                    (Rabbit*)XMALLOC(sizeof(Rabbit), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec->rabbit == NULL)
+            return MEMORY_E;
+        if (side == CLIENT_END) {
+            rabRet = RabbitSetKey(enc->rabbit, keys->client_write_key,
+                                  keys->client_write_IV);
+            if (rabRet != 0) return rabRet;
+            rabRet = RabbitSetKey(dec->rabbit, keys->server_write_key,
+                                  keys->server_write_IV);
+            if (rabRet != 0) return rabRet;
+        }
+        else {
+            rabRet = RabbitSetKey(enc->rabbit, keys->server_write_key,
+                                           keys->server_write_IV);
+            if (rabRet != 0) return rabRet;
+            rabRet = RabbitSetKey(dec->rabbit, keys->client_write_key,
+                                           keys->client_write_IV);
+            if (rabRet != 0) return rabRet;
+        }
+        enc->setup = 1;
+        dec->setup = 1;
+    }
+#endif
+    
+#ifdef BUILD_DES3
+    if (specs->bulk_cipher_algorithm == triple_des) {
+        if (enc->des3 == NULL)
+            enc->des3 = (Des3*)XMALLOC(sizeof(Des3), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc->des3 == NULL)
+            return MEMORY_E;
+        if (dec->des3 == NULL)
+            dec->des3 = (Des3*)XMALLOC(sizeof(Des3), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec->des3 == NULL)
+            return MEMORY_E;
+#ifdef HAVE_CAVIUM
+        if (devId != NO_CAVIUM_DEVICE) {
+            if (Des3_InitCavium(enc->des3, devId) != 0) {
+                CYASSL_MSG("Des3_InitCavium failed in SetKeys");
+                return CAVIUM_INIT_E;
+            }
+            if (Des3_InitCavium(dec->des3, devId) != 0) {
+                CYASSL_MSG("Des3_InitCavium failed in SetKeys");
+                return CAVIUM_INIT_E;
+            }
+        }
+#endif
+        if (side == CLIENT_END) {
+            Des3_SetKey(enc->des3, keys->client_write_key,
+                        keys->client_write_IV, DES_ENCRYPTION);
+            Des3_SetKey(dec->des3, keys->server_write_key,
+                        keys->server_write_IV, DES_DECRYPTION);
+        }
+        else {
+            Des3_SetKey(enc->des3, keys->server_write_key,
+                        keys->server_write_IV, DES_ENCRYPTION);
+            Des3_SetKey(dec->des3, keys->client_write_key,
+                keys->client_write_IV, DES_DECRYPTION);
+        }
+        enc->setup = 1;
+        dec->setup = 1;
+    }
+#endif
+
+#ifdef BUILD_AES
+    if (specs->bulk_cipher_algorithm == aes) {
+        if (enc->aes == NULL)
+            enc->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc->aes == NULL)
+            return MEMORY_E;
+        if (dec->aes == NULL)
+            dec->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec->aes == NULL)
+            return MEMORY_E;
+#ifdef HAVE_CAVIUM
+        if (devId != NO_CAVIUM_DEVICE) {
+            if (AesInitCavium(enc->aes, devId) != 0) {
+                CYASSL_MSG("AesInitCavium failed in SetKeys");
+                return CAVIUM_INIT_E;
+            }
+            if (AesInitCavium(dec->aes, devId) != 0) {
+                CYASSL_MSG("AesInitCavium failed in SetKeys");
+                return CAVIUM_INIT_E;
+            }
+        }
+#endif
+        if (side == CLIENT_END) {
+            AesSetKey(enc->aes, keys->client_write_key,
+                      specs->key_size, keys->client_write_IV,
+                      AES_ENCRYPTION);
+            AesSetKey(dec->aes, keys->server_write_key,
+                      specs->key_size, keys->server_write_IV,
+                      AES_DECRYPTION);
+        }
+        else {
+            AesSetKey(enc->aes, keys->server_write_key,
+                      specs->key_size, keys->server_write_IV,
+                      AES_ENCRYPTION);
+            AesSetKey(dec->aes, keys->client_write_key,
+                      specs->key_size, keys->client_write_IV,
+                      AES_DECRYPTION);
+        }
+        enc->setup = 1;
+        dec->setup = 1;
+    }
+#endif
+
+#ifdef BUILD_AESGCM
+    if (specs->bulk_cipher_algorithm == aes_gcm) {
+        if (enc->aes == NULL)
+            enc->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc->aes == NULL)
+            return MEMORY_E;
+        if (dec->aes == NULL)
+            dec->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec->aes == NULL)
+            return MEMORY_E;
+
+        if (side == CLIENT_END) {
+            AesGcmSetKey(enc->aes, keys->client_write_key, specs->key_size);
+            XMEMCPY(keys->aead_enc_imp_IV,
+                                     keys->client_write_IV, AEAD_IMP_IV_SZ);
+            AesGcmSetKey(dec->aes, keys->server_write_key, specs->key_size);
+            XMEMCPY(keys->aead_dec_imp_IV,
+                                     keys->server_write_IV, AEAD_IMP_IV_SZ);
+        }
+        else {
+            AesGcmSetKey(enc->aes, keys->server_write_key, specs->key_size);
+            XMEMCPY(keys->aead_enc_imp_IV,
+                                     keys->server_write_IV, AEAD_IMP_IV_SZ);
+            AesGcmSetKey(dec->aes, keys->client_write_key, specs->key_size);
+            XMEMCPY(keys->aead_dec_imp_IV,
+                                     keys->client_write_IV, AEAD_IMP_IV_SZ);
+        }
+        enc->setup = 1;
+        dec->setup = 1;
+    }
+#endif
+
+#ifdef HAVE_AESCCM
+    if (specs->bulk_cipher_algorithm == aes_ccm) {
+        if (enc->aes == NULL)
+            enc->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc->aes == NULL)
+            return MEMORY_E;
+        if (dec->aes == NULL)
+            dec->aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec->aes == NULL)
+            return MEMORY_E;
+
+        if (side == CLIENT_END) {
+            AesCcmSetKey(enc->aes, keys->client_write_key, specs->key_size);
+            XMEMCPY(keys->aead_enc_imp_IV,
+                                     keys->client_write_IV, AEAD_IMP_IV_SZ);
+            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 {
+            AesCcmSetKey(enc->aes, keys->server_write_key, specs->key_size);
+            XMEMCPY(keys->aead_enc_imp_IV,
+                                     keys->server_write_IV, AEAD_IMP_IV_SZ);
+            AesCcmSetKey(dec->aes, keys->client_write_key, specs->key_size);
+            XMEMCPY(keys->aead_dec_imp_IV,
+                                     keys->client_write_IV, AEAD_IMP_IV_SZ);
+        }
+        enc->setup = 1;
+        dec->setup = 1;
+    }
+#endif
+
+#ifdef HAVE_CAMELLIA
+    if (specs->bulk_cipher_algorithm == camellia) {
+        if (enc->cam == NULL)
+            enc->cam =
+                (Camellia*)XMALLOC(sizeof(Camellia), heap, DYNAMIC_TYPE_CIPHER);
+        if (enc->cam == NULL)
+            return MEMORY_E;
+        if (dec->cam == NULL)
+            dec->cam =
+                (Camellia*)XMALLOC(sizeof(Camellia), heap, DYNAMIC_TYPE_CIPHER);
+        if (dec->cam == NULL)
+            return MEMORY_E;
+        if (side == CLIENT_END) {
+            CamelliaSetKey(enc->cam, keys->client_write_key,
+                      specs->key_size, keys->client_write_IV);
+            CamelliaSetKey(dec->cam, keys->server_write_key,
+                      specs->key_size, keys->server_write_IV);
+        }
+        else {
+            CamelliaSetKey(enc->cam, keys->server_write_key,
+                      specs->key_size, keys->server_write_IV);
+            CamelliaSetKey(dec->cam, keys->client_write_key,
+                      specs->key_size, keys->client_write_IV);
+        }
+        enc->setup = 1;
+        dec->setup = 1;
+    }
+#endif
+
+#ifdef HAVE_NULL_CIPHER
+    if (specs->bulk_cipher_algorithm == cipher_null) {
+        enc->setup = 1;
+        dec->setup = 1;
+    }
+#endif
+
+    keys->sequence_number      = 0;
+    keys->peer_sequence_number = 0;
+    keys->encryptionOn         = 0;
+    (void)side;
+    (void)heap;
+    (void)enc;
+    (void)dec;
+    (void)specs;
+    (void)devId;
+
+    return 0;
+}
+
+
+/* TLS can call too */
+int StoreKeys(CYASSL* ssl, const byte* keyData)
+{
+    int sz, i = 0;
+    int devId = NO_CAVIUM_DEVICE;
+
+#ifdef HAVE_CAVIUM
+    devId = ssl->devId;
+#endif
+
+    if (ssl->specs.cipher_type != aead) {
+        sz = ssl->specs.hash_size;
+        XMEMCPY(ssl->keys.client_write_MAC_secret,&keyData[i], sz);
+        i += sz;
+        XMEMCPY(ssl->keys.server_write_MAC_secret,&keyData[i], sz);
+        i += sz;
+    }
+    sz = ssl->specs.key_size;
+    XMEMCPY(ssl->keys.client_write_key, &keyData[i], sz);
+    i += sz;
+    XMEMCPY(ssl->keys.server_write_key, &keyData[i], sz);
+    i += sz;
+
+    sz = ssl->specs.iv_size;
+    XMEMCPY(ssl->keys.client_write_IV, &keyData[i], sz);
+    i += sz;
+    XMEMCPY(ssl->keys.server_write_IV, &keyData[i], sz);
+
+#ifdef HAVE_AEAD
+    if (ssl->specs.cipher_type == aead) {
+        /* Initialize the AES-GCM explicit IV to a random number. */
+        RNG_GenerateBlock(ssl->rng, ssl->keys.aead_exp_IV, AEAD_EXP_IV_SZ);
+    }
+#endif
+
+    return SetKeys(&ssl->encrypt, &ssl->decrypt, &ssl->keys, &ssl->specs,
+                   ssl->options.side, ssl->heap, devId);
+}
+
+#ifndef NO_OLD_TLS
+int DeriveKeys(CYASSL* 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;
+
+    byte shaOutput[SHA_DIGEST_SIZE];
+    byte md5Input[SECRET_LEN + SHA_DIGEST_SIZE];
+    byte shaInput[KEY_PREFIX + SECRET_LEN + 2 * RAN_LEN];
+  
+    Md5 md5;
+    Sha sha;
+
+    byte keyData[KEY_PREFIX * MD5_DIGEST_SIZE];  /* max size */
+
+    InitMd5(&md5);
+    InitSha(&sha);
+
+    XMEMCPY(md5Input, ssl->arrays->masterSecret, SECRET_LEN);
+
+    for (i = 0; i < rounds; ++i) {
+        int j   = i + 1;
+        int idx = j;
+
+        if (!SetPrefix(shaInput, i)) {
+            return PREFIX_ERROR;
+        }
+
+        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);
+
+        ShaUpdate(&sha, shaInput, (word32)sizeof(shaInput) - KEY_PREFIX + j);
+        ShaFinal(&sha, shaOutput);
+
+        XMEMCPY(&md5Input[SECRET_LEN], shaOutput, SHA_DIGEST_SIZE);
+        Md5Update(&md5, md5Input, sizeof(md5Input));
+        Md5Final(&md5, keyData + i * MD5_DIGEST_SIZE);
+    }
+
+    return StoreKeys(ssl, keyData);
+}
+
+
+static void CleanPreMaster(CYASSL* ssl)
+{
+    int i, sz = ssl->arrays->preMasterSz;
+
+    for (i = 0; i < sz; i++)
+        ssl->arrays->preMasterSecret[i] = 0;
+
+    RNG_GenerateBlock(ssl->rng, ssl->arrays->preMasterSecret, sz);
+
+    for (i = 0; i < sz; i++)
+        ssl->arrays->preMasterSecret[i] = 0;
+
+}
+
+
+/* Create and store the master secret see page 32, 6.1 */
+static int MakeSslMasterSecret(CYASSL* ssl)
+{
+    byte   shaOutput[SHA_DIGEST_SIZE];
+    byte   md5Input[ENCRYPT_LEN + SHA_DIGEST_SIZE];
+    byte   shaInput[PREFIX + ENCRYPT_LEN + 2 * RAN_LEN];
+    int    i, ret;
+    word32 idx;
+    word32 pmsSz = ssl->arrays->preMasterSz;
+
+    Md5 md5;
+    Sha sha;
+
+#ifdef SHOW_SECRETS
+    {
+        word32 j;
+        printf("pre master secret: ");
+        for (j = 0; j < pmsSz; j++)
+            printf("%02x", ssl->arrays->preMasterSecret[j]);
+        printf("\n");
+    }
+#endif
+
+    InitMd5(&md5);
+    InitSha(&sha);
+
+    XMEMCPY(md5Input, ssl->arrays->preMasterSecret, pmsSz);
+
+    for (i = 0; i < MASTER_ROUNDS; ++i) {
+        byte prefix[PREFIX];
+        if (!SetPrefix(prefix, i)) {
+            return PREFIX_ERROR;
+        }
+
+        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;
+        ShaUpdate(&sha, shaInput, idx);
+        ShaFinal(&sha, shaOutput);
+
+        idx = pmsSz;  /* preSz */
+        XMEMCPY(md5Input + idx, shaOutput, SHA_DIGEST_SIZE);
+        idx += SHA_DIGEST_SIZE;
+        Md5Update(&md5, md5Input, idx);
+        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
+
+    ret = DeriveKeys(ssl);
+    CleanPreMaster(ssl);
+
+    return ret;
+}
+#endif
+
+
+/* Master wrapper, doesn't use SSL stack space in TLS mode */
+int MakeMasterSecret(CYASSL* 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/ocsp.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,343 @@
+/* ocsp.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef HAVE_OCSP
+
+#ifdef EBSNET
+    #include "rtip.h"
+    #include "socket.h"
+#endif
+
+#include <cyassl/ctaoerror.h>
+#include <cyassl/ocsp.h>
+#include <cyassl/internal.h>
+#include <ctype.h>
+
+#include <string.h>
+
+#ifndef EBSNET
+    #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/types.h>
+    #include <sys/socket.h>
+#endif
+
+
+CYASSL_API int ocsp_test(unsigned char* buf, int sz);
+#define CYASSL_OCSP_ENABLE       0x0001 /* Enable OCSP lookups */
+#define CYASSL_OCSP_URL_OVERRIDE 0x0002 /* Use the override URL instead of URL
+                                         * in certificate */
+#define CYASSL_OCSP_NO_NONCE     0x0004 /* Disables the request nonce */
+
+typedef struct sockaddr_in  SOCKADDR_IN_T;
+#define AF_INET_V    AF_INET
+#define SOCKET_T unsigned int
+   
+
+int CyaSSL_OCSP_Init(CYASSL_OCSP* ocsp)
+{
+    if (ocsp != NULL) {
+        XMEMSET(ocsp, 0, sizeof(*ocsp));
+        ocsp->useNonce = 1;
+        #ifndef CYASSL_USER_IO
+            ocsp->CBIOOcsp = EmbedOcspLookup;
+            ocsp->CBIOOcspRespFree = EmbedOcspRespFree;
+        #endif
+        return 0;
+    }
+
+    return -1;
+}
+
+
+static void FreeOCSP_Entry(OCSP_Entry* ocspe)
+{
+    CertStatus* tmp = ocspe->status;
+
+    CYASSL_ENTER("FreeOCSP_Entry");
+
+    while (tmp) {
+        CertStatus* next = tmp->next;
+        XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_STATUS);
+        tmp = next;
+    }
+}
+
+
+void CyaSSL_OCSP_Cleanup(CYASSL_OCSP* ocsp)
+{
+    OCSP_Entry* tmp = ocsp->ocspList;
+
+    ocsp->enabled = 0;
+    while (tmp) {
+        OCSP_Entry* next = tmp->next;
+        FreeOCSP_Entry(tmp);
+        XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_ENTRY);
+        tmp = next;
+    }
+}
+
+
+int CyaSSL_OCSP_set_override_url(CYASSL_OCSP* ocsp, const char* url)
+{
+    if (ocsp != NULL) {
+        int urlSz = (int)XSTRLEN(url);
+        if (urlSz < (int)sizeof(ocsp->overrideUrl)) {
+            XSTRNCPY(ocsp->overrideUrl, url, urlSz);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+
+static int InitOCSP_Entry(OCSP_Entry* ocspe, DecodedCert* cert)
+{
+    CYASSL_ENTER("InitOCSP_Entry");
+
+    ocspe->next = NULL;
+    XMEMCPY(ocspe->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE);
+    XMEMCPY(ocspe->issuerKeyHash, cert->issuerKeyHash, SHA_DIGEST_SIZE);
+    ocspe->status = NULL;
+    ocspe->totalStatus = 0;
+
+    return 0;
+}
+
+
+static OCSP_Entry* find_ocsp_entry(CYASSL_OCSP* ocsp, DecodedCert* cert)
+{
+    OCSP_Entry* entry = ocsp->ocspList;
+
+    while (entry)
+    {
+        if (XMEMCMP(entry->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE) == 0
+            && XMEMCMP(entry->issuerKeyHash, cert->issuerKeyHash,
+                                                        SHA_DIGEST_SIZE) == 0)
+        {
+            CYASSL_MSG("Found OCSP responder");
+            break;
+        }
+        else
+        {
+            entry = entry->next;
+        }
+    }
+
+    if (entry == NULL)
+    {
+        CYASSL_MSG("Add a new OCSP entry");
+        entry = (OCSP_Entry*)XMALLOC(sizeof(OCSP_Entry),
+                                                NULL, DYNAMIC_TYPE_OCSP_ENTRY);
+        if (entry != NULL)
+        {
+            InitOCSP_Entry(entry, cert);
+            entry->next = ocsp->ocspList;
+            ocsp->ocspList = entry;
+        }
+    }
+
+    return entry;
+}
+
+
+static CertStatus* find_cert_status(OCSP_Entry* ocspe, DecodedCert* cert)
+{
+    CertStatus* stat = ocspe->status;
+
+    while (stat)
+    {
+        if(stat->serialSz == cert->serialSz &&
+            (XMEMCMP(stat->serial, cert->serial, cert->serialSz) == 0))
+        {
+            break;
+        }
+        else
+        {
+            stat = stat->next;
+        }
+    }
+    if (stat == NULL)
+    {
+        stat = (CertStatus*)XMALLOC(sizeof(CertStatus),
+                                            NULL, DYNAMIC_TYPE_OCSP_STATUS);
+        if (stat != NULL)
+        {
+            XMEMCPY(stat->serial, cert->serial, cert->serialSz);
+            stat->serialSz = cert->serialSz;
+            stat->status = -1;
+            stat->nextDate[0] = 0;
+            ocspe->totalStatus++;
+
+            stat->next = ocspe->status;
+            ocspe->status = stat;
+        }
+    }
+
+    return stat;
+}
+
+
+static int xstat2err(int stat)
+{
+    switch (stat) {
+        case CERT_GOOD:
+            return 0;
+            break;
+        case CERT_REVOKED:
+            return OCSP_CERT_REVOKED;
+            break;
+        default:
+            return OCSP_CERT_UNKNOWN;
+            break;
+    }
+}
+
+
+int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP* ocsp, DecodedCert* cert)
+{
+    byte* ocspReqBuf = NULL;
+    int ocspReqSz = 2048;
+    byte* ocspRespBuf = NULL;
+    OcspRequest ocspRequest;
+    OcspResponse ocspResponse;
+    int result = 0;
+    OCSP_Entry* ocspe;
+    CertStatus* certStatus;
+    const char *url;
+    int urlSz;
+
+    /* If OCSP lookups are disabled, return success. */
+    if (!ocsp->enabled) {
+        CYASSL_MSG("OCSP lookup disabled, assuming CERT_GOOD");
+        return 0;
+    }
+
+    ocspe = find_ocsp_entry(ocsp, cert);
+    if (ocspe == NULL) {
+        CYASSL_MSG("alloc OCSP entry failed");
+        return MEMORY_ERROR;
+    }
+
+    certStatus = find_cert_status(ocspe, cert);
+    if (certStatus == NULL)
+    {
+        CYASSL_MSG("alloc OCSP cert status failed");
+        return MEMORY_ERROR;
+    }
+
+    if (certStatus->status != -1)
+    {
+        if (!ValidateDate(certStatus->thisDate,
+                                        certStatus->thisDateFormat, BEFORE) ||
+            (certStatus->nextDate[0] == 0) ||
+            !ValidateDate(certStatus->nextDate,
+                                        certStatus->nextDateFormat, AFTER))
+        {
+            CYASSL_MSG("\tinvalid status date, looking up cert");
+            certStatus->status = -1;
+        }
+        else
+        {
+            CYASSL_MSG("\tusing cached status");
+            result = xstat2err(certStatus->status);
+            return result;
+        }
+    }
+
+    if (ocsp->useOverrideUrl) {
+        if (ocsp->overrideUrl[0] != '\0') {
+            url = ocsp->overrideUrl;
+            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 {
+        CYASSL_MSG("\tcert doesn't have extAuthInfo, assuming CERT_GOOD");
+        return 0;
+    }
+
+    ocspReqBuf = (byte*)XMALLOC(ocspReqSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
+    if (ocspReqBuf == NULL) {
+        CYASSL_MSG("\talloc OCSP request buffer failed");
+        return MEMORY_ERROR;
+    }
+    InitOcspRequest(&ocspRequest, cert, ocsp->useNonce, ocspReqBuf, ocspReqSz);
+    ocspReqSz = EncodeOcspRequest(&ocspRequest);
+    
+    if (ocsp->CBIOOcsp) {
+        result = ocsp->CBIOOcsp(ocsp->IOCB_OcspCtx, url, urlSz,
+                                          ocspReqBuf, ocspReqSz, &ocspRespBuf);
+    }
+
+    if (result >= 0 && ocspRespBuf) {
+        InitOcspResponse(&ocspResponse, certStatus, ocspRespBuf, result);
+        OcspResponseDecode(&ocspResponse);
+    
+        if (ocspResponse.responseStatus != OCSP_SUCCESSFUL) {
+            CYASSL_MSG("OCSP Responder failure");
+            result = OCSP_LOOKUP_FAIL;
+        } else {
+            if (CompareOcspReqResp(&ocspRequest, &ocspResponse) == 0)
+            {
+                result = xstat2err(ocspResponse.status->status);
+            }
+            else
+            {
+                CYASSL_MSG("OCSP Response incorrect for Request");
+                result = OCSP_LOOKUP_FAIL;
+            }
+        }
+    }
+    else {
+        result = OCSP_LOOKUP_FAIL;
+    }
+
+    if (ocspReqBuf != NULL) {
+        XFREE(ocspReqBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
+    }
+    if (ocspRespBuf != NULL && ocsp->CBIOOcspRespFree) {
+        ocsp->CBIOOcspRespFree(ocsp->IOCB_OcspCtx, ocspRespBuf);
+    }
+
+    return result;
+}
+
+
+#endif /* HAVE_OCSP */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sniffer.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,2518 @@
+/* sniffer.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef CYASSL_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 <cyassl/openssl/ssl.h>
+#include <cyassl/internal.h>
+#include <cyassl/ctaoerror.h>
+#include <cyassl/sniffer.h>
+#include <cyassl/sniffer_error.h>
+
+
+#ifndef min
+
+static INLINE word32 min(word32 a, word32 b)
+{
+    return a > b ? b : a;
+}
+
+#endif
+
+
+/* Misc constants */
+enum {
+    MAX_SERVER_ADDRESS = 128, /* maximum server address 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 */
+    SNIFFER_TIMEOUT    = 900, /* Cache unclosed Sessions for 15 minutes */
+    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"
+};
+
+
+/* *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;
+
+
+/* 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 */
+    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 CyaSSL_Mutex ServerListMutex;
+
+
+/* Session Hash Table, mutex, and count */
+static SnifferSession* SessionTable[HASH_SIZE];
+static CyaSSL_Mutex SessionMutex;
+static int SessionCount = 0;
+
+
+/* Initialize overall Sniffer */
+void ssl_InitSniffer(void)
+{
+    CyaSSL_Init();
+    InitMutex(&ServerListMutex);
+    InitMutex(&SessionMutex);
+}
+
+
+/* Free Sniffer Server's resources/self */
+static void FreeSnifferServer(SnifferServer* srv)
+{
+    if (srv)
+        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);
+    CyaSSL_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;
+    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, userdata, sz);
+    return (int)XSTRLEN(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);
+    }
+}
+
+
+/* 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 = SERVER_END;
+        else
+            session->flags.side = CLIENT_END;
+    }    
+    
+    return session;
+}
+
+
+/* Sets the private key for a specific server and port  */
+/* returns 0 on success, -1 on error */
+int ssl_SetPrivateKey(const char* serverAddress, int port, const char* keyFile,
+                      int typeKey, const char* password, char* error)
+{
+    int            ret;
+    int            type = (typeKey == FILETYPE_PEM) ? SSL_FILETYPE_PEM :
+                                                      SSL_FILETYPE_ASN1;
+    SnifferServer* sniffer;
+    
+    TraceHeader();
+    TraceSetServer(serverAddress, port, keyFile);
+
+    sniffer = (SnifferServer*)malloc(sizeof(SnifferServer));
+    if (sniffer == NULL) {
+        SetError(MEMORY_STR, error, NULL, 0);
+        return -1;
+    }
+    InitSnifferServer(sniffer);
+
+    XSTRNCPY(sniffer->address, serverAddress, MAX_SERVER_ADDRESS);
+    sniffer->server = inet_addr(sniffer->address);
+    sniffer->port = port;
+    
+    /* start in client mode since SSL_new needs a cert for server */
+    sniffer->ctx = SSL_CTX_new(SSLv3_client_method());
+    if (!sniffer->ctx) {
+        SetError(MEMORY_STR, error, NULL, 0);
+        FreeSnifferServer(sniffer);
+        return -1;
+    }
+
+    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);
+        FreeSnifferServer(sniffer);
+        return -1;
+    }
+    Trace(NEW_SERVER_STR);
+    
+    LockMutex(&ServerListMutex);
+    
+    sniffer->next = ServerList;
+    ServerList = sniffer;
+    
+    UnLockMutex(&ServerListMutex);
+    
+    return 0;
+}
+
+
+/* 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, 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;
+
+    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;
+
+    InitRsaKey(&key, 0);
+   
+    ret = RsaPrivateKeyDecode(session->context->ctx->privateKey.buffer,
+                          &idx, &key, session->context->ctx->privateKey.length);
+    if (ret == 0) {
+        int length = RsaEncryptSize(&key);
+        
+        if (IsTLS(session->sslServer)) 
+            input += 2;     /* tls pre length */
+       
+        if (length > *sslBytes) { 
+            SetError(PARTIAL_INPUT_STR, error, session, FATAL_ERROR_STATE);
+            FreeRsaKey(&key);
+            return -1;
+        }
+        ret = RsaPrivateDecrypt(input, length, 
+                  session->sslServer->arrays->preMasterSecret,SECRET_LEN, &key);
+        
+        if (ret != SECRET_LEN) {
+            SetError(RSA_DECRYPT_STR, error, session, FATAL_ERROR_STATE);
+            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);
+        FreeRsaKey(&key);
+        return -1;
+    }
+    
+    if (SetCipherSpecs(session->sslServer) != 0) {
+        SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
+        FreeRsaKey(&key);
+        return -1;
+    }
+   
+    if (SetCipherSpecs(session->sslClient) != 0) {
+        SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
+        FreeRsaKey(&key);
+        return -1;
+    }
+
+    MakeMasterSecret(session->sslServer);
+    MakeMasterSecret(session->sslClient);
+#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   
+    
+    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 = (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 */
+        XMEMCPY(session->sslServer->arrays->sessionID,session->ticketID,ID_LEN);
+    }
+
+    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);
+        }
+        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;
+    
+    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 = (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 = (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 = (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* sslBytes, 
+                           SnifferSession* session, char* error)
+{
+    SSL*   ssl;
+    word32 inOutIdx = 0;
+    int    ret;
+                
+    if (session->flags.side == SERVER_END)
+        ssl = session->sslServer;
+    else
+        ssl = session->sslClient;
+    ret = DoFinished(ssl, input, &inOutIdx, 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) {
+            CYASSL_SESSION* sess = GetSession(session->sslServer, NULL);
+            if (sess == NULL)
+                AddSession(session->sslServer);  /* don't re add */
+            session->flags.cached = 1;
+         }
+    }
+
+    FreeHandshakeResources(ssl);
+
+    return ret;
+}
+
+
+/* Process HandShake input */
+static int DoHandShake(const byte* input, int* sslBytes,
+                       SnifferSession* session, char* error)
+{
+    byte type;
+    int  size;
+    int  ret = 0;
+    
+    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;
+    
+    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, 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;
+        default:
+            SetError(GOT_UNKNOWN_HANDSHAKE_STR, error, session, 0);
+            return -1;
+    }   
+
+    return ret;
+}
+
+
+/* Decrypt input into plain output */
+static void Decrypt(SSL* ssl, byte* output, const byte* input, word32 sz)
+{
+    switch (ssl->specs.bulk_cipher_algorithm) {
+        #ifdef BUILD_ARC4
+        case rc4:
+            Arc4Process(ssl->decrypt.arc4, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef BUILD_DES3
+        case triple_des:
+            Des3_CbcDecrypt(ssl->decrypt.des3, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef BUILD_AES
+        case aes:
+            AesCbcDecrypt(ssl->decrypt.aes, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef HAVE_HC128
+        case hc128:
+            Hc128_Process(ssl->decrypt.hc128, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef BUILD_RABBIT
+        case rabbit:
+            RabbitProcess(ssl->decrypt.rabbit, output, input, sz);
+            break;
+        #endif
+
+        #ifdef HAVE_CAMELLIA 
+        case camellia:
+            CamelliaCbcDecrypt(ssl->decrypt.cam, output, input, sz);
+            break;
+        #endif
+
+        default:
+            Trace(BAD_DECRYPT_TYPE);
+            break;
+    }
+}
+
+
+/* Decrypt input message into output, adjust output steam if needed */
+static const byte* DecryptMessage(SSL* ssl, const byte* input, word32 sz,
+                                  byte* output)
+{
+    Decrypt(ssl, output, input, sz);
+    ssl->keys.encryptSz = sz;
+    if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
+        return output + ssl->specs.block_size;     /* go past TLSv1.1 IV */
+    
+    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 + 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 = tcpInfo->dstPort;
+    session->cliPort = 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 = 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 = SERVER_END;
+    else
+        session->flags.side = CLIENT_END;        
+    
+    return session;
+}
+
+
+/* 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,
+                                *rhSize);    
+    if (ret < 0) {
+        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;
+}
+
+
+#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();
+    if (length < IP_HDR_SZ) {
+        SetError(PACKET_HDR_SHORT_STR, error, NULL, 0);
+        return -1;
+    }
+    if (CheckIpHdr((IpHdr*)packet, ipInfo, error) != 0)
+        return -1;
+    
+    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;
+    
+    *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 == 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 == 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 == SERVER_END) ? 
+                                     session->cliSeqStart :session->srvSeqStart;
+    word32  real     = tcpInfo->sequence - seqStart;
+    word32* expected = (session->flags.side == SERVER_END) ?
+                                  &session->cliExpected : &session->srvExpected;
+    PacketBuffer* reassemblyList = (session->flags.side == 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 == SERVER_END) ? 
+                                     session->srvSeqStart :session->cliSeqStart;
+        word32  real     = tcpInfo->ackNumber - seqStart;
+        word32  expected = (session->flags.side == 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 == 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) {
+        int rhSize;
+        int ret = DoOldHello(*session, *sslFrame, &rhSize, sslBytes, error);
+        if (ret < 0)
+            return -1;  /* error already set */
+        if (*sslBytes <= 0)
+            return 1;
+    }
+    
+    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 == SERVER_END) ?
+                      &session->cliReassemblyList : &session->srvReassemblyList;
+    word32*        expected = (session->flags.side == SERVER_END) ?
+                                  &session->cliExpected : &session->srvExpected;
+    /* buffer is on receiving end */
+    word32*        length = (session->flags.side == SERVER_END) ?
+                               &session->sslServer->buffers.inputBuffer.length :
+                               &session->sslClient->buffers.inputBuffer.length;
+    byte*          myBuffer = (session->flags.side == SERVER_END) ?
+                                session->sslServer->buffers.inputBuffer.buffer :
+                                session->sslClient->buffers.inputBuffer.buffer;
+    word32       bufferSize = (session->flags.side == SERVER_END) ?
+                            session->sslServer->buffers.inputBuffer.bufferSize :
+                            session->sslClient->buffers.inputBuffer.bufferSize;
+    SSL*               ssl  = (session->flags.side == 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*       tmp;
+    RecordLayerHeader rh;
+    int               rhSize = 0;
+    int               ret;
+    int               decoded = 0;      /* bytes stored for user in data */
+    int               notEnough;        /* notEnough bytes yet flag */
+    SSL*              ssl = (session->flags.side == SERVER_END) ?
+                                        session->sslServer : session->sslClient;
+doMessage:
+    notEnough = 0;
+    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;
+                }
+            }
+            XMEMCPY(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;
+    tmp = sslFrame + rhSize;   /* may have more than one record to process */
+    
+    /* decrypt if needed */
+    if ((session->flags.side == SERVER_END && session->flags.serverCipherOn)
+     || (session->flags.side == CLIENT_END && session->flags.clientCipherOn)) {
+        if (CheckAvailableSize(ssl, rhSize) < 0) {
+            SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        sslFrame = DecryptMessage(ssl, sslFrame, rhSize,
+                                  ssl->buffers.outputBuffer.buffer);
+    }
+            
+    switch ((enum ContentType)rh.type) {
+        case handshake:
+            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;
+            }
+            break;
+        case change_cipher_spec:
+            if (session->flags.side == SERVER_END)
+                session->flags.serverCipherOn = 1;
+            else
+                session->flags.clientCipherOn = 1;
+            Trace(GOT_CHANGE_CIPHER_STR);
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+            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);
+            }
+            break;
+        case alert:
+            Trace(GOT_ALERT_STR);
+            break;
+        case no_type:
+        default:
+            SetError(GOT_UNKNOWN_RECORD_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+    }
+    
+    if (tmp < end) {
+        Trace(ANOTHER_MSG_STR);
+        sslFrame = tmp;
+        sslBytes = (int)(end - tmp);
+        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 /* CYASSL_SNIFFER */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,9871 @@
+/* ssl.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#ifdef HAVE_ERRNO_H 
+    #include <errno.h>
+#endif
+
+
+#include <cyassl/ssl.h>
+#include <cyassl/internal.h>
+#include <cyassl/ctaoerror.h>
+#include <cyassl/ctaocrypt/coding.h>
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+    #include <cyassl/openssl/evp.h>
+#endif
+
+#ifdef OPENSSL_EXTRA
+    /* openssl headers begin */
+    #include <cyassl/openssl/hmac.h>
+    #include <cyassl/openssl/crypto.h>
+    #include <cyassl/openssl/des.h>
+    #include <cyassl/openssl/bn.h>
+    #include <cyassl/openssl/dh.h>
+    #include <cyassl/openssl/rsa.h>
+    #include <cyassl/openssl/pem.h>
+    /* openssl headers end, cyassl internal headers next */
+    #include <cyassl/ctaocrypt/hmac.h>
+    #include <cyassl/ctaocrypt/random.h>
+    #include <cyassl/ctaocrypt/des3.h>
+    #include <cyassl/ctaocrypt/md4.h>
+    #include <cyassl/ctaocrypt/md5.h>
+    #include <cyassl/ctaocrypt/arc4.h>
+    #ifdef CYASSL_SHA512
+        #include <cyassl/ctaocrypt/sha512.h>
+    #endif
+#endif
+
+#ifndef NO_FILESYSTEM
+    #if !defined(USE_WINDOWS_API) && !defined(NO_CYASSL_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 min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+#ifndef max
+
+    static INLINE word32 max(word32 a, word32 b)
+    {
+        return a > b ? a : b;
+    }
+
+#endif /* min */
+
+
+#ifndef CYASSL_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 CyaSSL_Mutex count_mutex;   /* init ref count mutex */
+
+
+
+CYASSL_CTX* CyaSSL_CTX_new(CYASSL_METHOD* method)
+{
+    CYASSL_CTX* ctx = NULL;
+
+    CYASSL_ENTER("CYASSL_CTX_new");
+
+    if (initRefCount == 0)
+        CyaSSL_Init(); /* user no longer forced to call Init themselves */
+
+    if (method == NULL)
+        return ctx;
+
+    ctx = (CYASSL_CTX*) XMALLOC(sizeof(CYASSL_CTX), 0, DYNAMIC_TYPE_CTX);
+    if (ctx) {
+        if (InitSSL_Ctx(ctx, method) < 0) {
+            CYASSL_MSG("Init CTX failed");
+            CyaSSL_CTX_free(ctx);
+            ctx = NULL;
+        }
+    }
+    else {
+        CYASSL_MSG("Alloc CTX failed, method freed");
+        XFREE(method, NULL, DYNAMIC_TYPE_METHOD);
+    }
+
+    CYASSL_LEAVE("CYASSL_CTX_new", 0);
+    return ctx;
+}
+
+
+void CyaSSL_CTX_free(CYASSL_CTX* ctx)
+{
+    CYASSL_ENTER("SSL_CTX_free");
+    if (ctx)
+        FreeSSL_Ctx(ctx);
+    CYASSL_LEAVE("SSL_CTX_free", 0);
+}
+
+
+CYASSL* CyaSSL_new(CYASSL_CTX* ctx)
+{
+    CYASSL* ssl = NULL;
+    int ret = 0;
+
+    (void)ret;
+    CYASSL_ENTER("SSL_new");
+
+    if (ctx == NULL)
+        return ssl;
+
+    ssl = (CYASSL*) XMALLOC(sizeof(CYASSL), ctx->heap,DYNAMIC_TYPE_SSL);
+    if (ssl)
+        if ( (ret = InitSSL(ssl, ctx)) < 0) {
+            FreeSSL(ssl);
+            ssl = 0;
+        }
+
+    CYASSL_LEAVE("SSL_new", ret);
+    return ssl;
+}
+
+
+void CyaSSL_free(CYASSL* ssl)
+{
+    CYASSL_ENTER("SSL_free");
+    if (ssl)
+        FreeSSL(ssl);
+    CYASSL_LEAVE("SSL_free", 0);
+}
+
+
+int CyaSSL_set_fd(CYASSL* ssl, int fd)
+{
+    CYASSL_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 CYASSL_DTLS
+        if (ssl->options.dtls) {
+            ssl->IOCB_ReadCtx = &ssl->buffers.dtlsCtx;
+            ssl->IOCB_WriteCtx = &ssl->buffers.dtlsCtx;
+            ssl->buffers.dtlsCtx.fd = fd;
+        }
+    #endif
+
+    CYASSL_LEAVE("SSL_set_fd", SSL_SUCCESS);
+    return SSL_SUCCESS;
+}
+
+
+int CyaSSL_get_fd(const CYASSL* ssl)
+{
+    CYASSL_ENTER("SSL_get_fd");
+    CYASSL_LEAVE("SSL_get_fd", ssl->rfd);
+    return ssl->rfd;
+}
+
+
+#ifndef CYASSL_LEANPSK
+void CyaSSL_set_using_nonblock(CYASSL* ssl, int nonblock)
+{
+    CYASSL_ENTER("CyaSSL_set_using_nonblock");
+    ssl->options.usingNonblock = (nonblock != 0);
+}
+
+
+int CyaSSL_get_using_nonblock(CYASSL* ssl)
+{
+    CYASSL_ENTER("CyaSSL_get_using_nonblock");
+    CYASSL_LEAVE("CyaSSL_get_using_nonblock", ssl->options.usingNonblock);
+    return ssl->options.usingNonblock;
+}
+
+
+int CyaSSL_dtls(CYASSL* ssl)
+{
+    return ssl->options.dtls;
+}
+
+
+int CyaSSL_dtls_set_peer(CYASSL* ssl, void* peer, unsigned int peerSz)
+{
+#ifdef CYASSL_DTLS
+    void* sa = (void*)XMALLOC(peerSz, ssl->heap, DYNAMIC_TYPE_SOCKADDR);
+    if (sa != NULL) {
+        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 CyaSSL_dtls_get_peer(CYASSL* ssl, void* peer, unsigned int* peerSz)
+{
+#ifdef CYASSL_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 /* CYASSL_LEANPSK */
+
+
+/* return underlyig connect or accept, SSL_SUCCESS on ok */
+int CyaSSL_negotiate(CYASSL* ssl)
+{
+    int err = SSL_FATAL_ERROR;
+
+    CYASSL_ENTER("CyaSSL_negotiate");
+#ifndef NO_CYASSL_SERVER
+    if (ssl->options.side == SERVER_END)
+        err = CyaSSL_accept(ssl);
+#endif
+
+#ifndef NO_CYASSL_CLIENT
+    if (ssl->options.side == CLIENT_END)
+        err = CyaSSL_connect(ssl);
+#endif
+
+    CYASSL_LEAVE("CyaSSL_negotiate", err);
+
+    return err;
+}
+
+
+#ifndef CYASSL_LEANPSK
+/* object size based on build */
+int CyaSSL_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
+    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 CYASSL_SHA384
+    printf("    sizeof SHA384       = %lu\n", sizeof(Sha384));
+#endif
+#ifdef CYASSL_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 CYASSL_CIPHER    = %lu\n", sizeof(CYASSL_CIPHER));
+    printf("sizeof CYASSL_SESSION   = %lu\n", sizeof(CYASSL_SESSION));
+    printf("sizeof CYASSL           = %lu\n", sizeof(CYASSL));
+    printf("sizeof CYASSL_CTX       = %lu\n", sizeof(CYASSL_CTX));
+#endif
+
+    return sizeof(CYASSL);
+}
+#endif
+
+/* XXX should be NO_DH */
+#ifndef NO_CERTS
+/* server Diffie-Hellman parameters, SSL_SUCCESS on ok */
+int CyaSSL_SetTmpDH(CYASSL* ssl, const unsigned char* p, int pSz,
+                    const unsigned char* g, int gSz)
+{
+    byte havePSK = 0;
+    byte haveRSA = 1;
+
+    CYASSL_ENTER("CyaSSL_SetTmpDH");
+    if (ssl == NULL || p == NULL || g == NULL) return BAD_FUNC_ARG;
+
+    if (ssl->options.side != 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);
+
+    CYASSL_LEAVE("CyaSSL_SetTmpDH", 0);
+    return SSL_SUCCESS;
+}
+#endif /* !NO_CERTS */
+
+
+int CyaSSL_write(CYASSL* ssl, const void* data, int sz)
+{
+    int ret;
+
+    CYASSL_ENTER("SSL_write()");
+
+#ifdef HAVE_ERRNO_H 
+    errno = 0;
+#endif
+
+    ret = SendData(ssl, data, sz);
+
+    CYASSL_LEAVE("SSL_write()", ret);
+
+    if (ret < 0)
+        return SSL_FATAL_ERROR;
+    else
+        return ret;
+}
+
+
+static int CyaSSL_read_internal(CYASSL* ssl, void* data, int sz, int peek)
+{
+    int ret; 
+
+    CYASSL_ENTER("CyaSSL_read_internal()");
+
+#ifdef HAVE_ERRNO_H 
+        errno = 0;
+#endif
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls)
+        ssl->dtls_expected_rx = max(sz + 100, MAX_MTU);
+#endif
+
+    ret = ReceiveData(ssl, (byte*)data, min(sz, OUTPUT_RECORD_SIZE), peek);
+
+    CYASSL_LEAVE("CyaSSL_read_internal()", ret);
+
+    if (ret < 0)
+        return SSL_FATAL_ERROR;
+    else
+        return ret;
+}
+
+
+int CyaSSL_peek(CYASSL* ssl, void* data, int sz)
+{
+    CYASSL_ENTER("CyaSSL_peek()");
+
+    return CyaSSL_read_internal(ssl, data, sz, TRUE);
+}
+
+
+int CyaSSL_read(CYASSL* ssl, void* data, int sz)
+{
+    CYASSL_ENTER("CyaSSL_read()");
+
+    return CyaSSL_read_internal(ssl, data, sz, FALSE);
+}
+
+
+#ifdef HAVE_CAVIUM
+
+/* let's use cavium, SSL_SUCCESS on ok */
+int CyaSSL_UseCavium(CYASSL* 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 CyaSSL_CTX_UseCavium(CYASSL_CTX* ctx, int devId)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    ctx->devId = devId;
+
+    return SSL_SUCCESS;
+}
+
+
+#endif /* HAVE_CAVIUM */
+
+#ifdef HAVE_SNI
+
+int CyaSSL_UseSNI(CYASSL* ssl, byte type, const void* data, word16 size)
+{
+	if (ssl == NULL)
+		return BAD_FUNC_ARG;
+
+    return TLSX_UseSNI(&ssl->extensions, type, data, size);
+}
+
+int CyaSSL_CTX_UseSNI(CYASSL_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_CYASSL_SERVER
+byte CyaSSL_SNI_Matched(CYASSL* ssl, byte type)
+{
+    return TLSX_SNI_Matched(ssl ? ssl->extensions : NULL, type);
+}
+
+void CyaSSL_SNI_SetOptions(CYASSL* ssl, byte type, byte options)
+{
+    if (ssl && ssl->extensions)
+        TLSX_SNI_SetOptions(ssl->extensions, type, options);
+}
+
+void CyaSSL_CTX_SNI_SetOptions(CYASSL_CTX* ctx, byte type, byte options)
+{
+    if (ctx && ctx->extensions)
+        TLSX_SNI_SetOptions(ctx->extensions, type, options);
+}
+#endif
+
+#endif /* HAVE_SNI */
+
+#ifndef CYASSL_LEANPSK
+int CyaSSL_send(CYASSL* ssl, const void* data, int sz, int flags)
+{
+    int ret; 
+    int oldFlags = ssl->wflags;
+
+    CYASSL_ENTER("CyaSSL_send()");
+
+    ssl->wflags = flags;
+    ret = CyaSSL_write(ssl, data, sz);
+    ssl->wflags = oldFlags;
+
+    CYASSL_LEAVE("CyaSSL_send()", ret);
+
+    return ret;
+}
+
+
+int CyaSSL_recv(CYASSL* ssl, void* data, int sz, int flags)
+{
+    int ret; 
+    int oldFlags = ssl->rflags;
+
+    CYASSL_ENTER("CyaSSL_recv()");
+
+    ssl->rflags = flags;
+    ret = CyaSSL_read(ssl, data, sz);
+    ssl->rflags = oldFlags;
+
+    CYASSL_LEAVE("CyaSSL_recv()", ret);
+
+    return ret;
+}
+#endif
+
+
+/* SSL_SUCCESS on ok */
+int CyaSSL_shutdown(CYASSL* ssl)
+{
+    CYASSL_ENTER("SSL_shutdown()");
+
+    if (ssl == NULL)
+        return SSL_FATAL_ERROR;
+
+    if (ssl->options.quietShutdown) {
+        CYASSL_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) {
+            CYASSL_ERROR(ssl->error);
+            return SSL_FATAL_ERROR;
+        }
+        ssl->options.sentNotify = 1;  /* don't send close_notify twice */
+    }
+
+    CYASSL_LEAVE("SSL_shutdown()", ssl->error);
+
+    ssl->error = SSL_ERROR_SYSCALL;   /* simulate OpenSSL behavior */
+
+    return SSL_SUCCESS;
+}
+
+
+int CyaSSL_get_error(CYASSL* ssl, int ret)
+{
+    CYASSL_ENTER("SSL_get_error");
+    CYASSL_LEAVE("SSL_get_error", ssl->error);
+    if (ret > 0)
+        return SSL_ERROR_NONE;
+
+    /* 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 CyaSSL_get_alert_history(CYASSL* ssl, CYASSL_ALERT_HISTORY *h)
+{
+    if (ssl && h) {
+        *h = ssl->alert_history;
+    }
+    return SSL_SUCCESS;
+}
+
+
+/* return TRUE if current error is want read */
+int CyaSSL_want_read(CYASSL* ssl)
+{
+    CYASSL_ENTER("SSL_want_read");
+    if (ssl->error == WANT_READ)
+        return 1;
+
+    return 0;
+}
+
+
+/* return TRUE if current error is want write */
+int CyaSSL_want_write(CYASSL* ssl)
+{
+    CYASSL_ENTER("SSL_want_write");
+    if (ssl->error == WANT_WRITE)
+        return 1;
+
+    return 0;
+}
+
+
+char* CyaSSL_ERR_error_string(unsigned long errNumber, char* data)
+{
+    static const char* msg = "Please supply a buffer for error string";
+
+    CYASSL_ENTER("ERR_error_string");
+    if (data) {
+        SetErrorString((int)errNumber, data);
+        return data;
+    }
+
+    return (char*)msg;
+}
+
+
+void CyaSSL_ERR_error_string_n(unsigned long e, char* buf, unsigned long len)
+{
+    CYASSL_ENTER("CyaSSL_ERR_error_string_n");
+    if (len >= MAX_ERROR_SZ)
+        CyaSSL_ERR_error_string(e, buf);
+    else {
+        char tmp[MAX_ERROR_SZ];
+
+        CYASSL_MSG("Error buffer too short, truncating");
+        if (len) {
+            CyaSSL_ERR_error_string(e, tmp);
+            XMEMCPY(buf, tmp, len-1);
+            buf[len-1] = '\0';
+        }
+    }
+}
+
+
+/* don't free temporary arrays at end of handshake */
+void CyaSSL_KeepArrays(CYASSL* ssl)
+{
+    if (ssl)
+        ssl->options.saveArrays = 1;
+}
+
+
+/* user doesn't need temporary arrays anymore, Free */
+void CyaSSL_FreeArrays(CYASSL* ssl)
+{
+    if (ssl && ssl->options.handShakeState == HANDSHAKE_DONE) {
+        ssl->options.saveArrays = 0;
+        FreeArrays(ssl, 1);
+    }
+}
+
+
+#ifndef NO_CERTS
+
+CYASSL_CERT_MANAGER* CyaSSL_CertManagerNew(void)
+{
+    CYASSL_CERT_MANAGER* cm = NULL;
+
+    CYASSL_ENTER("CyaSSL_CertManagerNew");
+
+    cm = (CYASSL_CERT_MANAGER*) XMALLOC(sizeof(CYASSL_CERT_MANAGER), 0,
+                                        DYNAMIC_TYPE_CERT_MANAGER);
+    if (cm) {
+        int i;
+
+        for (i = 0; i < CA_TABLE_SIZE; i++)
+            cm->caTable[i]  = NULL;
+        cm->heap            = NULL;
+        cm->caCacheCallback = NULL;
+        cm->crl             = NULL;
+        cm->crlEnabled      = 0;
+        cm->crlCheckAll     = 0;
+        cm->cbMissingCRL    = NULL;
+
+        if (InitMutex(&cm->caLock) != 0) {
+            CYASSL_MSG("Bad mutex init");
+            CyaSSL_CertManagerFree(cm);
+            return NULL;
+        }
+    }
+
+    return cm;
+}
+
+
+void CyaSSL_CertManagerFree(CYASSL_CERT_MANAGER* cm)
+{
+    CYASSL_ENTER("CyaSSL_CertManagerFree");
+
+    if (cm) {
+        #ifdef HAVE_CRL
+            if (cm->crl) 
+                FreeCRL(cm->crl, 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 CyaSSL_CertManagerUnloadCAs(CYASSL_CERT_MANAGER* cm)
+{
+    CYASSL_ENTER("CyaSSL_CertManagerUnloadCAs");
+
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    if (LockMutex(&cm->caLock) != 0)
+        return BAD_MUTEX_ERROR;
+
+    FreeSignerTable(cm->caTable, CA_TABLE_SIZE, NULL);
+
+    UnLockMutex(&cm->caLock);
+
+
+    return SSL_SUCCESS;
+}
+
+
+#endif /* !NO_CERTS */
+
+
+
+#ifndef NO_FILESYSTEM
+
+void CyaSSL_ERR_print_errors_fp(FILE* fp, int err)
+{
+    char data[MAX_ERROR_SZ + 1];
+
+    CYASSL_ENTER("CyaSSL_ERR_print_errors_fp");
+    SetErrorString(err, data);
+    fprintf(fp, "%s", data);
+}
+
+#endif
+
+
+int CyaSSL_pending(CYASSL* ssl)
+{
+    CYASSL_ENTER("SSL_pending");
+    return ssl->buffers.clearOutputBuffer.length;
+}
+
+
+#ifndef CYASSL_LEANPSK
+/* trun on handshake group messages for context */
+int CyaSSL_CTX_set_group_messages(CYASSL_CTX* ctx)
+{
+    if (ctx == NULL)
+       return BAD_FUNC_ARG;
+
+    ctx->groupMessages = 1;
+
+    return SSL_SUCCESS;
+}
+#endif
+
+
+#ifndef NO_CYASSL_CLIENT
+/* connect enough to get peer cert chain */
+int CyaSSL_connect_cert(CYASSL* ssl)
+{
+    int  ret;
+
+    if (ssl == NULL)
+        return SSL_FAILURE;
+
+    ssl->options.certOnly = 1;
+    ret = CyaSSL_connect(ssl);
+    ssl->options.certOnly   = 0;
+
+    return ret;
+}
+#endif
+
+
+#ifndef CYASSL_LEANPSK
+/* trun on handshake group messages for ssl object */
+int CyaSSL_set_group_messages(CYASSL* ssl)
+{
+    if (ssl == NULL)
+       return BAD_FUNC_ARG;
+
+    ssl->options.groupMessages = 1;
+
+    return SSL_SUCCESS;
+}
+
+
+int CyaSSL_SetVersion(CYASSL* ssl, int version)
+{
+    byte haveRSA = 1;
+    byte havePSK = 0;
+
+    CYASSL_ENTER("CyaSSL_SetVersion");
+
+    if (ssl == NULL) {
+        CYASSL_MSG("Bad function argument");
+        return BAD_FUNC_ARG;
+    }
+
+    switch (version) {
+#ifndef NO_OLD_TLS
+        case CYASSL_SSLV3:
+            ssl->version = MakeSSLv3();
+            break;
+#endif
+
+#ifndef NO_TLS
+    #ifndef NO_OLD_TLS
+        case CYASSL_TLSV1:
+            ssl->version = MakeTLSv1();
+            break;
+
+        case CYASSL_TLSV1_1:
+            ssl->version = MakeTLSv1_1();
+            break;
+    #endif
+        case CYASSL_TLSV1_2:
+            ssl->version = MakeTLSv1_2();
+            break;
+#endif
+
+        default:
+            CYASSL_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(CYASSL_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, SHA_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)
+{
+    CYASSL_CERT_MANAGER* cm = (CYASSL_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, SHA_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)
+{
+    CYASSL_CERT_MANAGER* cm = (CYASSL_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, SHA_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(CYASSL_CERT_MANAGER* cm, buffer der, int type, int verify)
+{
+    int         ret;
+    DecodedCert cert;
+    Signer*     signer = 0;
+    word32      row;
+    byte*       subjectHash;
+
+    CYASSL_MSG("Adding a CA");
+    InitDecodedCert(&cert, der.buffer, der.length, cm->heap);
+    ret = ParseCert(&cert, CA_TYPE, verify, cm);
+    CYASSL_MSG("    Parsed new CA");
+
+    #ifndef NO_SKID
+        subjectHash = cert.extSubjKeyId;
+    #else
+        subjectHash = cert.subjectHash;
+    #endif
+
+    if (ret == 0 && cert.isCA == 0 && type != CYASSL_USER_CA) {
+        CYASSL_MSG("    Can't add as CA if not actually one");
+        ret = NOT_CA_ERROR;
+    }
+    else if (ret == 0 && AlreadySigner(cm, subjectHash)) {
+        CYASSL_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 NO_SKID
+                XMEMCPY(signer->subjectKeyIdHash,
+                                            cert.extSubjKeyId, SHA_DIGEST_SIZE);
+            #endif
+            XMEMCPY(signer->subjectNameHash, cert.subjectHash, SHA_DIGEST_SIZE);
+            signer->next = NULL;   /* in case lock fails */
+
+            cert.publicKey = 0;  /* don't free here */
+            cert.subjectCN = 0;
+
+            #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 {
+                CYASSL_MSG("    CA Mutex Lock failed");
+                ret = BAD_MUTEX_ERROR;
+                FreeSigner(signer, cm->heap);
+            }
+        }
+    }
+
+    CYASSL_MSG("    Freeing Parsed CA");
+    FreeDecodedCert(&cert);
+    CYASSL_MSG("    Freeing der CA");
+    XFREE(der.buffer, cm->heap, DYNAMIC_TYPE_CA);
+    CYASSL_MSG("        OK Freeing der CA");
+
+    CYASSL_LEAVE("AddCA", ret);
+    if (ret == 0) return SSL_SUCCESS;
+    return 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 */
+        CYASSL_SESSION Sessions[SESSIONS_PER_ROW];
+    } SessionRow;
+
+    static SessionRow SessionCache[SESSION_ROWS];
+
+    static CyaSSL_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 */
+
+    /* for persistance, if changes to layout need to increment and modify
+       save_session_cache() and restore_session_cache and memory versions too */
+    #define CYASSL_CACHE_VERSION 2
+
+#endif /* NO_SESSION_CACHE */
+
+
+int CyaSSL_Init(void)
+{
+    int ret = SSL_SUCCESS;
+
+    CYASSL_ENTER("CyaSSL_Init");
+
+    if (initRefCount == 0) {
+#ifndef NO_SESSION_CACHE
+        if (InitMutex(&session_mutex) != 0)
+            ret = BAD_MUTEX_ERROR;
+#endif
+        if (InitMutex(&count_mutex) != 0)
+            ret = BAD_MUTEX_ERROR;
+    }
+    if (ret == SSL_SUCCESS) {
+        if (LockMutex(&count_mutex) != 0) {
+            CYASSL_MSG("Bad Lock Mutex count");
+            return BAD_MUTEX_ERROR;
+        }
+        initRefCount++;
+        UnLockMutex(&count_mutex);
+    }
+
+    return ret;
+}
+
+
+#ifndef NO_CERTS
+
+    /* Remove PEM header/footer, convert to ASN1, store any encrypted data 
+       info->consumed tracks of PEM bytes consumed in case multiple parts */
+    int PemToDer(const unsigned char* buff, long longSz, int type,
+                      buffer* der, void* heap, EncryptedInfo* info, int* eccKey)
+    {
+        char  header[PEM_LINE_LEN];
+        char  footer[PEM_LINE_LEN];
+        char* headerEnd;
+        char* footerEnd;
+        char* consumedEnd;
+        char* bufferEnd = (char*)(buff + longSz);
+        long  neededSz;
+        int   pkcs8    = 0;
+        int   pkcs8Enc = 0;
+        int   dynamicType = 0;
+        int   sz = (int)longSz;
+
+        (void)heap;
+        (void)dynamicType;
+
+        if (type == CERT_TYPE || type == CA_TYPE)  {
+            XSTRNCPY(header, "-----BEGIN CERTIFICATE-----", sizeof(header));
+            XSTRNCPY(footer, "-----END CERTIFICATE-----", sizeof(footer));
+            dynamicType = (type == CA_TYPE) ? DYNAMIC_TYPE_CA :
+                                              DYNAMIC_TYPE_CERT;
+        } else if (type == DH_PARAM_TYPE) {
+            XSTRNCPY(header, "-----BEGIN DH PARAMETERS-----", sizeof(header));
+            XSTRNCPY(footer, "-----END DH PARAMETERS-----", sizeof(footer));
+            dynamicType = DYNAMIC_TYPE_KEY;
+        } else if (type == CRL_TYPE) {
+            XSTRNCPY(header, "-----BEGIN X509 CRL-----", sizeof(header));
+            XSTRNCPY(footer, "-----END X509 CRL-----", sizeof(footer));
+            dynamicType = DYNAMIC_TYPE_CRL;
+        } else {
+            XSTRNCPY(header, "-----BEGIN RSA PRIVATE KEY-----", sizeof(header));
+            XSTRNCPY(footer, "-----END RSA PRIVATE KEY-----", sizeof(footer));
+            dynamicType = DYNAMIC_TYPE_KEY;
+        }
+
+        /* find header */
+        headerEnd = XSTRNSTR((char*)buff, header, sz);
+        if (!headerEnd && type == PRIVATEKEY_TYPE) {  /* may be pkcs8 */
+            XSTRNCPY(header, "-----BEGIN PRIVATE KEY-----", sizeof(header));
+            XSTRNCPY(footer, "-----END PRIVATE KEY-----", sizeof(footer));
+        
+            headerEnd = XSTRNSTR((char*)buff, header, sz);
+            if (headerEnd)
+                pkcs8 = 1;
+            else {
+                XSTRNCPY(header, "-----BEGIN ENCRYPTED PRIVATE KEY-----",
+                        sizeof(header));
+                XSTRNCPY(footer, "-----END ENCRYPTED PRIVATE KEY-----",
+                        sizeof(footer));
+
+                headerEnd = XSTRNSTR((char*)buff, header, sz);
+                if (headerEnd) {
+                    pkcs8Enc = 1;
+                    (void)pkcs8Enc;  /* only opensslextra will read */
+                }
+            }
+        }
+        if (!headerEnd && type == PRIVATEKEY_TYPE) {  /* may be ecc */
+            XSTRNCPY(header, "-----BEGIN EC PRIVATE KEY-----", sizeof(header));
+            XSTRNCPY(footer, "-----END EC PRIVATE KEY-----", sizeof(footer));
+        
+            headerEnd = XSTRNSTR((char*)buff, header, sz);
+            if (headerEnd)
+                *eccKey = 1;
+        }
+        if (!headerEnd && type == PRIVATEKEY_TYPE) {  /* may be dsa */
+            XSTRNCPY(header, "-----BEGIN DSA PRIVATE KEY-----", sizeof(header));
+            XSTRNCPY(footer, "-----END DSA PRIVATE KEY-----", sizeof(footer));
+        
+            headerEnd = XSTRNSTR((char*)buff, header, sz);
+        }
+        if (!headerEnd) {
+            CYASSL_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 defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+    {
+        /* remove encrypted header if there */
+        char encHeader[] = "Proc-Type";
+        char* line = XSTRNSTR((char*)buff, 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 (pkcs8)
+            return ToTraditional(der->buffer, der->length);
+
+#if defined(OPENSSL_EXTRA) && !defined(NO_PWDBASED)
+         if (pkcs8Enc) {
+            int  passwordSz;
+            char password[80];
+
+            if (!info || !info->ctx || !info->ctx->passwd_cb)
+                return SSL_BAD_FILE;  /* no callback error */
+            passwordSz = info->ctx->passwd_cb(password, sizeof(password), 0,
+                                              info->ctx->userdata);
+            return ToTraditionalEnc(der->buffer, der->length, password,
+                                    passwordSz);
+         }
+#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(CYASSL_CTX* ctx, const unsigned char* buff,
+                             long sz, int format, int type, CYASSL* ssl,
+                             long* used, int userChain)
+    {
+        EncryptedInfo info;
+        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;
+
+        info.set      = 0;
+        info.ctx      = ctx;
+        info.consumed = 0;
+        der.buffer    = 0;
+
+        (void)dynamicType;
+
+        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 (type == CA_TYPE)
+            dynamicType = DYNAMIC_TYPE_CA;
+        else if (type == CERT_TYPE)
+            dynamicType = DYNAMIC_TYPE_CERT;
+        else
+            dynamicType = DYNAMIC_TYPE_KEY;
+
+        if (format == SSL_FILETYPE_PEM) {
+            ret = PemToDer(buff, sz, type, &der, heap, &info, &eccKey);
+            if (ret < 0) {
+                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) {
+                byte   staticBuffer[FILE_BUFFER_SIZE];  /* tmp chain buffer */
+                byte*  chainBuffer = staticBuffer;
+                int    dynamicBuffer = 0;
+                word32 bufferSz = sizeof(staticBuffer);
+                long   consumed = info.consumed;
+                word32 idx = 0;
+                int    gotOne = 0;
+
+                if ( (sz - consumed) > (int)bufferSz) {
+                    CYASSL_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) {
+                        XFREE(der.buffer, heap, dynamicType);
+                        return MEMORY_E;
+                    }
+                    dynamicBuffer = 1;
+                }
+
+                CYASSL_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) {
+                            CYASSL_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) {
+                        CYASSL_MSG("We got one good PEM so stuff at end ok");
+                        break;
+                    }
+
+                    if (ret < 0) {
+                        CYASSL_MSG("   Error in Cert in Chain");
+                        XFREE(der.buffer, heap, dynamicType);
+                        return ret;
+                    }
+                    CYASSL_MSG("   Consumed another Cert in Chain");
+                }
+                CYASSL_MSG("Finished Processing Cert Chain");
+
+                if (ctx == NULL) {
+                    CYASSL_MSG("certChain needs context");
+                    return BAD_FUNC_ARG;
+                }
+                ctx->certChain.buffer = (byte*)XMALLOC(idx, heap,
+                                                       dynamicType);
+                if (ctx->certChain.buffer) {
+                    ctx->certChain.length = idx;
+                    XMEMCPY(ctx->certChain.buffer, chainBuffer, idx);
+                }
+                if (dynamicBuffer)
+                    XFREE(chainBuffer, heap, DYNAMIC_TYPE_FILE);
+                if (ctx->certChain.buffer == NULL) {
+                    XFREE(der.buffer, heap, dynamicType);
+                    return MEMORY_E;
+                }
+            }
+        }
+        else {  /* ASN1 (DER) or RAW (NTRU) */
+            der.buffer = (byte*) XMALLOC(sz, heap, dynamicType);
+            if (!der.buffer) return MEMORY_ERROR;
+            XMEMCPY(der.buffer, buff, sz);
+            der.length = (word32)sz;
+        }
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+        if (info.set) {
+            /* decrypt */
+            char password[80];
+            int  passwordSz;
+
+            byte key[AES_256_KEY_SIZE];
+            byte  iv[AES_IV_SIZE];
+
+            if (!ctx || !ctx->passwd_cb) {
+                XFREE(der.buffer, heap, dynamicType);
+                return NO_PASSWORD;
+            }
+
+            /* use file's salt for key derivation, hex decode first */
+            if (Base16_Decode(info.iv, info.ivSz, info.iv, &info.ivSz) != 0) {
+                XFREE(der.buffer, heap, dynamicType);
+                return ASN_INPUT_E;
+            }
+
+            passwordSz = ctx->passwd_cb(password, sizeof(password), 0,
+                                    ctx->userdata);
+            if ( (ret = EVP_BytesToKey(info.name, "MD5", info.iv,
+                            (byte*)password, passwordSz, 1, key, iv)) <= 0) {
+                XFREE(der.buffer, heap, dynamicType);
+                return ret;
+            }
+
+            if (XSTRNCMP(info.name, "DES-CBC", 7) == 0) {
+                Des enc;
+                Des_SetKey(&enc, key, info.iv, DES_DECRYPTION);
+                Des_CbcDecrypt(&enc, der.buffer, der.buffer, der.length);
+            }
+            else if (XSTRNCMP(info.name, "DES-EDE3-CBC", 13) == 0) {
+                Des3 enc;
+                Des3_SetKey(&enc, key, info.iv, DES_DECRYPTION);
+                Des3_CbcDecrypt(&enc, der.buffer, der.buffer, der.length);
+            }
+            else if (XSTRNCMP(info.name, "AES-128-CBC", 13) == 0) {
+                Aes enc;
+                AesSetKey(&enc, key, AES_128_KEY_SIZE, info.iv, AES_DECRYPTION);
+                AesCbcDecrypt(&enc, der.buffer, der.buffer, der.length);
+            }
+            else if (XSTRNCMP(info.name, "AES-192-CBC", 13) == 0) {
+                Aes enc;
+                AesSetKey(&enc, key, AES_192_KEY_SIZE, info.iv, AES_DECRYPTION);
+                AesCbcDecrypt(&enc, der.buffer, der.buffer, der.length);
+            }
+            else if (XSTRNCMP(info.name, "AES-256-CBC", 13) == 0) {
+                Aes enc;
+                AesSetKey(&enc, key, AES_256_KEY_SIZE, info.iv, AES_DECRYPTION);
+                AesCbcDecrypt(&enc, der.buffer, der.buffer, der.length);
+            }
+            else { 
+                XFREE(der.buffer, heap, dynamicType);
+                return SSL_BAD_FILE;
+            }
+        }
+#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */
+
+        if (type == CA_TYPE) {
+            if (ctx == NULL) {
+                CYASSL_MSG("Need context for CA load");
+                XFREE(der.buffer, heap, dynamicType);
+                return BAD_FUNC_ARG;
+            }
+            return AddCA(ctx->cm, der, CYASSL_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 */
+                RsaKey key;
+                word32 idx = 0;
+        
+                InitRsaKey(&key, 0);
+                if (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) {
+                        FreeRsaKey(&key);
+                        return SSL_BAD_FILE;
+                    }
+                } else {
+                    rsaKey = 1;
+                    (void)rsaKey;  /* for no ecc builds */
+                }
+                FreeRsaKey(&key);
+            }
+#endif
+#ifdef HAVE_ECC  
+            if (!rsaKey) {
+                /* make sure ECC key can be used */
+                word32  idx = 0;
+                ecc_key key;
+
+                ecc_init(&key);
+                if (EccPrivateKeyDecode(der.buffer,&idx,&key,der.length) != 0) {
+                    ecc_free(&key);
+                    return SSL_BAD_FILE;
+                }
+                ecc_free(&key);
+                eccKey = 1;
+                ctx->haveStaticECC = 1;
+                if (ssl)
+                    ssl->options.haveStaticECC = 1;
+            }
+#endif /* HAVE_ECC */
+        }
+        else if (type == CERT_TYPE) {
+            DecodedCert cert;
+
+            CYASSL_MSG("Checking cert signature type");
+            InitDecodedCert(&cert, der.buffer, der.length, heap);
+
+            if (DecodeToKey(&cert, 0) < 0) {
+                CYASSL_MSG("Decode to key failed");
+                return SSL_BAD_FILE; 
+            }            
+            switch (cert.signatureOID) {
+                case CTC_SHAwECDSA:
+                case CTC_SHA256wECDSA:
+                case CTC_SHA384wECDSA:
+                case CTC_SHA512wECDSA:
+                    CYASSL_MSG("ECDSA cert signature");
+                    if (ctx)
+                        ctx->haveECDSAsig = 1;
+                    if (ssl)
+                        ssl->options.haveECDSAsig = 1;
+                    break;
+                default:
+                    CYASSL_MSG("Not ECDSA cert signature");
+                    break;
+            }
+
+            FreeDecodedCert(&cert);
+        }
+
+        return SSL_SUCCESS;
+    }
+
+
+
+
+/* CA PEM file for verification, may have multiple/chain certs to process */
+static int ProcessChainBuffer(CYASSL_CTX* ctx, const unsigned char* buff,
+                            long sz, int format, int type, CYASSL* ssl)
+{
+    long used   = 0;
+    int  ret    = 0;
+    int  gotOne = 0;
+
+    CYASSL_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) {
+            CYASSL_MSG("We got one good PEM file so stuff at end ok");
+            ret = SSL_SUCCESS;
+            break;
+        }
+
+        if (ret < 0)
+            break;
+
+        CYASSL_MSG("   Processed a CA");
+        gotOne = 1;
+        used += consumed;
+    }
+
+    return ret;
+}
+
+
+/* Verify the ceritficate, SSL_SUCCESS for ok, < 0 for error */
+int CyaSSL_CertManagerVerifyBuffer(CYASSL_CERT_MANAGER* cm, const byte* buff,
+                                   long sz, int format)
+{
+    int ret = 0;
+    int eccKey = 0;  /* not used */
+
+    DecodedCert cert;
+    buffer      der;
+
+    CYASSL_ENTER("CyaSSL_CertManagerVerifyBuffer");
+
+    der.buffer = NULL;
+    der.length = 0;
+
+    if (format == SSL_FILETYPE_PEM) { 
+        EncryptedInfo info;
+            
+        info.set      = 0;
+        info.ctx      = NULL;
+        info.consumed = 0;
+        ret = PemToDer(buff, sz, CERT_TYPE, &der, cm->heap, &info, &eccKey);
+        InitDecodedCert(&cert, der.buffer, der.length, cm->heap);
+    }
+    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);
+
+    if (ret == 0)
+        return SSL_SUCCESS;
+    return ret;
+}
+
+
+#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*
+    #define XFOPEN     fopen 
+    #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
+
+
+/* process a file with name fname into ctx of format and type
+   userChain specifies a user certificate chain to pass during handshake */
+int ProcessFile(CYASSL_CTX* ctx, const char* fname, int format, int type,
+                CYASSL* ssl, int userChain, CYASSL_CRL* crl)
+{
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+    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)) {
+        CYASSL_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 CyaSSL_CTX_load_verify_locations(CYASSL_CTX* ctx, const char* file,
+                                     const char* path)
+{
+    int ret = SSL_SUCCESS;
+
+    CYASSL_ENTER("CyaSSL_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;
+        char   name[MAX_FILENAME_SZ];
+
+        XMEMSET(name, 0, sizeof(name));
+        XSTRNCPY(name, path, MAX_FILENAME_SZ - 4);
+        XSTRNCAT(name, "\\*", 3);
+
+        hFind = FindFirstFileA(name, &FindFileData);
+        if (hFind == INVALID_HANDLE_VALUE) {
+            CYASSL_MSG("FindFirstFile for path verify locations failed");
+            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));
+
+        FindClose(hFind);
+    #elif !defined(NO_CYASSL_DIR)
+        struct dirent* entry;
+        DIR*   dir = opendir(path);
+
+        if (dir == NULL) {
+            CYASSL_MSG("opendir path verify locations failed");
+            return BAD_PATH_ERROR;
+        }
+        while ( ret == SSL_SUCCESS && (entry = readdir(dir)) != NULL) {
+            char name[MAX_FILENAME_SZ];
+            struct stat s;
+
+            XMEMSET(name, 0, sizeof(name));
+            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) {
+                CYASSL_MSG("stat on name failed");
+                closedir(dir);
+                return BAD_PATH_ERROR;
+            }
+            if (s.st_mode & S_IFREG) {
+                ret = ProcessFile(ctx, name, SSL_FILETYPE_PEM, CA_TYPE, NULL,0,
+                                  NULL);
+            }
+        }
+        closedir(dir);
+    #endif
+    }
+
+    return ret;
+}
+
+
+/* Verify the ceritficate, SSL_SUCCESS for ok, < 0 for error */
+int CyaSSL_CertManagerVerify(CYASSL_CERT_MANAGER* cm, const char* fname,
+                             int format)
+{
+    int    ret = SSL_FATAL_ERROR;
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+    byte*  myBuffer = staticBuffer;
+    int    dynamic = 0;
+    long   sz = 0;
+    XFILE  file = XFOPEN(fname, "rb"); 
+
+    CYASSL_ENTER("CyaSSL_CertManagerVerify");
+
+    if (file == XBADFILE) return SSL_BAD_FILE;
+    XFSEEK(file, 0, XSEEK_END);
+    sz = XFTELL(file);
+    XREWIND(file);
+
+    if (sz > MAX_CYASSL_FILE_SIZE || sz < 0) {
+        CYASSL_MSG("CertManagerVerify file bad size");
+        XFCLOSE(file);
+        return SSL_BAD_FILE;
+    }
+
+    if (sz > (long)sizeof(staticBuffer)) {
+        CYASSL_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 = CyaSSL_CertManagerVerifyBuffer(cm, myBuffer, sz, format);
+
+    XFCLOSE(file);
+    if (dynamic) XFREE(myBuffer, cm->heap, DYNAMIC_TYPE_FILE);
+
+    return ret;
+}
+
+
+static INLINE CYASSL_METHOD* cm_pick_method(void)
+{
+    #ifndef NO_CYASSL_CLIENT
+        #ifdef NO_OLD_TLS
+            return CyaTLSv1_2_client_method();
+        #else
+            return CyaSSLv3_client_method();
+        #endif
+    #elif !defined(NO_CYASSL_SERVER)
+        #ifdef NO_OLD_TLS
+            return CyaTLSv1_2_server_method();
+        #else
+            return CyaSSLv3_server_method();
+        #endif
+    #else
+        return NULL;
+    #endif
+}
+
+
+/* like load verify locations, 1 for success, < 0 for error */
+int CyaSSL_CertManagerLoadCA(CYASSL_CERT_MANAGER* cm, const char* file,
+                             const char* path)
+{
+    int ret = SSL_FATAL_ERROR;
+    CYASSL_CTX* tmp;
+
+    CYASSL_ENTER("CyaSSL_CertManagerLoadCA");
+
+    if (cm == NULL) {
+        CYASSL_MSG("No CertManager error");
+        return ret;
+    }
+    tmp = CyaSSL_CTX_new(cm_pick_method());
+
+    if (tmp == NULL) {
+        CYASSL_MSG("CTX new failed");
+        return ret;
+    }
+
+    /* for tmp use */
+    CyaSSL_CertManagerFree(tmp->cm);
+    tmp->cm = cm;
+
+    ret = CyaSSL_CTX_load_verify_locations(tmp, file, path);
+
+    /* don't loose our good one */
+    tmp->cm = NULL;
+    CyaSSL_CTX_free(tmp);
+
+    return ret;
+}
+
+
+
+/* turn on CRL if off and compiled in, set options */
+int CyaSSL_CertManagerEnableCRL(CYASSL_CERT_MANAGER* cm, int options)
+{
+    int ret = SSL_SUCCESS;
+
+    (void)options;
+
+    CYASSL_ENTER("CyaSSL_CertManagerEnableCRL");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    #ifdef HAVE_CRL
+        if (cm->crl == NULL) {
+            cm->crl = (CYASSL_CRL*)XMALLOC(sizeof(CYASSL_CRL), cm->heap,
+                                           DYNAMIC_TYPE_CRL);
+            if (cm->crl == NULL)
+                return MEMORY_E;
+
+            if (InitCRL(cm->crl, cm) != 0) {
+                CYASSL_MSG("Init CRL failed");
+                FreeCRL(cm->crl, 1);
+                cm->crl = NULL;
+                return SSL_FAILURE;
+            }
+        }
+        cm->crlEnabled = 1;
+        if (options & CYASSL_CRL_CHECKALL)
+            cm->crlCheckAll = 1;
+    #else
+        ret = NOT_COMPILED_IN;
+    #endif
+
+    return ret;
+}
+
+
+int CyaSSL_CertManagerDisableCRL(CYASSL_CERT_MANAGER* cm)
+{
+    CYASSL_ENTER("CyaSSL_CertManagerDisableCRL");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    cm->crlEnabled = 0;
+
+    return SSL_SUCCESS;
+}
+
+
+int CyaSSL_CTX_check_private_key(CYASSL_CTX* ctx)
+{
+    /* TODO: check private against public for RSA match */
+    (void)ctx; 
+    CYASSL_ENTER("SSL_CTX_check_private_key");
+    return SSL_SUCCESS;
+}
+
+
+#ifdef HAVE_CRL
+
+
+/* check CRL if enabled, SSL_SUCCESS  */
+int CyaSSL_CertManagerCheckCRL(CYASSL_CERT_MANAGER* cm, byte* der, int sz)
+{
+    int         ret;
+    DecodedCert cert;
+
+    CYASSL_ENTER("CyaSSL_CertManagerCheckCRL");
+
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    if (cm->crlEnabled == 0)
+        return SSL_SUCCESS;
+
+    InitDecodedCert(&cert, der, sz, NULL);
+
+    ret = ParseCertRelative(&cert, CERT_TYPE, NO_VERIFY, cm);
+    if (ret != 0) {
+        CYASSL_MSG("ParseCert failed");
+        return ret;
+    }
+    else {
+        ret = CheckCertCRL(cm->crl, &cert);
+        if (ret != 0) {
+            CYASSL_MSG("CheckCertCRL failed");
+        }
+    }
+
+    FreeDecodedCert(&cert);
+
+    if (ret == 0)
+        return SSL_SUCCESS;  /* convert */
+
+    return ret;
+}
+
+
+int CyaSSL_CertManagerSetCRL_Cb(CYASSL_CERT_MANAGER* cm, CbMissingCRL cb)
+{
+    CYASSL_ENTER("CyaSSL_CertManagerSetCRL_Cb");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    cm->cbMissingCRL = cb;
+
+    return SSL_SUCCESS;
+}
+
+
+int CyaSSL_CertManagerLoadCRL(CYASSL_CERT_MANAGER* cm, const char* path,
+                              int type, int monitor)
+{
+    CYASSL_ENTER("CyaSSL_CertManagerLoadCRL");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    if (cm->crl == NULL) {
+        if (CyaSSL_CertManagerEnableCRL(cm, 0) != SSL_SUCCESS) {
+            CYASSL_MSG("Enable CRL failed");
+            return SSL_FATAL_ERROR;
+        }
+    }
+
+    return LoadCRL(cm->crl, path, type, monitor);
+}
+
+
+int CyaSSL_EnableCRL(CYASSL* ssl, int options)
+{
+    CYASSL_ENTER("CyaSSL_EnableCRL");
+    if (ssl)
+        return CyaSSL_CertManagerEnableCRL(ssl->ctx->cm, options);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_DisableCRL(CYASSL* ssl)
+{
+    CYASSL_ENTER("CyaSSL_DisableCRL");
+    if (ssl)
+        return CyaSSL_CertManagerDisableCRL(ssl->ctx->cm);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_LoadCRL(CYASSL* ssl, const char* path, int type, int monitor)
+{
+    CYASSL_ENTER("CyaSSL_LoadCRL");
+    if (ssl)
+        return CyaSSL_CertManagerLoadCRL(ssl->ctx->cm, path, type, monitor);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_SetCRL_Cb(CYASSL* ssl, CbMissingCRL cb)
+{
+    CYASSL_ENTER("CyaSSL_SetCRL_Cb");
+    if (ssl)
+        return CyaSSL_CertManagerSetCRL_Cb(ssl->ctx->cm, cb);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_CTX_EnableCRL(CYASSL_CTX* ctx, int options)
+{
+    CYASSL_ENTER("CyaSSL_CTX_EnableCRL");
+    if (ctx)
+        return CyaSSL_CertManagerEnableCRL(ctx->cm, options);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_CTX_DisableCRL(CYASSL_CTX* ctx)
+{
+    CYASSL_ENTER("CyaSSL_CTX_DisableCRL");
+    if (ctx)
+        return CyaSSL_CertManagerDisableCRL(ctx->cm);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_CTX_LoadCRL(CYASSL_CTX* ctx, const char* path, int type, int monitor)
+{
+    CYASSL_ENTER("CyaSSL_CTX_LoadCRL");
+    if (ctx)
+        return CyaSSL_CertManagerLoadCRL(ctx->cm, path, type, monitor);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_CTX_SetCRL_Cb(CYASSL_CTX* ctx, CbMissingCRL cb)
+{
+    CYASSL_ENTER("CyaSSL_CTX_SetCRL_Cb");
+    if (ctx)
+        return CyaSSL_CertManagerSetCRL_Cb(ctx->cm, cb);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+#endif /* HAVE_CRL */
+
+
+#ifdef CYASSL_DER_LOAD
+
+/* Add format parameter to allow DER load of CA files */
+int CyaSSL_CTX_der_load_verify_locations(CYASSL_CTX* ctx, const char* file,
+                                         int format)
+{
+    CYASSL_ENTER("CyaSSL_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 /* CYASSL_DER_LOAD */
+
+
+#ifdef CYASSL_CERT_GEN
+
+/* load pem cert from file into der buffer, return der size or error */
+int CyaSSL_PemCertToDer(const char* fileName, unsigned char* derBuf, int derSz) 
+{
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+    byte*  fileBuf = staticBuffer;
+    int    dynamic = 0;
+    int    ret;
+    int    ecc = 0;
+    long   sz = 0;
+    XFILE  file = XFOPEN(fileName, "rb"); 
+    EncryptedInfo info;
+    buffer        converted;
+
+    CYASSL_ENTER("CyaSSL_PemCertToDer");
+    converted.buffer = 0;
+
+    if (file == XBADFILE) return SSL_BAD_FILE;
+    XFSEEK(file, 0, XSEEK_END);
+    sz = XFTELL(file);
+    XREWIND(file);
+
+    if (sz > (long)sizeof(staticBuffer)) {
+        fileBuf = (byte*) XMALLOC(sz, 0, DYNAMIC_TYPE_FILE);
+        if (fileBuf == NULL) {
+            XFCLOSE(file);
+            return SSL_BAD_FILE;
+        }
+        dynamic = 1;
+    }
+    else if (sz < 0) {
+        XFCLOSE(file);
+        return SSL_BAD_FILE;
+    }
+
+    if ( (ret = (int)XFREAD(fileBuf, sz, 1, file)) < 0)
+        ret = SSL_BAD_FILE;
+    else
+        ret = PemToDer(fileBuf, sz, CA_TYPE, &converted, 0, &info, &ecc);
+
+    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); 
+    if (dynamic)
+        XFREE(fileBuf, 0, DYNAMIC_TYPE_FILE); 
+    XFCLOSE(file);
+
+    return ret;
+}
+
+#endif /* CYASSL_CERT_GEN */
+
+
+int CyaSSL_CTX_use_certificate_file(CYASSL_CTX* ctx, const char* file,
+                                    int format)
+{
+    CYASSL_ENTER("CyaSSL_CTX_use_certificate_file");
+    if (ProcessFile(ctx, file, format, CERT_TYPE, NULL, 0, NULL) == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+
+int CyaSSL_CTX_use_PrivateKey_file(CYASSL_CTX* ctx, const char* file,int format)
+{
+    CYASSL_ENTER("CyaSSL_CTX_use_PrivateKey_file");
+    if (ProcessFile(ctx, file, format, PRIVATEKEY_TYPE, NULL, 0, NULL)
+                    == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+
+int CyaSSL_CTX_use_certificate_chain_file(CYASSL_CTX* ctx, const char* file)
+{
+   /* procces up to MAX_CHAIN_DEPTH plus subject cert */
+   CYASSL_ENTER("CyaSSL_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;
+}
+
+
+#ifdef OPENSSL_EXTRA
+/* put SSL type in extra for now, not very common */
+
+int CyaSSL_use_certificate_file(CYASSL* ssl, const char* file, int format)
+{
+    CYASSL_ENTER("CyaSSL_use_certificate_file");
+    if (ProcessFile(ssl->ctx, file, format, CERT_TYPE, ssl, 0, NULL)
+                    == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+
+int CyaSSL_use_PrivateKey_file(CYASSL* ssl, const char* file, int format)
+{
+    CYASSL_ENTER("CyaSSL_use_PrivateKey_file");
+    if (ProcessFile(ssl->ctx, file, format, PRIVATEKEY_TYPE, ssl, 0, NULL)
+                                                                 == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+
+int CyaSSL_use_certificate_chain_file(CYASSL* ssl, const char* file)
+{
+   /* procces up to MAX_CHAIN_DEPTH plus subject cert */
+   CYASSL_ENTER("CyaSSL_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;
+}
+
+
+/* server wrapper for ctx or ssl Diffie-Hellman parameters */
+static int CyaSSL_SetTmpDH_buffer_wrapper(CYASSL_CTX* ctx, CYASSL* ssl,
+                                  const unsigned char* buf, long sz, int format)
+{
+    buffer der;
+    int    ret;
+    int    weOwnDer = 0;
+    byte   p[MAX_DH_SIZE];
+    byte   g[MAX_DH_SIZE];
+    word32 pSz = sizeof(p);
+    word32 gSz = sizeof(g);
+
+    der.buffer = (byte*)buf;
+    der.length = (word32)sz;
+
+    if (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM)
+        return SSL_BAD_FILETYPE;
+
+    if (format == SSL_FILETYPE_PEM) {
+        der.buffer = NULL;
+        ret = PemToDer(buf, sz, DH_PARAM_TYPE, &der, ctx->heap, NULL,NULL);
+        if (ret < 0) {
+            XFREE(der.buffer, ctx->heap, DYNAMIC_TYPE_KEY);
+            return ret;
+        }
+        weOwnDer = 1;
+    }
+
+    if (DhParamsLoad(der.buffer, der.length, p, &pSz, g, &gSz) < 0)
+        ret = SSL_BAD_FILETYPE;
+    else {
+        if (ssl)
+            ret = CyaSSL_SetTmpDH(ssl, p, pSz, g, gSz);
+        else
+            ret = CyaSSL_CTX_SetTmpDH(ctx, p, pSz, g, gSz);
+    }
+
+    if (weOwnDer)
+        XFREE(der.buffer, ctx->heap, DYNAMIC_TYPE_KEY);
+
+    return ret;
+}
+
+/* server Diffie-Hellman parameters, SSL_SUCCESS on ok */
+int CyaSSL_SetTmpDH_buffer(CYASSL* ssl, const unsigned char* buf, long sz,
+                           int format)
+{
+    return CyaSSL_SetTmpDH_buffer_wrapper(ssl->ctx, ssl, buf, sz, format);
+}
+
+
+/* server ctx Diffie-Hellman parameters, SSL_SUCCESS on ok */
+int CyaSSL_CTX_SetTmpDH_buffer(CYASSL_CTX* ctx, const unsigned char* buf,
+                               long sz, int format)
+{
+    return CyaSSL_SetTmpDH_buffer_wrapper(ctx, NULL, buf, sz, format);
+}
+
+
+#ifdef HAVE_ECC
+
+/* Set Temp CTX EC-DHE size in octets, should be 20 - 66 for 160 - 521 bit */
+int CyaSSL_CTX_SetTmpEC_DHE_Sz(CYASSL_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 CyaSSL_SetTmpEC_DHE_Sz(CYASSL* 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 */
+
+
+#if !defined(NO_FILESYSTEM)
+
+/* server Diffie-Hellman parameters */
+static int CyaSSL_SetTmpDH_file_wrapper(CYASSL_CTX* ctx, CYASSL* ssl,
+                                        const char* fname, int format)
+{
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+    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)) {
+        CYASSL_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 = CyaSSL_SetTmpDH_buffer(ssl, myBuffer, sz, format);
+        else
+            ret = CyaSSL_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 CyaSSL_SetTmpDH_file(CYASSL* ssl, const char* fname, int format)
+{
+    return CyaSSL_SetTmpDH_file_wrapper(ssl->ctx, ssl, fname, format);
+}
+
+
+/* server Diffie-Hellman parameters */
+int CyaSSL_CTX_SetTmpDH_file(CYASSL_CTX* ctx, const char* fname, int format)
+{
+    return CyaSSL_SetTmpDH_file_wrapper(ctx, NULL, fname, format);
+}
+
+
+#endif /* !NO_FILESYSTEM */
+#endif /* OPENSSL_EXTRA */
+
+#ifdef HAVE_NTRU
+
+int CyaSSL_CTX_use_NTRUPrivateKey_file(CYASSL_CTX* ctx, const char* file)
+{
+    CYASSL_ENTER("CyaSSL_CTX_use_NTRUPrivateKey_file");
+    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 */
+
+
+
+#if defined(OPENSSL_EXTRA)
+
+    int CyaSSL_CTX_use_RSAPrivateKey_file(CYASSL_CTX* ctx,const char* file,
+                                       int format)
+    {
+        CYASSL_ENTER("SSL_CTX_use_RSAPrivateKey_file");
+
+        return CyaSSL_CTX_use_PrivateKey_file(ctx, file, format);
+    }
+
+    int CyaSSL_use_RSAPrivateKey_file(CYASSL* ssl, const char* file, int format)
+    {
+        CYASSL_ENTER("CyaSSL_use_RSAPrivateKey_file");
+
+        return CyaSSL_use_PrivateKey_file(ssl, file, format);
+    }
+
+#endif /* OPENSSL_EXTRA */
+
+#endif /* NO_FILESYSTEM */
+
+
+void CyaSSL_CTX_set_verify(CYASSL_CTX* ctx, int mode, VerifyCallback vc)
+{
+    CYASSL_ENTER("CyaSSL_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 CyaSSL_set_verify(CYASSL* ssl, int mode, VerifyCallback vc)
+{
+    CYASSL_ENTER("CyaSSL_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 CyaSSL_SetCertCbCtx(CYASSL* ssl, void* ctx)
+{
+    CYASSL_ENTER("CyaSSL_SetCertCbCtx");
+    if (ssl)
+        ssl->verifyCbCtx = ctx;
+}
+
+
+/* store context CA Cache addition callback */
+void CyaSSL_CTX_SetCACb(CYASSL_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 CyaSSL_CTX_save_cert_cache(CYASSL_CTX* ctx, const char* fname)
+{
+    CYASSL_ENTER("CyaSSL_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 CyaSSL_CTX_restore_cert_cache(CYASSL_CTX* ctx, const char* fname)
+{
+    CYASSL_ENTER("CyaSSL_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 CyaSSL_CTX_memsave_cert_cache(CYASSL_CTX* ctx, void* mem, int sz, int* used)
+{
+    CYASSL_ENTER("CyaSSL_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 CyaSSL_CTX_memrestore_cert_cache(CYASSL_CTX* ctx, const void* mem, int sz)
+{
+    CYASSL_ENTER("CyaSSL_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 CyaSSL_CTX_get_cert_cache_memsize(CYASSL_CTX* ctx)
+{
+    CYASSL_ENTER("CyaSSL_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
+
+CYASSL_SESSION* CyaSSL_get_session(CYASSL* ssl)
+{
+    CYASSL_ENTER("SSL_get_session");
+    if (ssl)
+        return GetSession(ssl, 0);
+
+    return NULL;
+}
+
+
+int CyaSSL_set_session(CYASSL* ssl, CYASSL_SESSION* session)
+{
+    CYASSL_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 CyaSSL_SetServerID(CYASSL* ssl, const byte* id, int len, int newSession)
+{
+    CYASSL_SESSION* session = NULL;
+
+    CYASSL_ENTER("CyaSSL_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) {
+                CYASSL_MSG("SetSession failed");
+                session = NULL;
+            }
+        }
+    }
+
+    if (session == NULL) {
+        CYASSL_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)
+
+/* Session Cache Header information */
+typedef struct {
+    int version;     /* cache layout version id */
+    int rows;        /* session rows */
+    int columns;     /* session columns */
+    int sessionSz;   /* sizeof CYASSL_SESSION */
+} cache_header_t;
+
+/* current persistence layout is:
+
+   1) cache_header_t
+   2) SessionCache
+   3) ClientCache
+
+   update CYASSL_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 CyaSSL_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 CyaSSL_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
+
+    CYASSL_ENTER("CyaSSL_memsave_session_cache");
+
+    if (sz < CyaSSL_get_session_cache_memsize()) {
+        CYASSL_MSG("Memory buffer too small");
+        return BUFFER_E;
+    }
+
+    cache_header.version   = CYASSL_CACHE_VERSION;
+    cache_header.rows      = SESSION_ROWS;
+    cache_header.columns   = SESSIONS_PER_ROW;
+    cache_header.sessionSz = (int)sizeof(CYASSL_SESSION);
+    XMEMCPY(mem, &cache_header, sizeof(cache_header));
+
+    if (LockMutex(&session_mutex) != 0) {
+        CYASSL_MSG("Session cache mutex lock failed");
+        return BAD_MUTEX_ERROR;
+    }
+
+    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);
+
+    CYASSL_LEAVE("CyaSSL_memsave_session_cache", SSL_SUCCESS);
+
+    return SSL_SUCCESS; 
+}
+
+
+/* Restore the persistant session cache from memory */
+int CyaSSL_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
+
+    CYASSL_ENTER("CyaSSL_memrestore_session_cache");
+
+    if (sz < CyaSSL_get_session_cache_memsize()) {
+        CYASSL_MSG("Memory buffer too small");
+        return BUFFER_E;
+    }
+
+    XMEMCPY(&cache_header, mem, sizeof(cache_header));
+    if (cache_header.version   != CYASSL_CACHE_VERSION ||
+        cache_header.rows      != SESSION_ROWS ||
+        cache_header.columns   != SESSIONS_PER_ROW ||
+        cache_header.sessionSz != (int)sizeof(CYASSL_SESSION)) {
+
+        CYASSL_MSG("Session cache header match failed");
+        return CACHE_MATCH_ERROR;
+    }
+
+    if (LockMutex(&session_mutex) != 0) {
+        CYASSL_MSG("Session cache mutex lock failed");
+        return BAD_MUTEX_ERROR; 
+    }
+
+    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);
+
+    CYASSL_LEAVE("CyaSSL_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 CyaSSL_save_session_cache(const char *fname)
+{
+    XFILE  file; 
+    int    ret;
+    int    rc = SSL_SUCCESS;
+    int    i;
+    cache_header_t cache_header;
+
+    CYASSL_ENTER("CyaSSL_save_session_cache");
+
+    file = XFOPEN(fname, "w+b"); 
+    if (file == XBADFILE) {
+        CYASSL_MSG("Couldn't open session cache save file");
+        return SSL_BAD_FILE;
+    }
+    cache_header.version   = CYASSL_CACHE_VERSION;
+    cache_header.rows      = SESSION_ROWS;
+    cache_header.columns   = SESSIONS_PER_ROW;
+    cache_header.sessionSz = (int)sizeof(CYASSL_SESSION);
+
+    /* cache header */
+    ret = (int)XFWRITE(&cache_header, sizeof cache_header, 1, file);
+    if (ret != 1) {
+        CYASSL_MSG("Session cache header file write failed");
+        XFCLOSE(file);
+        return FWRITE_ERROR;
+    }
+
+    if (LockMutex(&session_mutex) != 0) {
+        CYASSL_MSG("Session cache mutex lock failed");
+        XFCLOSE(file);
+        return BAD_MUTEX_ERROR;
+    }
+
+    /* session cache */
+    for (i = 0; i < cache_header.rows; ++i) {
+        ret = (int)XFWRITE(SessionCache + i, sizeof(SessionRow), 1, file);
+        if (ret != 1) {
+            CYASSL_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) {
+            CYASSL_MSG("Client cache member file write failed");
+            rc = FWRITE_ERROR;
+            break;
+        }
+    }
+#endif /* NO_CLIENT_CACHE */
+
+    UnLockMutex(&session_mutex);
+
+    XFCLOSE(file);
+    CYASSL_LEAVE("CyaSSL_save_session_cache", rc);
+
+    return rc;
+}
+
+
+/* Restore the persistant session cache from file */
+/* doesn't use memstore because of additional memory use */
+int CyaSSL_restore_session_cache(const char *fname)
+{
+    XFILE  file; 
+    int    rc = SSL_SUCCESS; 
+    int    ret; 
+    int    i;
+    cache_header_t cache_header;
+
+    CYASSL_ENTER("CyaSSL_restore_session_cache");
+
+    file = XFOPEN(fname, "rb"); 
+    if (file == XBADFILE) {
+        CYASSL_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) {
+        CYASSL_MSG("Session cache header file read failed");
+        XFCLOSE(file);
+        return FREAD_ERROR;
+    }
+    if (cache_header.version   != CYASSL_CACHE_VERSION ||
+        cache_header.rows      != SESSION_ROWS ||
+        cache_header.columns   != SESSIONS_PER_ROW ||
+        cache_header.sessionSz != (int)sizeof(CYASSL_SESSION)) {
+
+        CYASSL_MSG("Session cache header match failed");
+        XFCLOSE(file);
+        return CACHE_MATCH_ERROR;
+    }
+
+    if (LockMutex(&session_mutex) != 0) {
+        CYASSL_MSG("Session cache mutex lock failed");
+        XFCLOSE(file);
+        return BAD_MUTEX_ERROR; 
+    }
+
+    /* session cache */
+    for (i = 0; i < cache_header.rows; ++i) {
+        ret = (int)XFREAD(SessionCache + i, sizeof(SessionRow), 1, file);
+        if (ret != 1) {
+            CYASSL_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) {
+            CYASSL_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);
+    CYASSL_LEAVE("CyaSSL_restore_session_cache", rc);
+
+    return rc;
+}
+
+#endif /* !NO_FILESYSTEM */
+#endif /* PERSIST_SESSION_CACHE */
+#endif /* NO_SESSION_CACHE */
+
+
+void CyaSSL_load_error_strings(void)   /* compatibility only */
+{}
+
+
+int CyaSSL_library_init(void)
+{
+    CYASSL_ENTER("SSL_library_init");
+    if (CyaSSL_Init() == SSL_SUCCESS)
+        return SSL_SUCCESS;
+    else
+        return SSL_FATAL_ERROR;
+}
+
+
+#ifndef NO_SESSION_CACHE
+
+/* on by default if built in but allow user to turn off */
+long CyaSSL_CTX_set_session_cache_mode(CYASSL_CTX* ctx, long mode)
+{
+    CYASSL_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 CYASSL_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 CYASSL_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 += 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(CYASSL_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(CYASSL_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(CYASSL_CERT_MANAGER* cm, byte* current, 
+                                 int row, int listSz, const byte* end)
+{
+    int idx = 0;
+
+    if (listSz < 0) {
+        CYASSL_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 += sizeof(signer->subjectKeyIdHash);
+        #endif
+
+        if (start + minSz > end) {
+            CYASSL_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 += sizeof(signer->pubKeySize);
+
+        /* keyOID */
+        XMEMCPY(&signer->keyOID, current + idx, sizeof(signer->keyOID));
+        idx += sizeof(signer->keyOID);
+    
+        /* pulicKey */
+        if (start + minSz + signer->pubKeySize > end) {
+            CYASSL_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 += sizeof(signer->nameLen);
+
+        /* name */
+        if (start + minSz + signer->pubKeySize + signer->nameLen > end) {
+            CYASSL_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(CYASSL_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 += sizeof(list->pubKeySize);
+
+        XMEMCPY(current + added, &list->keyOID,     sizeof(list->keyOID));
+        added += sizeof(list->keyOID);
+
+        XMEMCPY(current + added, list->publicKey, list->pubKeySize);
+        added += list->pubKeySize;
+
+        XMEMCPY(current + added, &list->nameLen, sizeof(list->nameLen));
+        added += 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(CYASSL_CERT_MANAGER* cm, void* mem, int sz)
+{
+    int realSz;
+    int ret = SSL_SUCCESS;
+    int i;
+
+    CYASSL_ENTER("DoMemSaveCertCache");
+
+    realSz = GetCertCacheMemSize(cm);
+    if (realSz > sz) {
+        CYASSL_MSG("Mem output buffer too small");
+        ret = BUFFER_E;
+    }
+    else {
+        byte*           current;
+        CertCacheHeader hdr;
+
+        hdr.version  = CYASSL_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(CYASSL_CERT_MANAGER* cm, const char* fname)
+{
+    XFILE file;
+    int   rc = SSL_SUCCESS;
+    int   memSz;
+    byte* mem;
+
+    CYASSL_ENTER("CM_SaveCertCache");
+
+    file = XFOPEN(fname, "w+b");
+    if (file == XBADFILE) {
+       CYASSL_MSG("Couldn't open cert cache save file");
+       return SSL_BAD_FILE;
+    }
+
+    if (LockMutex(&cm->caLock) != 0) {
+        CYASSL_MSG("LockMutex on caLock failed");
+        XFCLOSE(file);
+        return BAD_MUTEX_ERROR;
+    }
+
+    memSz = GetCertCacheMemSize(cm);
+    mem   = (byte*)XMALLOC(memSz, cm->heap, DYNAMIC_TYPE_TMP_BUFFER);    
+    if (mem == NULL) {
+        CYASSL_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) {
+                CYASSL_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(CYASSL_CERT_MANAGER* cm, const char* fname)
+{
+    XFILE file;
+    int   rc = SSL_SUCCESS;
+    int   ret;
+    int   memSz;
+    byte* mem;
+
+    CYASSL_ENTER("CM_RestoreCertCache");
+
+    file = XFOPEN(fname, "rb");
+    if (file == XBADFILE) {
+       CYASSL_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) {
+        CYASSL_MSG("Bad file size");
+        XFCLOSE(file);
+        return SSL_BAD_FILE;
+    }
+
+    mem = (byte*)XMALLOC(memSz, cm->heap, DYNAMIC_TYPE_TMP_BUFFER);
+    if (mem == NULL) {
+        CYASSL_MSG("Alloc for tmp buffer failed");
+        XFCLOSE(file);
+        return MEMORY_E;
+    }
+
+    ret = (int)XFREAD(mem, memSz, 1, file);
+    if (ret != 1) {
+        CYASSL_MSG("Cert file read error");
+        rc = FREAD_ERROR;
+    } else {
+        rc = CM_MemRestoreCertCache(cm, mem, memSz);
+        if (rc != SSL_SUCCESS) {
+            CYASSL_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(CYASSL_CERT_MANAGER* cm, void* mem, int sz, int* used)
+{
+    int ret = SSL_SUCCESS;
+
+    CYASSL_ENTER("CM_MemSaveCertCache");
+
+    if (LockMutex(&cm->caLock) != 0) {
+        CYASSL_MSG("LockMutex on caLock failed");
+        return BAD_MUTEX_ERROR;
+    }
+
+    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(CYASSL_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 */
+
+    CYASSL_ENTER("CM_MemRestoreCertCache");
+
+    if (current > end) {
+        CYASSL_MSG("Cert Cache Memory buffer too small");
+        return BUFFER_E;
+    }
+
+    if (hdr->version  != CYASSL_CACHE_CERT_VERSION ||
+        hdr->rows     != CA_TABLE_SIZE ||
+        hdr->signerSz != (int)sizeof(Signer)) {
+
+        CYASSL_MSG("Cert Cache Memory header mismatch");
+        return CACHE_MATCH_ERROR;
+    }
+
+    if (LockMutex(&cm->caLock) != 0) {
+        CYASSL_MSG("LockMutex on caLock failed");
+        return BAD_MUTEX_ERROR;
+    }
+
+    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) {
+            CYASSL_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(CYASSL_CERT_MANAGER* cm)
+{
+    int sz;
+
+    CYASSL_ENTER("CM_GetCertCacheMemSize");
+
+    if (LockMutex(&cm->caLock) != 0) {
+        CYASSL_MSG("LockMutex on caLock failed");
+        return BAD_MUTEX_ERROR;
+    }
+
+    sz = GetCertCacheMemSize(cm);
+
+    UnLockMutex(&cm->caLock);
+
+    return sz;
+}
+
+#endif /* PERSIST_CERT_CACHE */
+#endif /* NO_CERTS */
+
+
+int CyaSSL_CTX_set_cipher_list(CYASSL_CTX* ctx, const char* list)
+{
+    CYASSL_ENTER("CyaSSL_CTX_set_cipher_list");
+    if (SetCipherList(&ctx->suites, list))
+        return SSL_SUCCESS;
+    else
+        return SSL_FAILURE;
+}
+
+
+int CyaSSL_set_cipher_list(CYASSL* ssl, const char* list)
+{
+    CYASSL_ENTER("CyaSSL_set_cipher_list");
+    if (SetCipherList(ssl->suites, list)) {
+        byte haveRSA = 1;
+        byte havePSK = 0;
+
+        #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;
+    }
+    else
+        return SSL_FAILURE;
+}
+
+
+#ifndef CYASSL_LEANPSK
+#ifdef CYASSL_DTLS
+
+int CyaSSL_dtls_get_current_timeout(CYASSL* ssl)
+{
+    (void)ssl;
+
+    return ssl->dtls_timeout;
+}
+
+
+/* user may need to alter init dtls recv timeout, SSL_SUCCESS on ok */
+int CyaSSL_dtls_set_timeout_init(CYASSL* ssl, int timeout)
+{
+    if (ssl == NULL || timeout < 0)
+        return BAD_FUNC_ARG;
+
+    ssl->dtls_timeout_init = timeout;
+
+    return SSL_SUCCESS;
+}
+
+
+/* user may need to alter max dtls recv timeout, SSL_SUCCESS on ok */
+int CyaSSL_dtls_set_timeout_max(CYASSL* ssl, int timeout)
+{
+    if (ssl == NULL || timeout < 0)
+        return BAD_FUNC_ARG;
+
+    if (ssl->dtls_timeout_max < ssl->dtls_timeout_init) {
+        CYASSL_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 CyaSSL_dtls_got_timeout(CYASSL* 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_CYASSL_CLIENT
+
+    #ifndef NO_OLD_TLS
+    CYASSL_METHOD* CyaSSLv3_client_method(void)
+    {
+        CYASSL_METHOD* method =
+                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+        CYASSL_ENTER("SSLv3_client_method");
+        if (method)
+            InitSSL_Method(method, MakeSSLv3());
+        return method;
+    }
+    #endif
+
+    #ifdef CYASSL_DTLS
+        CYASSL_METHOD* CyaDTLSv1_client_method(void)
+        {
+            CYASSL_METHOD* method =
+                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+            CYASSL_ENTER("DTLSv1_client_method");
+            if (method)
+                InitSSL_Method(method, MakeDTLSv1());
+            return method;
+        }
+
+        CYASSL_METHOD* CyaDTLSv1_2_client_method(void)
+        {
+            CYASSL_METHOD* method =
+                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+            CYASSL_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 CyaSSL_connect(CYASSL* ssl)
+    {
+        int neededState;
+
+        CYASSL_ENTER("SSL_connect()");
+
+        #ifdef HAVE_ERRNO_H 
+            errno = 0;
+        #endif
+
+        if (ssl->options.side != CLIENT_END) {
+            CYASSL_ERROR(ssl->error = SIDE_ERROR);
+            return SSL_FATAL_ERROR;
+        }
+
+        #ifdef CYASSL_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;
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            }
+        #endif
+
+        if (ssl->buffers.outputBuffer.length > 0) {
+            if ( (ssl->error = SendBuffered(ssl)) == 0) {
+                ssl->options.connectState++;
+                CYASSL_MSG("connect state: Advanced from buffered send");
+            }
+            else {
+                CYASSL_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) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.connectState = CLIENT_HELLO_SENT;
+            CYASSL_MSG("connect state: CLIENT_HELLO_SENT");
+
+        case CLIENT_HELLO_SENT :
+            neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE :
+                                          SERVER_HELLODONE_COMPLETE;
+            #ifdef CYASSL_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) {
+                    CYASSL_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;
+            CYASSL_MSG("connect state: HELLO_AGAIN");
+
+        case HELLO_AGAIN :
+            if (ssl->options.certOnly)
+                return SSL_SUCCESS;
+
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls) {
+                    /* re-init hashes, exclude first hello and verify request */
+#ifndef NO_OLD_TLS
+                    InitMd5(&ssl->hashMd5);
+                    InitSha(&ssl->hashSha);
+#endif
+                    if (IsAtLeastTLSv1_2(ssl)) {
+                        #ifndef NO_SHA256
+                            InitSha256(&ssl->hashSha256);
+                        #endif
+                        #ifdef CYASSL_SHA384
+                            InitSha384(&ssl->hashSha384);
+                        #endif
+                    }
+                    if ( (ssl->error = SendClientHello(ssl)) != 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+                }
+            #endif
+
+            ssl->options.connectState = HELLO_AGAIN_REPLY;
+            CYASSL_MSG("connect state: HELLO_AGAIN_REPLY");
+
+        case HELLO_AGAIN_REPLY :
+            #ifdef CYASSL_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) {
+                                CYASSL_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;
+            CYASSL_MSG("connect state: FIRST_REPLY_DONE");
+
+        case FIRST_REPLY_DONE :
+            #ifndef NO_CERTS
+                if (ssl->options.sendVerify) {
+                    if ( (ssl->error = SendCertificate(ssl)) != 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+                    CYASSL_MSG("sent: certificate");
+                }
+                
+            #endif
+            ssl->options.connectState = FIRST_REPLY_FIRST;
+            CYASSL_MSG("connect state: FIRST_REPLY_FIRST");
+
+        case FIRST_REPLY_FIRST :
+            if (!ssl->options.resuming) {
+                if ( (ssl->error = SendClientKeyExchange(ssl)) != 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+                CYASSL_MSG("sent: client key exchange");
+            }
+
+            ssl->options.connectState = FIRST_REPLY_SECOND;
+            CYASSL_MSG("connect state: FIRST_REPLY_SECOND");
+
+        case FIRST_REPLY_SECOND :
+            #ifndef NO_CERTS
+                if (ssl->options.sendVerify) {
+                    if ( (ssl->error = SendCertificateVerify(ssl)) != 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+                    CYASSL_MSG("sent: certificate verify");
+                }
+            #endif
+            ssl->options.connectState = FIRST_REPLY_THIRD;
+            CYASSL_MSG("connect state: FIRST_REPLY_THIRD");
+
+        case FIRST_REPLY_THIRD :
+            if ( (ssl->error = SendChangeCipher(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            CYASSL_MSG("sent: change cipher spec");
+            ssl->options.connectState = FIRST_REPLY_FOURTH;
+            CYASSL_MSG("connect state: FIRST_REPLY_FOURTH");
+
+        case FIRST_REPLY_FOURTH :
+            if ( (ssl->error = SendFinished(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            CYASSL_MSG("sent: finished");
+            ssl->options.connectState = FINISHED_DONE;
+            CYASSL_MSG("connect state: FINISHED_DONE");
+
+        case FINISHED_DONE :
+            /* get response */
+            while (ssl->options.serverState < SERVER_FINISHED_COMPLETE)
+                if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+          
+            ssl->options.connectState = SECOND_REPLY_DONE;
+            CYASSL_MSG("connect state: SECOND_REPLY_DONE");
+
+        case SECOND_REPLY_DONE:
+            FreeHandshakeResources(ssl);
+            CYASSL_LEAVE("SSL_connect()", SSL_SUCCESS);
+            return SSL_SUCCESS;
+
+        default:
+            CYASSL_MSG("Unknown connect state ERROR");
+            return SSL_FATAL_ERROR; /* unknown connect state */
+        }
+    }
+
+#endif /* NO_CYASSL_CLIENT */
+
+
+/* server only parts */
+#ifndef NO_CYASSL_SERVER
+
+    #ifndef NO_OLD_TLS
+    CYASSL_METHOD* CyaSSLv3_server_method(void)
+    {
+        CYASSL_METHOD* method =
+                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+        CYASSL_ENTER("SSLv3_server_method");
+        if (method) {
+            InitSSL_Method(method, MakeSSLv3());
+            method->side = SERVER_END;
+        }
+        return method;
+    }
+    #endif
+
+
+    #ifdef CYASSL_DTLS
+        CYASSL_METHOD* CyaDTLSv1_server_method(void)
+        {
+            CYASSL_METHOD* method =
+                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+            CYASSL_ENTER("DTLSv1_server_method");
+            if (method) {
+                InitSSL_Method(method, MakeDTLSv1());
+                method->side = SERVER_END;
+            }
+            return method;
+        }
+
+        CYASSL_METHOD* CyaDTLSv1_2_server_method(void)
+        {
+            CYASSL_METHOD* method =
+                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+            CYASSL_ENTER("DTLSv1_2_server_method");
+            if (method) {
+                InitSSL_Method(method, MakeDTLSv1_2());
+                method->side = SERVER_END;
+            }
+            return method;
+        }
+    #endif
+
+
+    int CyaSSL_accept(CYASSL* ssl)
+    {
+        byte havePSK = 0;
+        CYASSL_ENTER("SSL_accept()");
+
+        #ifdef HAVE_ERRNO_H 
+            errno = 0;
+        #endif
+
+        #ifndef NO_PSK
+            havePSK = ssl->options.havePSK;
+        #endif
+        (void)havePSK;
+
+        if (ssl->options.side != SERVER_END) {
+            CYASSL_ERROR(ssl->error = SIDE_ERROR);
+            return SSL_FATAL_ERROR;
+        }
+
+        #ifndef NO_CERTS
+            /* in case used set_accept_state after init */
+            if (!havePSK && (ssl->buffers.certificate.buffer == NULL ||
+                             ssl->buffers.key.buffer == NULL)) {
+                CYASSL_MSG("accept error: don't have server cert and key");
+                ssl->error = NO_PRIVATE_KEY;
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+        #endif
+
+        #ifdef HAVE_ECC
+            /* in case used set_accept_state after init */
+            if (ssl->eccTempKeyPresent == 0) {
+                if (ecc_make_key(ssl->rng, ssl->eccTempKeySz,
+                                 ssl->eccTempKey) != 0) {
+                    ssl->error = ECC_MAKEKEY_ERROR;
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR; 
+                } 
+                ssl->eccTempKeyPresent = 1;
+            }
+        #endif
+
+        #ifdef CYASSL_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;
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            }
+        #endif
+
+        if (ssl->buffers.outputBuffer.length > 0) {
+            if ( (ssl->error = SendBuffered(ssl)) == 0) {
+                ssl->options.acceptState++;
+                CYASSL_MSG("accept state: Advanced from buffered send");
+            }
+            else {
+                CYASSL_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) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            ssl->options.acceptState = ACCEPT_CLIENT_HELLO_DONE;
+            CYASSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE");
+
+        case ACCEPT_CLIENT_HELLO_DONE :
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls)
+                    if ( (ssl->error = SendHelloVerifyRequest(ssl)) != 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+            #endif
+            ssl->options.acceptState = HELLO_VERIFY_SENT;
+            CYASSL_MSG("accept state HELLO_VERIFY_SENT");
+
+        case HELLO_VERIFY_SENT:
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls) {
+                    ssl->options.clientState = NULL_STATE;  /* get again */
+                    /* re-init hashes, exclude first hello and verify request */
+#ifndef NO_OLD_TLS
+                    InitMd5(&ssl->hashMd5);
+                    InitSha(&ssl->hashSha);
+#endif
+                    if (IsAtLeastTLSv1_2(ssl)) {
+                        #ifndef NO_SHA256
+                             InitSha256(&ssl->hashSha256);
+                        #endif
+                        #ifdef CYASSL_SHA384
+                            InitSha384(&ssl->hashSha384);
+                        #endif
+                    }
+
+                    while (ssl->options.clientState < CLIENT_HELLO_COMPLETE)
+                        if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                            CYASSL_ERROR(ssl->error);
+                            return SSL_FATAL_ERROR;
+                        }
+                }
+            #endif
+            ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE;
+            CYASSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE");
+
+        case ACCEPT_FIRST_REPLY_DONE :
+            if ( (ssl->error = SendServerHello(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.acceptState = SERVER_HELLO_SENT;
+            CYASSL_MSG("accept state SERVER_HELLO_SENT");
+
+        case SERVER_HELLO_SENT :
+            #ifndef NO_CERTS
+                if (!ssl->options.resuming) 
+                    if ( (ssl->error = SendCertificate(ssl)) != 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+            #endif
+            ssl->options.acceptState = CERT_SENT;
+            CYASSL_MSG("accept state CERT_SENT");
+
+        case CERT_SENT :
+            if (!ssl->options.resuming) 
+                if ( (ssl->error = SendServerKeyExchange(ssl)) != 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            ssl->options.acceptState = KEY_EXCHANGE_SENT;
+            CYASSL_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) {
+                            CYASSL_ERROR(ssl->error);
+                            return SSL_FATAL_ERROR;
+                        }
+            #endif
+            ssl->options.acceptState = CERT_REQ_SENT;
+            CYASSL_MSG("accept state CERT_REQ_SENT");
+
+        case CERT_REQ_SENT :
+            if (!ssl->options.resuming) 
+                if ( (ssl->error = SendServerHelloDone(ssl)) != 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            ssl->options.acceptState = SERVER_HELLO_DONE;
+            CYASSL_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) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+            }
+            ssl->options.acceptState = ACCEPT_SECOND_REPLY_DONE;
+            CYASSL_MSG("accept state  ACCEPT_SECOND_REPLY_DONE");
+          
+        case ACCEPT_SECOND_REPLY_DONE : 
+            if ( (ssl->error = SendChangeCipher(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.acceptState = CHANGE_CIPHER_SENT;
+            CYASSL_MSG("accept state  CHANGE_CIPHER_SENT");
+
+        case CHANGE_CIPHER_SENT : 
+            if ( (ssl->error = SendFinished(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+
+            ssl->options.acceptState = ACCEPT_FINISHED_DONE;
+            CYASSL_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) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+
+            ssl->options.acceptState = ACCEPT_THIRD_REPLY_DONE;
+            CYASSL_MSG("accept state ACCEPT_THIRD_REPLY_DONE");
+
+        case ACCEPT_THIRD_REPLY_DONE :
+            FreeHandshakeResources(ssl);
+            CYASSL_LEAVE("SSL_accept()", SSL_SUCCESS);
+            return SSL_SUCCESS;
+
+        default :
+            CYASSL_MSG("Unknown accept state ERROR");
+            return SSL_FATAL_ERROR;
+        }
+    }
+
+#endif /* NO_CYASSL_SERVER */
+
+
+int CyaSSL_Cleanup(void)
+{
+    int ret = SSL_SUCCESS;
+    int release = 0;
+
+    CYASSL_ENTER("CyaSSL_Cleanup");
+
+    if (initRefCount == 0)
+        return ret;  /* possibly no init yet, but not failure either way */
+
+    if (LockMutex(&count_mutex) != 0) {
+        CYASSL_MSG("Bad Lock Mutex count");
+        return BAD_MUTEX_ERROR;
+    }
+
+    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_ERROR;
+#endif
+    if (FreeMutex(&count_mutex) != 0)
+        ret = BAD_MUTEX_ERROR;
+
+    return ret;
+}
+
+
+#ifndef NO_SESSION_CACHE
+
+#ifndef NO_MD5
+
+/* some session IDs aren't random afterall, let's make them random */
+
+static INLINE word32 HashSession(const byte* sessionID, word32 len)
+{
+    byte digest[MD5_DIGEST_SIZE];
+    Md5  md5;
+
+    InitMd5(&md5);
+    Md5Update(&md5, sessionID, len);
+    Md5Final(&md5, digest);
+
+    return MakeWordFromHash(digest);
+}
+
+#elif !defined(NO_SHA)
+
+static INLINE word32 HashSession(const byte* sessionID, word32 len)
+{
+    byte digest[SHA_DIGEST_SIZE];
+    Sha  sha;
+
+    InitSha(&sha);
+    ShaUpdate(&sha, sessionID, len);
+    ShaFinal(&sha, digest);
+
+    return MakeWordFromHash(digest);
+}
+
+#elif !defined(NO_SHA256)
+
+static INLINE word32 HashSession(const byte* sessionID, word32 len)
+{
+    byte    digest[SHA256_DIGEST_SIZE];
+    Sha256  sha256;
+
+    InitSha256(&sha256);
+    Sha256Update(&sha256, sessionID, len);
+    Sha256Final(&sha256, digest);
+
+    return MakeWordFromHash(digest);
+}
+
+#else
+
+#error "We need a digest to hash the session IDs"
+
+#endif /* NO_MD5 */
+
+
+void CyaSSL_flush_sessions(CYASSL_CTX* ctx, long tm)
+{
+    /* static table now, no flusing needed */
+    (void)ctx;
+    (void)tm;
+}
+
+
+/* set ssl session timeout in seconds */
+int CyaSSL_set_timeout(CYASSL* ssl, unsigned int to)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    ssl->timeout = to;
+
+    return SSL_SUCCESS;
+}
+
+
+/* set ctx session timeout in seconds */
+int CyaSSL_CTX_set_timeout(CYASSL_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 */
+CYASSL_SESSION* GetSessionClient(CYASSL* ssl, const byte* id, int len)
+{
+    CYASSL_SESSION* ret = NULL;
+    word32          row;
+    int             idx;
+    int             count;
+
+    CYASSL_ENTER("GetSessionClient");
+
+    if (ssl->options.side == SERVER_END)
+        return NULL;
+
+    len = min(SERVER_ID_LEN, (word32)len);
+    row = HashSession(id, len) % SESSION_ROWS;
+
+    if (LockMutex(&session_mutex) != 0) {
+        CYASSL_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) {
+        CYASSL_SESSION* current;
+        ClientSession   clSess;
+
+        if (idx >= SESSIONS_PER_ROW || idx < 0) { /* sanity check */
+            CYASSL_MSG("Bad idx");
+            break;
+        }
+       
+        clSess = ClientCache[row].Clients[idx];
+
+        current = &SessionCache[clSess.serverRow].Sessions[clSess.serverIdx];
+        if (XMEMCMP(current->serverID, id, len) == 0) {
+            CYASSL_MSG("Found a serverid match for client");
+            if (LowResTimer() < (current->bornOn + current->timeout)) {
+                CYASSL_MSG("Session valid");
+                ret = current;
+                break;
+            } else {
+                CYASSL_MSG("Session timed out");  /* could have more for id */
+            }
+        } else {
+            CYASSL_MSG("ServerID not a match from client table");
+        }
+    }
+
+    UnLockMutex(&session_mutex);
+   
+    return ret; 
+}
+
+#endif /* NO_CLIENT_CACHE */
+
+
+CYASSL_SESSION* GetSession(CYASSL* ssl, byte* masterSecret)
+{
+    CYASSL_SESSION* ret = 0;
+    const byte*  id = NULL;
+    word32       row;
+    int          idx;
+    int          count;
+    
+    if (ssl->options.sessionCacheOff)
+        return NULL;
+
+    if (ssl->options.haveSessionId == 0)
+        return NULL;
+
+    if (ssl->arrays)
+        id = ssl->arrays->sessionID;
+    else
+        id = ssl->session.sessionID;
+
+    row = HashSession(id, ID_LEN) % SESSION_ROWS;
+
+    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) {
+        CYASSL_SESSION* current;
+        
+        if (idx >= SESSIONS_PER_ROW || idx < 0) { /* sanity check */
+            CYASSL_MSG("Bad idx");
+            break;
+        }
+
+        current = &SessionCache[row].Sessions[idx];
+        if (XMEMCMP(current->sessionID, id, ID_LEN) == 0) {
+            CYASSL_MSG("Found a session match");
+            if (LowResTimer() < (current->bornOn + current->timeout)) {
+                CYASSL_MSG("Session valid");
+                ret = current;
+                if (masterSecret)
+                    XMEMCPY(masterSecret, current->masterSecret, SECRET_LEN);
+            } else {
+                CYASSL_MSG("Session timed out");
+            }
+            break;  /* no more sessionIDs whether valid or not that match */
+        } else {
+            CYASSL_MSG("SessionID not a match at this idx");
+        }   
+    }
+
+    UnLockMutex(&session_mutex);
+    
+    return ret;
+}
+
+
+int SetSession(CYASSL* ssl, CYASSL_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 */
+}
+
+
+int AddSession(CYASSL* ssl)
+{
+    word32 row, idx;
+
+    if (ssl->options.sessionCacheOff)
+        return 0;
+
+    if (ssl->options.haveSessionId == 0)
+        return 0;
+
+    row = HashSession(ssl->arrays->sessionID, ID_LEN) % SESSION_ROWS;
+
+    if (LockMutex(&session_mutex) != 0)
+        return BAD_MUTEX_ERROR;
+
+    idx = SessionCache[row].nextIdx++;
+
+    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].timeout = ssl->timeout;
+    SessionCache[row].Sessions[idx].bornOn  = LowResTimer();
+
+#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 == CLIENT_END && ssl->session.idLen) {
+        word32 clientRow, clientIdx;
+
+        CYASSL_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)
+                                % SESSION_ROWS;
+        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 (UnLockMutex(&session_mutex) != 0)
+        return BAD_MUTEX_ERROR;
+
+    return 0;
+}
+
+
+    #ifdef SESSION_STATS
+
+    CYASSL_API
+    void PrintSessionStats(void)
+    {
+        word32 totalSessionsSeen = 0;
+        word32 totalSessionsNow = 0;
+        word32 rowNow;
+        int    i;
+        double E;               /* expected freq */
+        double chiSquare = 0;
+        
+        for (i = 0; i < SESSION_ROWS; i++) {
+            totalSessionsSeen += SessionCache[i].totalCount;
+
+            if (SessionCache[i].totalCount >= SESSIONS_PER_ROW)
+                rowNow = SESSIONS_PER_ROW;
+            else if (SessionCache[i].nextIdx == 0)
+                rowNow = 0;
+            else
+                rowNow = SessionCache[i].nextIdx;
+        
+            totalSessionsNow += rowNow;
+        }
+
+        printf("Total Sessions Seen = %d\n", totalSessionsSeen);
+        printf("Total Sessions Now  = %d\n", totalSessionsNow);
+
+        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");
+        else if (SESSION_ROWS == 211)
+            printf(".05 p value  = 244.8, chi-square should be less\n");
+        else if (SESSION_ROWS == 5981)
+            printf(".05 p value  = 6161.0, chi-square should be less\n");
+        else if (SESSION_ROWS == 3)
+            printf(".05 p value  =   6.0, chi-square should be less\n");
+        else if (SESSION_ROWS == 2861)
+            printf(".05 p value  = 2985.5, chi-square should be less\n");
+        printf("\n");
+    }
+
+    #endif /* SESSION_STATS */
+
+#else  /* NO_SESSION_CACHE */
+
+/* No session cache version */
+CYASSL_SESSION* GetSession(CYASSL* 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 CyaSSL_check_domain_name(CYASSL* ssl, const char* dn)
+{
+    CYASSL_ENTER("CyaSSL_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 CyaSSL zlib compression
+   returns SSL_SUCCESS for success, else error (not built in)
+*/
+int CyaSSL_set_compression(CYASSL* ssl)
+{
+    CYASSL_ENTER("CyaSSL_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 CyaSSL_writev(CYASSL* ssl, const struct iovec* iov, int iovcnt)
+        {
+            byte  tmp[FILE_BUFFER_SIZE];
+            byte* myBuffer    = tmp;
+            int   sending   = 0;
+            int   newBuffer = 0;
+            int   idx       = 0;
+            int   i;
+            int   ret;
+
+            CYASSL_ENTER("CyaSSL_writev");
+
+            for (i = 0; i < iovcnt; i++)
+                sending += (int)iov[i].iov_len;
+
+            if (sending > (int)sizeof(tmp)) {
+                byte* tmp2 = (byte*) XMALLOC(sending, ssl->heap,
+                                             DYNAMIC_TYPE_WRITEV);
+                if (!tmp2)
+                    return MEMORY_ERROR;
+                myBuffer = tmp2;
+                newBuffer = 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 = CyaSSL_write(ssl, myBuffer, sending);
+
+            if (newBuffer) XFREE(myBuffer, ssl->heap, DYNAMIC_TYPE_WRITEV);
+
+            return ret;
+        }
+    #endif
+#endif
+
+
+#ifdef CYASSL_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 CyaSSL_ex_wrapper(CYASSL* 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_CYASSL_CLIENT
+        if (ssl->options.side == CLIENT_END)
+            ret = CyaSSL_connect(ssl);
+#endif
+#ifndef NO_CYASSL_SERVER
+        if (ssl->options.side == SERVER_END)
+            ret = CyaSSL_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_CYASSL_CLIENT
+
+    int CyaSSL_connect_ex(CYASSL* ssl, HandShakeCallBack hsCb,
+                          TimeoutCallBack toCb, Timeval timeout)
+    {
+        CYASSL_ENTER("CyaSSL_connect_ex");
+        return CyaSSL_ex_wrapper(ssl, hsCb, toCb, timeout);
+    }
+
+#endif
+
+
+#ifndef NO_CYASSL_SERVER
+
+    int CyaSSL_accept_ex(CYASSL* ssl, HandShakeCallBack hsCb,
+                         TimeoutCallBack toCb,Timeval timeout)
+    {
+        CYASSL_ENTER("CyaSSL_accept_ex");
+        return CyaSSL_ex_wrapper(ssl, hsCb, toCb, timeout);
+    }
+
+#endif
+
+#endif /* CYASSL_CALLBACKS */
+
+
+#ifndef NO_PSK
+
+    void CyaSSL_CTX_set_psk_client_callback(CYASSL_CTX* ctx,
+                                         psk_client_callback cb)
+    {
+        CYASSL_ENTER("SSL_CTX_set_psk_client_callback");
+        ctx->havePSK = 1;
+        ctx->client_psk_cb = cb;
+    }
+
+
+    void CyaSSL_set_psk_client_callback(CYASSL* ssl, psk_client_callback cb)
+    {
+        byte haveRSA = 1;
+
+        CYASSL_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 CyaSSL_CTX_set_psk_server_callback(CYASSL_CTX* ctx,
+                                         psk_server_callback cb)
+    {
+        CYASSL_ENTER("SSL_CTX_set_psk_server_callback");
+        ctx->havePSK = 1;
+        ctx->server_psk_cb = cb;
+    }
+
+
+    void CyaSSL_set_psk_server_callback(CYASSL* ssl, psk_server_callback cb)
+    {
+        byte haveRSA = 1;
+
+        CYASSL_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* CyaSSL_get_psk_identity_hint(const CYASSL* ssl)
+    {
+        CYASSL_ENTER("SSL_get_psk_identity_hint");
+
+        if (ssl == NULL || ssl->arrays == NULL)
+            return NULL;
+
+        return ssl->arrays->server_hint;
+    }
+
+
+    const char* CyaSSL_get_psk_identity(const CYASSL* ssl)
+    {
+        CYASSL_ENTER("SSL_get_psk_identity");
+
+        if (ssl == NULL || ssl->arrays == NULL)
+            return NULL;
+
+        return ssl->arrays->client_identity;
+    }
+
+
+    int CyaSSL_CTX_use_psk_identity_hint(CYASSL_CTX* ctx, const char* hint)
+    {
+        CYASSL_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 CyaSSL_use_psk_identity_hint(CYASSL* ssl, const char* hint)
+    {
+        CYASSL_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 */
+
+
+#ifndef NO_CERTS
+/* used to be defined on NO_FILESYSTEM only, but are generally useful */
+
+    /* CyaSSL extension allows DER files to be loaded from buffers as well */
+    int CyaSSL_CTX_load_verify_buffer(CYASSL_CTX* ctx, const unsigned char* in,
+                                      long sz, int format)
+    {
+        CYASSL_ENTER("CyaSSL_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 CyaSSL_CTX_use_certificate_buffer(CYASSL_CTX* ctx,
+                                 const unsigned char* in, long sz, int format)
+    {
+        CYASSL_ENTER("CyaSSL_CTX_use_certificate_buffer");
+        return ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 0);
+    }
+
+
+    int CyaSSL_CTX_use_PrivateKey_buffer(CYASSL_CTX* ctx,
+                                 const unsigned char* in, long sz, int format)
+    {
+        CYASSL_ENTER("CyaSSL_CTX_use_PrivateKey_buffer");
+        return ProcessBuffer(ctx, in, sz, format, PRIVATEKEY_TYPE, NULL,NULL,0);
+    }
+
+
+    int CyaSSL_CTX_use_certificate_chain_buffer(CYASSL_CTX* ctx,
+                                 const unsigned char* in, long sz)
+    {
+        CYASSL_ENTER("CyaSSL_CTX_use_certificate_chain_buffer");
+        return ProcessBuffer(ctx, in, sz, SSL_FILETYPE_PEM, CERT_TYPE, NULL,
+                             NULL, 1);
+    }
+
+    int CyaSSL_use_certificate_buffer(CYASSL* ssl,
+                                 const unsigned char* in, long sz, int format)
+    {
+        CYASSL_ENTER("CyaSSL_use_certificate_buffer");
+        return ProcessBuffer(ssl->ctx, in, sz, format,CERT_TYPE,ssl,NULL,0);
+    }
+
+
+    int CyaSSL_use_PrivateKey_buffer(CYASSL* ssl,
+                                 const unsigned char* in, long sz, int format)
+    {
+        CYASSL_ENTER("CyaSSL_use_PrivateKey_buffer");
+        return ProcessBuffer(ssl->ctx, in, sz, format, PRIVATEKEY_TYPE, 
+                             ssl, NULL, 0);
+    }
+
+
+    int CyaSSL_use_certificate_chain_buffer(CYASSL* ssl,
+                                 const unsigned char* in, long sz)
+    {
+        CYASSL_ENTER("CyaSSL_use_certificate_chain_buffer");
+        return ProcessBuffer(ssl->ctx, in, sz, SSL_FILETYPE_PEM, CERT_TYPE,
+                             ssl, NULL, 1);
+    }
+
+    int CyaSSL_CTX_UnloadCAs(CYASSL_CTX* ctx)
+    {
+        CYASSL_ENTER("CyaSSL_CTX_UnloadCAs");
+
+        if (ctx == NULL)
+            return BAD_FUNC_ARG;
+
+        return CyaSSL_CertManagerUnloadCAs(ctx->cm);
+    }
+
+/* old NO_FILESYSTEM end */
+#endif /* !NO_CERTS */
+
+
+#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+
+
+    int CyaSSL_add_all_algorithms(void)
+    {
+        CYASSL_ENTER("CyaSSL_add_all_algorithms");
+        CyaSSL_Init();
+        return SSL_SUCCESS;
+    }
+
+
+    long CyaSSL_CTX_sess_set_cache_size(CYASSL_CTX* ctx, long sz)
+    {
+        /* cache size fixed at compile time in CyaSSL */
+        (void)ctx;
+        (void)sz;
+        return 0;
+    }
+
+
+    void CyaSSL_CTX_set_quiet_shutdown(CYASSL_CTX* ctx, int mode)
+    {
+        CYASSL_ENTER("CyaSSL_CTX_set_quiet_shutdown");
+        if (mode)
+            ctx->quietShutdown = 1;
+    }
+
+
+    void CyaSSL_set_quiet_shutdown(CYASSL* ssl, int mode)
+    {
+        CYASSL_ENTER("CyaSSL_CTX_set_quiet_shutdown");
+        if (mode)
+            ssl->options.quietShutdown = 1;
+    }
+
+
+    void CyaSSL_set_bio(CYASSL* ssl, CYASSL_BIO* rd, CYASSL_BIO* wr)
+    {
+        CYASSL_ENTER("SSL_set_bio");
+        CyaSSL_set_rfd(ssl, rd->fd);
+        CyaSSL_set_wfd(ssl, wr->fd);
+
+        ssl->biord = rd;
+        ssl->biowr = wr;
+    }
+
+
+    void CyaSSL_CTX_set_client_CA_list(CYASSL_CTX* ctx,
+                                       STACK_OF(CYASSL_X509_NAME)* names)
+    {
+        (void)ctx; 
+        (void)names; 
+    }
+
+
+    STACK_OF(CYASSL_X509_NAME)* CyaSSL_load_client_CA_file(const char* fname)
+    {
+        (void)fname;
+        return 0;
+    }
+
+
+    int CyaSSL_CTX_set_default_verify_paths(CYASSL_CTX* ctx)
+    {
+        /* TODO:, not needed in goahead */
+        (void)ctx; 
+        return SSL_NOT_IMPLEMENTED;
+    }
+
+
+    /* keyblock size in bytes or -1 */
+    int CyaSSL_get_keyblock_size(CYASSL* 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 CyaSSL_get_keys(CYASSL* 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 CyaSSL_set_accept_state(CYASSL* ssl)
+    {
+        byte haveRSA = 1;
+        byte havePSK = 0;
+
+        CYASSL_ENTER("SSL_set_accept_state");
+        ssl->options.side = 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 CyaSSL_is_init_finished(CYASSL* ssl)
+    {
+        if (ssl == NULL)
+            return 0;
+
+        if (ssl->options.handShakeState == HANDSHAKE_DONE)
+            return 1;
+
+        return 0;
+    }
+
+#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+    void CyaSSL_CTX_set_tmp_rsa_callback(CYASSL_CTX* ctx,
+                                      CYASSL_RSA*(*f)(CYASSL*, int, int))
+    {
+        /* CyaSSL verifies all these internally */   
+        (void)ctx; 
+        (void)f; 
+    }
+
+
+    void CyaSSL_set_shutdown(CYASSL* ssl, int opt)
+    {
+        (void)ssl; 
+        (void)opt; 
+    }
+
+
+    long CyaSSL_CTX_set_options(CYASSL_CTX* ctx, long opt)
+    {
+        /* goahead calls with 0, do nothing */ 
+        CYASSL_ENTER("SSL_CTX_set_options");
+        (void)ctx; 
+        return opt;
+    }
+
+
+    int CyaSSL_set_rfd(CYASSL* ssl, int rfd)
+    {
+        CYASSL_ENTER("SSL_set_rfd");
+        ssl->rfd = rfd;      /* not used directly to allow IO callbacks */
+
+        ssl->IOCB_ReadCtx  = &ssl->rfd;
+
+        return SSL_SUCCESS;
+    }
+
+
+    int CyaSSL_set_wfd(CYASSL* ssl, int wfd)
+    {
+        CYASSL_ENTER("SSL_set_wfd");
+        ssl->wfd = wfd;      /* not used directly to allow IO callbacks */
+
+        ssl->IOCB_WriteCtx  = &ssl->wfd;
+
+        return SSL_SUCCESS;
+    }
+
+
+    CYASSL_RSA* CyaSSL_RSA_generate_key(int len, unsigned long bits,
+                                          void(*f)(int, int, void*), void* data)
+    {
+        /* no tmp key needed, actual generation not supported */
+        CYASSL_ENTER("RSA_generate_key");
+        (void)len; 
+        (void)bits; 
+        (void)f; 
+        (void)data; 
+        return NULL;
+    }
+
+
+
+    CYASSL_X509* CyaSSL_X509_STORE_CTX_get_current_cert(
+                                                     CYASSL_X509_STORE_CTX* ctx)
+    {
+        (void)ctx; 
+        return 0;
+    }
+
+
+    int CyaSSL_X509_STORE_CTX_get_error(CYASSL_X509_STORE_CTX* ctx)
+    {
+        (void)ctx; 
+        return 0;
+    }
+
+
+    int CyaSSL_X509_STORE_CTX_get_error_depth(CYASSL_X509_STORE_CTX* ctx)
+    {
+        (void)ctx; 
+        return 0;
+    }
+
+
+    CYASSL_BIO_METHOD* CyaSSL_BIO_f_buffer(void)
+    {
+        static CYASSL_BIO_METHOD meth;
+
+        CYASSL_ENTER("BIO_f_buffer");
+        meth.type = BIO_BUFFER;
+
+        return &meth;
+    }
+
+
+    long CyaSSL_BIO_set_write_buffer_size(CYASSL_BIO* bio, long size)
+    {
+        /* CyaSSL has internal buffer, compatibility only */
+        CYASSL_ENTER("BIO_set_write_buffer_size");
+        (void)bio; 
+        return size; 
+    }
+
+
+    CYASSL_BIO_METHOD* CyaSSL_BIO_f_ssl(void)
+    {
+        static CYASSL_BIO_METHOD meth;
+
+        CYASSL_ENTER("BIO_f_ssl");
+        meth.type = BIO_SSL;
+
+        return &meth;
+    }
+
+
+    CYASSL_BIO* CyaSSL_BIO_new_socket(int sfd, int closeF)
+    {
+        CYASSL_BIO* bio = (CYASSL_BIO*) XMALLOC(sizeof(CYASSL_BIO), 0,
+                                                DYNAMIC_TYPE_OPENSSL);
+
+        CYASSL_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 CyaSSL_BIO_eof(CYASSL_BIO* b)
+    {
+        CYASSL_ENTER("BIO_eof");
+        if (b->eof)
+            return 1;
+
+        return 0;        
+    }
+
+
+    long CyaSSL_BIO_set_ssl(CYASSL_BIO* b, CYASSL* ssl, int closeF)
+    {
+        CYASSL_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;
+    }
+
+
+    CYASSL_BIO* CyaSSL_BIO_new(CYASSL_BIO_METHOD* method)
+    {
+        CYASSL_BIO* bio = (CYASSL_BIO*) XMALLOC(sizeof(CYASSL_BIO), 0,
+                                                DYNAMIC_TYPE_OPENSSL);
+        CYASSL_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 CyaSSL_BIO_get_mem_data(CYASSL_BIO* bio, const byte** p)
+    {
+        if (bio == NULL || p == NULL)
+            return SSL_FATAL_ERROR;
+
+        *p = bio->mem;
+
+        return bio->memLen;
+    }
+
+
+    CYASSL_BIO* CyaSSL_BIO_new_mem_buf(void* buf, int len)
+    {
+        CYASSL_BIO* bio = NULL;
+        if (buf == NULL)
+            return bio;
+
+        bio = CyaSSL_BIO_new(CyaSSL_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(CYASSL_MDK_ARM)
+    #define CloseSocket(s) closesocket(s)
+#else
+    #define CloseSocket(s) close(s)
+#endif
+
+    int CyaSSL_BIO_free(CYASSL_BIO* bio)
+    {
+        /* unchain?, doesn't matter in goahead since from free all */
+        CYASSL_ENTER("BIO_free");
+        if (bio) {
+            if (bio->close) {
+                if (bio->ssl)
+                    CyaSSL_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 CyaSSL_BIO_free_all(CYASSL_BIO* bio)
+    {
+        CYASSL_ENTER("BIO_free_all");
+        while (bio) {
+            CYASSL_BIO* next = bio->next;
+            CyaSSL_BIO_free(bio);
+            bio = next;
+        }
+        return 0;
+    }
+
+
+    int CyaSSL_BIO_read(CYASSL_BIO* bio, void* buf, int len)
+    {
+        int  ret;
+        CYASSL* ssl = 0;
+        CYASSL_BIO* front = bio;
+
+        CYASSL_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 = CyaSSL_read(ssl, buf, len);
+        if (ret == 0)
+            front->eof = 1;
+        else if (ret < 0) {
+            int err = CyaSSL_get_error(ssl, 0);
+            if ( !(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) )
+                front->eof = 1;
+        }
+        return ret;
+    }
+
+
+    int CyaSSL_BIO_write(CYASSL_BIO* bio, const void* data, int len)
+    {
+        int  ret;
+        CYASSL* ssl = 0;
+        CYASSL_BIO* front = bio;
+
+        CYASSL_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 = CyaSSL_write(ssl, data, len);
+        if (ret == 0)
+            front->eof = 1;
+        else if (ret < 0) {
+            int err = CyaSSL_get_error(ssl, 0);
+            if ( !(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) )
+                front->eof = 1;
+        }
+
+        return ret;
+    }
+
+
+    CYASSL_BIO* CyaSSL_BIO_push(CYASSL_BIO* top, CYASSL_BIO* append)
+    {
+        CYASSL_ENTER("BIO_push");
+        top->next    = append;
+        append->prev = top;
+
+        return top;
+    }
+
+
+    int CyaSSL_BIO_flush(CYASSL_BIO* bio)
+    {
+        /* for CyaSSL no flushing needed */
+        CYASSL_ENTER("BIO_flush");
+        (void)bio; 
+        return 1;
+    }
+
+
+#endif /* OPENSSL_EXTRA || GOAHEAD_WS */
+
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+
+    void CyaSSL_CTX_set_default_passwd_cb_userdata(CYASSL_CTX* ctx,
+                                                   void* userdata)
+    {
+        CYASSL_ENTER("SSL_CTX_set_default_passwd_cb_userdata");
+        ctx->userdata = userdata;
+    }
+
+
+    void CyaSSL_CTX_set_default_passwd_cb(CYASSL_CTX* ctx, pem_password_cb cb)
+    {
+        CYASSL_ENTER("SSL_CTX_set_default_passwd_cb");
+        ctx->passwd_cb = cb;
+    }
+
+    int CyaSSL_num_locks(void)
+    {
+        return 0;
+    }
+
+    void CyaSSL_set_locking_callback(void (*f)(int, int, const char*, int))
+    {
+        (void)f; 
+    }
+
+    void CyaSSL_set_id_callback(unsigned long (*f)(void))
+    {
+        (void)f; 
+    }
+
+    unsigned long CyaSSL_ERR_get_error(void)
+    {
+        /* TODO: */
+        return 0;
+    }
+
+    int CyaSSL_EVP_BytesToKey(const CYASSL_EVP_CIPHER* type,
+                       const CYASSL_EVP_MD* md, const byte* salt,
+                       const byte* data, int sz, int count, byte* key, byte* iv)
+    {
+        int keyLen = 0;
+        int ivLen  = 0;
+
+        Md5    myMD;
+        byte   digest[MD5_DIGEST_SIZE];
+
+        int j;
+        int keyLeft;
+        int ivLeft;
+        int keyOutput = 0;
+
+        CYASSL_ENTER("EVP_BytesToKey");
+        InitMd5(&myMD);
+
+        /* 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
+            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 */
+                Md5Update(&myMD, digest, MD5_DIGEST_SIZE);
+            /* data */
+            Md5Update(&myMD, data, sz);
+            /* salt */
+            if (salt)
+                Md5Update(&myMD, salt, EVP_SALT_SIZE);
+            Md5Final(&myMD, digest);
+            /* count */
+            for (j = 1; j < count; j++) {
+                Md5Update(&myMD, digest, MD5_DIGEST_SIZE);
+                Md5Final(&myMD, 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;
+            }
+        }
+        if (keyOutput != (keyLen + ivLen))
+            return 0;
+        return keyOutput;
+    }
+
+#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */
+
+
+#ifdef OPENSSL_EXTRA
+
+    unsigned long CyaSSLeay(void)
+    {
+        return SSLEAY_VERSION_NUMBER;
+    }
+
+
+    const char* CyaSSLeay_version(int type)
+    {
+        static const char* version = "SSLeay CyaSSL compatibility";
+        (void)type; 
+        return version;
+    }
+
+
+    void CyaSSL_MD5_Init(CYASSL_MD5_CTX* md5)
+    {
+        typedef char md5_test[sizeof(MD5_CTX) >= sizeof(Md5) ? 1 : -1];
+        (void)sizeof(md5_test);
+
+        CYASSL_ENTER("MD5_Init");
+        InitMd5((Md5*)md5);
+    }
+
+
+    void CyaSSL_MD5_Update(CYASSL_MD5_CTX* md5, const void* input,
+                           unsigned long sz)
+    {
+        CYASSL_ENTER("CyaSSL_MD5_Update");
+        Md5Update((Md5*)md5, (const byte*)input, (word32)sz);
+    }
+
+
+    void CyaSSL_MD5_Final(byte* input, CYASSL_MD5_CTX* md5)
+    {
+        CYASSL_ENTER("MD5_Final");
+        Md5Final((Md5*)md5, input);
+    }
+
+
+    void CyaSSL_SHA_Init(CYASSL_SHA_CTX* sha)
+    {
+        typedef char sha_test[sizeof(SHA_CTX) >= sizeof(Sha) ? 1 : -1];
+        (void)sizeof(sha_test);
+
+        CYASSL_ENTER("SHA_Init");
+        InitSha((Sha*)sha);
+    }
+
+
+    void CyaSSL_SHA_Update(CYASSL_SHA_CTX* sha, const void* input,
+                           unsigned long sz)
+    {
+        CYASSL_ENTER("SHA_Update");
+        ShaUpdate((Sha*)sha, (const byte*)input, (word32)sz);
+    }
+
+
+    void CyaSSL_SHA_Final(byte* input, CYASSL_SHA_CTX* sha)
+    {
+        CYASSL_ENTER("SHA_Final");
+        ShaFinal((Sha*)sha, input);
+    }
+
+
+    void CyaSSL_SHA1_Init(CYASSL_SHA_CTX* sha)
+    {
+        CYASSL_ENTER("SHA1_Init");
+        SHA_Init(sha);
+    }
+
+
+    void CyaSSL_SHA1_Update(CYASSL_SHA_CTX* sha, const void* input,
+                            unsigned long sz)
+    {
+        CYASSL_ENTER("SHA1_Update");
+        SHA_Update(sha, input, sz);
+    }
+
+
+    void CyaSSL_SHA1_Final(byte* input, CYASSL_SHA_CTX* sha)
+    {
+        CYASSL_ENTER("SHA1_Final");
+        SHA_Final(input, sha);
+    }
+
+
+    void CyaSSL_SHA256_Init(CYASSL_SHA256_CTX* sha256)
+    {
+        typedef char sha_test[sizeof(SHA256_CTX) >= sizeof(Sha256) ? 1 : -1];
+        (void)sizeof(sha_test);
+
+        CYASSL_ENTER("SHA256_Init");
+        InitSha256((Sha256*)sha256);
+    }
+
+
+    void CyaSSL_SHA256_Update(CYASSL_SHA256_CTX* sha, const void* input,
+                              unsigned long sz)
+    {
+        CYASSL_ENTER("SHA256_Update");
+        Sha256Update((Sha256*)sha, (const byte*)input, (word32)sz);
+    }
+
+
+    void CyaSSL_SHA256_Final(byte* input, CYASSL_SHA256_CTX* sha)
+    {
+        CYASSL_ENTER("SHA256_Final");
+        Sha256Final((Sha256*)sha, input);
+    }
+
+
+    #ifdef CYASSL_SHA384
+
+    void CyaSSL_SHA384_Init(CYASSL_SHA384_CTX* sha)
+    {
+        typedef char sha_test[sizeof(SHA384_CTX) >= sizeof(Sha384) ? 1 : -1];
+        (void)sizeof(sha_test);
+
+        CYASSL_ENTER("SHA384_Init");
+        InitSha384((Sha384*)sha);
+    }
+
+
+    void CyaSSL_SHA384_Update(CYASSL_SHA384_CTX* sha, const void* input,
+                           unsigned long sz)
+    {
+        CYASSL_ENTER("SHA384_Update");
+        Sha384Update((Sha384*)sha, (const byte*)input, (word32)sz);
+    }
+
+
+    void CyaSSL_SHA384_Final(byte* input, CYASSL_SHA384_CTX* sha)
+    {
+        CYASSL_ENTER("SHA384_Final");
+        Sha384Final((Sha384*)sha, input);
+    }
+
+    #endif /* CYASSL_SHA384 */
+
+
+   #ifdef CYASSL_SHA512
+
+    void CyaSSL_SHA512_Init(CYASSL_SHA512_CTX* sha)
+    {
+        typedef char sha_test[sizeof(SHA512_CTX) >= sizeof(Sha512) ? 1 : -1];
+        (void)sizeof(sha_test);
+
+        CYASSL_ENTER("SHA512_Init");
+        InitSha512((Sha512*)sha);
+    }
+
+
+    void CyaSSL_SHA512_Update(CYASSL_SHA512_CTX* sha, const void* input,
+                           unsigned long sz)
+    {
+        CYASSL_ENTER("SHA512_Update");
+        Sha512Update((Sha512*)sha, (const byte*)input, (word32)sz);
+    }
+
+
+    void CyaSSL_SHA512_Final(byte* input, CYASSL_SHA512_CTX* sha)
+    {
+        CYASSL_ENTER("SHA512_Final");
+        Sha512Final((Sha512*)sha, input);
+    }
+
+    #endif /* CYASSL_SHA512 */
+
+
+    const CYASSL_EVP_MD* CyaSSL_EVP_md5(void)
+    {
+        static const char* type = "MD5";
+        CYASSL_ENTER("EVP_md5");
+        return type;
+    }
+
+
+    const CYASSL_EVP_MD* CyaSSL_EVP_sha1(void)
+    {
+        static const char* type = "SHA";
+        CYASSL_ENTER("EVP_sha1");
+        return type;
+    }
+
+
+    const CYASSL_EVP_MD* CyaSSL_EVP_sha256(void)
+    {
+        static const char* type = "SHA256";
+        CYASSL_ENTER("EVP_sha256");
+        return type;
+    }
+
+    #ifdef CYASSL_SHA384
+
+    const CYASSL_EVP_MD* CyaSSL_EVP_sha384(void)
+    {
+        static const char* type = "SHA384";
+        CYASSL_ENTER("EVP_sha384");
+        return type;
+    }
+
+    #endif /* CYASSL_SHA384 */
+
+    #ifdef CYASSL_SHA512
+
+    const CYASSL_EVP_MD* CyaSSL_EVP_sha512(void)
+    {
+        static const char* type = "SHA512";
+        CYASSL_ENTER("EVP_sha512");
+        return type;
+    }
+
+    #endif /* CYASSL_SHA512 */
+
+
+    void CyaSSL_EVP_MD_CTX_init(CYASSL_EVP_MD_CTX* ctx)
+    {
+        CYASSL_ENTER("EVP_CIPHER_MD_CTX_init");
+        (void)ctx; 
+        /* do nothing */ 
+    }
+
+
+    const CYASSL_EVP_CIPHER* CyaSSL_EVP_aes_128_cbc(void)
+    {
+        static const char* type = "AES128-CBC";
+        CYASSL_ENTER("CyaSSL_EVP_aes_128_cbc");
+        return type;
+    }
+
+
+    const CYASSL_EVP_CIPHER* CyaSSL_EVP_aes_192_cbc(void)
+    {
+        static const char* type = "AES192-CBC";
+        CYASSL_ENTER("CyaSSL_EVP_aes_192_cbc");
+        return type;
+    }
+
+
+    const CYASSL_EVP_CIPHER* CyaSSL_EVP_aes_256_cbc(void)
+    {
+        static const char* type = "AES256-CBC";
+        CYASSL_ENTER("CyaSSL_EVP_aes_256_cbc");
+        return type;
+    }
+
+
+    const CYASSL_EVP_CIPHER* CyaSSL_EVP_aes_128_ctr(void)
+    {
+        static const char* type = "AES128-CTR";
+        CYASSL_ENTER("CyaSSL_EVP_aes_128_ctr");
+        return type;
+    }
+
+
+    const CYASSL_EVP_CIPHER* CyaSSL_EVP_aes_192_ctr(void)
+    {
+        static const char* type = "AES192-CTR";
+        CYASSL_ENTER("CyaSSL_EVP_aes_192_ctr");
+        return type;
+    }
+
+
+    const CYASSL_EVP_CIPHER* CyaSSL_EVP_aes_256_ctr(void)
+    {
+        static const char* type = "AES256-CTR";
+        CYASSL_ENTER("CyaSSL_EVP_aes_256_ctr");
+        return type;
+    }
+
+
+    const CYASSL_EVP_CIPHER* CyaSSL_EVP_des_cbc(void)
+    {
+        static const char* type = "DES-CBC";
+        CYASSL_ENTER("CyaSSL_EVP_des_cbc");
+        return type;
+    }
+
+
+    const CYASSL_EVP_CIPHER* CyaSSL_EVP_des_ede3_cbc(void)
+    {
+        static const char* type = "DES-EDE3-CBC";
+        CYASSL_ENTER("CyaSSL_EVP_des_ede3_cbc");
+        return type;
+    }
+
+
+    const CYASSL_EVP_CIPHER* CyaSSL_EVP_rc4(void)
+    {
+        static const char* type = "ARC4";
+        CYASSL_ENTER("CyaSSL_EVP_rc4");
+        return type;
+    }
+
+
+    const CYASSL_EVP_CIPHER* CyaSSL_EVP_enc_null(void)
+    {
+        static const char* type = "NULL";
+        CYASSL_ENTER("CyaSSL_EVP_enc_null");
+        return type;
+    }
+
+
+    int CyaSSL_EVP_MD_CTX_cleanup(CYASSL_EVP_MD_CTX* ctx)
+    {
+        CYASSL_ENTER("EVP_MD_CTX_cleanup");
+        (void)ctx; 
+        return 0;
+    }
+
+
+
+    void CyaSSL_EVP_CIPHER_CTX_init(CYASSL_EVP_CIPHER_CTX* ctx)
+    {
+        CYASSL_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 CyaSSL_EVP_CIPHER_CTX_cleanup(CYASSL_EVP_CIPHER_CTX* ctx)
+    {
+        CYASSL_ENTER("EVP_CIPHER_CTX_cleanup");
+        if (ctx) {
+            ctx->cipherType = 0xff;  /* no more init */
+            ctx->keyLen     = 0;
+        }
+
+        return SSL_SUCCESS;
+    }    
+
+
+    /* SSL_SUCCESS on ok */
+    int  CyaSSL_EVP_CipherInit(CYASSL_EVP_CIPHER_CTX* ctx,
+                               const CYASSL_EVP_CIPHER* type, byte* key,
+                               byte* iv, int enc)
+    {
+        CYASSL_ENTER("CyaSSL_EVP_CipherInit");
+        if (ctx == NULL) {
+            CYASSL_MSG("no ctx");
+            return 0;   /* failure */
+        }
+
+        if (type == NULL && ctx->cipherType == 0xff) {
+            CYASSL_MSG("no type set");
+            return 0;   /* failure */
+        }
+
+        if (ctx->cipherType == AES_128_CBC_TYPE || (type &&
+                                       XSTRNCMP(type, "AES128-CBC", 10) == 0)) {
+            CYASSL_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)
+                AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                          ctx->enc ? AES_ENCRYPTION : AES_DECRYPTION);
+            if (iv && key == NULL)
+                AesSetIV(&ctx->cipher.aes, iv);
+        }
+        else if (ctx->cipherType == AES_192_CBC_TYPE || (type &&
+                                       XSTRNCMP(type, "AES192-CBC", 10) == 0)) {
+            CYASSL_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)
+                AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                          ctx->enc ? AES_ENCRYPTION : AES_DECRYPTION);
+            if (iv && key == NULL)
+                AesSetIV(&ctx->cipher.aes, iv);
+        }
+        else if (ctx->cipherType == AES_256_CBC_TYPE || (type &&
+                                       XSTRNCMP(type, "AES256-CBC", 10) == 0)) {
+            CYASSL_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)
+                AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                          ctx->enc ? AES_ENCRYPTION : AES_DECRYPTION);
+            if (iv && key == NULL)
+                AesSetIV(&ctx->cipher.aes, iv);
+        }
+#ifdef CYASSL_AES_COUNTER
+        else if (ctx->cipherType == AES_128_CTR_TYPE || (type &&
+                                       XSTRNCMP(type, "AES128-CTR", 10) == 0)) {
+            CYASSL_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)
+                AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                          AES_ENCRYPTION);
+            if (iv && key == NULL)
+                AesSetIV(&ctx->cipher.aes, iv);
+        }
+        else if (ctx->cipherType == AES_192_CTR_TYPE || (type &&
+                                       XSTRNCMP(type, "AES192-CTR", 10) == 0)) {
+            CYASSL_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)
+                AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                          AES_ENCRYPTION);
+            if (iv && key == NULL)
+                AesSetIV(&ctx->cipher.aes, iv);
+        }
+        else if (ctx->cipherType == AES_256_CTR_TYPE || (type &&
+                                       XSTRNCMP(type, "AES256-CTR", 10) == 0)) {
+            CYASSL_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)
+                AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                          AES_ENCRYPTION);
+            if (iv && key == NULL)
+                AesSetIV(&ctx->cipher.aes, iv);
+        }
+#endif /* CYASSL_AES_CTR */
+        else if (ctx->cipherType == DES_CBC_TYPE || (type &&
+                                       XSTRNCMP(type, "DES-CBC", 7) == 0)) {
+            CYASSL_MSG("DES-CBC");
+            ctx->cipherType = DES_CBC_TYPE;
+            ctx->keyLen     = 8;
+            if (enc == 0 || enc == 1)
+                ctx->enc = enc ? 1 : 0;
+            if (key)
+                Des_SetKey(&ctx->cipher.des, key, iv,
+                          ctx->enc ? DES_ENCRYPTION : DES_DECRYPTION);
+            if (iv && key == NULL)
+                Des_SetIV(&ctx->cipher.des, iv);
+        }
+        else if (ctx->cipherType == DES_EDE3_CBC_TYPE || (type &&
+                                     XSTRNCMP(type, "DES-EDE3-CBC", 11) == 0)) {
+            CYASSL_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)
+                Des3_SetKey(&ctx->cipher.des3, key, iv,
+                          ctx->enc ? DES_ENCRYPTION : DES_DECRYPTION);
+            if (iv && key == NULL)
+                Des3_SetIV(&ctx->cipher.des3, iv);
+        }
+        else if (ctx->cipherType == ARC4_TYPE || (type &&
+                                     XSTRNCMP(type, "ARC4", 4) == 0)) {
+            CYASSL_MSG("ARC4");
+            ctx->cipherType = ARC4_TYPE;
+            if (ctx->keyLen == 0)  /* user may have already set */
+                ctx->keyLen = 16;  /* default to 128 */
+            if (key)
+                Arc4SetKey(&ctx->cipher.arc4, key, ctx->keyLen); 
+        }
+        else if (ctx->cipherType == NULL_CIPHER_TYPE || (type &&
+                                     XSTRNCMP(type, "NULL", 4) == 0)) {
+            CYASSL_MSG("NULL cipher");
+            ctx->cipherType = NULL_CIPHER_TYPE;
+            ctx->keyLen = 0; 
+        }
+        else
+            return 0;   /* failure */
+
+
+        return SSL_SUCCESS;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_EVP_CIPHER_CTX_key_length(CYASSL_EVP_CIPHER_CTX* ctx)
+    {
+        CYASSL_ENTER("CyaSSL_EVP_CIPHER_CTX_key_length");
+        if (ctx)
+            return ctx->keyLen;
+
+        return 0;   /* failure */
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_EVP_CIPHER_CTX_set_key_length(CYASSL_EVP_CIPHER_CTX* ctx,
+                                             int keylen)
+    {
+        CYASSL_ENTER("CyaSSL_EVP_CIPHER_CTX_set_key_length");
+        if (ctx)
+            ctx->keyLen = keylen;
+        else
+            return 0;  /* failure */
+
+        return SSL_SUCCESS;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_EVP_Cipher(CYASSL_EVP_CIPHER_CTX* ctx, byte* dst, byte* src,
+                          word32 len)
+    {
+        int ret = 0;
+        CYASSL_ENTER("CyaSSL_EVP_Cipher");
+
+        if (ctx == NULL || dst == NULL || src == NULL) {
+            CYASSL_MSG("Bad function argument");
+            return 0;  /* failure */
+        }
+
+        if (ctx->cipherType == 0xff) { 
+            CYASSL_MSG("no init");
+            return 0;  /* failure */
+        }
+
+        switch (ctx->cipherType) {
+
+            case AES_128_CBC_TYPE :
+            case AES_192_CBC_TYPE :
+            case AES_256_CBC_TYPE :
+                CYASSL_MSG("AES CBC");
+                if (ctx->enc)
+                    ret = AesCbcEncrypt(&ctx->cipher.aes, dst, src, len);
+                else
+                    ret = AesCbcDecrypt(&ctx->cipher.aes, dst, src, len);
+                break;
+
+#ifdef CYASSL_AES_COUNTER
+            case AES_128_CTR_TYPE :
+            case AES_192_CTR_TYPE :
+            case AES_256_CTR_TYPE :
+                    CYASSL_MSG("AES CTR");
+                    AesCtrEncrypt(&ctx->cipher.aes, dst, src, len);
+                break;
+#endif
+
+            case DES_CBC_TYPE :
+                if (ctx->enc)
+                    Des_CbcEncrypt(&ctx->cipher.des, dst, src, len);
+                else
+                    Des_CbcDecrypt(&ctx->cipher.des, dst, src, len);
+                break;
+                
+            case DES_EDE3_CBC_TYPE :
+                if (ctx->enc)
+                    Des3_CbcEncrypt(&ctx->cipher.des3, dst, src, len);
+                else
+                    Des3_CbcDecrypt(&ctx->cipher.des3, dst, src, len);
+                break;
+
+            case ARC4_TYPE :
+                Arc4Process(&ctx->cipher.arc4, dst, src, len);
+                break;
+
+            case NULL_CIPHER_TYPE :
+                XMEMCPY(dst, src, len);
+                break;
+
+            default: {
+                CYASSL_MSG("bad type");
+                return 0;  /* failure */
+            }
+        }
+
+        if (ret != 0) {
+            CYASSL_MSG("CyaSSL_EVP_Cipher failure");
+            return 0;  /* failuer */ 
+        }
+
+        CYASSL_MSG("CyaSSL_EVP_Cipher success");
+        return SSL_SUCCESS;  /* success */ 
+    }
+
+
+    /* store for external read of iv, SSL_SUCCESS on success */
+    int  CyaSSL_StoreExternalIV(CYASSL_EVP_CIPHER_CTX* ctx)
+    {
+        CYASSL_ENTER("CyaSSL_StoreExternalIV");
+
+        if (ctx == NULL) {
+            CYASSL_MSG("Bad function argument");
+            return SSL_FATAL_ERROR;
+        }
+    
+        switch (ctx->cipherType) {
+
+            case AES_128_CBC_TYPE :
+            case AES_192_CBC_TYPE :
+            case AES_256_CBC_TYPE :
+                CYASSL_MSG("AES CBC");
+                memcpy(ctx->iv, &ctx->cipher.aes.reg, AES_BLOCK_SIZE);
+                break;
+
+#ifdef CYASSL_AES_COUNTER
+            case AES_128_CTR_TYPE :
+            case AES_192_CTR_TYPE :
+            case AES_256_CTR_TYPE :
+                CYASSL_MSG("AES CTR");
+                memcpy(ctx->iv, &ctx->cipher.aes.reg, AES_BLOCK_SIZE);
+                break;
+#endif
+
+            case DES_CBC_TYPE :
+                CYASSL_MSG("DES CBC");
+                memcpy(ctx->iv, &ctx->cipher.des.reg, DES_BLOCK_SIZE);
+                break;
+                
+            case DES_EDE3_CBC_TYPE :
+                CYASSL_MSG("DES EDE3 CBC");
+                memcpy(ctx->iv, &ctx->cipher.des.reg, DES_BLOCK_SIZE);
+                break;
+
+            case ARC4_TYPE :
+                CYASSL_MSG("ARC4");
+                break;
+
+            case NULL_CIPHER_TYPE :
+                CYASSL_MSG("NULL");
+                break;
+
+            default: {
+                CYASSL_MSG("bad type");
+                return SSL_FATAL_ERROR;
+            }
+        }    
+        return SSL_SUCCESS;
+    }
+
+
+    /* set internal IV from external, SSL_SUCCESS on success */
+    int  CyaSSL_SetInternalIV(CYASSL_EVP_CIPHER_CTX* ctx)
+    {
+
+        CYASSL_ENTER("CyaSSL_SetInternalIV");
+
+        if (ctx == NULL) {
+            CYASSL_MSG("Bad function argument");
+            return SSL_FATAL_ERROR;
+        }
+    
+        switch (ctx->cipherType) {
+
+            case AES_128_CBC_TYPE :
+            case AES_192_CBC_TYPE :
+            case AES_256_CBC_TYPE :
+                CYASSL_MSG("AES CBC");
+                memcpy(&ctx->cipher.aes.reg, ctx->iv, AES_BLOCK_SIZE);
+                break;
+
+#ifdef CYASSL_AES_COUNTER
+            case AES_128_CTR_TYPE :
+            case AES_192_CTR_TYPE :
+            case AES_256_CTR_TYPE :
+                CYASSL_MSG("AES CTR");
+                memcpy(&ctx->cipher.aes.reg, ctx->iv, AES_BLOCK_SIZE);
+                break;
+#endif
+
+            case DES_CBC_TYPE :
+                CYASSL_MSG("DES CBC");
+                memcpy(&ctx->cipher.des.reg, ctx->iv, DES_BLOCK_SIZE);
+                break;
+                
+            case DES_EDE3_CBC_TYPE :
+                CYASSL_MSG("DES EDE3 CBC");
+                memcpy(&ctx->cipher.des.reg, ctx->iv, DES_BLOCK_SIZE);
+                break;
+
+            case ARC4_TYPE :
+                CYASSL_MSG("ARC4");
+                break;
+
+            case NULL_CIPHER_TYPE :
+                CYASSL_MSG("NULL");
+                break;
+
+            default: {
+                CYASSL_MSG("bad type");
+                return SSL_FATAL_ERROR;
+            }
+        }    
+        return SSL_SUCCESS;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_EVP_DigestInit(CYASSL_EVP_MD_CTX* ctx, const CYASSL_EVP_MD* type)
+    {
+        CYASSL_ENTER("EVP_DigestInit");
+        if (XSTRNCMP(type, "MD5", 3) == 0) {
+             ctx->macType = MD5;
+             CyaSSL_MD5_Init((MD5_CTX*)&ctx->hash);
+        }
+        else if (XSTRNCMP(type, "SHA256", 6) == 0) {
+             ctx->macType = SHA256;
+             CyaSSL_SHA256_Init((SHA256_CTX*)&ctx->hash);
+        }
+    #ifdef CYASSL_SHA384
+        else if (XSTRNCMP(type, "SHA384", 6) == 0) {
+             ctx->macType = SHA384;
+             CyaSSL_SHA384_Init((SHA384_CTX*)&ctx->hash);
+        }
+    #endif
+    #ifdef CYASSL_SHA512
+        else if (XSTRNCMP(type, "SHA512", 6) == 0) {
+             ctx->macType = SHA512;
+             CyaSSL_SHA512_Init((SHA512_CTX*)&ctx->hash);
+        }
+    #endif
+        /* has to be last since would pick or 256, 384, or 512 too */
+        else if (XSTRNCMP(type, "SHA", 3) == 0) {
+             ctx->macType = SHA;
+             CyaSSL_SHA_Init((SHA_CTX*)&ctx->hash);
+        }    
+        else
+             return BAD_FUNC_ARG;
+
+        return SSL_SUCCESS;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_EVP_DigestUpdate(CYASSL_EVP_MD_CTX* ctx, const void* data,
+                                unsigned long sz)
+    {
+        CYASSL_ENTER("EVP_DigestUpdate");
+        if (ctx->macType == MD5) 
+            CyaSSL_MD5_Update((MD5_CTX*)&ctx->hash, data, (unsigned long)sz);
+        else if (ctx->macType == SHA) 
+            CyaSSL_SHA_Update((SHA_CTX*)&ctx->hash, data, (unsigned long)sz);
+        else if (ctx->macType == SHA256) 
+            CyaSSL_SHA256_Update((SHA256_CTX*)&ctx->hash, data,
+                                 (unsigned long)sz);
+    #ifdef CYASSL_SHA384
+        else if (ctx->macType == SHA384) 
+            CyaSSL_SHA384_Update((SHA384_CTX*)&ctx->hash, data,
+                                 (unsigned long)sz);
+    #endif
+    #ifdef CYASSL_SHA512
+        else if (ctx->macType == SHA512) 
+            CyaSSL_SHA512_Update((SHA512_CTX*)&ctx->hash, data,
+                                 (unsigned long)sz);
+    #endif
+        else
+            return BAD_FUNC_ARG;
+
+        return SSL_SUCCESS;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_EVP_DigestFinal(CYASSL_EVP_MD_CTX* ctx, unsigned char* md,
+                               unsigned int* s)
+    {
+        CYASSL_ENTER("EVP_DigestFinal");
+        if (ctx->macType == MD5) {
+            CyaSSL_MD5_Final(md, (MD5_CTX*)&ctx->hash);
+            if (s) *s = MD5_DIGEST_SIZE;
+        }
+        else if (ctx->macType == SHA) {
+            CyaSSL_SHA_Final(md, (SHA_CTX*)&ctx->hash);
+            if (s) *s = SHA_DIGEST_SIZE;
+        }
+        else if (ctx->macType == SHA256) {
+            CyaSSL_SHA256_Final(md, (SHA256_CTX*)&ctx->hash);
+            if (s) *s = SHA256_DIGEST_SIZE;
+        }
+    #ifdef CYASSL_SHA384
+        else if (ctx->macType == SHA384) {
+            CyaSSL_SHA384_Final(md, (SHA384_CTX*)&ctx->hash);
+            if (s) *s = SHA384_DIGEST_SIZE;
+        }
+    #endif
+    #ifdef CYASSL_SHA512
+        else if (ctx->macType == SHA512) {
+            CyaSSL_SHA512_Final(md, (SHA512_CTX*)&ctx->hash);
+            if (s) *s = SHA512_DIGEST_SIZE;
+        }
+    #endif
+        else
+            return BAD_FUNC_ARG;
+
+        return SSL_SUCCESS;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_EVP_DigestFinal_ex(CYASSL_EVP_MD_CTX* ctx, unsigned char* md,
+                                  unsigned int* s)
+    {
+        CYASSL_ENTER("EVP_DigestFinal_ex");
+        return EVP_DigestFinal(ctx, md, s);
+    }
+
+
+    unsigned char* CyaSSL_HMAC(const CYASSL_EVP_MD* evp_md, const void* key,
+                               int key_len, const unsigned char* d, int n,
+                               unsigned char* md, unsigned int* md_len)
+    {
+        Hmac hmac;
+
+        CYASSL_ENTER("HMAC");
+        if (!md) return 0;  /* no static buffer support */
+
+        if (XSTRNCMP(evp_md, "MD5", 3) == 0) {
+            HmacSetKey(&hmac, MD5, (const byte*)key, key_len);
+            if (md_len) *md_len = MD5_DIGEST_SIZE;
+        }
+        else if (XSTRNCMP(evp_md, "SHA", 3) == 0) {
+            HmacSetKey(&hmac, SHA, (const byte*)key, key_len);    
+            if (md_len) *md_len = SHA_DIGEST_SIZE;
+        }
+        else
+            return 0;
+
+        HmacUpdate(&hmac, d, n);
+        HmacFinal(&hmac, md);
+    
+        return md;
+    }
+
+    void CyaSSL_ERR_clear_error(void)
+    {
+        /* TODO: */
+    }
+
+
+    int CyaSSL_RAND_status(void)
+    {
+        return SSL_SUCCESS;  /* CTaoCrypt provides enough seed internally */
+    }
+
+
+
+    void CyaSSL_RAND_add(const void* add, int len, double entropy)
+    {
+        (void)add;
+        (void)len;
+        (void)entropy;
+
+        /* CyaSSL seeds/adds internally, use explicit RNG if you want
+           to take control */
+    }
+
+    
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_DES_key_sched(CYASSL_const_DES_cblock* key,
+                             CYASSL_DES_key_schedule* schedule)
+    {
+        CYASSL_ENTER("DES_key_sched");
+        XMEMCPY(schedule, key, sizeof(const_DES_cblock));
+        return SSL_SUCCESS;
+    }
+
+
+    void CyaSSL_DES_cbc_encrypt(const unsigned char* input,
+                     unsigned char* output, long length,
+                     CYASSL_DES_key_schedule* schedule, CYASSL_DES_cblock* ivec,
+                     int enc)
+    {
+        Des myDes;
+        CYASSL_ENTER("DES_cbc_encrypt");
+        Des_SetKey(&myDes, (const byte*)schedule, (const byte*)ivec, !enc);
+
+        if (enc)
+            Des_CbcEncrypt(&myDes, output, input, (word32)length);
+        else
+            Des_CbcDecrypt(&myDes, output, input, (word32)length);
+    }
+
+
+    /* correctly sets ivec for next call */
+    void CyaSSL_DES_ncbc_encrypt(const unsigned char* input,
+                     unsigned char* output, long length,
+                     CYASSL_DES_key_schedule* schedule, CYASSL_DES_cblock* ivec,
+                     int enc)
+    {
+        Des myDes;
+        CYASSL_ENTER("DES_ncbc_encrypt");
+        Des_SetKey(&myDes, (const byte*)schedule, (const byte*)ivec, !enc);
+
+        if (enc)
+            Des_CbcEncrypt(&myDes, output, input, (word32)length);
+        else
+            Des_CbcDecrypt(&myDes, output, input, (word32)length);
+
+        XMEMCPY(ivec, output + length - sizeof(DES_cblock), sizeof(DES_cblock));
+    }
+
+
+    void CyaSSL_ERR_free_strings(void)
+    {
+        /* handled internally */
+    }
+
+
+    void CyaSSL_ERR_remove_state(unsigned long state)
+    {
+        /* TODO: GetErrors().Remove(); */
+        (void)state; 
+    }
+
+
+    void CyaSSL_EVP_cleanup(void)
+    {
+        /* nothing to do here */
+    }
+
+
+    void CyaSSL_cleanup_all_ex_data(void)
+    {
+        /* nothing to do here */
+    }
+
+
+    long CyaSSL_CTX_set_mode(CYASSL_CTX* ctx, long mode)
+    {
+        /* SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER is CyaSSL default mode */
+
+        CYASSL_ENTER("SSL_CTX_set_mode");
+        if (mode == SSL_MODE_ENABLE_PARTIAL_WRITE)
+            ctx->partialWrite = 1;
+
+        return mode;
+    }
+
+
+    long CyaSSL_CTX_get_mode(CYASSL_CTX* ctx)
+    {
+        /* TODO: */
+        (void)ctx; 
+        return 0;
+    }
+
+
+    void CyaSSL_CTX_set_default_read_ahead(CYASSL_CTX* ctx, int m)
+    {
+        /* TODO: maybe? */
+        (void)ctx; 
+        (void)m; 
+    }
+
+
+    int CyaSSL_CTX_set_session_id_context(CYASSL_CTX* ctx,
+                                       const unsigned char* sid_ctx,
+                                       unsigned int sid_ctx_len)
+    {
+        /* No application specific context needed for cyaSSL */
+        (void)ctx; 
+        (void)sid_ctx; 
+        (void)sid_ctx_len; 
+        return SSL_SUCCESS;
+    }
+
+
+    long CyaSSL_CTX_sess_get_cache_size(CYASSL_CTX* ctx)
+    {
+        /* TODO: maybe? */
+        (void)ctx; 
+        return (~0);
+    }
+
+    unsigned long CyaSSL_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)
+
+    CYASSL_X509* CyaSSL_get_peer_certificate(CYASSL* ssl)
+    {
+        CYASSL_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 CyaSSL_FreeX509(CYASSL_X509* x509)
+    {
+        CYASSL_ENTER("CyaSSL_FreeX509");
+        FreeX509(x509); 
+    }
+
+
+    /* return the next, if any, altname from the peer cert */
+    char* CyaSSL_X509_get_next_altname(CYASSL_X509* cert)
+    {
+        char* ret = NULL;
+        CYASSL_ENTER("CyaSSL_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;
+    }
+
+
+    CYASSL_X509_NAME* CyaSSL_X509_get_issuer_name(CYASSL_X509* cert)
+    {
+        CYASSL_ENTER("X509_get_issuer_name");
+        return &cert->issuer;
+    }
+
+
+    CYASSL_X509_NAME* CyaSSL_X509_get_subject_name(CYASSL_X509* cert)
+    {
+        CYASSL_ENTER("X509_get_subject_name");
+        return &cert->subject;
+    }
+
+
+    /* copy name into in buffer, at most sz bytes, if buffer is null will
+       malloc buffer, call responsible for freeing                     */
+    char* CyaSSL_X509_NAME_oneline(CYASSL_X509_NAME* name, char* in, int sz)
+    {
+        int copySz = min(sz, name->sz);
+
+        CYASSL_ENTER("CyaSSL_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;
+    }
+
+
+    /* 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 CyaSSL_X509_get_serial_number(CYASSL_X509* x509, byte* in, int* inOutSz)
+    {
+        CYASSL_ENTER("CyaSSL_X509_get_serial_number");
+        if (x509 == NULL || in == NULL || *inOutSz < x509->serialSz)
+            return BAD_FUNC_ARG;
+
+        XMEMCPY(in, x509->serial, x509->serialSz);
+        *inOutSz = x509->serialSz;
+
+        return SSL_SUCCESS;
+    }
+
+
+    const byte* CyaSSL_X509_get_der(CYASSL_X509* x509, int* outSz)
+    { 
+        CYASSL_ENTER("CyaSSL_X509_get_der");
+        
+        if (x509 == NULL || outSz == NULL)
+            return NULL;
+
+        *outSz = (int)x509->derCert.length;
+        return x509->derCert.buffer;
+    }
+
+#endif /* KEEP_PEER_CERT || SESSION_CERTS */
+
+
+#ifdef OPENSSL_EXTRA
+    int CyaSSL_set_ex_data(CYASSL* 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 CyaSSL_set_session_id_context(CYASSL* ssl, const unsigned char* id,
+                                   unsigned int len)
+    {
+        (void)ssl;
+        (void)id;
+        (void)len;
+        return 0;
+    }
+
+
+    void CyaSSL_set_connect_state(CYASSL* ssl)
+    {
+        (void)ssl;
+        /* client by default */ 
+    }
+#endif
+
+    int CyaSSL_get_shutdown(const CYASSL* ssl)
+    {
+        return (ssl->options.isClosed  ||
+                ssl->options.connReset ||
+                ssl->options.sentNotify);
+    }
+
+
+    int CyaSSL_session_reused(CYASSL* ssl)
+    {
+        return ssl->options.resuming;
+    }
+
+#ifdef OPENSSL_EXTRA
+    void CyaSSL_SESSION_free(CYASSL_SESSION* session)
+    {
+        (void)session;
+    }
+#endif
+
+    const char* CyaSSL_get_version(CYASSL* ssl)
+    {
+        CYASSL_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";
+    }
+
+    int CyaSSL_get_current_cipher_suite(CYASSL* ssl)
+    {
+        CYASSL_ENTER("SSL_get_current_cipher_suite");
+        if (ssl)
+            return (ssl->options.cipherSuite0 << 8) | ssl->options.cipherSuite;
+        return 0;
+    }
+
+    CYASSL_CIPHER* CyaSSL_get_current_cipher(CYASSL* ssl)
+    {
+        CYASSL_ENTER("SSL_get_current_cipher");
+        if (ssl)
+            return &ssl->cipher;
+        else
+            return NULL;
+    }
+
+
+    const char* CyaSSL_CIPHER_get_name(const CYASSL_CIPHER* cipher)
+    {
+        (void)cipher;
+
+        CYASSL_ENTER("SSL_CIPHER_get_name");
+#ifndef NO_ERROR_STRINGS
+        if (cipher) {
+#ifdef HAVE_ECC
+            if (cipher->ssl->options.cipherSuite0 == ECC_BYTE) {
+            /* ECC suites */
+            switch (cipher->ssl->options.cipherSuite) {
+#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
+
+#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
+                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
+
+                default:
+                    return "NONE";
+            }
+            }
+#endif  /* ECC */
+            if (cipher->ssl->options.cipherSuite0 != ECC_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";
+    #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
+                case TLS_PSK_WITH_AES_128_CBC_SHA256 :
+                    return "TLS_PSK_WITH_AES_128_CBC_SHA256";
+    #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
+        #ifdef HAVE_AESCCM
+                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";
+        #endif
+                case TLS_PSK_WITH_NULL_SHA256 :
+                    return "TLS_PSK_WITH_NULL_SHA256";
+    #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_CBC_MD5 :
+                    return "TLS_RSA_WITH_HC_128_CBC_MD5";
+        #endif
+        #ifndef NO_SHA
+                case TLS_RSA_WITH_HC_128_CBC_SHA :
+                    return "TLS_RSA_WITH_HC_128_CBC_SHA";
+        #endif
+    #endif /* NO_HC128 */
+    #ifndef NO_SHA
+        #ifndef NO_RABBIT
+                case TLS_RSA_WITH_RABBIT_CBC_SHA :
+                    return "TLS_RSA_WITH_RABBIT_CBC_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 */
+                default:
+                    return "NONE";
+            }  /* switch */
+            }  /* normal / ECC */
+        }
+#endif /* NO_ERROR_STRINGS */
+        return "NONE";
+    }
+
+
+    const char* CyaSSL_get_cipher(CYASSL* ssl)
+    {
+        CYASSL_ENTER("CyaSSL_get_cipher");
+        return CyaSSL_CIPHER_get_name(CyaSSL_get_current_cipher(ssl));
+    }
+
+#ifdef OPENSSL_EXTRA
+
+/* XXX shuld be NO_DH */
+#ifndef NO_CERTS
+    /* server ctx Diffie-Hellman parameters, SSL_SUCCESS on ok */
+    int CyaSSL_CTX_SetTmpDH(CYASSL_CTX* ctx, const unsigned char* p, int pSz,
+                            const unsigned char* g, int gSz)
+    {
+        CYASSL_ENTER("CyaSSL_CTX_SetTmpDH");
+        if (ctx == NULL || p == NULL || g == NULL) return BAD_FUNC_ARG;
+
+        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;
+
+        CYASSL_LEAVE("CyaSSL_CTX_SetTmpDH", 0);
+        return SSL_SUCCESS;
+    }
+#endif /* !NO_CERTS */
+
+
+    char* CyaSSL_CIPHER_description(CYASSL_CIPHER* cipher, char* in, int len)
+    {
+        (void)cipher;
+        (void)in;
+        (void)len;
+        return 0;
+    }
+
+
+    CYASSL_SESSION* CyaSSL_get1_session(CYASSL* ssl)  /* what's ref count */
+    {
+        (void)ssl;
+        return 0;
+    }
+
+
+    void CyaSSL_X509_free(CYASSL_X509* buf)
+    {
+        (void)buf;
+    }
+
+
+    /* was do nothing */
+    /*
+    void OPENSSL_free(void* buf)
+    {
+        (void)buf;
+    }
+    */
+
+
+    int CyaSSL_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;
+    }
+
+
+    CYASSL_METHOD* CyaSSLv2_client_method(void)
+    {
+        return 0;
+    }
+
+
+    CYASSL_METHOD* CyaSSLv2_server_method(void)
+    {
+        return 0;
+    }
+
+
+#ifndef NO_MD4
+
+    void CyaSSL_MD4_Init(CYASSL_MD4_CTX* md4)
+    {
+        /* make sure we have a big enough buffer */
+        typedef char ok[sizeof(md4->buffer) >= sizeof(Md4) ? 1 : -1];
+        (void) sizeof(ok);
+ 
+        CYASSL_ENTER("MD4_Init");
+        InitMd4((Md4*)md4);    
+    }
+
+
+    void CyaSSL_MD4_Update(CYASSL_MD4_CTX* md4, const void* data,
+                           unsigned long len)
+    {
+        CYASSL_ENTER("MD4_Update");
+        Md4Update((Md4*)md4, (const byte*)data, (word32)len); 
+    }
+
+
+    void CyaSSL_MD4_Final(unsigned char* digest, CYASSL_MD4_CTX* md4)
+    {
+        CYASSL_ENTER("MD4_Final");
+        Md4Final((Md4*)md4, digest); 
+    }
+
+#endif /* NO_MD4 */
+
+
+    CYASSL_BIO* CyaSSL_BIO_pop(CYASSL_BIO* top)
+    {
+        (void)top;
+        return 0;
+    }
+
+
+    int CyaSSL_BIO_pending(CYASSL_BIO* bio)
+    {
+        (void)bio;
+        return 0;
+    }
+
+
+
+    CYASSL_BIO_METHOD* CyaSSL_BIO_s_mem(void)
+    {
+        static CYASSL_BIO_METHOD meth;
+
+        CYASSL_ENTER("BIO_s_mem");
+        meth.type = BIO_MEMORY;
+
+        return &meth;
+    }
+
+
+    CYASSL_BIO_METHOD* CyaSSL_BIO_f_base64(void)
+    {
+        return 0;
+    }
+
+
+    void CyaSSL_BIO_set_flags(CYASSL_BIO* bio, int flags)
+    {
+        (void)bio;
+        (void)flags;
+    }
+
+
+
+    void CyaSSL_RAND_screen(void)
+    {
+    
+    }
+
+
+    const char* CyaSSL_RAND_file_name(char* fname, unsigned long len)
+    {
+        (void)fname;
+        (void)len;
+        return 0;
+    }
+
+
+    int CyaSSL_RAND_write_file(const char* fname)
+    {
+        (void)fname;
+        return 0;
+    }
+
+
+    int CyaSSL_RAND_load_file(const char* fname, long len)
+    {
+        (void)fname;
+        /* CTaoCrypt provides enough entropy internally or will report error */
+        if (len == -1)
+            return 1024;
+        else
+            return (int)len;
+    }
+
+
+    int CyaSSL_RAND_egd(const char* path)
+    {
+        (void)path;
+        return 0;
+    }
+
+
+
+    CYASSL_COMP_METHOD* CyaSSL_COMP_zlib(void)
+    {
+        return 0;
+    }
+
+
+    CYASSL_COMP_METHOD* CyaSSL_COMP_rle(void)
+    {
+        return 0;
+    }
+
+
+    int CyaSSL_COMP_add_compression_method(int method, void* data)
+    {
+        (void)method;
+        (void)data;
+        return 0;
+    }
+
+
+
+    int CyaSSL_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 CyaSSL_set_dynlock_create_callback(CYASSL_dynlock_value* (*f)(
+                                                              const char*, int))
+    {
+        (void)f;
+    }
+
+
+    void CyaSSL_set_dynlock_lock_callback(
+                 void (*f)(int, CYASSL_dynlock_value*, const char*, int))
+    {
+        (void)f;
+    }
+
+
+    void CyaSSL_set_dynlock_destroy_callback(
+                      void (*f)(CYASSL_dynlock_value*, const char*, int))
+    {
+        (void)f;
+    }
+
+
+
+    const char* CyaSSL_X509_verify_cert_error_string(long err)
+    {
+        (void)err;
+        return 0;
+    }
+
+
+
+    int CyaSSL_X509_LOOKUP_add_dir(CYASSL_X509_LOOKUP* lookup, const char* dir,
+                                   long len)
+    {
+        (void)lookup;
+        (void)dir;
+        (void)len;
+        return 0;
+    }
+
+
+    int CyaSSL_X509_LOOKUP_load_file(CYASSL_X509_LOOKUP* lookup,
+                                     const char* file, long len)
+    {
+        (void)lookup;
+        (void)file;
+        (void)len;
+        return 0;
+    }
+
+
+    CYASSL_X509_LOOKUP_METHOD* CyaSSL_X509_LOOKUP_hash_dir(void)
+    {
+        return 0;
+    }
+
+
+    CYASSL_X509_LOOKUP_METHOD* CyaSSL_X509_LOOKUP_file(void)
+    {
+        return 0;
+    }
+
+
+
+    CYASSL_X509_LOOKUP* CyaSSL_X509_STORE_add_lookup(CYASSL_X509_STORE* store,
+                                                   CYASSL_X509_LOOKUP_METHOD* m)
+    {
+        (void)store;
+        (void)m;
+        return 0;
+    }
+
+
+    CYASSL_X509_STORE* CyaSSL_X509_STORE_new(void)
+    {
+        return 0;
+    }
+
+
+    int CyaSSL_X509_STORE_get_by_subject(CYASSL_X509_STORE_CTX* ctx, int idx,
+                                CYASSL_X509_NAME* name, CYASSL_X509_OBJECT* obj)
+    {
+        (void)ctx;
+        (void)idx;
+        (void)name;
+        (void)obj;
+        return 0;
+    }
+
+
+    int CyaSSL_X509_STORE_CTX_init(CYASSL_X509_STORE_CTX* ctx,
+         CYASSL_X509_STORE* store, CYASSL_X509* x509, STACK_OF(CYASSL_X509)* sk)
+    {
+        (void)ctx;
+        (void)store;
+        (void)x509;
+        (void)sk;
+        return 0;
+    }
+
+
+    void CyaSSL_X509_STORE_CTX_cleanup(CYASSL_X509_STORE_CTX* ctx)
+    {
+        (void)ctx;
+    }
+
+
+
+    CYASSL_ASN1_TIME* CyaSSL_X509_CRL_get_lastUpdate(CYASSL_X509_CRL* crl)
+    {
+        (void)crl;
+        return 0;
+    }
+
+
+    CYASSL_ASN1_TIME* CyaSSL_X509_CRL_get_nextUpdate(CYASSL_X509_CRL* crl)
+    {
+        (void)crl;
+        return 0;
+    }
+
+
+
+    CYASSL_EVP_PKEY* CyaSSL_X509_get_pubkey(CYASSL_X509* x509)
+    {
+        (void)x509;
+        return 0;
+    }
+
+
+    int CyaSSL_X509_CRL_verify(CYASSL_X509_CRL* crl, CYASSL_EVP_PKEY* key)
+    {
+        (void)crl;
+        (void)key;
+        return 0;
+    }
+
+
+    void CyaSSL_X509_STORE_CTX_set_error(CYASSL_X509_STORE_CTX* ctx, int err)
+    {
+        (void)ctx;
+        (void)err;
+    }
+
+
+    void CyaSSL_X509_OBJECT_free_contents(CYASSL_X509_OBJECT* obj)
+    {
+        (void)obj;
+    }
+
+
+    void CyaSSL_EVP_PKEY_free(CYASSL_EVP_PKEY* key)
+    {
+        (void)key;
+    }
+
+
+    int CyaSSL_X509_cmp_current_time(const CYASSL_ASN1_TIME* asnTime)
+    {
+        (void)asnTime;
+        return 0;
+    }
+
+
+    int CyaSSL_sk_X509_REVOKED_num(CYASSL_X509_REVOKED* revoked)
+    {
+        (void)revoked;
+        return 0;
+    }
+
+
+
+    CYASSL_X509_REVOKED* CyaSSL_X509_CRL_get_REVOKED(CYASSL_X509_CRL* crl)
+    {
+        (void)crl;
+        return 0;
+    }
+
+
+    CYASSL_X509_REVOKED* CyaSSL_sk_X509_REVOKED_value(
+                                        CYASSL_X509_REVOKED* revoked, int value)
+    {
+        (void)revoked;
+        (void)value;
+        return 0;
+    }
+
+
+
+    CYASSL_ASN1_INTEGER* CyaSSL_X509_get_serialNumber(CYASSL_X509* x509)
+    {
+        (void)x509;
+        return 0;
+    }
+
+
+    int CyaSSL_ASN1_TIME_print(CYASSL_BIO* bio, const CYASSL_ASN1_TIME* asnTime)
+    {
+        (void)bio;
+        (void)asnTime;
+        return 0;
+    }
+
+
+
+    int CyaSSL_ASN1_INTEGER_cmp(const CYASSL_ASN1_INTEGER* a,
+                                const CYASSL_ASN1_INTEGER* b)
+    {
+        (void)a;
+        (void)b;
+        return 0;
+    }
+
+
+    long CyaSSL_ASN1_INTEGER_get(const CYASSL_ASN1_INTEGER* i)
+    {
+        (void)i;
+        return 0;
+    }
+
+
+
+    void* CyaSSL_X509_STORE_CTX_get_ex_data(CYASSL_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 CyaSSL_get_ex_data_X509_STORE_CTX_idx(void)
+    {
+        return 0;
+    }
+
+
+    void* CyaSSL_get_ex_data(const CYASSL* 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 CyaSSL_CTX_set_info_callback(CYASSL_CTX* ctx, void (*f)(void))
+    {
+        (void)ctx;
+        (void)f;
+    }
+
+
+    unsigned long CyaSSL_ERR_peek_error(void)
+    {
+        return 0;
+    }
+
+
+    int CyaSSL_ERR_GET_REASON(int err)
+    {
+        (void)err;
+        return 0;
+    }
+
+
+    char* CyaSSL_alert_type_string_long(int alertID)
+    {
+        (void)alertID;
+        return 0;
+    }
+
+
+    char* CyaSSL_alert_desc_string_long(int alertID)
+    {
+        (void)alertID;
+        return 0;
+    }
+
+
+    char* CyaSSL_state_string_long(CYASSL* ssl)
+    {
+        (void)ssl;
+        return 0;
+    }
+
+
+    int CyaSSL_PEM_def_callback(char* name, int num, int w, void* key)
+    {
+        (void)name;
+        (void)num;
+        (void)w;
+        (void)key;
+        return 0;
+    }
+    
+
+    long CyaSSL_CTX_sess_accept(CYASSL_CTX* ctx)
+    {
+        (void)ctx;
+        return 0;
+    }
+
+
+    long CyaSSL_CTX_sess_connect(CYASSL_CTX* ctx)
+    {
+        (void)ctx;
+        return 0;
+    }
+
+
+    long CyaSSL_CTX_sess_accept_good(CYASSL_CTX* ctx)
+    {
+        (void)ctx;
+        return 0;
+    }
+
+
+    long CyaSSL_CTX_sess_connect_good(CYASSL_CTX* ctx)
+    {
+        (void)ctx;
+        return 0;
+    }
+
+
+    long CyaSSL_CTX_sess_accept_renegotiate(CYASSL_CTX* ctx)
+    {
+        (void)ctx;
+        return 0;
+    }
+
+
+    long CyaSSL_CTX_sess_connect_renegotiate(CYASSL_CTX* ctx)
+    {
+        (void)ctx;
+        return 0;
+    }
+
+
+    long CyaSSL_CTX_sess_hits(CYASSL_CTX* ctx)
+    {
+        (void)ctx;
+        return 0;
+    }
+
+
+    long CyaSSL_CTX_sess_cb_hits(CYASSL_CTX* ctx)
+    {
+        (void)ctx;
+        return 0;
+    }
+
+
+    long CyaSSL_CTX_sess_cache_full(CYASSL_CTX* ctx)
+    {
+        (void)ctx;
+        return 0;
+    }
+
+
+    long CyaSSL_CTX_sess_misses(CYASSL_CTX* ctx)
+    {
+        (void)ctx;
+        return 0;
+    }
+
+
+    long CyaSSL_CTX_sess_timeouts(CYASSL_CTX* ctx)
+    {
+        (void)ctx;
+        return 0;
+    }
+
+
+    long CyaSSL_CTX_sess_number(CYASSL_CTX* ctx)
+    {
+        (void)ctx;
+        return 0;
+    }
+
+
+    void CyaSSL_DES_set_key_unchecked(CYASSL_const_DES_cblock* myDes,
+                                                   CYASSL_DES_key_schedule* key)
+    {
+        (void)myDes;
+        (void)key;
+    }
+
+
+    void CyaSSL_DES_set_odd_parity(CYASSL_DES_cblock* myDes)
+    {
+        (void)myDes;
+    }
+
+    
+    void CyaSSL_DES_ecb_encrypt(CYASSL_DES_cblock* desa,
+                 CYASSL_DES_cblock* desb, CYASSL_DES_key_schedule* key, int len)
+    {
+        (void)desa;
+        (void)desb;
+        (void)key;
+        (void)len;
+    }
+
+    int CyaSSL_BIO_printf(CYASSL_BIO* bio, const char* format, ...)
+    {
+        (void)bio;
+        (void)format;
+        return 0;
+    }
+
+
+    int CyaSSL_ASN1_UTCTIME_print(CYASSL_BIO* bio, const CYASSL_ASN1_UTCTIME* a)
+    {
+        (void)bio;
+        (void)a;
+        return 0;
+    }
+    
+
+    int  CyaSSL_sk_num(CYASSL_X509_REVOKED* rev)
+    {
+        (void)rev;
+        return 0;
+    }
+
+
+    void* CyaSSL_sk_value(CYASSL_X509_REVOKED* rev, int i)
+    {
+        (void)rev;
+        (void)i;
+        return 0;
+    }
+
+
+    /* stunnel 4.28 needs */
+    void* CyaSSL_CTX_get_ex_data(const CYASSL_CTX* ctx, int d)
+    {
+        (void)ctx;
+        (void)d;
+        return 0;
+    }
+
+
+    int CyaSSL_CTX_set_ex_data(CYASSL_CTX* ctx, int d, void* p)
+    {
+        (void)ctx;
+        (void)d;
+        (void)p;
+        return SSL_SUCCESS;
+    }
+
+
+    void CyaSSL_CTX_sess_set_get_cb(CYASSL_CTX* ctx,
+                        CYASSL_SESSION*(*f)(CYASSL*, unsigned char*, int, int*))
+    {
+        (void)ctx;
+        (void)f;
+    }
+
+
+    void CyaSSL_CTX_sess_set_new_cb(CYASSL_CTX* ctx,
+                                 int (*f)(CYASSL*, CYASSL_SESSION*))
+    {
+        (void)ctx;
+        (void)f;
+    }
+
+
+    void CyaSSL_CTX_sess_set_remove_cb(CYASSL_CTX* ctx, void (*f)(CYASSL_CTX*,
+                                                            CYASSL_SESSION*))
+    {
+        (void)ctx;
+        (void)f;
+    }
+
+
+    int CyaSSL_i2d_SSL_SESSION(CYASSL_SESSION* sess, unsigned char** p)
+    {
+        (void)sess;
+        (void)p;
+        return sizeof(CYASSL_SESSION);
+    }
+
+
+    CYASSL_SESSION* CyaSSL_d2i_SSL_SESSION(CYASSL_SESSION** sess,
+                                    const unsigned char** p, long i)
+    {
+        (void)p;
+        (void)i;
+        if (sess)
+            return *sess;
+        return NULL;
+    }
+
+
+    long CyaSSL_SESSION_get_timeout(const CYASSL_SESSION* sess)
+    {
+        CYASSL_ENTER("CyaSSL_SESSION_get_timeout");
+        return sess->timeout;
+    }
+
+
+    long CyaSSL_SESSION_get_time(const CYASSL_SESSION* sess)
+    {
+        CYASSL_ENTER("CyaSSL_SESSION_get_time");
+        return sess->bornOn;
+    }
+
+
+    int CyaSSL_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*  CyaSSL_X509_get_subjectCN(CYASSL_X509* x509)
+    {
+        if (x509 == NULL)
+            return NULL;
+
+        return x509->subjectCN;
+    }
+#endif /* KEEP_PEER_CERT */
+
+#ifdef OPENSSL_EXTRA
+
+#ifdef FORTRESS
+    int CyaSSL_cmp_peer_cert_to_file(CYASSL* ssl, const char *fname)
+    {
+        int ret = SSL_FATAL_ERROR;
+
+        CYASSL_ENTER("CyaSSL_cmp_peer_cert_to_file");
+        if (ssl != NULL && fname != NULL)
+        {
+            XFILE         file = XBADFILE;
+            long          sz = 0;
+            byte          staticBuffer[FILE_BUFFER_SIZE];
+            byte*         myBuffer = staticBuffer;
+            CYASSL_CTX*   ctx = ssl->ctx;
+            EncryptedInfo info;
+            buffer        fileDer;
+            int           eccKey = 0;
+            CYASSL_X509*  peer_cert = &ssl->peerCert;
+
+            info.set = 0;
+            info.ctx = ctx;
+            info.consumed = 0;
+            fileDer.buffer = 0;
+
+            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)) {
+                CYASSL_MSG("Getting dynamic buffer");
+                myBuffer = (byte*) XMALLOC(sz, ctx->heap, DYNAMIC_TYPE_FILE);
+            }
+            
+            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;
+            }
+
+            XFCLOSE(file);
+            if (fileDer.buffer)
+                XFREE(fileDer.buffer, ctx->heap, DYNAMIC_TYPE_CERT);
+            if (myBuffer && (myBuffer != staticBuffer))
+                XFREE(myBuffer, ctx->heap, DYNAMIC_TYPE_FILE);
+        }
+
+        return ret;
+    }
+#endif
+
+
+static RNG globalRNG;
+static int initGlobalRNG = 0;
+
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_RAND_seed(const void* seed, int len)
+    {
+
+        CYASSL_MSG("CyaSSL_RAND_seed");
+
+        (void)seed;
+        (void)len;
+
+        if (initGlobalRNG == 0) {
+            if (InitRng(&globalRNG) < 0) {
+                CYASSL_MSG("CyaSSL Init Global RNG failed");
+            }
+            initGlobalRNG = 1;
+        }
+
+        return SSL_SUCCESS;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_RAND_bytes(unsigned char* buf, int num)
+    {
+        RNG    tmpRNG;
+        RNG*   rng = &tmpRNG; 
+
+        CYASSL_ENTER("RAND_bytes");
+        if (InitRng(&tmpRNG) != 0) {
+            CYASSL_MSG("Bad RNG Init, trying global");
+            if (initGlobalRNG == 0) {
+                CYASSL_MSG("Global RNG no Init");
+                return 0; 
+            }
+            rng = &globalRNG;
+        }
+
+        RNG_GenerateBlock(rng, buf, num);
+
+        return SSL_SUCCESS;
+    }
+
+    CYASSL_BN_CTX* CyaSSL_BN_CTX_new(void)
+    {
+        static int ctx;  /* ctaocrypt doesn't now need ctx */
+
+        CYASSL_MSG("CyaSSL_BN_CTX_new");
+
+        return (CYASSL_BN_CTX*)&ctx;
+    }
+
+    void CyaSSL_BN_CTX_init(CYASSL_BN_CTX* ctx)
+    {
+        (void)ctx;
+        CYASSL_MSG("CyaSSL_BN_CTX_init");
+    }
+
+
+    void CyaSSL_BN_CTX_free(CYASSL_BN_CTX* ctx)
+    {
+        (void)ctx;
+        CYASSL_MSG("CyaSSL_BN_CTX_free");
+
+        /* do free since static ctx that does nothing */
+    }
+
+
+    static void InitCyaSSL_BigNum(CYASSL_BIGNUM* bn)
+    { 
+        CYASSL_MSG("InitCyaSSL_BigNum");
+        if (bn) {
+            bn->neg      = 0;
+            bn->internal = NULL;
+        }
+    }
+
+
+    CYASSL_BIGNUM* CyaSSL_BN_new(void)
+    {
+        CYASSL_BIGNUM* external;
+        mp_int*        mpi;
+
+        CYASSL_MSG("CyaSSL_BN_new");
+
+        mpi = (mp_int*) XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT);
+        if (mpi == NULL) {
+            CYASSL_MSG("CyaSSL_BN_new malloc mpi failure");
+            return NULL;
+        }
+
+        external = (CYASSL_BIGNUM*) XMALLOC(sizeof(CYASSL_BIGNUM), NULL,
+                                            DYNAMIC_TYPE_BIGINT);
+        if (external == NULL) {
+            CYASSL_MSG("CyaSSL_BN_new malloc CYASSL_BIGNUM failure");
+            XFREE(mpi, NULL, DYNAMIC_TYPE_BIGINT);
+            return NULL;
+        }
+
+        InitCyaSSL_BigNum(external);
+        external->internal = mpi;
+        if (mp_init(mpi) != MP_OKAY) {
+            CyaSSL_BN_free(external); 
+            return NULL;
+        }
+
+        return external;
+    }
+
+
+    void CyaSSL_BN_free(CYASSL_BIGNUM* bn)
+    {
+        CYASSL_MSG("CyaSSL_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 CyaSSL_BN_clear_free(CYASSL_BIGNUM* bn)
+    {
+        CYASSL_MSG("CyaSSL_BN_clear_free");
+
+        CyaSSL_BN_free(bn);
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_BN_sub(CYASSL_BIGNUM* r, const CYASSL_BIGNUM* a,
+                      const CYASSL_BIGNUM* b)
+    {
+        CYASSL_MSG("CyaSSL_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;
+
+        CYASSL_MSG("CyaSSL_BN_sub mp_sub failed");
+        return 0;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_BN_mod(CYASSL_BIGNUM* r, const CYASSL_BIGNUM* a,
+	                  const CYASSL_BIGNUM* b, const CYASSL_BN_CTX* c)
+    {
+        (void)c;
+        CYASSL_MSG("CyaSSL_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;
+
+        CYASSL_MSG("CyaSSL_BN_mod mp_mod failed");
+        return 0;
+    }
+
+
+    const CYASSL_BIGNUM* CyaSSL_BN_value_one(void)
+    {
+        static CYASSL_BIGNUM* bn_one = NULL;
+
+        CYASSL_MSG("CyaSSL_BN_value_one");
+
+        if (bn_one == NULL) {
+            bn_one = CyaSSL_BN_new();
+            if (bn_one)
+                mp_set_int((mp_int*)bn_one->internal, 1);
+        }
+
+        return bn_one;
+    }
+
+
+    int CyaSSL_BN_num_bytes(const CYASSL_BIGNUM* bn)
+    {
+        CYASSL_MSG("CyaSSL_BN_num_bytes");
+
+        if (bn == NULL || bn->internal == NULL)
+            return 0;
+
+        return mp_unsigned_bin_size((mp_int*)bn->internal);
+    }
+
+
+    int CyaSSL_BN_num_bits(const CYASSL_BIGNUM* bn)
+    {
+        CYASSL_MSG("CyaSSL_BN_num_bits");
+
+        if (bn == NULL || bn->internal == NULL)
+            return 0;
+
+        return mp_count_bits((mp_int*)bn->internal);
+    }
+
+
+    int CyaSSL_BN_is_zero(const CYASSL_BIGNUM* bn)
+    {
+        CYASSL_MSG("CyaSSL_BN_is_zero");
+
+        if (bn == NULL || bn->internal == NULL)
+            return 0;
+
+        return mp_iszero((mp_int*)bn->internal);
+    }
+
+
+    int CyaSSL_BN_is_one(const CYASSL_BIGNUM* bn)
+    {
+        CYASSL_MSG("CyaSSL_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 CyaSSL_BN_is_odd(const CYASSL_BIGNUM* bn)
+    {
+        CYASSL_MSG("CyaSSL_BN_is_odd");
+
+        if (bn == NULL || bn->internal == NULL)
+            return 0;
+
+        return mp_isodd((mp_int*)bn->internal);
+    }
+
+
+    int CyaSSL_BN_cmp(const CYASSL_BIGNUM* a, const CYASSL_BIGNUM* b)
+    {
+        CYASSL_MSG("CyaSSL_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 CyaSSL_BN_bn2bin(const CYASSL_BIGNUM* bn, unsigned char* r)
+    {
+        CYASSL_MSG("CyaSSL_BN_bn2bin");
+
+        if (bn == NULL || bn->internal == NULL) {
+            CYASSL_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) {
+            CYASSL_MSG("mp_to_unsigned_bin error");
+            return SSL_FATAL_ERROR;
+        }
+
+        return mp_unsigned_bin_size((mp_int*)bn->internal);
+    }
+
+
+    CYASSL_BIGNUM* CyaSSL_BN_bin2bn(const unsigned char* str, int len,
+	                            CYASSL_BIGNUM* ret)
+    {
+        CYASSL_MSG("CyaSSL_BN_bin2bn");
+
+        if (ret && ret->internal) {
+            if (mp_read_unsigned_bin((mp_int*)ret->internal, str, len) != 0) {
+                CYASSL_MSG("mp_read_unsigned_bin failure");
+                return NULL;
+            } 
+        }
+        else {
+            CYASSL_MSG("CyaSSL_BN_bin2bn wants return bignum");
+        }
+
+        return ret;
+    }
+
+
+    int CyaSSL_mask_bits(CYASSL_BIGNUM* bn, int n)
+    {
+        (void)bn;
+        (void)n;
+        CYASSL_MSG("CyaSSL_BN_mask_bits");
+
+        return SSL_FATAL_ERROR;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_BN_rand(CYASSL_BIGNUM* bn, int bits, int top, int bottom)
+    {
+        byte          buff[1024];
+        RNG           tmpRNG;
+        RNG*          rng = &tmpRNG; 
+        int           len = bits/8;
+
+        (void)top;
+        (void)bottom;
+        CYASSL_MSG("CyaSSL_BN_rand");
+
+        if (bn == NULL || bn->internal == NULL) {
+            CYASSL_MSG("Bad function arguments");
+            return 0; 
+        }
+
+        if (bits % 8)
+            len++;
+
+        if ( (InitRng(&tmpRNG)) != 0) {
+            CYASSL_MSG("Bad RNG Init, trying global");
+            if (initGlobalRNG == 0) {
+                CYASSL_MSG("Global RNG no Init");
+                return 0; 
+            }
+            rng = &globalRNG;
+        }
+
+        RNG_GenerateBlock(rng, buff, len);
+        buff[0]     |= 0x80 | 0x40;
+        buff[len-1] |= 0x01;
+
+        if (mp_read_unsigned_bin((mp_int*)bn->internal,buff,len) != MP_OKAY) {
+            CYASSL_MSG("mp read bin failed");
+            return 0;
+        }
+                
+        return SSL_SUCCESS;
+    }
+
+
+    int CyaSSL_BN_is_bit_set(const CYASSL_BIGNUM* bn, int n)
+    {
+        (void)bn;
+        (void)n;
+
+        CYASSL_MSG("CyaSSL_BN_is_bit_set");
+
+        return 0;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_BN_hex2bn(CYASSL_BIGNUM** bn, const char* str)
+    {
+        byte    decoded[1024];
+        word32  decSz = sizeof(decoded);
+
+        CYASSL_MSG("CyaSSL_BN_hex2bn");
+
+        if (str == NULL) {
+            CYASSL_MSG("Bad function argument");
+            return 0;
+        }
+
+        if (Base16_Decode((byte*)str, (int)XSTRLEN(str), decoded, &decSz) < 0) {
+            CYASSL_MSG("Bad Base16_Decode error");
+            return 0;
+        }
+
+        if (bn == NULL)
+            return decSz;
+
+        if (*bn == NULL) {
+            *bn = CyaSSL_BN_new();
+            if (*bn == NULL) {
+                CYASSL_MSG("BN new failed");
+                return 0;
+            }
+        }
+
+        if (CyaSSL_BN_bin2bn(decoded, decSz, *bn) == NULL) {
+            CYASSL_MSG("Bad bin2bn error");
+            return 0;
+        }
+
+        return SSL_SUCCESS;
+    }
+
+
+    CYASSL_BIGNUM* CyaSSL_BN_dup(const CYASSL_BIGNUM* bn)
+    {
+        CYASSL_BIGNUM* ret;
+
+        CYASSL_MSG("CyaSSL_BN_dup");
+
+        if (bn == NULL || bn->internal == NULL) {
+            CYASSL_MSG("bn NULL error");
+            return NULL;
+        }
+
+        ret = CyaSSL_BN_new();
+        if (ret == NULL) {
+            CYASSL_MSG("bn new error");
+            return NULL;
+        }
+
+        if (mp_copy((mp_int*)bn->internal, (mp_int*)ret->internal) != MP_OKAY) {
+            CYASSL_MSG("mp_copy error");
+            CyaSSL_BN_free(ret);
+            return NULL;
+        }
+
+        return ret;
+    }
+
+
+    CYASSL_BIGNUM* CyaSSL_BN_copy(CYASSL_BIGNUM* r, const CYASSL_BIGNUM* bn)
+    {
+        (void)r;
+        (void)bn;
+
+        CYASSL_MSG("CyaSSL_BN_copy");
+
+        return NULL;
+    }
+
+
+    int CyaSSL_BN_set_word(CYASSL_BIGNUM* bn, unsigned long w)
+    {
+        (void)bn;
+        (void)w;
+
+        CYASSL_MSG("CyaSSL_BN_set_word");
+
+        return SSL_FATAL_ERROR;
+    }
+
+
+    int CyaSSL_BN_dec2bn(CYASSL_BIGNUM** bn, const char* str)
+    {
+        (void)bn;
+        (void)str;
+
+        CYASSL_MSG("CyaSSL_BN_dec2bn");
+
+        return SSL_FATAL_ERROR;
+    }
+
+
+    char* CyaSSL_BN_bn2dec(const CYASSL_BIGNUM* bn)
+    {
+        (void)bn;
+
+        CYASSL_MSG("CyaSSL_BN_bn2dec");
+
+        return NULL;
+    }
+
+
+    static void InitCyaSSL_DH(CYASSL_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;
+        }
+    }
+
+
+    CYASSL_DH* CyaSSL_DH_new(void)
+    {
+        CYASSL_DH* external;
+        DhKey*     key;
+
+        CYASSL_MSG("CyaSSL_DH_new");
+
+        key = (DhKey*) XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH);
+        if (key == NULL) {
+            CYASSL_MSG("CyaSSL_DH_new malloc DhKey failure");
+            return NULL;
+        }
+
+        external = (CYASSL_DH*) XMALLOC(sizeof(CYASSL_DH), NULL,
+                                        DYNAMIC_TYPE_DH);
+        if (external == NULL) {
+            CYASSL_MSG("CyaSSL_DH_new malloc CYASSL_DH failure");
+            XFREE(key, NULL, DYNAMIC_TYPE_DH);
+            return NULL;
+        }
+
+        InitCyaSSL_DH(external);
+        InitDhKey(key);
+        external->internal = key;
+
+        return external;
+    }
+
+
+    void CyaSSL_DH_free(CYASSL_DH* dh)
+    {
+        CYASSL_MSG("CyaSSL_DH_free");
+
+        if (dh) {
+            if (dh->internal) {
+                FreeDhKey((DhKey*)dh->internal);
+                XFREE(dh->internal, NULL, DYNAMIC_TYPE_DH);
+                dh->internal = NULL;
+            }
+            CyaSSL_BN_free(dh->priv_key);
+            CyaSSL_BN_free(dh->pub_key);
+            CyaSSL_BN_free(dh->g);
+            CyaSSL_BN_free(dh->p);
+            InitCyaSSL_DH(dh);  /* set back to NULLs for safety */
+
+            XFREE(dh, NULL, DYNAMIC_TYPE_DH);
+        }
+    }
+
+
+    static int SetDhInternal(CYASSL_DH* dh) 
+    {
+        unsigned char p[1024];
+        unsigned char g[1024];
+        int           pSz = sizeof(p);
+        int           gSz = sizeof(g);
+
+        CYASSL_ENTER("SetDhInternal");
+
+        if (dh == NULL || dh->p == NULL || dh->g == NULL) {
+            CYASSL_MSG("Bad function arguments");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (CyaSSL_BN_bn2bin(dh->p, NULL) > pSz) {
+            CYASSL_MSG("Bad p internal size");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (CyaSSL_BN_bn2bin(dh->g, NULL) > gSz) {
+            CYASSL_MSG("Bad g internal size");
+            return SSL_FATAL_ERROR;
+        }
+
+        pSz = CyaSSL_BN_bn2bin(dh->p, p);
+        gSz = CyaSSL_BN_bn2bin(dh->g, g);
+        
+        if (pSz <= 0 || gSz <= 0) {
+            CYASSL_MSG("Bad BN2bin set");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (DhSetKey((DhKey*)dh->internal, p, pSz, g, gSz) < 0) {
+            CYASSL_MSG("Bad DH SetKey");
+            return SSL_FATAL_ERROR;
+        }
+
+        dh->inSet = 1;
+
+        return 0;
+    }
+
+
+    int CyaSSL_DH_size(CYASSL_DH* dh)
+    {
+        CYASSL_MSG("CyaSSL_DH_size");
+
+        if (dh == NULL)
+            return 0;
+
+        return CyaSSL_BN_num_bytes(dh->p);
+    }
+
+
+    /* return SSL_SUCCESS on ok, else 0 */
+    int CyaSSL_DH_generate_key(CYASSL_DH* dh)
+    {
+        unsigned char pub [768];
+        unsigned char priv[768];
+        word32        pubSz  = sizeof(pub);
+        word32        privSz = sizeof(priv);
+        RNG           tmpRNG;
+        RNG*          rng = &tmpRNG; 
+
+        CYASSL_MSG("CyaSSL_DH_generate_key");
+
+        if (dh == NULL || dh->p == NULL || dh->g == NULL) {
+            CYASSL_MSG("Bad function arguments");
+            return 0; 
+        }
+
+        if (dh->inSet == 0) {
+            if (SetDhInternal(dh) < 0) {
+                CYASSL_MSG("Bad DH set internal");
+                return 0; 
+            }
+        }
+
+        if ( (InitRng(&tmpRNG)) != 0) {
+            CYASSL_MSG("Bad RNG Init, trying global");
+            if (initGlobalRNG == 0) {
+                CYASSL_MSG("Global RNG no Init");
+                return 0; 
+            }
+            rng = &globalRNG;
+        }
+
+        if (DhGenerateKeyPair((DhKey*)dh->internal, rng, priv, &privSz,
+                                pub, &pubSz) < 0) {
+            CYASSL_MSG("Bad DhGenerateKeyPair");
+            return 0; 
+        }
+
+        if (dh->pub_key)
+            CyaSSL_BN_free(dh->pub_key);
+        dh->pub_key = CyaSSL_BN_new();
+        if (dh->pub_key == NULL) {
+            CYASSL_MSG("Bad DH new pub");
+            return 0; 
+        }
+
+        if (dh->priv_key)
+            CyaSSL_BN_free(dh->priv_key);
+        dh->priv_key = CyaSSL_BN_new();
+        if (dh->priv_key == NULL) {
+            CYASSL_MSG("Bad DH new priv");
+            return 0; 
+        }
+
+        if (CyaSSL_BN_bin2bn(pub, pubSz, dh->pub_key) == NULL) {
+            CYASSL_MSG("Bad DH bn2bin error pub");
+            return 0; 
+        }
+
+        if (CyaSSL_BN_bin2bn(priv, privSz, dh->priv_key) == NULL) {
+            CYASSL_MSG("Bad DH bn2bin error priv");
+            return 0; 
+        }
+
+        CYASSL_MSG("CyaSSL_generate_key success");
+        return SSL_SUCCESS;
+    }
+
+
+    /* return key size on ok, 0 otherwise */
+    int CyaSSL_DH_compute_key(unsigned char* key, CYASSL_BIGNUM* otherPub,
+                              CYASSL_DH* dh)
+    {
+        unsigned char pub [1024];
+        unsigned char priv[1024];
+        word32        pubSz  = sizeof(pub);
+        word32        privSz = sizeof(priv);
+        word32        keySz;
+
+        CYASSL_MSG("CyaSSL_DH_compute_key");
+
+        if (dh == NULL || dh->priv_key == NULL || otherPub == NULL) {
+            CYASSL_MSG("Bad function arguments");
+            return 0; 
+        }
+
+        keySz = (word32)DH_size(dh);
+        if (keySz == 0) {
+            CYASSL_MSG("Bad DH_size");
+            return 0;
+        }
+
+        if (CyaSSL_BN_bn2bin(dh->priv_key, NULL) > (int)privSz) {
+            CYASSL_MSG("Bad priv internal size");
+            return 0;
+        }
+
+        if (CyaSSL_BN_bn2bin(otherPub, NULL) > (int)pubSz) {
+            CYASSL_MSG("Bad otherPub size");
+            return 0;
+        }
+
+        privSz = CyaSSL_BN_bn2bin(dh->priv_key, priv);
+        pubSz  = CyaSSL_BN_bn2bin(otherPub, pub);
+        
+        if (privSz <= 0 || pubSz <= 0) {
+            CYASSL_MSG("Bad BN2bin set");
+            return 0;
+        }
+
+        if (DhAgree((DhKey*)dh->internal, key, &keySz, priv, privSz, pub,
+                    pubSz) < 0) {
+            CYASSL_MSG("DhAgree failed");
+            return 0;
+        }
+
+        CYASSL_MSG("CyaSSL_compute_key success");
+        return (int)keySz;
+    }
+
+
+#ifndef NO_DSA
+    static void InitCyaSSL_DSA(CYASSL_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;
+        }
+    }
+
+
+    CYASSL_DSA* CyaSSL_DSA_new(void)
+    {
+        CYASSL_DSA* external;
+        DsaKey*     key;
+
+        CYASSL_MSG("CyaSSL_DSA_new");
+
+        key = (DsaKey*) XMALLOC(sizeof(DsaKey), NULL, DYNAMIC_TYPE_DSA);
+        if (key == NULL) {
+            CYASSL_MSG("CyaSSL_DSA_new malloc DsaKey failure");
+            return NULL;
+        }
+
+        external = (CYASSL_DSA*) XMALLOC(sizeof(CYASSL_DSA), NULL,
+                                        DYNAMIC_TYPE_DSA);
+        if (external == NULL) {
+            CYASSL_MSG("CyaSSL_DSA_new malloc CYASSL_DSA failure");
+            XFREE(key, NULL, DYNAMIC_TYPE_DSA);
+            return NULL;
+        }
+
+        InitCyaSSL_DSA(external);
+        InitDsaKey(key);
+        external->internal = key;
+
+        return external;
+    }
+
+
+    void CyaSSL_DSA_free(CYASSL_DSA* dsa)
+    {
+        CYASSL_MSG("CyaSSL_DSA_free");
+
+        if (dsa) {
+            if (dsa->internal) {
+                FreeDsaKey((DsaKey*)dsa->internal);
+                XFREE(dsa->internal, NULL, DYNAMIC_TYPE_DSA);
+                dsa->internal = NULL;
+            }
+            CyaSSL_BN_free(dsa->priv_key);
+            CyaSSL_BN_free(dsa->pub_key);
+            CyaSSL_BN_free(dsa->g);
+            CyaSSL_BN_free(dsa->q);
+            CyaSSL_BN_free(dsa->p);
+            InitCyaSSL_DSA(dsa);  /* set back to NULLs for safety */
+
+            XFREE(dsa, NULL, DYNAMIC_TYPE_DSA);
+        }
+    }
+
+
+    int CyaSSL_DSA_generate_key(CYASSL_DSA* dsa)
+    {
+        (void)dsa;
+
+        CYASSL_MSG("CyaSSL_DSA_generate_key");
+
+        return 0;  /* key gen not needed by server */
+    }
+
+
+    int CyaSSL_DSA_generate_parameters_ex(CYASSL_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;
+
+        CYASSL_MSG("CyaSSL_DSA_generate_parameters_ex");
+
+        return 0;  /* key gen not needed by server */
+    }
+#endif /* NO_DSA */
+
+    static void InitCyaSSL_Rsa(CYASSL_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;
+        }
+    }
+
+
+    CYASSL_RSA* CyaSSL_RSA_new(void)
+    {
+        CYASSL_RSA* external;
+        RsaKey*     key;
+
+        CYASSL_MSG("CyaSSL_RSA_new");
+
+        key = (RsaKey*) XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA);
+        if (key == NULL) {
+            CYASSL_MSG("CyaSSL_RSA_new malloc RsaKey failure");
+            return NULL;
+        }
+
+        external = (CYASSL_RSA*) XMALLOC(sizeof(CYASSL_RSA), NULL,
+                                         DYNAMIC_TYPE_RSA);
+        if (external == NULL) {
+            CYASSL_MSG("CyaSSL_RSA_new malloc CYASSL_RSA failure");
+            XFREE(key, NULL, DYNAMIC_TYPE_RSA);
+            return NULL;
+        }
+
+        InitCyaSSL_Rsa(external);
+        InitRsaKey(key, NULL);
+        external->internal = key;
+
+        return external;
+    }
+
+
+    void CyaSSL_RSA_free(CYASSL_RSA* rsa)
+    {
+        CYASSL_MSG("CyaSSL_RSA_free");
+
+        if (rsa) {
+            if (rsa->internal) {
+                FreeRsaKey((RsaKey*)rsa->internal);
+                XFREE(rsa->internal, NULL, DYNAMIC_TYPE_RSA);
+                rsa->internal = NULL;
+            }
+            CyaSSL_BN_free(rsa->iqmp);
+            CyaSSL_BN_free(rsa->dmq1);
+            CyaSSL_BN_free(rsa->dmp1);
+            CyaSSL_BN_free(rsa->q);
+            CyaSSL_BN_free(rsa->p);
+            CyaSSL_BN_free(rsa->d);
+            CyaSSL_BN_free(rsa->e);
+            CyaSSL_BN_free(rsa->n);
+            InitCyaSSL_Rsa(rsa);  /* set back to NULLs for safety */
+
+            XFREE(rsa, NULL, DYNAMIC_TYPE_RSA);
+        }
+    }
+
+
+    static int SetIndividualExternal(CYASSL_BIGNUM** bn, mp_int* mpi)
+    {
+        CYASSL_MSG("Entering SetIndividualExternal");
+
+        if (mpi == NULL) {
+            CYASSL_MSG("mpi NULL error");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (*bn == NULL) {
+            *bn = CyaSSL_BN_new();
+            if (*bn == NULL) {
+                CYASSL_MSG("SetIndividualExternal alloc failed");
+                return SSL_FATAL_ERROR;
+            }
+        }
+
+        if (mp_copy(mpi, (mp_int*)((*bn)->internal)) != MP_OKAY) {
+            CYASSL_MSG("mp_copy error");
+            return SSL_FATAL_ERROR;
+        }
+
+        return 0;
+    }
+
+
+#ifndef NO_DSA
+    static int SetDsaExternal(CYASSL_DSA* dsa)
+    {
+        DsaKey* key;
+        CYASSL_MSG("Entering SetDsaExternal");
+
+        if (dsa == NULL || dsa->internal == NULL) {
+            CYASSL_MSG("dsa key NULL error");
+            return SSL_FATAL_ERROR;
+        }
+
+        key = (DsaKey*)dsa->internal;
+
+        if (SetIndividualExternal(&dsa->p, &key->p) < 0) {
+            CYASSL_MSG("dsa p key error");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (SetIndividualExternal(&dsa->q, &key->q) < 0) {
+            CYASSL_MSG("dsa q key error");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (SetIndividualExternal(&dsa->g, &key->g) < 0) {
+            CYASSL_MSG("dsa g key error");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (SetIndividualExternal(&dsa->pub_key, &key->y) < 0) {
+            CYASSL_MSG("dsa y key error");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (SetIndividualExternal(&dsa->priv_key, &key->x) < 0) {
+            CYASSL_MSG("dsa x key error");
+            return SSL_FATAL_ERROR;
+        }
+
+        dsa->exSet = 1;
+
+        return 0;
+    }
+#endif /* NO_DSA */
+
+
+    static int SetRsaExternal(CYASSL_RSA* rsa)
+    {
+        RsaKey* key;
+        CYASSL_MSG("Entering SetRsaExternal");
+
+        if (rsa == NULL || rsa->internal == NULL) {
+            CYASSL_MSG("rsa key NULL error");
+            return SSL_FATAL_ERROR;
+        }
+
+        key = (RsaKey*)rsa->internal;
+
+        if (SetIndividualExternal(&rsa->n, &key->n) < 0) {
+            CYASSL_MSG("rsa n key error");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (SetIndividualExternal(&rsa->e, &key->e) < 0) {
+            CYASSL_MSG("rsa e key error");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (SetIndividualExternal(&rsa->d, &key->d) < 0) {
+            CYASSL_MSG("rsa d key error");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (SetIndividualExternal(&rsa->p, &key->p) < 0) {
+            CYASSL_MSG("rsa p key error");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (SetIndividualExternal(&rsa->q, &key->q) < 0) {
+            CYASSL_MSG("rsa q key error");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (SetIndividualExternal(&rsa->dmp1, &key->dP) < 0) {
+            CYASSL_MSG("rsa dP key error");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (SetIndividualExternal(&rsa->dmq1, &key->dQ) < 0) {
+            CYASSL_MSG("rsa dQ key error");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (SetIndividualExternal(&rsa->iqmp, &key->u) < 0) {
+            CYASSL_MSG("rsa u key error");
+            return SSL_FATAL_ERROR;
+        }
+
+        rsa->exSet = 1;
+
+        return 0;
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_RSA_generate_key_ex(CYASSL_RSA* rsa, int bits, CYASSL_BIGNUM* bn,
+                                   void* cb)
+    {
+        RNG rng;
+
+        CYASSL_MSG("CyaSSL_RSA_generate_key_ex");
+
+        (void)rsa;
+        (void)bits;
+        (void)cb;
+        (void)bn;
+    
+        if (InitRng(&rng) < 0) {
+            CYASSL_MSG("RNG init failed");
+            return SSL_FATAL_ERROR;
+        }
+
+#ifdef CYASSL_KEY_GEN
+        if (MakeRsaKey((RsaKey*)rsa->internal, bits, 65537, &rng) < 0) {
+            CYASSL_MSG("MakeRsaKey failed");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (SetRsaExternal(rsa) < 0) {
+            CYASSL_MSG("SetRsaExternal failed");
+            return SSL_FATAL_ERROR;
+        }
+
+        rsa->inSet = 1;
+
+        return SSL_SUCCESS;
+#else
+        CYASSL_MSG("No Key Gen built in");
+        return SSL_FATAL_ERROR;
+#endif
+
+    }
+
+
+    /* SSL_SUCCESS on ok */
+    int CyaSSL_RSA_blinding_on(CYASSL_RSA* rsa, CYASSL_BN_CTX* bn)
+    {
+        (void)rsa;
+        (void)bn;
+
+        CYASSL_MSG("CyaSSL_RSA_blinding_on");
+
+        return SSL_SUCCESS;  /* on by default */
+    }
+
+
+    int CyaSSL_RSA_public_encrypt(int len, unsigned char* fr,
+	                            unsigned char* to, CYASSL_RSA* rsa, int padding)
+    {
+        (void)len;
+        (void)fr;
+        (void)to;
+        (void)rsa;
+        (void)padding;
+
+        CYASSL_MSG("CyaSSL_RSA_public_encrypt");
+
+        return SSL_FATAL_ERROR;
+    }
+
+
+    int CyaSSL_RSA_private_decrypt(int len, unsigned char* fr,
+	                            unsigned char* to, CYASSL_RSA* rsa, int padding)
+    {
+        (void)len;
+        (void)fr;
+        (void)to;
+        (void)rsa;
+        (void)padding;
+
+        CYASSL_MSG("CyaSSL_RSA_private_decrypt");
+
+        return SSL_FATAL_ERROR;
+    }
+
+
+    int CyaSSL_RSA_size(const CYASSL_RSA* rsa)
+    {
+        CYASSL_MSG("CyaSSL_RSA_size");
+
+        if (rsa == NULL)
+            return 0;
+
+        return CyaSSL_BN_num_bytes(rsa->n);
+    }
+
+
+#ifndef NO_DSA
+    /* return SSL_SUCCESS on success, < 0 otherwise */
+    int CyaSSL_DSA_do_sign(const unsigned char* d, unsigned char* sigRet,
+                           CYASSL_DSA* dsa)
+    {
+        RNG    tmpRNG;
+        RNG*   rng = &tmpRNG; 
+
+        CYASSL_MSG("CyaSSL_DSA_do_sign");
+
+        if (d == NULL || sigRet == NULL || dsa == NULL) {
+            CYASSL_MSG("Bad function arguments");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (dsa->inSet == 0) {
+            CYASSL_MSG("No DSA internal set");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (InitRng(&tmpRNG) != 0) {
+            CYASSL_MSG("Bad RNG Init, trying global");
+            if (initGlobalRNG == 0) {
+                CYASSL_MSG("Global RNG no Init");
+                return SSL_FATAL_ERROR; 
+            }
+            rng = &globalRNG;
+        }
+
+        if (DsaSign(d, sigRet, (DsaKey*)dsa->internal, rng) < 0) {
+            CYASSL_MSG("DsaSign failed");
+            return SSL_FATAL_ERROR;
+        }
+
+        return SSL_SUCCESS;
+    }
+#endif /* NO_DSA */
+
+
+    /* return SSL_SUCCES on ok, 0 otherwise */
+    int CyaSSL_RSA_sign(int type, const unsigned char* m,
+                               unsigned int mLen, unsigned char* sigRet,
+                               unsigned int* sigLen, CYASSL_RSA* rsa)
+    {
+        byte   encodedSig[MAX_ENCODED_SIG_SZ];
+        word32 outLen;
+        word32 signSz;
+        RNG    tmpRNG;
+        RNG*   rng = &tmpRNG; 
+
+        CYASSL_MSG("CyaSSL_RSA_sign");
+
+        if (m == NULL || sigRet == NULL || sigLen == NULL || rsa == NULL) {
+            CYASSL_MSG("Bad function arguments");
+            return 0;
+        }
+
+        if (rsa->inSet == 0) {
+            CYASSL_MSG("No RSA internal set");
+            return 0;
+        }
+
+        outLen = (word32)CyaSSL_BN_num_bytes(rsa->n);
+        if (outLen == 0) {
+            CYASSL_MSG("Bad RSA size");
+            return 0;
+        }
+       
+        if (InitRng(&tmpRNG) != 0) {
+            CYASSL_MSG("Bad RNG Init, trying global");
+            if (initGlobalRNG == 0) {
+                CYASSL_MSG("Global RNG no Init");
+                return 0; 
+            }
+            rng = &globalRNG;
+        }
+
+        switch (type) {
+            case NID_md5:
+                type = MD5h;
+                break;
+
+            case NID_sha1:
+                type = SHAh;
+                break;
+
+            default:
+                CYASSL_MSG("Bad md type");
+                return 0;
+        }
+
+        signSz = EncodeSignature(encodedSig, m, mLen, type);
+        if (signSz == 0) {
+            CYASSL_MSG("Bad Encode Signature");
+            return 0;
+        }
+
+        *sigLen = RsaSSL_Sign(encodedSig, signSz, sigRet, outLen,
+                              (RsaKey*)rsa->internal, rng);
+        if (*sigLen <= 0) {
+            CYASSL_MSG("Bad Rsa Sign");
+            return 0;
+        }
+
+        CYASSL_MSG("CyaSSL_RSA_sign success");
+        return SSL_SUCCESS;
+    }
+
+
+    int CyaSSL_RSA_public_decrypt(int flen, unsigned char* from,
+                              unsigned char* to, CYASSL_RSA* rsa, int padding)
+    {
+        (void)flen;
+        (void)from;
+        (void)to;
+        (void)rsa;
+        (void)padding;
+
+        CYASSL_MSG("CyaSSL_RSA_public_decrypt");
+
+        return SSL_FATAL_ERROR;
+    }
+
+
+    /* generate p-1 and q-1, SSL_SUCCESS on ok */
+    int CyaSSL_RSA_GenAdd(CYASSL_RSA* rsa)
+    {
+        int    err;
+        mp_int tmp;
+
+        CYASSL_MSG("CyaSSL_RsaGenAdd");
+
+        if (rsa == NULL || rsa->p == NULL || rsa->q == NULL || rsa->d == NULL ||
+                           rsa->dmp1 == NULL || rsa->dmq1 == NULL) {
+            CYASSL_MSG("rsa no init error");
+            return SSL_FATAL_ERROR;
+        }
+
+        if (mp_init(&tmp) != MP_OKAY) {
+            CYASSL_MSG("mp_init error");
+            return SSL_FATAL_ERROR;
+        }
+
+        err = mp_sub_d((mp_int*)rsa->p->internal, 1, &tmp);
+        if (err != MP_OKAY)
+            CYASSL_MSG("mp_sub_d error");
+        else
+            err = mp_mod((mp_int*)rsa->d->internal, &tmp,
+                         (mp_int*)rsa->dmp1->internal);
+
+        if (err != MP_OKAY)
+            CYASSL_MSG("mp_mod error");
+        else
+            err = mp_sub_d((mp_int*)rsa->q->internal, 1, &tmp);
+        if (err != MP_OKAY)
+            CYASSL_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;
+    }
+
+
+    void CyaSSL_HMAC_Init(CYASSL_HMAC_CTX* ctx, const void* key, int keylen,
+                      const EVP_MD* type)
+    {
+        CYASSL_MSG("CyaSSL_HMAC_Init");
+
+        if (ctx == NULL) {
+            CYASSL_MSG("no ctx on init");
+            return;
+        }
+
+        if (type) {
+            CYASSL_MSG("init has type");
+
+            if (XSTRNCMP(type, "MD5", 3) == 0) {
+                CYASSL_MSG("md5 hmac");
+                ctx->type = MD5;
+            }
+            else if (XSTRNCMP(type, "SHA256", 6) == 0) {
+                CYASSL_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) {
+                CYASSL_MSG("sha hmac");
+                ctx->type = SHA;
+            }
+            else {
+                CYASSL_MSG("bad init type");
+            }
+        }
+
+        if (key && keylen) {
+            CYASSL_MSG("keying hmac");
+            HmacSetKey(&ctx->hmac, ctx->type, (const byte*)key, (word32)keylen);
+        }
+    }
+
+
+    void CyaSSL_HMAC_Update(CYASSL_HMAC_CTX* ctx, const unsigned char* data,
+                        int len)
+    {
+        CYASSL_MSG("CyaSSL_HMAC_Update");
+
+        if (ctx && data) {
+            CYASSL_MSG("updating hmac");
+            HmacUpdate(&ctx->hmac, data, (word32)len);
+        }
+    }
+
+
+    void CyaSSL_HMAC_Final(CYASSL_HMAC_CTX* ctx, unsigned char* hash,
+                       unsigned int* len)
+    {
+        CYASSL_MSG("CyaSSL_HMAC_Final");
+
+        if (ctx && hash) {
+            CYASSL_MSG("final hmac");
+            HmacFinal(&ctx->hmac, hash);
+
+            if (len) {
+                CYASSL_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:
+                        CYASSL_MSG("bad hmac type");
+                }
+            }
+        }
+    }
+
+
+    void CyaSSL_HMAC_cleanup(CYASSL_HMAC_CTX* ctx)
+    {
+        (void)ctx;
+
+        CYASSL_MSG("CyaSSL_HMAC_cleanup");
+    }
+
+
+    const CYASSL_EVP_MD* CyaSSL_EVP_get_digestbynid(int id)
+    {
+        CYASSL_MSG("CyaSSL_get_digestbynid");
+
+        switch(id) {
+            case NID_md5:
+                return CyaSSL_EVP_md5();
+
+            case NID_sha1:
+                return CyaSSL_EVP_sha1();
+
+            default:
+                CYASSL_MSG("Bad digest id value");
+        }
+
+        return NULL;
+    }
+
+
+    CYASSL_RSA* CyaSSL_EVP_PKEY_get1_RSA(CYASSL_EVP_PKEY* key)
+    {
+        (void)key;
+        CYASSL_MSG("CyaSSL_EVP_PKEY_get1_RSA");
+
+        return NULL;
+    }
+
+
+    CYASSL_DSA* CyaSSL_EVP_PKEY_get1_DSA(CYASSL_EVP_PKEY* key)
+    {
+        (void)key;
+        CYASSL_MSG("CyaSSL_EVP_PKEY_get1_DSA");
+
+        return NULL;
+    }
+
+
+    void* CyaSSL_EVP_X_STATE(const CYASSL_EVP_CIPHER_CTX* ctx)
+    {
+        CYASSL_MSG("CyaSSL_EVP_X_STATE");
+
+        if (ctx) {
+            switch (ctx->cipherType) {
+                case ARC4_TYPE:
+                    CYASSL_MSG("returning arc4 state");
+                    return (void*)&ctx->cipher.arc4.x;
+                    break;
+
+                default:
+                    CYASSL_MSG("bad x state type");
+                    return 0;
+            }
+        }
+
+        return NULL;
+    }
+
+
+    int CyaSSL_EVP_X_STATE_LEN(const CYASSL_EVP_CIPHER_CTX* ctx)
+    {
+        CYASSL_MSG("CyaSSL_EVP_X_STATE_LEN");
+
+        if (ctx) {
+            switch (ctx->cipherType) {
+                case ARC4_TYPE:
+                    CYASSL_MSG("returning arc4 state size");
+                    return sizeof(Arc4);
+                    break;
+
+                default:
+                    CYASSL_MSG("bad x state type");
+                    return 0;
+            }
+        }
+
+        return 0;
+    }
+
+
+    void CyaSSL_3des_iv(CYASSL_EVP_CIPHER_CTX* ctx, int doset,
+                                unsigned char* iv, int len)
+    {
+        (void)len;
+
+        CYASSL_MSG("CyaSSL_3des_iv");
+
+        if (ctx == NULL || iv == NULL) {
+            CYASSL_MSG("Bad function argument");
+            return;
+        }
+
+        if (doset)
+            Des3_SetIV(&ctx->cipher.des3, iv);
+        else
+            memcpy(iv, &ctx->cipher.des3.reg, DES_BLOCK_SIZE);
+    }
+
+
+    void CyaSSL_aes_ctr_iv(CYASSL_EVP_CIPHER_CTX* ctx, int doset,
+                          unsigned char* iv, int len)
+    {
+        (void)len;
+
+        CYASSL_MSG("CyaSSL_aes_ctr_iv");
+
+        if (ctx == NULL || iv == NULL) {
+            CYASSL_MSG("Bad function argument");
+            return;
+        }
+
+        if (doset)
+            AesSetIV(&ctx->cipher.aes, iv);
+        else
+            memcpy(iv, &ctx->cipher.aes.reg, AES_BLOCK_SIZE);
+    }
+
+
+    const CYASSL_EVP_MD* CyaSSL_EVP_ripemd160(void)
+    {
+        CYASSL_MSG("CyaSSL_ripemd160");
+
+        return NULL;
+    }
+
+
+    int CyaSSL_EVP_MD_size(const CYASSL_EVP_MD* type)
+    {
+        CYASSL_MSG("CyaSSL_EVP_MD_size");
+
+        if (type == NULL) {
+            CYASSL_MSG("No md type arg");
+            return BAD_FUNC_ARG;
+        }
+
+        if (XSTRNCMP(type, "MD5", 3) == 0) {
+            return MD5_DIGEST_SIZE;
+        }
+        else if (XSTRNCMP(type, "SHA256", 6) == 0) {
+            return SHA256_DIGEST_SIZE;
+        }
+    #ifdef CYASSL_SHA384
+        else if (XSTRNCMP(type, "SHA384", 6) == 0) {
+            return SHA384_DIGEST_SIZE;
+        }
+    #endif
+    #ifdef CYASSL_SHA512
+        else if (XSTRNCMP(type, "SHA512", 6) == 0) {
+            return SHA512_DIGEST_SIZE;
+        }
+    #endif
+        /* has to be last since would pick or 256, 384, or 512 too */
+        else if (XSTRNCMP(type, "SHA", 3) == 0) {
+            return SHA_DIGEST_SIZE;
+        }   
+
+        return BAD_FUNC_ARG;
+    }
+
+
+    int CyaSSL_EVP_CIPHER_CTX_iv_length(const CYASSL_EVP_CIPHER_CTX* ctx)
+    {
+        CYASSL_MSG("CyaSSL_EVP_CIPHER_CTX_iv_length");
+
+        switch (ctx->cipherType) {
+
+            case AES_128_CBC_TYPE :
+            case AES_192_CBC_TYPE :
+            case AES_256_CBC_TYPE :
+                CYASSL_MSG("AES CBC");
+                return AES_BLOCK_SIZE;
+                break;
+
+#ifdef CYASSL_AES_COUNTER
+            case AES_128_CTR_TYPE :
+            case AES_192_CTR_TYPE :
+            case AES_256_CTR_TYPE :
+                CYASSL_MSG("AES CTR");
+                return AES_BLOCK_SIZE;
+                break;
+#endif
+
+            case DES_CBC_TYPE :
+                CYASSL_MSG("DES CBC");
+                return DES_BLOCK_SIZE;
+                break;
+                
+            case DES_EDE3_CBC_TYPE :
+                CYASSL_MSG("DES EDE3 CBC");
+                return DES_BLOCK_SIZE;
+                break;
+
+            case ARC4_TYPE :
+                CYASSL_MSG("ARC4");
+                return 0;
+                break;
+
+            case NULL_CIPHER_TYPE :
+                CYASSL_MSG("NULL");
+                return 0;
+                break;
+
+            default: {
+                CYASSL_MSG("bad type");
+            }
+        }    
+        return 0;
+    }
+
+
+    void CyaSSL_OPENSSL_free(void* p)
+    {
+        CYASSL_MSG("CyaSSL_OPENSSL_free");
+
+        XFREE(p, NULL, 0);
+    }
+
+
+    int CyaSSL_PEM_write_bio_RSAPrivateKey(CYASSL_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;
+
+        CYASSL_MSG("CyaSSL_PEM_write_bio_RSAPrivateKey");
+
+        return SSL_FATAL_ERROR;
+    }
+
+
+
+    int CyaSSL_PEM_write_bio_DSAPrivateKey(CYASSL_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;
+
+        CYASSL_MSG("CyaSSL_PEM_write_bio_DSAPrivateKey");
+
+        return SSL_FATAL_ERROR;
+    }
+
+
+
+    CYASSL_EVP_PKEY* CyaSSL_PEM_read_bio_PrivateKey(CYASSL_BIO* bio,
+                        CYASSL_EVP_PKEY** key, pem_password_cb cb, void* arg)
+    {
+        (void)bio;
+        (void)key;
+        (void)cb;
+        (void)arg;
+
+        CYASSL_MSG("CyaSSL_PEM_read_bio_PrivateKey");
+
+        return NULL;
+    }
+
+
+
+/* Return bytes written to buff or < 0 for error */
+int CyaSSL_KeyPemToDer(const unsigned char* pem, int pemSz, unsigned char* buff,
+                       int buffSz, const char* pass)
+{
+    EncryptedInfo info;
+    int           eccKey = 0;
+    int           ret;
+    buffer        der;
+
+    (void)pass;
+
+    CYASSL_ENTER("CyaSSL_KeyPemToDer");
+
+    if (pem == NULL || buff == NULL || buffSz <= 0) {
+        CYASSL_MSG("Bad pem der args"); 
+        return BAD_FUNC_ARG;
+    }
+
+    info.set       = 0;
+    info.ctx      = NULL;
+    info.consumed = 0;
+    der.buffer    = NULL;
+
+    ret = PemToDer(pem, pemSz, PRIVATEKEY_TYPE, &der, NULL, &info, &eccKey);
+    if (ret < 0) {
+        CYASSL_MSG("Bad Pem To Der"); 
+    }
+    else {
+        if (der.length <= (word32)buffSz) {
+            XMEMCPY(buff, der.buffer, der.length);
+            ret = der.length;
+        }
+        else {
+            CYASSL_MSG("Bad der length");
+            ret = BAD_FUNC_ARG;
+        }
+    }
+
+    XFREE(der.buffer, NULL, DYANMIC_KEY_TYPE);
+
+    return ret;
+}
+
+
+/* Load RSA from Der, SSL_SUCCESS on success < 0 on error */
+int CyaSSL_RSA_LoadDer(CYASSL_RSA* rsa, const unsigned char* der,  int derSz)
+{
+    word32 idx = 0;
+    int    ret;
+
+    CYASSL_ENTER("CyaSSL_RSA_LoadDer");
+
+    if (rsa == NULL || rsa->internal == NULL || der == NULL || derSz <= 0) {
+        CYASSL_MSG("Bad function arguments");
+        return BAD_FUNC_ARG;
+    }
+
+    ret = RsaPrivateKeyDecode(der, &idx, (RsaKey*)rsa->internal, derSz);
+    if (ret < 0) {
+        CYASSL_MSG("RsaPrivateKeyDecode failed");
+        return ret;
+    }
+
+    if (SetRsaExternal(rsa) < 0) {
+        CYASSL_MSG("SetRsaExternal failed");
+        return SSL_FATAL_ERROR;
+    }
+
+    rsa->inSet = 1;
+
+    return SSL_SUCCESS;
+}
+
+
+#ifndef NO_DSA
+/* Load DSA from Der, SSL_SUCCESS on success < 0 on error */
+int CyaSSL_DSA_LoadDer(CYASSL_DSA* dsa, const unsigned char* der,  int derSz)
+{
+    word32 idx = 0;
+    int    ret;
+
+    CYASSL_ENTER("CyaSSL_DSA_LoadDer");
+
+    if (dsa == NULL || dsa->internal == NULL || der == NULL || derSz <= 0) {
+        CYASSL_MSG("Bad function arguments");
+        return BAD_FUNC_ARG;
+    }
+
+    ret = DsaPrivateKeyDecode(der, &idx, (DsaKey*)dsa->internal, derSz);
+    if (ret < 0) {
+        CYASSL_MSG("DsaPrivateKeyDecode failed");
+        return ret;
+    }
+
+    if (SetDsaExternal(dsa) < 0) {
+        CYASSL_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 */
+CYASSL_X509_CHAIN* CyaSSL_get_peer_chain(CYASSL* ssl)
+{
+    CYASSL_ENTER("CyaSSL_get_peer_chain");
+    if (ssl)
+        return &ssl->session.chain;
+
+    return 0;
+}
+
+
+/* Get peer's certificate chain total count */
+int CyaSSL_get_chain_count(CYASSL_X509_CHAIN* chain)
+{
+    CYASSL_ENTER("CyaSSL_get_chain_count");
+    if (chain)
+        return chain->count;
+
+    return 0;
+}
+
+
+/* Get peer's ASN.1 DER ceritifcate at index (idx) length in bytes */
+int CyaSSL_get_chain_length(CYASSL_X509_CHAIN* chain, int idx)
+{
+    CYASSL_ENTER("CyaSSL_get_chain_length");
+    if (chain)
+        return chain->certs[idx].length;
+
+    return 0;
+}
+
+
+/* Get peer's ASN.1 DER ceritifcate at index (idx) */
+byte* CyaSSL_get_chain_cert(CYASSL_X509_CHAIN* chain, int idx)
+{
+    CYASSL_ENTER("CyaSSL_get_chain_cert");
+    if (chain)
+        return chain->certs[idx].buffer;
+
+    return 0;
+}
+
+
+/* Get peer's CyaSSL X509 ceritifcate at index (idx) */
+CYASSL_X509* CyaSSL_get_chain_X509(CYASSL_X509_CHAIN* chain, int idx)
+{
+    int          ret;
+    CYASSL_X509* x509;
+    DecodedCert  dCert;
+
+    CYASSL_ENTER("CyaSSL_get_chain_X509");
+    if (chain == NULL)
+        return NULL;
+
+    InitDecodedCert(&dCert, chain->certs[idx].buffer, chain->certs[idx].length,
+                    NULL);
+    ret = ParseCertRelative(&dCert, CERT_TYPE, 0, NULL);
+    if (ret != 0) {
+        CYASSL_MSG("Failed to parse cert");
+        FreeDecodedCert(&dCert);
+        return NULL;
+    }
+
+    x509 = (CYASSL_X509*)XMALLOC(sizeof(CYASSL_X509), NULL, DYNAMIC_TYPE_X509);
+    if (x509 == NULL) {
+        CYASSL_MSG("Failed alloc X509");
+        FreeDecodedCert(&dCert);
+        return NULL;
+    }
+    InitX509(x509, 1);
+
+    ret = CopyDecodedToX509(x509, &dCert);
+    if (ret != 0) {
+        CYASSL_MSG("Failed to copy decoded");
+        XFREE(x509, NULL, DYNAMIC_TYPE_X509);
+        x509 = NULL;
+    }
+    FreeDecodedCert(&dCert);
+
+    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  CyaSSL_get_chain_cert_pem(CYASSL_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;
+
+    CYASSL_ENTER("CyaSSL_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* CyaSSL_get_sessionID(const CYASSL_SESSION* session)
+{
+    CYASSL_ENTER("CyaSSL_get_sessionID");
+    if (session)
+        return session->sessionID;
+
+    return NULL;
+}
+
+
+#endif /* SESSION_CERTS */
+
+
+long CyaSSL_CTX_OCSP_set_options(CYASSL_CTX* ctx, long options)
+{
+    CYASSL_ENTER("CyaSSL_CTX_OCSP_set_options");
+#ifdef HAVE_OCSP
+    if (ctx != NULL) {
+        ctx->ocsp.enabled = (options & CYASSL_OCSP_ENABLE) != 0;
+        ctx->ocsp.useOverrideUrl = (options & CYASSL_OCSP_URL_OVERRIDE) != 0;
+        ctx->ocsp.useNonce = (options & CYASSL_OCSP_NO_NONCE) == 0;
+        return 1;
+    }
+    return 0;
+#else
+    (void)ctx;
+    (void)options;
+    return NOT_COMPILED_IN;
+#endif
+}
+
+
+int CyaSSL_CTX_OCSP_set_override_url(CYASSL_CTX* ctx, const char* url)
+{
+    CYASSL_ENTER("CyaSSL_CTX_OCSP_set_override_url");
+#ifdef HAVE_OCSP
+    return CyaSSL_OCSP_set_override_url(&ctx->ocsp, url);
+#else
+    (void)ctx;
+    (void)url;
+    return NOT_COMPILED_IN;
+#endif
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tls.c	Thu Sep 05 10:33:04 2013 +0000
@@ -0,0 +1,1252 @@
+/* tls.c
+ *
+ * Copyright (C) 2006-2013 wolfSSL Inc.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL 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.
+ *
+ * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <cyassl/ctaocrypt/settings.h>
+
+#include <cyassl/ssl.h>
+#include <cyassl/internal.h>
+#include <cyassl/ctaoerror.h>
+#include <cyassl/ctaocrypt/hmac.h>
+
+
+
+#ifndef NO_TLS
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+#ifdef CYASSL_SHA384
+    #define PHASH_MAX_DIGEST_SIZE SHA384_DIGEST_SIZE
+#else
+    #define PHASH_MAX_DIGEST_SIZE SHA256_DIGEST_SIZE
+#endif
+
+/* compute p_hash for MD5, SHA-1, SHA-256, or SHA-384 for TLSv1 PRF */
+static void p_hash(byte* result, word32 resLen, const byte* secret,
+                   word32 secLen, const byte* seed, word32 seedLen, int hash)
+{
+    word32   len = PHASH_MAX_DIGEST_SIZE;
+    word32   times;
+    word32   lastLen;
+    word32   lastTime;
+    word32   i;
+    word32   idx = 0;
+    byte     previous[PHASH_MAX_DIGEST_SIZE];  /* max size */
+    byte     current[PHASH_MAX_DIGEST_SIZE];   /* max size */
+
+    Hmac hmac;
+
+    switch (hash) {
+        #ifndef NO_MD5
+        case md5_mac:
+        {
+            len = MD5_DIGEST_SIZE;
+            hash = MD5;
+        }
+        break;
+        #endif
+        #ifndef NO_SHA256
+        case sha256_mac:
+        {
+            len = SHA256_DIGEST_SIZE;
+            hash = SHA256;
+        }
+        break;
+        #endif
+        #ifdef CYASSL_SHA384
+        case sha384_mac:
+        {
+            len = SHA384_DIGEST_SIZE;
+            hash = SHA384;
+        }
+        break;
+        #endif
+#ifndef NO_SHA
+        case sha_mac:
+        default:
+        {
+            len = SHA_DIGEST_SIZE;
+            hash = SHA;
+        }
+        break;
+#endif
+    }
+
+    times = resLen / len;
+    lastLen = resLen % len;
+    if (lastLen) times += 1;
+    lastTime = times - 1;
+
+    HmacSetKey(&hmac, hash, secret, secLen);
+    HmacUpdate(&hmac, seed, seedLen);       /* A0 = seed */
+    HmacFinal(&hmac, previous);             /* A1 */
+
+    for (i = 0; i < times; i++) {
+        HmacUpdate(&hmac, previous, len);
+        HmacUpdate(&hmac, seed, seedLen);
+        HmacFinal(&hmac, current);
+
+        if ( (i == lastTime) && lastLen)
+            XMEMCPY(&result[idx], current, min(lastLen, sizeof(current)));
+        else {
+            XMEMCPY(&result[idx], current, len);
+            idx += len;
+            HmacUpdate(&hmac, previous, len);
+            HmacFinal(&hmac, previous);
+        }
+    }
+    XMEMSET(previous, 0, sizeof previous);
+    XMEMSET(current, 0, sizeof current);
+    XMEMSET(&hmac, 0, sizeof hmac);
+}
+
+
+
+#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 void doPRF(byte* digest, word32 digLen, const byte* secret,word32 secLen,
+            const byte* label, word32 labLen, const byte* seed, word32 seedLen)
+{
+    word32 half = (secLen + 1) / 2;
+
+    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 */
+
+    if (half > MAX_PRF_HALF)
+        return;
+    if (labLen + seedLen > MAX_PRF_LABSEED)
+        return;
+    if (digLen > MAX_PRF_DIG)
+        return;
+
+    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);
+
+    p_hash(md5_result, digLen, md5_half, half, labelSeed, labLen + seedLen,
+           md5_mac);
+    p_hash(sha_result, digLen, sha_half, half, labelSeed, labLen + seedLen,
+           sha_mac);
+    get_xor(digest, digLen, md5_result, sha_result);
+}
+
+#endif
+
+
+/* Wrapper to call straight thru to p_hash in TSL 1.2 cases to remove stack
+   use */
+static void 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)
+{
+    if (useAtLeastSha256) {
+        byte labelSeed[MAX_PRF_LABSEED];    /* labLen + seedLen is real size */
+
+        if (labLen + seedLen > MAX_PRF_LABSEED)
+            return;
+
+        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;
+        p_hash(digest, digLen, secret, secLen, labelSeed, labLen + seedLen,
+               hash_type);
+    }
+#ifndef NO_OLD_TLS
+    else
+        doPRF(digest, digLen, secret, secLen, label, labLen, seed, seedLen);
+#endif
+}
+
+
+#ifdef CYASSL_SHA384
+    #define HSHASH_SZ SHA384_DIGEST_SIZE
+#else
+    #define HSHASH_SZ FINISHED_SZ
+#endif
+
+
+void BuildTlsFinished(CYASSL* ssl, Hashes* hashes, const byte* sender)
+{
+    const byte* side;
+    byte        handshake_hash[HSHASH_SZ];
+    word32      hashSz = FINISHED_SZ;
+
+#ifndef NO_OLD_TLS
+    Md5Final(&ssl->hashMd5, handshake_hash);
+    ShaFinal(&ssl->hashSha, &handshake_hash[MD5_DIGEST_SIZE]);
+#endif
+    
+    if (IsAtLeastTLSv1_2(ssl)) {
+#ifndef NO_SHA256
+        if (ssl->specs.mac_algorithm <= sha256_mac) {
+            Sha256Final(&ssl->hashSha256, handshake_hash);
+            hashSz = SHA256_DIGEST_SIZE;
+        }
+#endif
+#ifdef CYASSL_SHA384
+        if (ssl->specs.mac_algorithm == sha384_mac) {
+            Sha384Final(&ssl->hashSha384, handshake_hash);
+            hashSz = SHA384_DIGEST_SIZE;
+        }
+#endif
+    }
+   
+    if ( XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0)
+        side = tls_client;
+    else
+        side = tls_server;
+
+    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";
+
+
+int DeriveTlsKeys(CYASSL* ssl)
+{
+    int length = 2 * ssl->specs.hash_size + 
+                 2 * ssl->specs.key_size  +
+                 2 * ssl->specs.iv_size;
+    byte         seed[SEED_LEN];
+    byte         key_data[MAX_PRF_DIG];
+
+    XMEMCPY(seed, ssl->arrays->serverRandom, RAN_LEN);
+    XMEMCPY(&seed[RAN_LEN], ssl->arrays->clientRandom, RAN_LEN);
+
+    PRF(key_data, length, ssl->arrays->masterSecret, SECRET_LEN, key_label,
+        KEY_LABEL_SZ, seed, SEED_LEN, IsAtLeastTLSv1_2(ssl),
+        ssl->specs.mac_algorithm);
+
+    return StoreKeys(ssl, key_data);
+}
+
+
+int MakeTlsMasterSecret(CYASSL* ssl)
+{
+    byte seed[SEED_LEN];
+    
+    XMEMCPY(seed, ssl->arrays->clientRandom, RAN_LEN);
+    XMEMCPY(&seed[RAN_LEN], ssl->arrays->serverRandom, RAN_LEN);
+
+    PRF(ssl->arrays->masterSecret, SECRET_LEN,
+        ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz,
+        master_label, MASTER_LABEL_SZ, 
+        seed, SEED_LEN, IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
+
+#ifdef SHOW_SECRETS
+    {
+        int i;
+        printf("master secret: ");
+        for (i = 0; i < SECRET_LEN; i++)
+            printf("%02x", ssl->arrays->masterSecret[i]);
+        printf("\n");
+    }
+#endif
+
+    return DeriveTlsKeys(ssl);
+}
+
+
+/* Used by EAP-TLS and EAP-TTLS to derive keying material from
+ * the master_secret. */
+int CyaSSL_make_eap_keys(CYASSL* ssl, void* msk, unsigned int len,
+                                                              const char* label)
+{
+    byte seed[SEED_LEN];
+
+    /*
+     * 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);
+
+    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);
+
+    return 0;
+}
+
+
+/*** next for static INLINE s copied from cyassl_int.c ***/
+
+/* convert 16 bit integer to opaque */
+static INLINE void c16toa(word16 u16, byte* c)
+{
+    c[0] = (u16 >> 8) & 0xff;
+    c[1] =  u16 & 0xff;
+}
+
+/* convert opaque to 16 bit integer */
+static INLINE void ato16(const byte* c, word16* u16)
+{
+    *u16 = (c[0] << 8) | (c[1]);
+}
+
+
+/* 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(CYASSL* ssl, int verify)
+{
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        if (verify)
+            return ssl->keys.dtls_peer_sequence_number; /* 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 CYASSL_DTLS
+
+static INLINE word32 GetEpoch(CYASSL* ssl, int verify)
+{
+    if (verify)
+        return ssl->keys.dtls_peer_epoch; 
+    else
+        return ssl->keys.dtls_epoch; 
+}
+
+#endif /* CYASSL_DTLS */
+
+
+static INLINE const byte* GetMacSecret(CYASSL* ssl, int verify)
+{
+    if ( (ssl->options.side == CLIENT_END && !verify) ||
+         (ssl->options.side == SERVER_END &&  verify) )
+        return ssl->keys.client_write_MAC_secret;
+    else
+        return ssl->keys.server_write_MAC_secret;
+}
+
+/*** end copy ***/
+
+
+/* TLS type HMAC */
+void TLS_hmac(CYASSL* ssl, byte* digest, const byte* in, word32 sz,
+              int content, int verify)
+{
+    Hmac hmac;
+    byte seq[SEQ_SZ];
+    byte length[LENGTH_SZ];
+    byte inner[ENUM_LEN + VERSION_SZ + LENGTH_SZ]; /* type + version +len */
+    int  type;
+
+    XMEMSET(seq, 0, SEQ_SZ);
+    c16toa((word16)sz, length);
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls)
+        c16toa((word16)GetEpoch(ssl, verify), seq);
+#endif
+    c32toa(GetSEQIncrement(ssl, verify), &seq[sizeof(word32)]);
+    
+    switch (ssl->specs.mac_algorithm) {
+        #ifndef NO_MD5
+        case md5_mac:
+        {
+            type = MD5;
+        }
+        break;
+        #endif
+        #ifndef NO_SHA256
+        case sha256_mac:
+        {
+            type = SHA256;
+        }
+        break;
+        #endif
+        #ifdef CYASSL_SHA384
+        case sha384_mac:
+        {
+            type = SHA384;
+        }
+        break;
+        #endif
+#ifndef NO_SHA
+        case sha_mac:
+        default:
+        {
+            type = SHA;
+        }
+        break;
+#endif
+    }
+    HmacSetKey(&hmac, type, GetMacSecret(ssl, verify), ssl->specs.hash_size);
+    
+    HmacUpdate(&hmac, seq, SEQ_SZ);                               /* seq_num */
+    inner[0] = (byte)content;                                     /* type */
+    inner[ENUM_LEN] = ssl->version.major;
+    inner[ENUM_LEN + ENUM_LEN] = ssl->version.minor;              /* version */
+    XMEMCPY(&inner[ENUM_LEN + VERSION_SZ], length, LENGTH_SZ);     /* length */
+    HmacUpdate(&hmac, inner, sizeof(inner));
+    HmacUpdate(&hmac, in, sz);                                /* content */
+    HmacFinal(&hmac, digest);
+}
+
+#ifdef HAVE_TLS_EXTENSIONS
+
+static int TLSX_Append(TLSX** list, TLSX_Type type)
+{
+    TLSX* extension;
+
+    if (list == NULL) /* won't check type since this function is static */
+        return BAD_FUNC_ARG;
+
+    if ((extension = XMALLOC(sizeof(TLSX), 0, DYNAMIC_TYPE_TLSX)) == NULL)
+        return MEMORY_E;
+
+    extension->type = type;
+    extension->data = NULL;
+    extension->resp = 0;
+    extension->next = *list;
+    *list = extension;
+
+    return 0;
+}
+
+#ifndef NO_CYASSL_SERVER
+
+static void TLSX_SetResponse(CYASSL* 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 CYASSL_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 CYASSL_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;
+        break;
+    }
+
+    sni->type = type;
+    sni->next = *list;
+
+#ifndef NO_CYASSL_SERVER
+    sni->options = 0;
+    sni->matched = 0;
+#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 CYASSL_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 CYASSL_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_CYASSL_SERVER
+static void TLSX_SNI_SetMatched(TLSX* extensions, byte type)
+{
+    TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
+    SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+
+    if (sni) {
+        sni->matched = 1;
+        CYASSL_MSG("SNI did match!");
+    }
+}
+
+byte TLSX_SNI_Matched(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->matched;
+
+    return 0;
+}
+#endif
+
+static int TLSX_SNI_Parse(CYASSL* ssl, byte* input, word16 length,
+                                                                 byte isRequest)
+{
+#ifndef NO_CYASSL_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) {
+        if (!isRequest) {
+            CYASSL_MSG("Unexpected SNI response from server");
+        }
+
+        return 0; /* not using SNI */
+    }
+
+    if (!isRequest) {
+        if (length) {
+            CYASSL_MSG("SNI response should be empty!");
+        }
+
+        return 0; /* nothing to do */
+    }
+
+#ifndef NO_CYASSL_SERVER
+
+    if (OPAQUE16_LEN > length)
+        return INCOMPLETE_DATA;
+
+    ato16(input, &size);
+    offset += OPAQUE16_LEN;
+
+    /* validating sni list length */
+    if (length != OPAQUE16_LEN + size)
+        return INCOMPLETE_DATA;
+
+    for (size = 0; offset < length; offset += size) {
+        SNI *sni;
+        byte type = input[offset++];
+
+        if (offset + OPAQUE16_LEN > length)
+            return INCOMPLETE_DATA;
+
+        ato16(input + offset, &size);
+        offset += OPAQUE16_LEN;
+
+        if (offset + size > length)
+            return INCOMPLETE_DATA;
+
+        if (!(sni = TLSX_SNI_Find((SNI *) extension->data, type))) {
+            continue; /* not using this SNI type */
+        }
+
+        switch(type) {
+            case CYASSL_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 & CYASSL_SNI_ANSWER_ON_MISMATCH) {
+                    int r = TLSX_UseSNI(&ssl->extensions, type, (byte *) "", 0);
+
+                    if (r) return r; /* throw error */
+
+                    if (matched) TLSX_SNI_SetMatched(ssl->extensions, type);
+                } else if (!(sni->options & CYASSL_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 = NULL;
+    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;
+
+    extension = *extensions;
+
+    /* find SNI extension if it already exists. */
+    while (extension && extension->type != SERVER_NAME_INDICATION)
+        extension = extension->next;
+
+    /* push new SNI extension if it doesn't exists. */
+    if (!extension) {
+        if ((ret = TLSX_Append(extensions, SERVER_NAME_INDICATION)) != 0) {
+            TLSX_SNI_Free(sni);
+            return ret;
+        }
+
+        extension = *extensions;
+    }
+
+    /* 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 (replacement) */
+    while ((sni = sni->next)) {
+        if (sni->next && sni->next->type == type) {
+            SNI *next = sni->next;
+
+            sni->next = next->next;
+            TLSX_SNI_Free(next);
+
+            break;
+        }
+    }
+
+    return 0;
+}
+
+#ifndef NO_CYASSL_SERVER
+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;
+}
+#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(x)
+#define SNI_GET_SIZE(x) 0
+#define SNI_WRITE(x) 0
+#define SNI_PARSE(x) 0
+
+#endif /* HAVE_SNI */
+
+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;
+        }
+
+        XFREE(extension, 0, DYNAMIC_TYPE_TLSX);
+    }
+}
+
+#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 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, extension->type)) {
+            /* type + data length */
+            length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
+
+            switch (extension->type) {
+                case SERVER_NAME_INDICATION:
+                    if (isRequest)
+                        length += SNI_GET_SIZE((SNI *) extension->data);
+                    break;
+            }
+
+            TURN_ON(semaphore, 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, extension->type)) {
+            /* 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((SNI *) extension->data,
+                                                               output + offset);
+                    break;
+            }
+
+            /* writing extension data length */
+            c16toa(offset - length_offset,
+                                         output + length_offset - OPAQUE16_LEN);
+
+            TURN_ON(semaphore, extension->type);
+        }
+    }
+
+    return offset;
+}
+
+#ifndef NO_CYASSL_CLIENT
+
+word16 TLSX_GetRequestSize(CYASSL* ssl)
+{
+    word16 length = 0;
+
+    if (ssl && IsTLS(ssl)) {
+        byte semaphore[16] = {0};
+
+        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(CYASSL* ssl, byte* output)
+{
+    word16 offset = 0;
+
+    if (ssl && IsTLS(ssl) && output) {
+        byte semaphore[16] = {0};
+
+        offset += OPAQUE16_LEN; /* extensions length */
+
+        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_CYASSL_CLIENT */
+
+#ifndef NO_CYASSL_SERVER
+
+word16 TLSX_GetResponseSize(CYASSL* ssl)
+{
+    word16 length = 0;
+    byte semaphore[16] = {0};
+
+    if (ssl && IsTLS(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(CYASSL *ssl, byte* output)
+{
+    word16 offset = 0;
+
+    if (ssl && IsTLS(ssl) && output) {
+        byte semaphore[16] = {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_CYASSL_SERVER */
+
+int TLSX_Parse(CYASSL* ssl, byte* input, word16 length, byte isRequest,
+                                                                 Suites *suites)
+{
+    int ret = 0;
+    word16 offset = 0;
+
+    if (!ssl || !input || !suites)
+        return BAD_FUNC_ARG;
+
+    while (ret == 0 && offset < length) {
+        word16 type;
+        word16 size;
+
+        if (length - offset < HELLO_EXT_TYPE_SZ + OPAQUE16_LEN)
+            return INCOMPLETE_DATA;
+
+        ato16(input + offset, &type);
+        offset += HELLO_EXT_TYPE_SZ;
+
+        ato16(input + offset, &size);
+        offset += OPAQUE16_LEN;
+
+        if (offset + size > length)
+            return INCOMPLETE_DATA;
+
+        switch (type) {
+            case SERVER_NAME_INDICATION:
+                CYASSL_MSG("SNI extension received");
+
+                ret = SNI_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 INCOMPLETE_DATA;
+
+                        XMEMCPY(suites->hashSigAlgo,
+                                input + offset + OPAQUE16_LEN,
+                                min(suites->hashSigAlgoSz,
+                                                        HELLO_EXT_SIGALGO_MAX));
+                    }
+                } else {
+                    CYASSL_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
+
+#endif /* HAVE_TLS_EXTENSIONS */
+
+
+#ifndef NO_CYASSL_CLIENT
+
+#ifndef NO_OLD_TLS
+
+    CYASSL_METHOD* CyaTLSv1_client_method(void)
+    {
+        CYASSL_METHOD* method =
+                             (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
+                                                      DYNAMIC_TYPE_METHOD);
+        if (method)
+            InitSSL_Method(method, MakeTLSv1());
+        return method;
+    }
+
+
+    CYASSL_METHOD* CyaTLSv1_1_client_method(void)
+    {
+        CYASSL_METHOD* method =
+                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_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 */
+
+    CYASSL_METHOD* CyaTLSv1_2_client_method(void)
+    {
+        CYASSL_METHOD* method =
+                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+        if (method)
+            InitSSL_Method(method, MakeTLSv1_2());
+        return method;
+    }
+
+#endif
+
+
+    CYASSL_METHOD* CyaSSLv23_client_method(void)
+    {
+        CYASSL_METHOD* method =
+                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_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_CYASSL_CLIENT */
+
+
+
+#ifndef NO_CYASSL_SERVER
+
+#ifndef NO_OLD_TLS
+
+    CYASSL_METHOD* CyaTLSv1_server_method(void)
+    {
+        CYASSL_METHOD* method =
+                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeTLSv1());
+            method->side = SERVER_END;
+        }
+        return method;
+    }
+
+
+    CYASSL_METHOD* CyaTLSv1_1_server_method(void)
+    {
+        CYASSL_METHOD* method =
+                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeTLSv1_1());
+            method->side = SERVER_END;
+        }
+        return method;
+    }
+
+#endif /* !NO_OLD_TLS */
+
+#ifndef NO_SHA256   /* can't use without SHA256 */
+
+    CYASSL_METHOD* CyaTLSv1_2_server_method(void)
+    {
+        CYASSL_METHOD* method =
+                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeTLSv1_2());
+            method->side = SERVER_END;
+        }
+        return method;
+    }
+
+#endif
+
+
+    CYASSL_METHOD* CyaSSLv23_server_method(void)
+    {
+        CYASSL_METHOD* method =
+                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_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      = SERVER_END;
+#ifndef NO_OLD_TLS
+            method->downgrade = 1;
+#endif /* !NO_OLD_TLS */
+        }
+        return method;
+    }
+
+
+
+#endif /* NO_CYASSL_SERVER */
+#endif /* NO_TLS */
+