SSL/TLS Library

Dependents:  

CyaSSL is SSL/TLS library for embedded systems.

wolfssl.com

Files at this revision

API Documentation at this revision

Comitter:
wolfSSL
Date:
Sun Apr 20 12:40:57 2014 +0000
Commit message:
CyaSSL SSL/TLS Library 2.9.4;

Changed in this revision

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/fips.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/fips_test.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/pkcs7.c Show annotated file Show diff for this revision Revisions of this file
ctaocrypt/src/port.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/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/error-crypt.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/fips_test.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/pkcs7.h Show annotated file Show diff for this revision Revisions of this file
cyassl/ctaocrypt/port.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/error-ssl.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
src/crl.c Show annotated file Show diff for this revision Revisions of this file
src/internal.c Show annotated file Show diff for this revision Revisions of this file
src/io.c Show annotated file Show diff for this revision Revisions of this file
src/keys.c Show annotated file Show diff for this revision Revisions of this file
src/ocsp.c Show annotated file Show diff for this revision Revisions of this file
src/sniffer.c Show annotated file Show diff for this revision Revisions of this file
src/ssl.c Show annotated file Show diff for this revision Revisions of this file
src/tls.c Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/aes.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,3496 @@
+/* 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
+
+#ifdef HAVE_FIPS
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+#endif
+
+#include <cyassl/ctaocrypt/aes.h>
+#include <cyassl/ctaocrypt/error-crypt.h>
+#include <cyassl/ctaocrypt/logging.h>
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/src/misc.c>
+#endif
+#ifdef DEBUG_AESNI
+    #include <stdio.h>
+#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 int  AesCaviumCbcEncrypt(Aes* aes, byte* out, const byte* in,
+                                    word32 length);
+    static int  AesCaviumCbcDecrypt(Aes* aes, byte* out, const byte* in,
+                                    word32 length);
+#endif
+
+#if defined(CYASSL_PIC32MZ_CRYPT)
+
+#include "../../cyassl/ctaocrypt/port/pic32/pic32mz-crypt.h"
+#define DEBUG_CYASSL
+
+    /* core hardware crypt engine driver */
+    static void AesCrypt(Aes *aes, byte* out, const byte* in, word32 sz,
+                                            int dir, int algo, int cryptoalgo)
+    {
+        securityAssociation *sa_p ;
+        bufferDescriptor *bd_p ;
+
+        volatile securityAssociation sa __attribute__((aligned (8)));
+        volatile bufferDescriptor bd __attribute__((aligned (8)));
+        volatile int k ;
+
+        /* get uncached address */
+        sa_p = KVA0_TO_KVA1(&sa) ;
+        bd_p = KVA0_TO_KVA1(&bd) ;
+
+        /* Sync cache and physical memory */
+        if(PIC32MZ_IF_RAM(in)) {
+            XMEMCPY((void *)KVA0_TO_KVA1(in), (void *)in, sz);
+        }
+        XMEMSET((void *)KVA0_TO_KVA1(out), 0, sz);
+        /* Set up the Security Association */
+        XMEMSET((byte *)KVA0_TO_KVA1(&sa), 0, sizeof(sa));
+        sa_p->SA_CTRL.ALGO = algo ; /* AES */
+        sa_p->SA_CTRL.LNC = 1;
+        sa_p->SA_CTRL.LOADIV = 1;
+        sa_p->SA_CTRL.FB = 1;
+        sa_p->SA_CTRL.ENCTYPE = dir ; /* Encryption/Decryption */
+        sa_p->SA_CTRL.CRYPTOALGO = cryptoalgo;
+
+        if(cryptoalgo == PIC32_CRYPTOALGO_AES_GCM){
+            switch(aes->keylen) {
+            case 32:
+                sa_p->SA_CTRL.KEYSIZE = PIC32_AES_KEYSIZE_256 ;
+                break ;
+            case 24:
+                sa_p->SA_CTRL.KEYSIZE = PIC32_AES_KEYSIZE_192 ;
+                break ;
+            case 16:
+                sa_p->SA_CTRL.KEYSIZE = PIC32_AES_KEYSIZE_128 ;
+                break ;
+            }
+        } else
+            sa_p->SA_CTRL.KEYSIZE = PIC32_AES_KEYSIZE_128 ;
+
+        ByteReverseWords(
+        (word32 *)KVA0_TO_KVA1(sa.SA_ENCKEY + 8 - aes->keylen/sizeof(word32)),
+                         (word32 *)aes->key_ce, aes->keylen);
+        ByteReverseWords(
+        (word32*)KVA0_TO_KVA1(sa.SA_ENCIV), (word32 *)aes->iv_ce, 16);
+
+        XMEMSET((byte *)KVA0_TO_KVA1(&bd), 0, sizeof(bd));
+        /* Set up the Buffer Descriptor */
+        bd_p->BD_CTRL.BUFLEN = sz;
+        if(cryptoalgo == PIC32_CRYPTOALGO_AES_GCM) {
+            if(sz % 0x10)
+                bd_p->BD_CTRL.BUFLEN = (sz/0x10 + 1) * 0x10 ;
+        }
+        bd_p->BD_CTRL.LIFM = 1;
+        bd_p->BD_CTRL.SA_FETCH_EN = 1;
+        bd_p->BD_CTRL.LAST_BD = 1;
+        bd_p->BD_CTRL.DESC_EN = 1;
+
+        bd_p->SA_ADDR = (unsigned int)KVA_TO_PA(&sa) ; 
+        bd_p->SRCADDR = (unsigned int)KVA_TO_PA(in) ; 
+        bd_p->DSTADDR = (unsigned int)KVA_TO_PA(out); 
+        bd_p->MSGLEN = sz ;
+
+        CECON = 1 << 6;
+        while (CECON);
+
+        /* Run the engine */
+        CEBDPADDR = (unsigned int)KVA_TO_PA(&bd) ;
+        CEINTEN = 0x07;
+        CECON = 0x27;
+
+        WAIT_ENGINE ;
+
+        if((cryptoalgo == PIC32_CRYPTOALGO_CBC) ||
+           (cryptoalgo == PIC32_CRYPTOALGO_TCBC)||
+           (cryptoalgo == PIC32_CRYPTOALGO_RCBC)) {
+            /* set iv for the next call */
+            if(dir == PIC32_ENCRYPTION) {
+	        XMEMCPY((void *)aes->iv_ce,
+                        (void*)KVA0_TO_KVA1(out + sz - AES_BLOCK_SIZE),
+                        AES_BLOCK_SIZE) ;
+	    } else {
+                ByteReverseWords((word32*)aes->iv_ce,
+                        (word32 *)KVA0_TO_KVA1(in + sz - AES_BLOCK_SIZE),
+                        AES_BLOCK_SIZE);
+	    }
+        }
+        XMEMCPY((byte *)out, (byte *)KVA0_TO_KVA1(out), sz) ;
+        ByteReverseWords((word32*)out, (word32 *)out, sz);
+    }
+
+    int AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+    {
+        AesCrypt(aes, out, in, sz, PIC32_ENCRYPTION, PIC32_ALGO_AES,
+                                                      PIC32_CRYPTOALGO_RCBC );
+    }
+
+    int AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+    {
+        AesCrypt(aes, out, in, sz, PIC32_DECRYPTION, PIC32_ALGO_AES,
+                                                      PIC32_CRYPTOALGO_RCBC);
+    }
+
+    #if defined(CYASSL_AES_COUNTER)
+    void AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+    {
+        int i ;
+        char out_block[AES_BLOCK_SIZE] ;
+        int odd ;
+        int even ;
+        char *tmp ; /* (char *)aes->tmp, for short */
+
+        tmp = (char *)aes->tmp ;
+        if(aes->left) {
+            if((aes->left + sz) >= AES_BLOCK_SIZE){
+                odd = AES_BLOCK_SIZE - aes->left ;
+            } else {
+                odd = sz ;
+            }
+            XMEMCPY(tmp+aes->left, in, odd) ;
+            if((odd+aes->left) == AES_BLOCK_SIZE){
+                AesCrypt(aes, out_block, tmp, AES_BLOCK_SIZE,
+                    PIC32_ENCRYPTION, PIC32_ALGO_AES, PIC32_CRYPTOALGO_RCTR);
+                XMEMCPY(out, out_block+aes->left, odd) ;
+                aes->left = 0 ;
+                XMEMSET(tmp, 0x0, AES_BLOCK_SIZE) ;
+                /* Increment IV */
+                for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
+                    if (++((byte *)aes->iv_ce)[i])
+                        break ;
+                }
+            }
+            in += odd ;
+            out+= odd ;
+            sz -= odd ;
+        }
+        odd = sz % AES_BLOCK_SIZE ;  /* if there is tail flagment */
+        if(sz / AES_BLOCK_SIZE) {
+            even = (sz/AES_BLOCK_SIZE)*AES_BLOCK_SIZE ;
+            AesCrypt(aes, out, in, even, PIC32_ENCRYPTION, PIC32_ALGO_AES,
+                                                    PIC32_CRYPTOALGO_RCTR);
+            out += even ;
+            in  += even ;
+            do {  /* Increment IV */
+                for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
+                    if (++((byte *)aes->iv_ce)[i])
+                        break ;
+                }
+                even -= AES_BLOCK_SIZE ;
+            } while((int)even > 0) ;
+        }
+        if(odd) {
+            XMEMSET(tmp+aes->left, 0x0, AES_BLOCK_SIZE - aes->left) ;
+            XMEMCPY(tmp+aes->left, in, odd) ;
+            AesCrypt(aes, out_block, tmp, AES_BLOCK_SIZE,
+                    PIC32_ENCRYPTION, PIC32_ALGO_AES, PIC32_CRYPTOALGO_RCTR);
+            XMEMCPY(out, out_block+aes->left,odd) ;
+            aes->left += odd ;
+        }
+    }
+    #endif /* CYASSL_AES_COUNTER */
+
+    #ifdef HAVE_AESGCM
+    #define HAVE_AES_ENGINE
+    /* Hardware AESGCM borows most of the software AESGCM, GMAC */
+    #endif
+
+#endif /* CYASSL_PIC32MZ_CRYPT */
+
+#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 */
+
+
+#elif  defined(HAVE_COLDFIRE_SEC)
+
+#include "sec.h"
+#include "mcf548x_sec.h"
+#include "mcf548x_siu.h"
+
+#include "memory_pools.h"
+extern TX_BYTE_POOL mp_ncached;  /* Non Cached memory pool */
+#define AES_BUFFER_SIZE (AES_BLOCK_SIZE * 8)
+static unsigned char *AESBuffer = NULL ;
+
+#define SEC_DESC_AES_CBC_ENCRYPT 0x60300010
+#define SEC_DESC_AES_CBC_DECRYPT 0x60200010
+#define AES_BLOCK_LENGTH 16
+
+extern volatile unsigned char __MBAR[];
+
+int AesCbcEncrypt(Aes* aes, byte* po, const byte* pi, word32 sz)
+{
+	return(AesCbcCrypt(aes, po, pi, sz, SEC_DESC_AES_CBC_ENCRYPT)) ;
+}
+
+int AesCbcDecrypt(Aes* aes, byte* po, const byte* pi, word32 sz)
+{
+	return(AesCbcCrypt(aes, po, pi, sz, SEC_DESC_AES_CBC_DECRYPT)) ;
+}
+	
+static int AesCbcCrypt(Aes* aes, byte* po, const byte* pi, word32 sz, word32 descHeader)
+{
+
+	int i ; int stat1, stat2 ;
+	int ret ; int size ;
+	static SECdescriptorType descriptor;
+	volatile int v ;
+    
+    if((pi == NULL) || (po == NULL))
+        return BAD_FUNC_ARG;/*wrong pointer*/
+    
+	while(sz) {
+		if((sz%AES_BUFFER_SIZE) == sz) {
+			size = sz ;
+			sz = 0 ;
+		} else {
+			size = AES_BUFFER_SIZE ;
+			sz -= AES_BUFFER_SIZE ;
+		}
+		
+   		/* Set descriptor for SEC */
+		descriptor.header = descHeader ;
+		/*
+		descriptor.length1 = 0x0;
+		descriptor.pointer1 = NULL;
+		*/
+		descriptor.length2 = AES_BLOCK_SIZE;
+		descriptor.pointer2 = (byte *)aes->reg ; /* Initial Vector */
+	
+		switch(aes->rounds) {
+			case 10: descriptor.length3 = 16 ; break ;
+			case 12: descriptor.length3 = 24 ; break ;
+			case 14: descriptor.length3 = 32 ; break ;
+		}
+
+		descriptor.pointer3 = (byte *)aes->key;
+		descriptor.length4 = size;
+		descriptor.pointer4 = (byte *)pi ;
+		descriptor.length5 = size;
+		descriptor.pointer5 = AESBuffer ;
+		/*
+		descriptor.length6 = 0x0;
+		descriptor.pointer6 = NULL;
+		descriptor.length7 = 0x0;
+		descriptor.pointer7 = NULL;
+		descriptor.nextDescriptorPtr = NULL;
+		*/
+		
+		/* Initialize SEC and wait for encryption to complete */
+		MCF_SEC_CCCR0 = 0x00000000;
+			
+		/* Point SEC to the location of the descriptor */
+		MCF_SEC_FR0 = (uint32)&descriptor;	
+
+		/* poll SISR to determine when channel is complete */
+		i=0 ;
+		while (!(MCF_SEC_SISRL) && !(MCF_SEC_SISRH))i++ ;
+		for(v=0; v<100; v++) ;
+		
+		ret = MCF_SEC_SISRH;
+		stat1 = MCF_SEC_AESSR ;	
+		stat2 = MCF_SEC_AESISR ;
+		if(ret & 0xe0000000)
+		{
+			db_printf("Aes_Cbc(i=%d):ISRH=%08x, AESSR=%08x, AESISR=%08x\n", i, ret, stat1, stat2) ;
+		}
+		
+		XMEMCPY(po, AESBuffer, size) ;
+
+		if(descHeader == SEC_DESC_AES_CBC_ENCRYPT) {
+			XMEMCPY((void*)aes->reg, (void*)&(po[size-AES_BLOCK_SIZE]), AES_BLOCK_SIZE) ;
+		} else {
+			XMEMCPY((void*)aes->reg, (void*)&(pi[size-AES_BLOCK_SIZE]), AES_BLOCK_SIZE) ;
+		}
+		
+		pi += size ; 
+		po += size ;
+	}
+	
+	return 0 ; /* for descriptier header 0xff000000 mode */
+}
+
+int AesSetKey(Aes* aes, const byte* userKey, word32 keylen, const byte* iv,
+                  int dir)
+{
+	int status ;
+	
+	if(AESBuffer == NULL) {
+		status = tx_byte_allocate(&mp_ncached,(void *)&AESBuffer, AES_BUFFER_SIZE,TX_NO_WAIT);
+	}
+
+    if (!((keylen == 16) || (keylen == 24) || (keylen == 32)))
+        return BAD_FUNC_ARG;
+    if (aes == NULL)
+        return BAD_FUNC_ARG;    
+    
+    aes->rounds = keylen/4 + 6;
+
+    XMEMCPY(aes->key, userKey, keylen);         
+    if (iv)
+        XMEMCPY(aes->reg, iv, AES_BLOCK_SIZE);
+    return 0;
+}
+
+#elif defined FREESCALE_MMCAU
+    /*
+     * Freescale mmCAU hardware AES support through the CAU/mmCAU library.
+     * Documentation located in ColdFire/ColdFire+ CAU and Kinetis mmCAU
+     * Software Library User Guide (See note in README).
+     */
+    #include "cau_api.h"
+
+    int AesSetKey(Aes* aes, const byte* userKey, word32 keylen, const byte* iv,
+                  int dir)
+    {
+        byte *rk = (byte*)aes->key;
+
+        if (!((keylen == 16) || (keylen == 24) || (keylen == 32)))
+            return BAD_FUNC_ARG;
+
+        if (rk == NULL)
+            return BAD_FUNC_ARG;
+
+        aes->rounds = keylen/4 + 6;
+        cau_aes_set_key(userKey, keylen*8, rk);
+
+        return AesSetIV(aes, iv);
+    }
+
+    int AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+    {
+        int i;
+        int offset = 0;
+        int len = sz;
+
+        byte *iv, *enc_key;
+        byte temp_block[AES_BLOCK_SIZE];
+
+        iv      = (byte*)aes->reg;
+        enc_key = (byte*)aes->key;
+
+        while (len > 0)
+        {
+            XMEMCPY(temp_block, in + offset, AES_BLOCK_SIZE);
+
+            /* XOR block with IV for CBC */
+            for (i = 0; i < AES_BLOCK_SIZE; i++)
+                temp_block[i] ^= iv[i];
+
+            cau_aes_encrypt(temp_block, enc_key, aes->rounds, out + offset);
+
+            len    -= AES_BLOCK_SIZE;
+            offset += AES_BLOCK_SIZE;
+
+            /* store IV for next block */
+            XMEMCPY(iv, out + offset - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+        }
+
+        return 0;
+    }
+
+    int AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+    {
+        int i;
+        int offset = 0;
+        int len = sz;
+
+        byte* iv, *dec_key;
+        byte temp_block[AES_BLOCK_SIZE];
+
+        iv      = (byte*)aes->reg;
+        dec_key = (byte*)aes->key;
+
+        while (len > 0)
+        {
+            XMEMCPY(temp_block, in + offset, AES_BLOCK_SIZE);
+
+            cau_aes_decrypt(in + offset, dec_key, aes->rounds, out + offset);
+
+            /* XOR block with IV for CBC */
+            for (i = 0; i < AES_BLOCK_SIZE; i++)
+                (out + offset)[i] ^= iv[i];
+
+            /* store IV for next block */
+            XMEMCPY(iv, temp_block, AES_BLOCK_SIZE);
+
+            len    -= AES_BLOCK_SIZE;
+            offset += AES_BLOCK_SIZE;
+        }
+
+        return 0;
+    }
+
+
+#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_ECB_encrypt(const unsigned char* in, unsigned char* out,
+                     unsigned long length, const unsigned char* KS, int nr)
+                     asm ("AES_ECB_encrypt");
+
+
+void AES_ECB_decrypt(const unsigned char* in, unsigned char* out,
+                     unsigned long length, const unsigned char* KS, int nr)
+                     asm ("AES_ECB_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 */
+    #ifdef CYASSL_AES_COUNTER
+        aes->left = 0;
+    #endif /* CYASSL_AES_COUNTER */
+
+    aes->rounds = keylen/4 + 6;
+
+    XMEMCPY(rk, userKey, keylen);
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords(rk, rk, keylen);
+    #endif
+
+#ifdef CYASSL_PIC32MZ_CRYPT
+    {
+        word32 *akey1 = aes->key_ce;
+        word32 *areg = aes->iv_ce ;
+        aes->keylen = keylen ;
+        XMEMCPY(akey1, userKey, keylen);
+        if (iv)
+            XMEMCPY(areg, iv, AES_BLOCK_SIZE);
+        else
+            XMEMSET(areg,  0, AES_BLOCK_SIZE);
+    }
+#endif
+
+    switch(keylen)
+    {
+    case 16:
+        while (1)
+        {
+            temp  = rk[3];
+            rk[4] = rk[0] ^
+                (Te[4][GETBYTE(temp, 2)] & 0xff000000) ^
+                (Te[4][GETBYTE(temp, 1)] & 0x00ff0000) ^
+                (Te[4][GETBYTE(temp, 0)] & 0x0000ff00) ^
+                (Te[4][GETBYTE(temp, 3)] & 0x000000ff) ^
+                rcon[i];
+            rk[5] = rk[1] ^ rk[4];
+            rk[6] = rk[2] ^ rk[5];
+            rk[7] = rk[3] ^ rk[6];
+            if (++i == 10)
+                break;
+            rk += 4;
+        }
+        break;
+
+    case 24:
+        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 (haveAESNI && aes->use_aesni) {
+        #ifdef DEBUG_AESNI
+            printf("about to aes encrypt\n");
+            printf("in  = %p\n", inBlock);
+            printf("out = %p\n", outBlock);
+            printf("aes->key = %p\n", aes->key);
+            printf("aes->rounds = %d\n", aes->rounds);
+            printf("sz = %d\n", AES_BLOCK_SIZE);
+        #endif
+
+        /* check alignment, decrypt doesn't need alignment */
+        if ((word)inBlock % 16) {
+        #ifndef NO_CYASSL_ALLOC_ALIGN
+            byte* tmp = (byte*)XMALLOC(AES_BLOCK_SIZE, NULL,
+                                                      DYNAMIC_TYPE_TMP_BUFFER);
+            if (tmp == NULL) return;
+
+            XMEMCPY(tmp, inBlock, AES_BLOCK_SIZE);
+            AES_ECB_encrypt(tmp, tmp, AES_BLOCK_SIZE, (byte*)aes->key,
+                            aes->rounds);
+            XMEMCPY(outBlock, tmp, AES_BLOCK_SIZE);
+            XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            return;
+        #else
+            CYASSL_MSG("AES-ECB encrypt with bad alignment");
+            return;
+        #endif
+        }
+
+        AES_ECB_encrypt(inBlock, outBlock, AES_BLOCK_SIZE, (byte*)aes->key,
+                        aes->rounds);
+
+        return;
+    }
+    else {
+        #ifdef DEBUG_AESNI
+            printf("Skipping AES-NI\n");
+        #endif
+    }
+#endif
+
+    /*
+     * map byte array block to cipher state
+     * and add initial round key:
+     */
+    XMEMCPY(&s0, inBlock,                  sizeof(s0));
+    XMEMCPY(&s1, inBlock + sizeof(s0),     sizeof(s1));
+    XMEMCPY(&s2, inBlock + 2 * sizeof(s0), sizeof(s2));
+    XMEMCPY(&s3, inBlock + 3 * sizeof(s0), sizeof(s3));
+
+    #ifdef LITTLE_ENDIAN_ORDER
+        s0 = ByteReverseWord32(s0);
+        s1 = ByteReverseWord32(s1);
+        s2 = ByteReverseWord32(s2);
+        s3 = ByteReverseWord32(s3);
+    #endif
+
+    s0 ^= rk[0];
+    s1 ^= rk[1];
+    s2 ^= rk[2];
+    s3 ^= rk[3];
+   
+    /*
+     * Nr - 1 full rounds:
+     */
+
+    for (;;) {
+        t0 =
+            Te[0][GETBYTE(s0, 3)]  ^
+            Te[1][GETBYTE(s1, 2)]  ^
+            Te[2][GETBYTE(s2, 1)]  ^
+            Te[3][GETBYTE(s3, 0)]  ^
+            rk[4];
+        t1 =
+            Te[0][GETBYTE(s1, 3)]  ^
+            Te[1][GETBYTE(s2, 2)]  ^
+            Te[2][GETBYTE(s3, 1)]  ^
+            Te[3][GETBYTE(s0, 0)]  ^
+            rk[5];
+        t2 =
+            Te[0][GETBYTE(s2, 3)] ^
+            Te[1][GETBYTE(s3, 2)]  ^
+            Te[2][GETBYTE(s0, 1)]  ^
+            Te[3][GETBYTE(s1, 0)]  ^
+            rk[6];
+        t3 =
+            Te[0][GETBYTE(s3, 3)] ^
+            Te[1][GETBYTE(s0, 2)]  ^
+            Te[2][GETBYTE(s1, 1)]  ^
+            Te[3][GETBYTE(s2, 0)]  ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+        
+        s0 =
+            Te[0][GETBYTE(t0, 3)] ^
+            Te[1][GETBYTE(t1, 2)] ^
+            Te[2][GETBYTE(t2, 1)] ^
+            Te[3][GETBYTE(t3, 0)] ^
+            rk[0];
+        s1 =
+            Te[0][GETBYTE(t1, 3)] ^
+            Te[1][GETBYTE(t2, 2)] ^
+            Te[2][GETBYTE(t3, 1)] ^
+            Te[3][GETBYTE(t0, 0)] ^
+            rk[1];
+        s2 =
+            Te[0][GETBYTE(t2, 3)] ^
+            Te[1][GETBYTE(t3, 2)] ^
+            Te[2][GETBYTE(t0, 1)] ^
+            Te[3][GETBYTE(t1, 0)] ^
+            rk[2];
+        s3 =
+            Te[0][GETBYTE(t3, 3)] ^
+            Te[1][GETBYTE(t0, 2)] ^
+            Te[2][GETBYTE(t1, 1)] ^
+            Te[3][GETBYTE(t2, 0)] ^
+            rk[3];
+    }
+
+    /*
+     * apply last round and
+     * map cipher state to byte array block:
+     */
+
+    s0 =
+        (Te[4][GETBYTE(t0, 3)] & 0xff000000) ^
+        (Te[4][GETBYTE(t1, 2)] & 0x00ff0000) ^
+        (Te[4][GETBYTE(t2, 1)] & 0x0000ff00) ^
+        (Te[4][GETBYTE(t3, 0)] & 0x000000ff) ^
+        rk[0];
+    s1 =
+        (Te[4][GETBYTE(t1, 3)] & 0xff000000) ^
+        (Te[4][GETBYTE(t2, 2)] & 0x00ff0000) ^
+        (Te[4][GETBYTE(t3, 1)] & 0x0000ff00) ^
+        (Te[4][GETBYTE(t0, 0)] & 0x000000ff) ^
+        rk[1];
+    s2 =
+        (Te[4][GETBYTE(t2, 3)] & 0xff000000) ^
+        (Te[4][GETBYTE(t3, 2)] & 0x00ff0000) ^
+        (Te[4][GETBYTE(t0, 1)] & 0x0000ff00) ^
+        (Te[4][GETBYTE(t1, 0)] & 0x000000ff) ^
+        rk[2];
+    s3 =
+        (Te[4][GETBYTE(t3, 3)] & 0xff000000) ^
+        (Te[4][GETBYTE(t0, 2)] & 0x00ff0000) ^
+        (Te[4][GETBYTE(t1, 1)] & 0x0000ff00) ^
+        (Te[4][GETBYTE(t2, 0)] & 0x000000ff) ^
+        rk[3];
+
+    /* write out */
+    #ifdef LITTLE_ENDIAN_ORDER
+        s0 = ByteReverseWord32(s0);
+        s1 = ByteReverseWord32(s1);
+        s2 = ByteReverseWord32(s2);
+        s3 = ByteReverseWord32(s3);
+    #endif
+
+    XMEMCPY(outBlock,                  &s0, sizeof(s0));
+    XMEMCPY(outBlock + sizeof(s0),     &s1, sizeof(s1));
+    XMEMCPY(outBlock + 2 * sizeof(s0), &s2, sizeof(s2));
+    XMEMCPY(outBlock + 3 * sizeof(s0), &s3, sizeof(s3));
+}
+
+
+static void 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 (haveAESNI && aes->use_aesni) {
+        #ifdef DEBUG_AESNI
+            printf("about to aes decrypt\n");
+            printf("in  = %p\n", inBlock);
+            printf("out = %p\n", outBlock);
+            printf("aes->key = %p\n", aes->key);
+            printf("aes->rounds = %d\n", aes->rounds);
+            printf("sz = %d\n", AES_BLOCK_SIZE);
+        #endif
+
+        /* if input and output same will overwrite input iv */
+        XMEMCPY(aes->tmp, inBlock, AES_BLOCK_SIZE);
+        AES_ECB_decrypt(inBlock, outBlock, AES_BLOCK_SIZE, (byte*)aes->key,
+                        aes->rounds);
+        return;
+    }
+    else {
+        #ifdef DEBUG_AESNI
+            printf("Skipping AES-NI\n");
+        #endif
+    }
+#endif
+
+    /*
+     * map byte array block to cipher state
+     * and add initial round key:
+     */
+    XMEMCPY(&s0, inBlock,                  sizeof(s0));
+    XMEMCPY(&s1, inBlock + sizeof(s0),     sizeof(s1));
+    XMEMCPY(&s2, inBlock + 2 * sizeof(s0), sizeof(s2));
+    XMEMCPY(&s3, inBlock + 3 * sizeof(s0), sizeof(s3));
+
+    #ifdef LITTLE_ENDIAN_ORDER
+        s0 = ByteReverseWord32(s0);
+        s1 = ByteReverseWord32(s1);
+        s2 = ByteReverseWord32(s2);
+        s3 = ByteReverseWord32(s3);
+    #endif
+
+    s0 ^= rk[0];
+    s1 ^= rk[1];
+    s2 ^= rk[2];
+    s3 ^= rk[3];
+   
+    /*
+     * Nr - 1 full rounds:
+     */
+
+    for (;;) {
+        t0 =
+            Td[0][GETBYTE(s0, 3)] ^
+            Td[1][GETBYTE(s3, 2)] ^
+            Td[2][GETBYTE(s2, 1)] ^
+            Td[3][GETBYTE(s1, 0)] ^
+            rk[4];
+        t1 =
+            Td[0][GETBYTE(s1, 3)] ^
+            Td[1][GETBYTE(s0, 2)] ^
+            Td[2][GETBYTE(s3, 1)] ^
+            Td[3][GETBYTE(s2, 0)] ^
+            rk[5];
+        t2 =
+            Td[0][GETBYTE(s2, 3)] ^
+            Td[1][GETBYTE(s1, 2)] ^
+            Td[2][GETBYTE(s0, 1)] ^
+            Td[3][GETBYTE(s3, 0)] ^
+            rk[6];
+        t3 =
+            Td[0][GETBYTE(s3, 3)] ^
+            Td[1][GETBYTE(s2, 2)] ^
+            Td[2][GETBYTE(s1, 1)] ^
+            Td[3][GETBYTE(s0, 0)] ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Td[0][GETBYTE(t0, 3)] ^
+            Td[1][GETBYTE(t3, 2)] ^
+            Td[2][GETBYTE(t2, 1)] ^
+            Td[3][GETBYTE(t1, 0)] ^
+            rk[0];
+        s1 =
+            Td[0][GETBYTE(t1, 3)] ^
+            Td[1][GETBYTE(t0, 2)] ^
+            Td[2][GETBYTE(t3, 1)] ^
+            Td[3][GETBYTE(t2, 0)] ^
+            rk[1];
+        s2 =
+            Td[0][GETBYTE(t2, 3)] ^
+            Td[1][GETBYTE(t1, 2)] ^
+            Td[2][GETBYTE(t0, 1)] ^
+            Td[3][GETBYTE(t3, 0)] ^
+            rk[2];
+        s3 =
+            Td[0][GETBYTE(t3, 3)] ^
+            Td[1][GETBYTE(t2, 2)] ^
+            Td[2][GETBYTE(t1, 1)] ^
+            Td[3][GETBYTE(t0, 0)] ^
+            rk[3];
+    }
+    /*
+     * apply last round and
+     * map cipher state to byte array block:
+     */
+    s0 =
+        (Td[4][GETBYTE(t0, 3)] & 0xff000000) ^
+        (Td[4][GETBYTE(t3, 2)] & 0x00ff0000) ^
+        (Td[4][GETBYTE(t2, 1)] & 0x0000ff00) ^
+        (Td[4][GETBYTE(t1, 0)] & 0x000000ff) ^
+        rk[0];
+    s1 =
+        (Td[4][GETBYTE(t1, 3)] & 0xff000000) ^
+        (Td[4][GETBYTE(t0, 2)] & 0x00ff0000) ^
+        (Td[4][GETBYTE(t3, 1)] & 0x0000ff00) ^
+        (Td[4][GETBYTE(t2, 0)] & 0x000000ff) ^
+        rk[1];
+    s2 =
+        (Td[4][GETBYTE(t2, 3)] & 0xff000000) ^
+        (Td[4][GETBYTE(t1, 2)] & 0x00ff0000) ^
+        (Td[4][GETBYTE(t0, 1)] & 0x0000ff00) ^
+        (Td[4][GETBYTE(t3, 0)] & 0x000000ff) ^
+        rk[2];
+    s3 =
+        (Td[4][GETBYTE(t3, 3)] & 0xff000000) ^
+        (Td[4][GETBYTE(t2, 2)] & 0x00ff0000) ^
+        (Td[4][GETBYTE(t1, 1)] & 0x0000ff00) ^
+        (Td[4][GETBYTE(t0, 0)] & 0x000000ff) ^
+        rk[3];
+
+    /* write out */
+    #ifdef LITTLE_ENDIAN_ORDER
+        s0 = ByteReverseWord32(s0);
+        s1 = ByteReverseWord32(s1);
+        s2 = ByteReverseWord32(s2);
+        s3 = ByteReverseWord32(s3);
+    #endif
+
+    XMEMCPY(outBlock,                  &s0, sizeof(s0));
+    XMEMCPY(outBlock + sizeof(s0),     &s1, sizeof(s1));
+    XMEMCPY(outBlock + 2 * sizeof(s0), &s2, sizeof(s2));
+    XMEMCPY(outBlock + 3 * sizeof(s0), &s3, sizeof(s3));
+}
+
+#ifndef HAVE_AES_ENGINE
+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;
+}
+#endif
+
+#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 */
+
+
+#if defined(CYASSL_AES_COUNTER) && !defined(HAVE_AES_ENGINE)
+
+/* 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)
+{
+    byte* tmp = (byte*)aes->tmp + AES_BLOCK_SIZE - aes->left;
+
+    /* consume any unused bytes left in aes->tmp */
+    while (aes->left && sz) {
+       *(out++) = *(in++) ^ *(tmp++);
+       aes->left--;
+       sz--;
+    }
+
+    /* do as many block size ops as possible */
+    while (sz >= AES_BLOCK_SIZE) {
+        AesEncrypt(aes, (byte*)aes->reg, out);
+        IncrementAesCounter((byte*)aes->reg);
+        xorbuf(out, in, AES_BLOCK_SIZE);
+
+        out += AES_BLOCK_SIZE;
+        in  += AES_BLOCK_SIZE;
+        sz  -= AES_BLOCK_SIZE;
+        aes->left = 0;
+    }
+
+    /* handle non block size remaining and sotre unused byte count in left */
+    if (sz) {
+        AesEncrypt(aes, (byte*)aes->reg, (byte*)aes->tmp);
+        IncrementAesCounter((byte*)aes->reg);
+
+        aes->left = AES_BLOCK_SIZE;
+        tmp = (byte*)aes->tmp;
+
+        while (sz--) {
+            *(out++) = *(in++) ^ *(tmp++);
+            aes->left--;
+        }
+    }
+}
+
+#endif /* 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);
+    AesSetKey(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 counter[AES_BLOCK_SIZE];
+    byte *ctr ;
+    byte scratch[AES_BLOCK_SIZE];
+
+    CYASSL_ENTER("AesGcmEncrypt");
+
+#ifdef CYASSL_PIC32MZ_CRYPT
+    ctr = (char *)aes->iv_ce ;
+#else
+    ctr = counter ;
+#endif
+
+    XMEMSET(ctr, 0, AES_BLOCK_SIZE);
+    XMEMCPY(ctr, iv, ivSz);
+    InitGcmCounter(ctr);
+
+#ifdef CYASSL_PIC32MZ_CRYPT
+    if(blocks)
+        AesCrypt(aes, out, in, blocks*AES_BLOCK_SIZE,
+             PIC32_ENCRYPTION, PIC32_ALGO_AES, PIC32_CRYPTOALGO_AES_GCM );
+#endif
+    while (blocks--) {
+        IncrementGcmCounter(ctr);
+        #ifndef CYASSL_PIC32MZ_CRYPT
+        AesEncrypt(aes, ctr, scratch);
+        xorbuf(scratch, p, AES_BLOCK_SIZE);
+        XMEMCPY(c, scratch, AES_BLOCK_SIZE);
+        #endif
+        p += AES_BLOCK_SIZE;
+        c += AES_BLOCK_SIZE;
+    }
+
+    if (partial != 0) {
+        IncrementGcmCounter(ctr);
+        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 counter[AES_BLOCK_SIZE];
+    byte *ctr ;
+    byte scratch[AES_BLOCK_SIZE];
+
+    CYASSL_ENTER("AesGcmDecrypt");
+
+#ifdef CYASSL_PIC32MZ_CRYPT
+    ctr = (char *)aes->iv_ce ;
+#else
+    ctr = counter ;
+#endif
+
+    XMEMSET(ctr, 0, AES_BLOCK_SIZE);
+    XMEMCPY(ctr, iv, ivSz);
+    InitGcmCounter(ctr);
+
+    /* Calculate the authTag again using the received auth data and the
+     * cipher text. */
+    {
+        byte Tprime[AES_BLOCK_SIZE];
+        byte EKY0[AES_BLOCK_SIZE];
+
+        GHASH(aes, authIn, authInSz, in, sz, Tprime, sizeof(Tprime));
+        AesEncrypt(aes, ctr, EKY0);
+        xorbuf(Tprime, EKY0, sizeof(Tprime));
+
+        if (XMEMCMP(authTag, Tprime, authTagSz) != 0) {
+            return AES_GCM_AUTH_E;
+        }
+    }
+ 
+#ifdef CYASSL_PIC32MZ_CRYPT
+    if(blocks)
+        AesCrypt(aes, out, in, blocks*AES_BLOCK_SIZE,
+             PIC32_DECRYPTION, PIC32_ALGO_AES, PIC32_CRYPTOALGO_AES_GCM );
+#endif
+
+    while (blocks--) {
+        IncrementGcmCounter(ctr);
+        #ifndef CYASSL_PIC32MZ_CRYPT
+        AesEncrypt(aes, ctr, scratch);
+        xorbuf(scratch, c, AES_BLOCK_SIZE);
+        XMEMCPY(p, scratch, AES_BLOCK_SIZE);
+        #endif
+        p += AES_BLOCK_SIZE;
+        c += AES_BLOCK_SIZE;
+    }
+    if (partial != 0) {
+        IncrementGcmCounter(ctr);
+        AesEncrypt(aes, ctr, scratch);
+        xorbuf(scratch, c, partial);
+        XMEMCPY(p, scratch, partial);
+    }
+    return 0;
+}
+
+
+
+CYASSL_API void GmacSetKey(Gmac* gmac, const byte* key, word32 len)
+{
+    AesGcmSetKey(&gmac->aes, key, len);
+}
+
+
+CYASSL_API void GmacUpdate(Gmac* gmac, const byte* iv, word32 ivSz,
+                              const byte* authIn, word32 authInSz,
+                              byte* authTag, word32 authTagSz)
+{
+    AesGcmEncrypt(&gmac->aes, NULL, NULL, 0, iv, ivSz,
+                                         authTag, authTagSz, authIn, authInSz);
+}
+
+#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));
+    AesSetKey(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];
+    byte lenSz;
+    word32 i;
+
+    XMEMCPY(B+1, nonce, nonceSz);
+    lenSz = AES_BLOCK_SIZE - 1 - (byte)nonceSz;
+    B[0] = (authInSz > 0 ? 64 : 0)
+         + (8 * (((byte)authTagSz - 2) / 2))
+         + (lenSz - 1);
+    for (i = 0; i < lenSz; i++)
+        B[AES_BLOCK_SIZE - 1 - i] = (inSz >> (8 * i)) & 0xFF;
+
+    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;
+    byte lenSz;
+    word32 i, oSz;
+    int result = 0;
+
+    o = out;
+    oSz = inSz;
+    XMEMCPY(B+1, nonce, nonceSz);
+    lenSz = AES_BLOCK_SIZE - 1 - (byte)nonceSz;
+
+    B[0] = lenSz - 1;
+    for (i = 0; i < lenSz; i++)
+        B[AES_BLOCK_SIZE - 1 - i] = 0;
+    B[15] = 1;
+    
+    while (oSz >= AES_BLOCK_SIZE) {
+        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 * (((byte)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);
+    else
+        XMEMSET(aes->reg,  0, 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 int 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");
+            return -1;
+        }
+        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");
+            return -1;
+        }
+        XMEMCPY(aes->reg, out + offset+length - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+    }
+    return 0;
+}
+
+static int AesCaviumCbcDecrypt(Aes* aes, byte* out, const byte* in,
+                               word32 length)
+{
+    word32 requestId;
+    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");
+            return -1;
+        }
+        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");
+            return -1;
+        }
+        XMEMCPY(aes->reg, aes->tmp, AES_BLOCK_SIZE);
+    }
+    return 0;
+}
+
+#endif /* HAVE_CAVIUM */
+
+#endif /* NO_AES */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/arc4.c	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,1406 @@
+/* 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
+
+
+#ifdef __thumb__
+
+#define INNERMUL                    \
+__asm__(                                \
+    " LDR    r0,%1            \n\t" \
+    " ADDS   r0,r0,%0         \n\t" \
+    " ITE    CS               \n\t" \
+    " MOVCS  %0,#1            \n\t" \
+    " MOVCC  %0,#0            \n\t" \
+    " UMLAL  r0,%0,%3,%4      \n\t" \
+    " STR    r0,%1            \n\t" \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(*tmpm++),"m"(_c[0]):"r0","cc");
+
+#define PROPCARRY                  \
+__asm__(                               \
+    " LDR   r0,%1            \n\t" \
+    " ADDS  r0,r0,%0         \n\t" \
+    " STR   r0,%1            \n\t" \
+    " ITE   CS               \n\t" \
+    " MOVCS %0,#1            \n\t" \
+    " MOVCC %0,#0            \n\t" \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"m"(_c[0]):"r0","cc");
+
+
+/* TAO thumb mode uses ite (if then else) to detect carry directly
+ * fixed unmatched constraint warning by changing 1 to m  */
+
+#else  /* __thumb__ */
+
+#define INNERMUL                    \
+__asm__(                                \
+    " LDR    r0,%1            \n\t" \
+    " ADDS   r0,r0,%0         \n\t" \
+    " MOVCS  %0,#1            \n\t" \
+    " MOVCC  %0,#0            \n\t" \
+    " UMLAL  r0,%0,%3,%4      \n\t" \
+    " STR    r0,%1            \n\t" \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(*tmpm++),"1"(_c[0]):"r0","cc");
+
+#define PROPCARRY                  \
+__asm__(                               \
+    " LDR   r0,%1            \n\t" \
+    " ADDS  r0,r0,%0         \n\t" \
+    " STR   r0,%1            \n\t" \
+    " MOVCS %0,#1            \n\t" \
+    " MOVCC %0,#0            \n\t" \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"r0","cc");
+
+#endif /* __thumb__ */
+
+#elif defined(TFM_PPC32)
+
+/* PPC32 */
+#define MONT_START 
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                     \
+__asm__(                                 \
+   " mullw    16,%3,%4       \n\t"   \
+   " mulhwu   17,%3,%4       \n\t"   \
+   " addc     16,16,%0       \n\t"   \
+   " addze    17,17          \n\t"   \
+   " lwz      18,%1          \n\t"   \
+   " addc     16,16,18       \n\t"   \
+   " addze    %0,17          \n\t"   \
+   " stw      16,%1          \n\t"   \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(tmpm[0]),"1"(_c[0]):"16", "17", "18","cc"); ++tmpm;
+
+#define PROPCARRY                    \
+__asm__(                                 \
+   " lwz      16,%1         \n\t"    \
+   " addc     16,16,%0      \n\t"    \
+   " stw      16,%1         \n\t"    \
+   " xor      %0,%0,%0      \n\t"    \
+   " addze    %0,%0         \n\t"    \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"16","cc");
+
+#elif defined(TFM_PPC64)
+
+/* PPC64 */
+#define MONT_START 
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                     \
+__asm__(                                 \
+   " mulld    16,%3,%4       \n\t"   \
+   " mulhdu   17,%3,%4       \n\t"   \
+   " addc     16,16,%0       \n\t"   \
+   " addze    17,17          \n\t"   \
+   " ldx      18,0,%1        \n\t"   \
+   " addc     16,16,18       \n\t"   \
+   " addze    %0,17          \n\t"   \
+   " sdx      16,0,%1        \n\t"   \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(tmpm[0]),"1"(_c[0]):"16", "17", "18","cc"); ++tmpm;
+
+#define PROPCARRY                    \
+__asm__(                                 \
+   " ldx      16,0,%1       \n\t"    \
+   " addc     16,16,%0      \n\t"    \
+   " sdx      16,0,%1       \n\t"    \
+   " xor      %0,%0,%0      \n\t"    \
+   " addze    %0,%0         \n\t"    \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"16","cc");
+
+/******************************************************************/
+
+#elif defined(TFM_AVR32)
+
+/* AVR32 */
+#define MONT_START 
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                    \
+__asm__(                                \
+    " ld.w   r2,%1            \n\t" \
+    " add    r2,%0            \n\t" \
+    " eor    r3,r3            \n\t" \
+    " acr    r3               \n\t" \
+    " macu.d r2,%3,%4         \n\t" \
+    " st.w   %1,r2            \n\t" \
+    " mov    %0,r3            \n\t" \
+:"=r"(cy),"=r"(_c):"0"(cy),"r"(mu),"r"(*tmpm++),"1"(_c):"r2","r3");
+
+#define PROPCARRY                    \
+__asm__(                                 \
+   " ld.w     r2,%1         \n\t"    \
+   " add      r2,%0         \n\t"    \
+   " st.w     %1,r2         \n\t"    \
+   " eor      %0,%0         \n\t"    \
+   " acr      %0            \n\t"    \
+:"=r"(cy),"=r"(&_c[0]):"0"(cy),"1"(&_c[0]):"r2","cc");
+
+#else
+
+/* ISO C code */
+#define MONT_START 
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                                      \
+   do { fp_word t;                                    \
+   t  = ((fp_word)_c[0] + (fp_word)cy) +              \
+                (((fp_word)mu) * ((fp_word)*tmpm++)); \
+   _c[0] = (fp_digit)t;                               \
+   cy = (fp_digit)(t >> DIGIT_BIT);                   \
+   } while (0)
+
+#define PROPCARRY \
+   do { fp_digit t = _c[0] += cy; cy = (t < cy); } while (0)
+
+#endif
+/******************************************************************/
+
+
+#define LO  0
+/* end fp_montogomery_reduce.c asm */
+
+
+/* start fp_sqr_comba.c asm */
+#if defined(TFM_X86)
+
+/* x86-32 optimized */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+#define SQRADD(i, j)                                      \
+__asm__(                                            \
+     "movl  %6,%%eax     \n\t"                            \
+     "mull  %%eax        \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i) :"%eax","%edx","cc");
+
+#define SQRADD2(i, j)                                     \
+__asm__(                                            \
+     "movl  %6,%%eax     \n\t"                            \
+     "mull  %7           \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","%edx", "cc");
+
+#define SQRADDSC(i, j)                                    \
+__asm__(                                                     \
+     "movl  %3,%%eax     \n\t"                            \
+     "mull  %4           \n\t"                            \
+     "movl  %%eax,%0     \n\t"                            \
+     "movl  %%edx,%1     \n\t"                            \
+     "xorl  %2,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "g"(i), "g"(j) :"%eax","%edx","cc");
+
+/* TAO removed sc0,1,2 as input to remove warning so %6,%7 become %3,%4 */
+
+#define SQRADDAC(i, j)                                    \
+__asm__(                                                     \
+     "movl  %6,%%eax     \n\t"                            \
+     "mull  %7           \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%eax","%edx","cc");
+
+#define SQRADDDB                                          \
+__asm__(                                                     \
+     "addl %6,%0         \n\t"                            \
+     "adcl %7,%1         \n\t"                            \
+     "adcl %8,%2         \n\t"                            \
+     "addl %6,%0         \n\t"                            \
+     "adcl %7,%1         \n\t"                            \
+     "adcl %8,%2         \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(sc0), "r"(sc1), "r"(sc2) : "cc");
+
+#elif defined(TFM_X86_64)
+/* x86-64 optimized */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+#define SQRADD(i, j)                                      \
+__asm__(                                                     \
+     "movq  %6,%%rax     \n\t"                            \
+     "mulq  %%rax        \n\t"                            \
+     "addq  %%rax,%0     \n\t"                            \
+     "adcq  %%rdx,%1     \n\t"                            \
+     "adcq  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "g"(i) :"%rax","%rdx","cc");
+
+#define SQRADD2(i, j)                                     \
+__asm__(                                                     \
+     "movq  %6,%%rax     \n\t"                            \
+     "mulq  %7           \n\t"                            \
+     "addq  %%rax,%0     \n\t"                            \
+     "adcq  %%rdx,%1     \n\t"                            \
+     "adcq  $0,%2        \n\t"                            \
+     "addq  %%rax,%0     \n\t"                            \
+     "adcq  %%rdx,%1     \n\t"                            \
+     "adcq  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "g"(i), "g"(j)  :"%rax","%rdx","cc");
+
+#define SQRADDSC(i, j)                                    \
+__asm__(                                                     \
+     "movq  %3,%%rax     \n\t"                            \
+     "mulq  %4           \n\t"                            \
+     "movq  %%rax,%0     \n\t"                            \
+     "movq  %%rdx,%1     \n\t"                            \
+     "xorq  %2,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "g"(i), "g"(j) :"%rax","%rdx","cc");
+
+/* TAO removed sc0,1,2 as input to remove warning so %6,%7 become %3,%4 */
+
+#define SQRADDAC(i, j)                                                         \
+__asm__(                                                     \
+     "movq  %6,%%rax     \n\t"                            \
+     "mulq  %7           \n\t"                            \
+     "addq  %%rax,%0     \n\t"                            \
+     "adcq  %%rdx,%1     \n\t"                            \
+     "adcq  $0,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%rax","%rdx","cc");
+
+#define SQRADDDB                                          \
+__asm__(                                                     \
+     "addq %6,%0         \n\t"                            \
+     "adcq %7,%1         \n\t"                            \
+     "adcq %8,%2         \n\t"                            \
+     "addq %6,%0         \n\t"                            \
+     "adcq %7,%1         \n\t"                            \
+     "adcq %8,%2         \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(sc0), "r"(sc1), "r"(sc2) : "cc");
+
+#elif defined(TFM_SSE2)
+
+/* SSE2 Optimized */
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI \
+   __asm__("emms");
+
+#define SQRADD(i, j)                                      \
+__asm__(                                            \
+     "movd  %6,%%mm0     \n\t"                            \
+     "pmuludq %%mm0,%%mm0\n\t"                            \
+     "movd  %%mm0,%%eax  \n\t"                            \
+     "psrlq $32,%%mm0    \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "movd  %%mm0,%%eax  \n\t"                            \
+     "adcl  %%eax,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i) :"%eax","cc");
+
+#define SQRADD2(i, j)                                     \
+__asm__(                                            \
+     "movd  %6,%%mm0     \n\t"                            \
+     "movd  %7,%%mm1     \n\t"                            \
+     "pmuludq %%mm1,%%mm0\n\t"                            \
+     "movd  %%mm0,%%eax  \n\t"                            \
+     "psrlq $32,%%mm0    \n\t"                            \
+     "movd  %%mm0,%%edx  \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","%edx","cc");
+
+#define SQRADDSC(i, j)                                                         \
+__asm__(                                            \
+     "movd  %3,%%mm0     \n\t"                            \
+     "movd  %4,%%mm1     \n\t"                            \
+     "pmuludq %%mm1,%%mm0\n\t"                            \
+     "movd  %%mm0,%0     \n\t"                            \
+     "psrlq $32,%%mm0    \n\t"                            \
+     "movd  %%mm0,%1     \n\t"                            \
+     "xorl  %2,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "m"(i), "m"(j));
+
+/* TAO removed sc0,1,2 as input to remove warning so %6,%7 become %3,%4 */
+
+#define SQRADDAC(i, j)                                                         \
+__asm__(                                            \
+     "movd  %6,%%mm0     \n\t"                            \
+     "movd  %7,%%mm1     \n\t"                            \
+     "pmuludq %%mm1,%%mm0\n\t"                            \
+     "movd  %%mm0,%%eax  \n\t"                            \
+     "psrlq $32,%%mm0    \n\t"                            \
+     "movd  %%mm0,%%edx  \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "m"(i), "m"(j)  :"%eax","%edx","cc");
+
+#define SQRADDDB                                          \
+__asm__(                                                     \
+     "addl %6,%0         \n\t"                            \
+     "adcl %7,%1         \n\t"                            \
+     "adcl %8,%2         \n\t"                            \
+     "addl %6,%0         \n\t"                            \
+     "adcl %7,%1         \n\t"                            \
+     "adcl %8,%2         \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(sc0), "r"(sc1), "r"(sc2) : "cc");
+
+#elif defined(TFM_ARM)
+
+/* ARM code */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)                                             \
+__asm__(                                                             \
+"  UMULL  r0,r1,%6,%6              \n\t"                         \
+"  ADDS   %0,%0,r0                 \n\t"                         \
+"  ADCS   %1,%1,r1                 \n\t"                         \
+"  ADC    %2,%2,#0                 \n\t"                         \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i) : "r0", "r1", "cc");
+	
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)                                            \
+__asm__(                                                             \
+"  UMULL  r0,r1,%6,%7              \n\t"                         \
+"  ADDS   %0,%0,r0                 \n\t"                         \
+"  ADCS   %1,%1,r1                 \n\t"                         \
+"  ADC    %2,%2,#0                 \n\t"                         \
+"  ADDS   %0,%0,r0                 \n\t"                         \
+"  ADCS   %1,%1,r1                 \n\t"                         \
+"  ADC    %2,%2,#0                 \n\t"                         \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "cc");
+
+#define SQRADDSC(i, j)                                           \
+__asm__(                                                             \
+"  UMULL  %0,%1,%3,%4              \n\t"                         \
+"  SUB    %2,%2,%2                 \n\t"                         \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2) : "r"(i), "r"(j) : "cc");
+
+/* TAO removed sc0,1,2 as input to remove warning so %6,%7 become %3,%4 */
+
+#define SQRADDAC(i, j)                                           \
+__asm__(                                                             \
+"  UMULL  r0,r1,%6,%7              \n\t"                         \
+"  ADDS   %0,%0,r0                 \n\t"                         \
+"  ADCS   %1,%1,r1                 \n\t"                         \
+"  ADC    %2,%2,#0                 \n\t"                         \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2) : "0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j) : "r0", "r1", "cc");
+
+#define SQRADDDB                                                 \
+__asm__(                                                             \
+"  ADDS  %0,%0,%3                     \n\t"                      \
+"  ADCS  %1,%1,%4                     \n\t"                      \
+"  ADC   %2,%2,%5                     \n\t"                      \
+"  ADDS  %0,%0,%3                     \n\t"                      \
+"  ADCS  %1,%1,%4                     \n\t"                      \
+"  ADC   %2,%2,%5                     \n\t"                      \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "cc");
+
+#elif defined(TFM_PPC32)
+
+/* PPC32 */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)             \
+__asm__(                             \
+   " mullw  16,%6,%6       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhwu 16,%6,%6       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i):"16","cc");
+
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)            \
+__asm__(                             \
+   " mullw  16,%6,%7       \n\t" \
+   " mulhwu 17,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " adde   %1,%1,17       \n\t" \
+   " addze  %2,%2          \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " adde   %1,%1,17       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"16", "17","cc");
+
+#define SQRADDSC(i, j)            \
+__asm__(                              \
+   " mullw  %0,%6,%7        \n\t" \
+   " mulhwu %1,%6,%7        \n\t" \
+   " xor    %2,%2,%2        \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i),"r"(j) : "cc");
+
+#define SQRADDAC(i, j)           \
+__asm__(                             \
+   " mullw  16,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhwu 16,%6,%7       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j):"16", "cc");
+
+#define SQRADDDB                  \
+__asm__(                              \
+   " addc   %0,%0,%3        \n\t" \
+   " adde   %1,%1,%4        \n\t" \
+   " adde   %2,%2,%5        \n\t" \
+   " addc   %0,%0,%3        \n\t" \
+   " adde   %1,%1,%4        \n\t" \
+   " adde   %2,%2,%5        \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "cc");
+
+#elif defined(TFM_PPC64)
+/* PPC64 */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)             \
+__asm__(                             \
+   " mulld  16,%6,%6       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhdu 16,%6,%6       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i):"16","cc");
+
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)            \
+__asm__(                             \
+   " mulld  16,%6,%7       \n\t" \
+   " mulhdu 17,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " adde   %1,%1,17       \n\t" \
+   " addze  %2,%2          \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " adde   %1,%1,17       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"16", "17","cc");
+
+#define SQRADDSC(i, j)            \
+__asm__(                              \
+   " mulld  %0,%6,%7        \n\t" \
+   " mulhdu %1,%6,%7        \n\t" \
+   " xor    %2,%2,%2        \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i),"r"(j) : "cc");
+
+#define SQRADDAC(i, j)           \
+__asm__(                             \
+   " mulld  16,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhdu 16,%6,%7       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j):"16", "cc");
+
+#define SQRADDDB                  \
+__asm__(                              \
+   " addc   %0,%0,%3        \n\t" \
+   " adde   %1,%1,%4        \n\t" \
+   " adde   %2,%2,%5        \n\t" \
+   " addc   %0,%0,%3        \n\t" \
+   " adde   %1,%1,%4        \n\t" \
+   " adde   %2,%2,%5        \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "cc");
+
+
+#elif defined(TFM_AVR32)
+
+/* AVR32 */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)             \
+__asm__(                             \
+   " mulu.d r2,%6,%6       \n\t" \
+   " add    %0,%0,r2       \n\t" \
+   " adc    %1,%1,r3       \n\t" \
+   " acr    %2             \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i):"r2","r3");
+
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)            \
+__asm__(                             \
+   " mulu.d r2,%6,%7       \n\t" \
+   " add    %0,%0,r2       \n\t" \
+   " adc    %1,%1,r3       \n\t" \
+   " acr    %2,            \n\t" \
+   " add    %0,%0,r2       \n\t" \
+   " adc    %1,%1,r3       \n\t" \
+   " acr    %2,            \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"r2", "r3");
+
+#define SQRADDSC(i, j)            \
+__asm__(                              \
+   " mulu.d r2,%6,%7        \n\t" \
+   " mov    %0,r2           \n\t" \
+   " mov    %1,r3           \n\t" \
+   " eor    %2,%2           \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i),"r"(j) : "r2", "r3");
+
+#define SQRADDAC(i, j)           \
+__asm__(                             \
+   " mulu.d r2,%6,%7       \n\t" \
+   " add    %0,%0,r2       \n\t" \
+   " adc    %1,%1,r3       \n\t" \
+   " acr    %2             \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j):"r2", "r3");
+
+#define SQRADDDB                  \
+__asm__(                              \
+   " add    %0,%0,%3        \n\t" \
+   " adc    %1,%1,%4        \n\t" \
+   " adc    %2,%2,%5        \n\t" \
+   " add    %0,%0,%3        \n\t" \
+   " adc    %1,%1,%4        \n\t" \
+   " adc    %2,%2,%5        \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "cc");
+
+
+#else
+
+#define TFM_ISO
+
+/* ISO C portable code */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)                                 \
+   do { fp_word t;                                   \
+   t = c0 + ((fp_word)i) * ((fp_word)j);  c0 = (fp_digit)t;    \
+   t = c1 + (t >> DIGIT_BIT);             c1 = (fp_digit)t;    \
+                                          c2 +=(fp_digit) (t >> DIGIT_BIT); \
+   } while (0);
+  
+
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)                                                 \
+   do { fp_word t;                                                    \
+   t  = ((fp_word)i) * ((fp_word)j);                                  \
+   tt = (fp_word)c0 + t;                 c0 = (fp_digit)tt;           \
+   tt = (fp_word)c1 + (tt >> DIGIT_BIT); c1 = (fp_digit)tt;           \
+                                         c2 +=(fp_digit)( tt >> DIGIT_BIT);    \
+   tt = (fp_word)c0 + t;                 c0 = (fp_digit)tt;                    \
+   tt = (fp_word)c1 + (tt >> DIGIT_BIT); c1 = (fp_digit)tt;            \
+                                         c2 +=(fp_digit) (tt >> DIGIT_BIT);    \
+   } while (0);
+
+#define SQRADDSC(i, j)                                                         \
+   do { fp_word t;                                                             \
+      t =  ((fp_word)i) * ((fp_word)j);                                        \
+      sc0 = (fp_digit)t; sc1 = (t >> DIGIT_BIT); sc2 = 0;                      \
+   } while (0);
+
+#define SQRADDAC(i, j)                                                         \
+   do { fp_word t;                                                             \
+   t = sc0 + ((fp_word)i) * ((fp_word)j);  sc0 =  (fp_digit)t;                 \
+   t = sc1 + (t >> DIGIT_BIT);             sc1 =  (fp_digit)t;                 \
+                                           sc2 += (fp_digit)(t >> DIGIT_BIT);  \
+   } while (0);
+
+#define SQRADDDB                                                               \
+   do { fp_word t;                                                             \
+   t = ((fp_word)sc0) + ((fp_word)sc0) + c0; c0 = (fp_digit)t;                 \
+   t = ((fp_word)sc1) + ((fp_word)sc1) + c1 + (t >> DIGIT_BIT);                \
+                                             c1 = (fp_digit)t;                 \
+   c2 = c2 + (fp_digit)(((fp_word)sc2) + ((fp_word)sc2) + (t >> DIGIT_BIT));   \
+   } while (0);
+
+#endif
+
+#ifdef TFM_SMALL_SET
+    #include "fp_sqr_comba_small_set.i"
+#endif
+
+#if defined(TFM_SQR3)
+    #include "fp_sqr_comba_3.i"
+#endif
+#if defined(TFM_SQR4)
+    #include "fp_sqr_comba_4.i"
+#endif
+#if defined(TFM_SQR6)
+    #include "fp_sqr_comba_6.i"
+#endif
+#if defined(TFM_SQR7)
+    #include "fp_sqr_comba_7.i"
+#endif
+#if defined(TFM_SQR8)
+    #include "fp_sqr_comba_8.i"
+#endif
+#if defined(TFM_SQR9)
+    #include "fp_sqr_comba_9.i"
+#endif
+#if defined(TFM_SQR12)
+    #include "fp_sqr_comba_12.i"
+#endif
+#if defined(TFM_SQR17)
+    #include "fp_sqr_comba_17.i"
+#endif
+#if defined(TFM_SQR20)
+    #include "fp_sqr_comba_20.i"
+#endif
+#if defined(TFM_SQR24)
+    #include "fp_sqr_comba_24.i"
+#endif
+#if defined(TFM_SQR28)
+    #include "fp_sqr_comba_28.i"
+#endif
+#if defined(TFM_SQR32)
+    #include "fp_sqr_comba_32.i"
+#endif
+#if defined(TFM_SQR48)
+    #include "fp_sqr_comba_48.i"
+#endif
+#if defined(TFM_SQR64)
+    #include "fp_sqr_comba_64.i"
+#endif
+/* end fp_sqr_comba.c asm */
+
+/* start fp_mul_comba.c asm */
+/* these are the combas.  Worship them. */
+#if defined(TFM_X86)
+/* Generic x86 optimized code */
+
+/* anything you need at the start */
+#define COMBA_START
+
+/* clear the chaining variables */
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+/* forward the carry to the next digit */
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+/* store the first sum */
+#define COMBA_STORE(x) \
+   x = c0;
+
+/* store the second sum [carry] */
+#define COMBA_STORE2(x) \
+   x = c1;
+
+/* anything you need at the end */
+#define COMBA_FINI
+
+/* this should multiply i and j  */
+#define MULADD(i, j)                                      \
+__asm__(                                                      \
+     "movl  %6,%%eax     \n\t"                            \
+     "mull  %7           \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","%edx","cc");
+
+#elif defined(TFM_X86_64)
+/* x86-64 optimized */
+
+/* anything you need at the start */
+#define COMBA_START
+
+/* clear the chaining variables */
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+/* forward the carry to the next digit */
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+/* store the first sum */
+#define COMBA_STORE(x) \
+   x = c0;
+
+/* store the second sum [carry] */
+#define COMBA_STORE2(x) \
+   x = c1;
+
+/* anything you need at the end */
+#define COMBA_FINI
+
+/* this should multiply i and j  */
+#define MULADD(i, j)                                      \
+__asm__  (                                                    \
+     "movq  %6,%%rax     \n\t"                            \
+     "mulq  %7           \n\t"                            \
+     "addq  %%rax,%0     \n\t"                            \
+     "adcq  %%rdx,%1     \n\t"                            \
+     "adcq  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "g"(i), "g"(j)  :"%rax","%rdx","cc");
+
+#elif defined(TFM_SSE2)
+/* use SSE2 optimizations */
+
+/* anything you need at the start */
+#define COMBA_START
+
+/* clear the chaining variables */
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+/* forward the carry to the next digit */
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+/* store the first sum */
+#define COMBA_STORE(x) \
+   x = c0;
+
+/* store the second sum [carry] */
+#define COMBA_STORE2(x) \
+   x = c1;
+
+/* anything you need at the end */
+#define COMBA_FINI \
+   __asm__("emms");
+
+/* this should multiply i and j  */
+#define MULADD(i, j)                                     \
+__asm__(                                                     \
+    "movd  %6,%%mm0     \n\t"                            \
+    "movd  %7,%%mm1     \n\t"                            \
+    "pmuludq %%mm1,%%mm0\n\t"                            \
+    "movd  %%mm0,%%eax  \n\t"                            \
+    "psrlq $32,%%mm0    \n\t"                            \
+    "addl  %%eax,%0     \n\t"                            \
+    "movd  %%mm0,%%eax  \n\t"                            \
+    "adcl  %%eax,%1     \n\t"                            \
+    "adcl  $0,%2        \n\t"                            \
+    :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","cc");
+
+#elif defined(TFM_ARM)
+/* ARM code */
+
+#define COMBA_START 
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI
+
+#define MULADD(i, j)                                          \
+__asm__(                                                          \
+"  UMULL  r0,r1,%6,%7           \n\t"                         \
+"  ADDS   %0,%0,r0              \n\t"                         \
+"  ADCS   %1,%1,r1              \n\t"                         \
+"  ADC    %2,%2,#0              \n\t"                         \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "cc");
+
+#elif defined(TFM_PPC32)
+/* For 32-bit PPC */
+
+#define COMBA_START
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI 
+   
+/* untested: will mulhwu change the flags?  Docs say no */
+#define MULADD(i, j)              \
+__asm__(                              \
+   " mullw  16,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhwu 16,%6,%7       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"16");
+
+#elif defined(TFM_PPC64)
+/* For 64-bit PPC */
+
+#define COMBA_START
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI 
+   
+/* untested: will mulhwu change the flags?  Docs say no */
+#define MULADD(i, j)              \
+____asm__(                              \
+   " mulld  16,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhdu 16,%6,%7       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"16");
+
+#elif defined(TFM_AVR32)
+
+/* ISO C code */
+
+#define COMBA_START
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI 
+   
+#define MULADD(i, j)             \
+____asm__(                             \
+   " mulu.d r2,%6,%7        \n\t"\
+   " add    %0,r2           \n\t"\
+   " adc    %1,%1,r3        \n\t"\
+   " acr    %2              \n\t"\
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"r2","r3");
+
+#else
+/* ISO C code */
+
+#define COMBA_START
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI 
+   
+#define MULADD(i, j)                                                                                                                                  \
+   do { fp_word t;                                                    \
+   t = (fp_word)c0 + ((fp_word)i) * ((fp_word)j); c0 = (fp_digit)t;   \
+   t = (fp_word)c1 + (t >> DIGIT_BIT);                                \
+   c1 = (fp_digit)t; c2 += (fp_digit)(t >> DIGIT_BIT);                \
+   } while (0);
+
+#endif
+
+
+#ifdef TFM_SMALL_SET
+    #include "fp_mul_comba_small_set.i"
+#endif
+
+#if defined(TFM_MUL3)
+    #include "fp_mul_comba_3.i"
+#endif
+#if defined(TFM_MUL4)
+    #include "fp_mul_comba_4.i"
+#endif
+#if defined(TFM_MUL6)
+    #include "fp_mul_comba_6.i"
+#endif
+#if defined(TFM_MUL7)
+    #include "fp_mul_comba_7.i"
+#endif
+#if defined(TFM_MUL8)
+    #include "fp_mul_comba_8.i"
+#endif
+#if defined(TFM_MUL9)
+    #include "fp_mul_comba_9.i"
+#endif
+#if defined(TFM_MUL12)
+    #include "fp_mul_comba_12.i"
+#endif
+#if defined(TFM_MUL17)
+    #include "fp_mul_comba_17.i"
+#endif
+#if defined(TFM_MUL20)
+    #include "fp_mul_comba_20.i"
+#endif
+#if defined(TFM_MUL24)
+    #include "fp_mul_comba_24.i"
+#endif
+#if defined(TFM_MUL28)
+    #include "fp_mul_comba_28.i"
+#endif
+#if defined(TFM_MUL32)
+    #include "fp_mul_comba_32.i"
+#endif
+#if defined(TFM_MUL48)
+    #include "fp_mul_comba_48.i"
+#endif
+#if defined(TFM_MUL64)
+    #include "fp_mul_comba_64.i"
+#endif
+
+/* end fp_mul_comba.c asm */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/asn.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,6524 @@
+/* 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/error-crypt.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(FREESCALE_MQX)
+    #include <time.h>
+    #define XTIME(t1) mqx_time((t1))
+    #define XGMTIME(c) gmtime((c))
+    #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t))
+#elif defined(CYASSL_MDK_ARM)
+    #if defined(CYASSL_MDK5)
+        #include "cmsis_os.h"
+    #else
+        #include <rtl.h>
+    #endif
+    #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;
+
+#ifdef MICROCHIP_MPLAB_HARMONY 
+    sec = TCPIP_SNTP_UTCSecondsGet();
+#else
+    sec = SNTPGetUTCSeconds();
+#endif
+    *timer = (time_t) sec;
+
+    return *timer;
+}
+
+#endif /* MICROCHIP_TCPIP */
+
+
+#ifdef FREESCALE_MQX
+
+time_t mqx_time(time_t* timer)
+{
+    time_t localTime;
+    TIME_STRUCT time_s;
+
+    if (timer == NULL)
+        timer = &localTime;
+
+    _time_get(&time_s);
+    *timer = (time_t) time_s.SECONDS;
+
+    return *timer;
+}
+
+#endif /* FREESCALE_MQX */
+
+
+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 */
+
+
+CYASSL_LOCAL 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;
+}
+
+
+CYASSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len,
+                           word32 maxIdx)
+{
+    int    length = -1;
+    word32 idx    = *inOutIdx;
+
+    if (input[idx++] != (ASN_SEQUENCE | ASN_CONSTRUCTED) ||
+            GetLength(input, &idx, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    *len      = length;
+    *inOutIdx = idx;
+
+    return length;
+}
+
+
+CYASSL_LOCAL int GetSet(const byte* input, word32* inOutIdx, int* len,
+                        word32 maxIdx)
+{
+    int    length = -1;
+    word32 idx    = *inOutIdx;
+
+    if (input[idx++] != (ASN_SET | ASN_CONSTRUCTED) ||
+            GetLength(input, &idx, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    *len      = length;
+    *inOutIdx = idx;
+
+    return length;
+}
+
+
+/* winodws header clash for WinCE using GetVersion */
+CYASSL_LOCAL 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;
+}
+
+
+CYASSL_LOCAL int GetInt(mp_int* mpi, const byte* input, word32* inOutIdx,
+                  word32 maxIdx)
+{
+    word32 i = *inOutIdx;
+    byte   b = input[i++];
+    int    length;
+
+    if (b != ASN_INTEGER)
+        return ASN_PARSE_E;
+
+    if (GetLength(input, &i, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    if ( (b = input[i++]) == 0x00)
+        length--;
+    else
+        i--;
+
+    if (mp_init(mpi) != MP_OKAY)
+        return MP_INIT_E;
+
+    if (mp_read_unsigned_bin(mpi, (byte*)input + i, length) != 0) {
+        mp_clear(mpi);
+        return ASN_GETINT_E;
+    }
+
+    *inOutIdx = i + length;
+    return 0;
+}
+
+
+static int GetObjectId(const byte* input, word32* inOutIdx, word32* oid,
+                     word32 maxIdx)
+{
+    int    length;
+    word32 i = *inOutIdx;
+    byte   b;
+    *oid = 0;
+    
+    b = input[i++];
+    if (b != ASN_OBJECT_ID) 
+        return ASN_OBJECT_ID_E;
+    
+    if (GetLength(input, &i, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+    
+    while(length--)
+        *oid += input[i++];
+    /* just sum it up for now */
+    
+    *inOutIdx = i;
+    
+    return 0;
+}
+
+
+CYASSL_LOCAL 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 length;
+}
+
+
+#ifndef NO_PWDBASED
+
+/* Check To see if PKCS version algo is supported, set id if it is return 0
+   < 0 on error */
+static int CheckAlgo(int first, int second, int* id, int* version)
+{
+    *id      = ALGO_ID_E;
+    *version = PKCS5;   /* default */
+
+    if (first == 1) {
+        switch (second) {
+        case 1:
+            *id = PBE_SHA1_RC4_128;
+            *version = PKCS12;
+            return 0;
+        case 3:
+            *id = PBE_SHA1_DES3;
+            *version = PKCS12;
+            return 0;
+        default:
+            return ALGO_ID_E;
+        }
+    }
+
+    if (first != PKCS5)
+        return ASN_INPUT_E;  /* VERSION ERROR */
+
+    if (second == PBES2) {
+        *version = PKCS5v2;
+        return 0;
+    }
+
+    switch (second) {
+    case 3:                   /* see RFC 2898 for ids */
+        *id = PBE_MD5_DES;
+        return 0;
+    case 10:
+        *id = PBE_SHA1_DES;
+        return 0;
+    default:
+        return ALGO_ID_E;
+
+    }
+}
+
+
+/* Check To see if PKCS v2 algo is supported, set id if it is return 0
+   < 0 on error */
+static int CheckAlgoV2(int oid, int* id)
+{
+    switch (oid) {
+    case 69:
+        *id = PBE_SHA1_DES;
+        return 0;
+    case 652:
+        *id = PBE_SHA1_DES3;
+        return 0;
+    default:
+        return ALGO_ID_E;
+
+    }
+}
+
+
+/* Decrypt intput in place from parameters based on id */
+static int DecryptKey(const char* password, int passwordSz, byte* salt,
+                      int saltSz, int iterations, int id, byte* input,
+                      int length, int version, byte* cbcIv)
+{
+    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;
+
+            ret = Des_SetKey(&dec, key, desIv, DES_DECRYPTION);
+            if (ret != 0)
+                return ret;
+
+            Des_CbcDecrypt(&dec, input, input, length);
+            break;
+        }
+
+        case DES3_TYPE:
+        {
+            Des3   dec;
+            byte*  desIv = key + 24;
+
+            if (version == PKCS5v2 || version == PKCS12)
+                desIv = cbcIv;
+            ret = Des3_SetKey(&dec, key, desIv, DES_DECRYPTION);
+            if (ret != 0)
+                return ret;
+            ret = Des3_CbcDecrypt(&dec, input, input, length);
+            if (ret != 0)
+                return ret;
+            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)
+{
+    if (key == NULL || p == NULL || g == NULL || pSz == 0 || gSz == 0)
+        return BAD_FUNC_ARG;
+
+    /* may have leading 0 */
+    if (p[0] == 0) {
+        pSz--; p++;
+    }
+
+    if (g[0] == 0) {
+        gSz--; g++;
+    }
+
+    if (mp_init(&key->p) != MP_OKAY)
+        return MP_INIT_E;
+    if (mp_read_unsigned_bin(&key->p, p, pSz) != 0) {
+        mp_clear(&key->p);
+        return ASN_DH_KEY_E;
+    }
+
+    if (mp_init(&key->g) != MP_OKAY) {
+        mp_clear(&key->p);
+        return MP_INIT_E;
+    }
+    if (mp_read_unsigned_bin(&key->g, g, gSz) != 0) {
+        mp_clear(&key->g);
+        mp_clear(&key->p);
+        return ASN_DH_KEY_E;
+    }
+
+    return 0;
+}
+
+
+#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->pubKeySize      = 0;
+    cert->pubKeyStored    = 0;
+    cert->version         = 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->extKeyUsageSet  = 0;
+    cert->extKeyUsage     = 0;
+    cert->extExtKeyUsageSet = 0;
+    cert->extExtKeyUsage    = 0;
+    cert->isCA            = 0;
+#ifdef HAVE_PKCS7
+    cert->issuerRaw       = NULL;
+    cert->issuerRawLen    = 0;
+#endif
+#ifdef 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;
+#endif /* CYASSL_CERT_GEN */
+    cert->beforeDate      = NULL;
+    cert->beforeDateLen   = 0;
+    cert->afterDate       = NULL;
+    cert->afterDateLen    = 0;
+#ifdef OPENSSL_EXTRA
+    XMEMSET(&cert->issuerName, 0, sizeof(DecodedName));
+    XMEMSET(&cert->subjectName, 0, sizeof(DecodedName));
+    cert->extBasicConstSet = 0;
+    cert->extBasicConstCrit = 0;
+    cert->extBasicConstPlSet = 0;
+    cert->pathLength = 0;
+    cert->extSubjAltNameSet = 0;
+    cert->extSubjAltNameCrit = 0;
+    cert->extAuthKeyIdCrit = 0;
+    cert->extSubjKeyIdCrit = 0;
+    cert->extKeyUsageCrit = 0;
+    cert->extExtKeyUsageCrit = 0;
+    cert->extExtKeyUsageSrc = NULL;
+    cert->extExtKeyUsageSz = 0;
+    cert->extExtKeyUsageCount = 0;
+    cert->extAuthKeyIdSrc = NULL;
+    cert->extAuthKeyIdSz = 0;
+    cert->extSubjKeyIdSrc = NULL;
+    cert->extSubjKeyIdSz = 0;
+#endif /* OPENSSL_EXTRA */
+#ifdef HAVE_ECC
+    cert->pkCurveOID = 0;
+#endif /* HAVE_ECC */
+#ifdef CYASSL_SEP
+    cert->deviceTypeSz = 0;
+    cert->deviceType = NULL;
+    cert->hwTypeSz = 0;
+    cert->hwType = NULL;
+    cert->hwSerialNumSz = 0;
+    cert->hwSerialNum = NULL;
+    #ifdef OPENSSL_EXTRA
+        cert->extCertPolicySet = 0;
+        cert->extCertPolicyCrit = 0;
+    #endif /* OPENSSL_EXTRA */
+#endif /* CYASSL_SEP */
+}
+
+
+void FreeAltNames(DNS_entry* altNames, void* heap)
+{
+    (void)heap;
+
+    while (altNames) {
+        DNS_entry* tmp = altNames->next;
+
+        XFREE(altNames->name, heap, DYNAMIC_TYPE_ALTNAME);
+        XFREE(altNames,       heap, DYNAMIC_TYPE_ALTNAME);
+        altNames = tmp;
+    }
+}
+
+
+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);
+#ifdef CYASSL_SEP
+    XFREE(cert->deviceType, cert->heap, 0);
+    XFREE(cert->hwType, cert->heap, 0);
+    XFREE(cert->hwSerialNum, cert->heap, 0);
+#endif /* CYASSL_SEP */
+#ifdef OPENSSL_EXTRA
+    if (cert->issuerName.fullName != NULL)
+        XFREE(cert->issuerName.fullName, NULL, DYNAMIC_TYPE_X509);
+    if (cert->subjectName.fullName != NULL)
+        XFREE(cert->subjectName.fullName, NULL, DYNAMIC_TYPE_X509);
+#endif /* OPENSSL_EXTRA */
+}
+
+
+static int GetCertHeader(DecodedCert* cert)
+{
+    int    ret = 0, len;
+    byte   serialTmp[EXTERNAL_SERIAL_SIZE];
+    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, &cert->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 ( (ret = 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 recvd = cert->srcIdx;
+
+    if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0)
+        return ASN_PARSE_E;
+   
+    recvd = cert->srcIdx - recvd;
+    length += recvd;
+
+    while (recvd--)
+       cert->srcIdx--;
+
+    cert->pubKeySize = length;
+    cert->publicKey = cert->source + cert->srcIdx;
+    cert->srcIdx += length;
+
+    return 0;
+}
+#endif
+
+
+#ifdef HAVE_ECC
+
+    /* return 0 on sucess if the ECC curve oid sum is supported */
+    static int CheckCurve(word32 oid)
+    {
+        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) {
+   #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;
+
+            return 0;
+        }
+    #endif /* HAVE_NTRU */
+    #ifdef HAVE_ECC
+        case ECDSAk:
+        {
+            int    oidSz = 0;
+            byte   b = cert->source[cert->srcIdx++];
+        
+            if (b != ASN_OBJECT_ID) 
+                return ASN_OBJECT_ID_E;
+
+            if (GetLength(cert->source,&cert->srcIdx,&oidSz,cert->maxIdx) < 0)
+                return ASN_PARSE_E;
+
+            while(oidSz--)
+                cert->pkCurveOID += cert->source[cert->srcIdx++];
+
+            if (CheckCurve(cert->pkCurveOID) < 0)
+                return ECC_CURVE_OID_E;
+
+            /* key header */
+            b = cert->source[cert->srcIdx++];
+            if (b != ASN_BIT_STRING)
+                return ASN_BITSTR_E;
+
+            if (GetLength(cert->source,&cert->srcIdx,&length,cert->maxIdx) < 0)
+                return ASN_PARSE_E;
+            b = cert->source[cert->srcIdx++];
+            if (b != 0x00)
+                return ASN_EXPECT_0_E;
+
+            /* actual key, use length - 1 since ate preceding 0 */
+            length -= 1;
+
+            cert->publicKey = (byte*) XMALLOC(length, cert->heap,
+                                              DYNAMIC_TYPE_PUBLIC_KEY);
+            if (cert->publicKey == NULL)
+                return MEMORY_E;
+            XMEMCPY(cert->publicKey, &cert->source[cert->srcIdx], length);
+            cert->pubKeyStored = 1;
+            cert->pubKeySize   = length;
+
+            cert->srcIdx += length;
+
+            return 0;
+        }
+    #endif /* HAVE_ECC */
+        default:
+            return ASN_UNKNOWN_OID_E;
+    }
+}
+
+
+/* process NAME, either issuer or subject */
+static int GetName(DecodedCert* cert, int nameType)
+{
+    Sha    sha;     /* MUST have SHA-1 hash for cert names */
+    int    length;  /* length of all distinguished names */
+    int    dummy;
+    int    ret;
+    char* full = (nameType == ISSUER) ? cert->issuer : cert->subject;
+    word32 idx;
+    #ifdef OPENSSL_EXTRA
+        DecodedName* dName =
+                  (nameType == ISSUER) ? &cert->issuerName : &cert->subjectName;
+    #endif /* OPENSSL_EXTRA */
+
+    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;
+
+    ret = InitSha(&sha);
+    if (ret != 0)
+        return ret;
+    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;
+
+#ifdef HAVE_PKCS7
+    /* store pointer to raw issuer */
+    if (nameType == ISSUER) {
+        cert->issuerRaw = &cert->source[cert->srcIdx];
+        cert->issuerRawLen = length - cert->srcIdx;
+    }
+#endif
+
+    while (cert->srcIdx < (word32)length) {
+        byte   b;
+        byte   joint[2];
+        byte   tooBig = FALSE;
+        int    oidSz;
+
+        if (GetSet(cert->source, &cert->srcIdx, &dummy, cert->maxIdx) < 0) {
+            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 + 14) > (int)(ASN_NAME_MAX - idx)) {
+                /* include biggest pre fix header too 4 = "/serialNumber=" */
+                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;
+                }
+                #ifdef OPENSSL_EXTRA
+                    dName->cnIdx = cert->srcIdx;
+                    dName->cnLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+            else if (id == ASN_SUR_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/SN=", 4);
+                    idx += 4;
+                    copy = TRUE;
+                }
+                #ifdef CYASSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectSN = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectSNLen = strLen;
+                    }
+                #endif /* CYASSL_CERT_GEN */
+                #ifdef OPENSSL_EXTRA
+                    dName->snIdx = cert->srcIdx;
+                    dName->snLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+            else if (id == ASN_COUNTRY_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/C=", 3);
+                    idx += 3;
+                    copy = TRUE;
+                }
+                #ifdef CYASSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectC = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectCLen = strLen;
+                    }
+                #endif /* CYASSL_CERT_GEN */
+                #ifdef OPENSSL_EXTRA
+                    dName->cIdx = cert->srcIdx;
+                    dName->cLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+            else if (id == ASN_LOCALITY_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/L=", 3);
+                    idx += 3;
+                    copy = TRUE;
+                }
+                #ifdef CYASSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectL = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectLLen = strLen;
+                    }
+                #endif /* CYASSL_CERT_GEN */
+                #ifdef OPENSSL_EXTRA
+                    dName->lIdx = cert->srcIdx;
+                    dName->lLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+            else if (id == ASN_STATE_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/ST=", 4);
+                    idx += 4;
+                    copy = TRUE;
+                }
+                #ifdef CYASSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectST = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectSTLen = strLen;
+                    }
+                #endif /* CYASSL_CERT_GEN */
+                #ifdef OPENSSL_EXTRA
+                    dName->stIdx = cert->srcIdx;
+                    dName->stLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+            else if (id == ASN_ORG_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/O=", 3);
+                    idx += 3;
+                    copy = TRUE;
+                }
+                #ifdef CYASSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectO = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectOLen = strLen;
+                    }
+                #endif /* CYASSL_CERT_GEN */
+                #ifdef OPENSSL_EXTRA
+                    dName->oIdx = cert->srcIdx;
+                    dName->oLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+            else if (id == ASN_ORGUNIT_NAME) {
+                if (!tooBig) {
+                    XMEMCPY(&full[idx], "/OU=", 4);
+                    idx += 4;
+                    copy = TRUE;
+                }
+                #ifdef CYASSL_CERT_GEN
+                    if (nameType == SUBJECT) {
+                        cert->subjectOU = (char*)&cert->source[cert->srcIdx];
+                        cert->subjectOULen = strLen;
+                    }
+                #endif /* CYASSL_CERT_GEN */
+                #ifdef OPENSSL_EXTRA
+                    dName->ouIdx = cert->srcIdx;
+                    dName->ouLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+            else if (id == ASN_SERIAL_NUMBER) {
+                if (!tooBig) {
+                   XMEMCPY(&full[idx], "/serialNumber=", 14);
+                   idx += 14;
+                   copy = TRUE;
+                }
+                #ifdef OPENSSL_EXTRA
+                    dName->snIdx = cert->srcIdx;
+                    dName->snLen = strLen;
+                #endif /* OPENSSL_EXTRA */
+            }
+
+            if (copy && !tooBig) {
+                XMEMCPY(&full[idx], &cert->source[cert->srcIdx], strLen);
+                idx += strLen;
+            }
+
+            cert->srcIdx += strLen;
+        }
+        else {
+            /* skip */
+            byte email = FALSE;
+            byte uid   = FALSE;
+            int  adv;
+
+            if (joint[0] == 0x2a && joint[1] == 0x86)  /* email id hdr */
+                email = TRUE;
+
+            if (joint[0] == 0x9  && joint[1] == 0x92)  /* uid id hdr */
+                uid = TRUE;
+
+            cert->srcIdx += oidSz + 1;
+
+            if (GetLength(cert->source, &cert->srcIdx, &adv, cert->maxIdx) < 0)
+                return ASN_PARSE_E;
+
+            if (adv > (int)(ASN_NAME_MAX - idx)) {
+                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 */
+                #ifdef OPENSSL_EXTRA
+                    dName->emailIdx = cert->srcIdx;
+                    dName->emailLen = adv;
+                #endif /* OPENSSL_EXTRA */
+
+                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;
+                }
+                #ifdef OPENSSL_EXTRA
+                    dName->uidIdx = cert->srcIdx;
+                    dName->uidLen = adv;
+                #endif /* OPENSSL_EXTRA */
+            }
+
+            cert->srcIdx += adv;
+        }
+    }
+    full[idx++] = 0;
+
+    #ifdef OPENSSL_EXTRA
+    {
+        int totalLen = 0;
+
+        if (dName->cnLen != 0)
+            totalLen += dName->cnLen + 4;
+        if (dName->snLen != 0)
+            totalLen += dName->snLen + 4;
+        if (dName->cLen != 0)
+            totalLen += dName->cLen + 3;
+        if (dName->lLen != 0)
+            totalLen += dName->lLen + 3;
+        if (dName->stLen != 0)
+            totalLen += dName->stLen + 4;
+        if (dName->oLen != 0)
+            totalLen += dName->oLen + 3;
+        if (dName->ouLen != 0)
+            totalLen += dName->ouLen + 4;
+        if (dName->emailLen != 0)
+            totalLen += dName->emailLen + 14;
+        if (dName->uidLen != 0)
+            totalLen += dName->uidLen + 5;
+        if (dName->serialLen != 0)
+            totalLen += dName->serialLen + 14;
+
+        dName->fullName = (char*)XMALLOC(totalLen + 1, NULL, DYNAMIC_TYPE_X509);
+        if (dName->fullName != NULL) {
+            idx = 0;
+
+            if (dName->cnLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/CN=", 4);
+                idx += 4;
+                XMEMCPY(&dName->fullName[idx],
+                                     &cert->source[dName->cnIdx], dName->cnLen);
+                dName->cnIdx = idx;
+                idx += dName->cnLen;
+            }
+            if (dName->snLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/SN=", 4);
+                idx += 4;
+                XMEMCPY(&dName->fullName[idx],
+                                     &cert->source[dName->snIdx], dName->snLen);
+                dName->snIdx = idx;
+                idx += dName->snLen;
+            }
+            if (dName->cLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/C=", 3);
+                idx += 3;
+                XMEMCPY(&dName->fullName[idx],
+                                       &cert->source[dName->cIdx], dName->cLen);
+                dName->cIdx = idx;
+                idx += dName->cLen;
+            }
+            if (dName->lLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/L=", 3);
+                idx += 3;
+                XMEMCPY(&dName->fullName[idx],
+                                       &cert->source[dName->lIdx], dName->lLen);
+                dName->lIdx = idx;
+                idx += dName->lLen;
+            }
+            if (dName->stLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/ST=", 4);
+                idx += 4;
+                XMEMCPY(&dName->fullName[idx],
+                                     &cert->source[dName->stIdx], dName->stLen);
+                dName->stIdx = idx;
+                idx += dName->stLen;
+            }
+            if (dName->oLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/O=", 3);
+                idx += 3;
+                XMEMCPY(&dName->fullName[idx],
+                                       &cert->source[dName->oIdx], dName->oLen);
+                dName->oIdx = idx;
+                idx += dName->oLen;
+            }
+            if (dName->ouLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/OU=", 4);
+                idx += 4;
+                XMEMCPY(&dName->fullName[idx],
+                                     &cert->source[dName->ouIdx], dName->ouLen);
+                dName->ouIdx = idx;
+                idx += dName->ouLen;
+            }
+            if (dName->emailLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/emailAddress=", 14);
+                idx += 14;
+                XMEMCPY(&dName->fullName[idx],
+                               &cert->source[dName->emailIdx], dName->emailLen);
+                dName->emailIdx = idx;
+                idx += dName->emailLen;
+            }
+            if (dName->uidLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/UID=", 5);
+                idx += 5;
+                XMEMCPY(&dName->fullName[idx],
+                                   &cert->source[dName->uidIdx], dName->uidLen);
+                dName->uidIdx = idx;
+                idx += dName->uidLen;
+            }
+            if (dName->serialLen != 0) {
+                dName->entryCount++;
+                XMEMCPY(&dName->fullName[idx], "/serialNumber=", 14);
+                idx += 14;
+                XMEMCPY(&dName->fullName[idx],
+                             &cert->source[dName->serialIdx], dName->serialLen);
+                dName->serialIdx = idx;
+                idx += dName->serialLen;
+            }
+            dName->fullName[idx] = '\0';
+            dName->fullNameLen = totalLen;
+        }
+    }
+    #endif /* OPENSSL_EXTRA */
+
+    return 0;
+}
+
+
+#ifndef NO_TIME_H
+
+/* to the second */
+static int DateGreaterThan(const struct tm* a, const struct tm* b)
+{
+    if (a->tm_year > b->tm_year)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon > b->tm_mon)
+        return 1;
+    
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+           a->tm_mday > b->tm_mday)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+        a->tm_mday == b->tm_mday && a->tm_hour > b->tm_hour)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+        a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour &&
+        a->tm_min > b->tm_min)
+        return 1;
+
+    if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon &&
+        a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour &&
+        a->tm_min  == b->tm_min  && a->tm_sec > b->tm_sec)
+        return 1;
+
+    return 0; /* false */
+}
+
+
+static INLINE int DateLessThan(const struct tm* a, const struct tm* b)
+{
+    return !DateGreaterThan(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);
+
+    if (dateType == BEFORE) {
+        if (DateLessThan(localTime, &certTime))
+            return 0;
+    }
+    else
+        if (DateGreaterThan(localTime, &certTime))
+            return 0;
+
+    return 1;
+}
+
+#endif /* NO_TIME_H */
+
+
+static int GetDate(DecodedCert* cert, int dateType)
+{
+    int    length;
+    byte   date[MAX_DATE_SIZE];
+    byte   b;
+    word32 startIdx = 0;
+
+    if (dateType == BEFORE)
+        cert->beforeDate = &cert->source[cert->srcIdx];
+    else
+        cert->afterDate = &cert->source[cert->srcIdx];
+    startIdx = cert->srcIdx;
+
+    b = cert->source[cert->srcIdx++];
+    if (b != ASN_UTC_TIME && b != ASN_GENERALIZED_TIME)
+        return ASN_TIME_E;
+
+    if (GetLength(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE)
+        return ASN_DATE_SZ_E;
+
+    XMEMCPY(date, &cert->source[cert->srcIdx], length);
+    cert->srcIdx += length;
+
+    if (dateType == BEFORE)
+        cert->beforeDateLen = cert->srcIdx - startIdx;
+    else
+        cert->afterDateLen  = cert->srcIdx - startIdx;
+
+    if (!XVALIDATE_DATE(date, b, dateType)) {
+        if (dateType == BEFORE)
+            return ASN_BEFORE_DATE_E;
+        else
+            return ASN_AFTER_DATE_E;
+    }
+
+    return 0;
+}
+
+
+static int GetValidity(DecodedCert* cert, int verify)
+{
+    int length;
+    int badDate = 0;
+
+    if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    if (GetDate(cert, BEFORE) < 0 && verify)
+        badDate = ASN_BEFORE_DATE_E;           /* continue parsing */
+    
+    if (GetDate(cert, AFTER) < 0 && verify)
+        return ASN_AFTER_DATE_E;
+   
+    if (badDate != 0)
+        return badDate;
+
+    return 0;
+}
+
+
+int DecodeToKey(DecodedCert* cert, int verify)
+{
+    int badDate = 0;
+    int ret;
+
+    if ( (ret = GetCertHeader(cert)) < 0)
+        return ret;
+
+    CYASSL_MSG("Got Cert Header");
+
+    if ( (ret = GetAlgoId(cert->source, &cert->srcIdx, &cert->signatureOID,
+                          cert->maxIdx)) < 0)
+        return ret;
+
+    CYASSL_MSG("Got Algo ID");
+
+    if ( (ret = GetName(cert, ISSUER)) < 0)
+        return ret;
+
+    if ( (ret = GetValidity(cert, verify)) < 0)
+        badDate = ret;
+
+    if ( (ret = GetName(cert, SUBJECT)) < 0)
+        return ret;
+
+    CYASSL_MSG("Got Subject Name");
+
+    if ( (ret = GetKey(cert)) < 0)
+        return ret;
+
+    CYASSL_MSG("Got Key");
+
+    if (badDate != 0)
+        return badDate;
+
+    return ret;
+}
+
+
+static int GetSignature(DecodedCert* cert)
+{
+    int    length;
+    byte   b = cert->source[cert->srcIdx++];
+
+    if (b != ASN_BIT_STRING)
+        return ASN_BITSTR_E;
+
+    if (GetLength(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    cert->sigLength = length;
+
+    b = cert->source[cert->srcIdx++];
+    if (b != 0x00)
+        return ASN_EXPECT_0_E;
+
+    cert->sigLength--;
+    cert->signature = &cert->source[cert->srcIdx];
+    cert->srcIdx += cert->sigLength;
+
+    return 0;
+}
+
+
+static word32 SetDigest(const byte* digest, word32 digSz, byte* output)
+{
+    output[0] = ASN_OCTET_STRING;
+    output[1] = (byte)digSz;
+    XMEMCPY(&output[2], digest, digSz);
+
+    return digSz + 2;
+} 
+
+
+static word32 BytePrecision(word32 value)
+{
+    word32 i;
+    for (i = sizeof(value); i; --i)
+        if (value >> ((i - 1) * CYASSL_BIT_SIZE))
+            break;
+
+    return i;
+}
+
+
+CYASSL_LOCAL word32 SetLength(word32 length, byte* output)
+{
+    word32 i = 0, j;
+
+    if (length < ASN_LONG_LENGTH)
+        output[i++] = (byte)length;
+    else {
+        output[i++] = (byte)(BytePrecision(length) | ASN_LONG_LENGTH);
+      
+        for (j = BytePrecision(length); j; --j) {
+            output[i] = (byte)(length >> ((j - 1) * CYASSL_BIT_SIZE));
+            i++;
+        }
+    }
+
+    return i;
+}
+
+
+CYASSL_LOCAL word32 SetSequence(word32 len, byte* output)
+{
+    output[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
+    return SetLength(len, output + 1) + 1;
+}
+
+CYASSL_LOCAL word32 SetOctetString(word32 len, byte* output)
+{
+    output[0] = ASN_OCTET_STRING;
+    return SetLength(len, output + 1) + 1;
+}
+
+/* Write a set header to output */
+CYASSL_LOCAL word32 SetSet(word32 len, byte* output)
+{
+    output[0] = ASN_SET | ASN_CONSTRUCTED;
+    return SetLength(len, output + 1) + 1;
+}
+
+CYASSL_LOCAL word32 SetImplicit(byte tag, byte number, word32 len, byte* output)
+{
+
+    output[0] = ((tag == ASN_SEQUENCE || tag == ASN_SET) ? ASN_CONSTRUCTED : 0)
+                    | ASN_CONTEXT_SPECIFIC | number;
+    return SetLength(len, output + 1) + 1;
+}
+
+CYASSL_LOCAL word32 SetExplicit(byte number, word32 len, byte* output)
+{
+    output[0] = ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | number;
+    return SetLength(len, output + 1) + 1;
+}
+
+
+#if defined(HAVE_ECC) && defined(CYASSL_CERT_GEN)
+
+static word32 SetCurve(ecc_key* key, byte* output)
+{
+
+    /* curve types */
+    static const byte ECC_192v1_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d,
+                                             0x03, 0x01, 0x01};
+    static const byte ECC_256v1_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d,
+                                            0x03, 0x01, 0x07};
+    static const byte ECC_160r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00,
+                                             0x02};
+    static const byte ECC_224r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00,
+                                             0x21};
+    static const byte ECC_384r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00,
+                                             0x22};
+    static const byte ECC_521r1_AlgoID[] = { 0x2b, 0x81, 0x04, 0x00,
+                                             0x23};
+
+    int    oidSz = 0;
+    int    idx = 0;
+    int    lenSz = 0;
+    const  byte* oid = 0;
+
+    output[0] = ASN_OBJECT_ID;
+    idx++;
+
+    switch (key->dp->size) {
+        case 20:
+            oidSz = sizeof(ECC_160r1_AlgoID);
+            oid   =        ECC_160r1_AlgoID;
+            break;
+
+        case 24:
+            oidSz = sizeof(ECC_192v1_AlgoID);
+            oid   =        ECC_192v1_AlgoID;
+            break;
+
+        case 28:
+            oidSz = sizeof(ECC_224r1_AlgoID);
+            oid   =        ECC_224r1_AlgoID;
+            break;
+
+        case 32:
+            oidSz = sizeof(ECC_256v1_AlgoID);
+            oid   =        ECC_256v1_AlgoID;
+            break;
+
+        case 48:
+            oidSz = sizeof(ECC_384r1_AlgoID);
+            oid   =        ECC_384r1_AlgoID;
+            break;
+
+        case 66:
+            oidSz = sizeof(ECC_521r1_AlgoID);
+            oid   =        ECC_521r1_AlgoID;
+            break;
+
+        default:
+            return ASN_UNKNOWN_OID_E;
+    }
+    lenSz = SetLength(oidSz, output+idx);
+    idx += lenSz;
+
+    XMEMCPY(output+idx, oid, oidSz);
+    idx += oidSz;
+
+    return idx;
+}
+
+#endif /* HAVE_ECC && CYASSL_CERT_GEN */
+
+
+CYASSL_LOCAL word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz)
+{
+    /* adding TAG_NULL and 0 to end */
+    
+    /* hashTypes */
+    static const byte shaAlgoID[]    = { 0x2b, 0x0e, 0x03, 0x02, 0x1a,
+                                         0x05, 0x00 };
+    static const byte sha256AlgoID[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+                                         0x04, 0x02, 0x01, 0x05, 0x00 };
+    static const byte sha384AlgoID[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+                                         0x04, 0x02, 0x02, 0x05, 0x00 };
+    static const byte sha512AlgoID[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+                                         0x04, 0x02, 0x03, 0x05, 0x00 };
+    static const byte md5AlgoID[]    = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+                                         0x02, 0x05, 0x05, 0x00  };
+    static const byte md2AlgoID[]    = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+                                         0x02, 0x02, 0x05, 0x00};
+
+    /* blkTypes, no NULL tags because IV is there instead */
+    static const byte desCbcAlgoID[]  = { 0x2B, 0x0E, 0x03, 0x02, 0x07 };
+    static const byte des3CbcAlgoID[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                          0x0D, 0x03, 0x07 };
+
+    /* RSA sigTypes */
+    #ifndef NO_RSA
+        static const byte md5wRSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7,
+                                            0x0d, 0x01, 0x01, 0x04, 0x05, 0x00};
+        static const byte shawRSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7,
+                                            0x0d, 0x01, 0x01, 0x05, 0x05, 0x00};
+        static const byte sha256wRSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7,
+                                            0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00};
+        static const byte sha384wRSA_AlgoID[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
+                                            0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00};
+        static const byte sha512wRSA_AlgoID[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
+                                            0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00};
+    #endif /* NO_RSA */
+ 
+    /* ECDSA sigTypes */
+    #ifdef HAVE_ECC 
+        static const byte shawECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d,
+                                                 0x04, 0x01, 0x05, 0x00};
+        static const byte sha256wECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE,0x3d,
+                                                 0x04, 0x03, 0x02, 0x05, 0x00};
+        static const byte sha384wECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE,0x3d,
+                                                 0x04, 0x03, 0x03, 0x05, 0x00};
+        static const byte sha512wECDSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE,0x3d,
+                                                 0x04, 0x03, 0x04, 0x05, 0x00};
+    #endif /* HAVE_ECC */
+ 
+    /* RSA keyType */
+    #ifndef NO_RSA
+        static const byte RSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+                                            0x01, 0x01, 0x01, 0x05, 0x00};
+    #endif /* NO_RSA */
+
+    #ifdef HAVE_ECC 
+        /* ECC keyType */
+        /* no tags, so set tagSz smaller later */
+        static const byte ECC_AlgoID[] = { 0x2a, 0x86, 0x48, 0xCE, 0x3d,
+                                           0x02, 0x01};
+    #endif /* HAVE_ECC */
+
+    int    algoSz = 0;
+    int    tagSz  = 2;   /* tag null and terminator */
+    word32 idSz, seqSz;
+    const  byte* algoName = 0;
+    byte ID_Length[MAX_LENGTH_SZ];
+    byte seqArray[MAX_SEQ_SZ + 1];  /* add object_id to end */
+
+    if (type == hashType) {
+        switch (algoOID) {
+        case SHAh:
+            algoSz = sizeof(shaAlgoID);
+            algoName = shaAlgoID;
+            break;
+
+        case SHA256h:
+            algoSz = sizeof(sha256AlgoID);
+            algoName = sha256AlgoID;
+            break;
+
+        case SHA384h:
+            algoSz = sizeof(sha384AlgoID);
+            algoName = sha384AlgoID;
+            break;
+
+        case SHA512h:
+            algoSz = sizeof(sha512AlgoID);
+            algoName = sha512AlgoID;
+            break;
+
+        case MD2h:
+            algoSz = sizeof(md2AlgoID);
+            algoName = md2AlgoID;
+            break;
+
+        case MD5h:
+            algoSz = sizeof(md5AlgoID);
+            algoName = md5AlgoID;
+            break;
+
+        default:
+            CYASSL_MSG("Unknown Hash Algo");
+            return 0;  /* UNKOWN_HASH_E; */
+        }
+    }
+    else if (type == blkType) {
+        switch (algoOID) {
+        case DESb:
+            algoSz = sizeof(desCbcAlgoID);
+            algoName = desCbcAlgoID;
+            tagSz = 0;
+            break;
+        case DES3b:
+            algoSz = sizeof(des3CbcAlgoID);
+            algoName = des3CbcAlgoID;
+            tagSz = 0;
+            break;
+        default:
+            CYASSL_MSG("Unknown Block Algo");
+            return 0;
+        }
+    }
+    else if (type == sigType) {    /* sigType */
+        switch (algoOID) {
+        #ifndef NO_RSA
+            case CTC_MD5wRSA:
+                algoSz = sizeof(md5wRSA_AlgoID);
+                algoName = md5wRSA_AlgoID;
+                break;
+
+            case CTC_SHAwRSA:
+                algoSz = sizeof(shawRSA_AlgoID);
+                algoName = shawRSA_AlgoID;
+                break;
+
+            case CTC_SHA256wRSA:
+                algoSz = sizeof(sha256wRSA_AlgoID);
+                algoName = sha256wRSA_AlgoID;
+                break;
+
+            case CTC_SHA384wRSA:
+                algoSz = sizeof(sha384wRSA_AlgoID);
+                algoName = sha384wRSA_AlgoID;
+                break;
+
+            case CTC_SHA512wRSA:
+                algoSz = sizeof(sha512wRSA_AlgoID);
+                algoName = sha512wRSA_AlgoID;
+                break;
+        #endif /* NO_RSA */
+        #ifdef HAVE_ECC 
+            case CTC_SHAwECDSA:
+                algoSz = sizeof(shawECDSA_AlgoID);
+                algoName = shawECDSA_AlgoID;
+                break;
+
+            case CTC_SHA256wECDSA:
+                algoSz = sizeof(sha256wECDSA_AlgoID);
+                algoName = sha256wECDSA_AlgoID;
+                break;
+
+            case CTC_SHA384wECDSA:
+                algoSz = sizeof(sha384wECDSA_AlgoID);
+                algoName = sha384wECDSA_AlgoID;
+                break;
+
+            case CTC_SHA512wECDSA:
+                algoSz = sizeof(sha512wECDSA_AlgoID);
+                algoName = sha512wECDSA_AlgoID;
+                break;
+        #endif /* HAVE_ECC */
+        default:
+            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 */
+        #ifdef HAVE_ECC 
+            case ECDSAk:
+                algoSz = sizeof(ECC_AlgoID);
+                algoName = ECC_AlgoID;
+                tagSz = 0;
+                break;
+        #endif /* HAVE_ECC */
+        default:
+            CYASSL_MSG("Unknown Key Algo");
+            return 0;
+        }
+    }
+    else {
+        CYASSL_MSG("Unknown Algo type");
+        return 0;
+    }
+
+    idSz  = SetLength(algoSz - tagSz, ID_Length); /* don't include tags */
+    seqSz = SetSequence(idSz + algoSz + 1 + curveSz, seqArray); 
+                 /* +1 for object id, curveID of curveSz follows for ecc */
+    seqArray[seqSz++] = ASN_OBJECT_ID;
+
+    XMEMCPY(output, seqArray, seqSz);
+    XMEMCPY(output + seqSz, ID_Length, idSz);
+    XMEMCPY(output + seqSz + idSz, algoName, algoSz);
+
+    return seqSz + idSz + algoSz;
+
+}
+
+
+word32 EncodeSignature(byte* out, const byte* digest, word32 digSz, int hashOID)
+{
+    byte digArray[MAX_ENCODED_DIG_SZ];
+    byte algoArray[MAX_ALGO_SZ];
+    byte seqArray[MAX_SEQ_SZ];
+    word32 encDigSz, algoSz, seqSz; 
+
+    encDigSz = SetDigest(digest, digSz, digArray);
+    algoSz   = SetAlgoID(hashOID, algoArray, hashType, 0);
+    seqSz    = SetSequence(encDigSz + algoSz, seqArray);
+
+    XMEMCPY(out, seqArray, seqSz);
+    XMEMCPY(out + seqSz, algoArray, algoSz);
+    XMEMCPY(out + seqSz + algoSz, digArray, encDigSz);
+
+    return encDigSz + algoSz + seqSz;
+}
+
+
+/* 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;
+            ret = InitSha(&sha);
+            if (ret != 0) {
+                CYASSL_MSG("InitSha failed");
+                return 0;  /*  not confirmed */
+            }
+            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;
+            ret = InitSha256(&sha256);
+            if (ret != 0) {
+                CYASSL_MSG("InitSha256 failed");
+                return 0;  /*  not confirmed */
+            }
+            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;
+            ret = InitSha512(&sha512);
+            if (ret != 0) {
+                CYASSL_MSG("InitSha512 failed");
+                return 0;  /*  not confirmed */
+            }
+            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;
+            ret = InitSha384(&sha384);
+            if (ret != 0) {
+                CYASSL_MSG("InitSha384 failed");
+                return 0;  /*  not confirmed */
+            }
+            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;
+    }
+    (void)typeH;  /* some builds won't read */
+
+    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;
+            }
+                
+            ret = InitRsaKey(&pubKey, heap);
+            if (ret != 0) return ret;
+            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 int 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 ASN_PARSE_E;
+    }
+
+    while (length > 0) {
+        byte       b = input[idx++];
+
+        length--;
+
+        /* Save DNS Type names in the altNames list. */
+        /* Save Other Type names in the cert's OidMap */
+        if (b == (ASN_CONTEXT_SPECIFIC | ASN_DNS_TYPE)) {
+            DNS_entry* dnsEntry;
+            int strLen;
+            word32 lenStartIdx = idx;
+
+            if (GetLength(input, &idx, &strLen, sz) < 0) {
+                CYASSL_MSG("\tfail: str length");
+                return ASN_PARSE_E;
+            }
+            length -= (idx - lenStartIdx);
+
+            dnsEntry = (DNS_entry*)XMALLOC(sizeof(DNS_entry), cert->heap,
+                                        DYNAMIC_TYPE_ALTNAME);
+            if (dnsEntry == NULL) {
+                CYASSL_MSG("\tOut of Memory");
+                return ASN_PARSE_E;
+            }
+
+            dnsEntry->name = (char*)XMALLOC(strLen + 1, cert->heap,
+                                         DYNAMIC_TYPE_ALTNAME);
+            if (dnsEntry->name == NULL) {
+                CYASSL_MSG("\tOut of Memory");
+                XFREE(dnsEntry, cert->heap, DYNAMIC_TYPE_ALTNAME);
+                return ASN_PARSE_E;
+            }
+
+            XMEMCPY(dnsEntry->name, &input[idx], strLen);
+            dnsEntry->name[strLen] = '\0';
+
+            dnsEntry->next = cert->altNames;
+            cert->altNames = dnsEntry;
+
+            length -= strLen;
+            idx    += strLen;
+        }
+#ifdef CYASSL_SEP
+        else if (b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | ASN_OTHER_TYPE))
+        {
+            int strLen;
+            word32 lenStartIdx = idx;
+            word32 oid = 0;
+
+            if (GetLength(input, &idx, &strLen, sz) < 0) {
+                CYASSL_MSG("\tfail: other name length");
+                return ASN_PARSE_E;
+            }
+            /* Consume the rest of this sequence. */
+            length -= (strLen + idx - lenStartIdx);
+
+            if (GetObjectId(input, &idx, &oid, sz) < 0) {
+                CYASSL_MSG("\tbad OID");
+                return ASN_PARSE_E;
+            }
+
+            if (oid != HW_NAME_OID) {
+                CYASSL_MSG("\tincorrect OID");
+                return ASN_PARSE_E;
+            }
+
+            if (input[idx++] != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) {
+                CYASSL_MSG("\twrong type");
+                return ASN_PARSE_E;
+            }
+
+            if (GetLength(input, &idx, &strLen, sz) < 0) {
+                CYASSL_MSG("\tfail: str len");
+                return ASN_PARSE_E;
+            }
+
+            if (GetSequence(input, &idx, &strLen, sz) < 0) {
+                CYASSL_MSG("\tBad Sequence");
+                return ASN_PARSE_E;
+            }
+
+            if (input[idx++] != ASN_OBJECT_ID) {
+                CYASSL_MSG("\texpected OID");
+                return ASN_PARSE_E;
+            }
+
+            if (GetLength(input, &idx, &strLen, sz) < 0) {
+                CYASSL_MSG("\tfailed: str len");
+                return ASN_PARSE_E;
+            }
+
+            cert->hwType = (byte*)XMALLOC(strLen, cert->heap, 0);
+            if (cert->hwType == NULL) {
+                CYASSL_MSG("\tOut of Memory");
+                return MEMORY_E;
+            }
+
+            XMEMCPY(cert->hwType, &input[idx], strLen);
+            cert->hwTypeSz = strLen;
+            idx += strLen;
+
+            if (input[idx++] != ASN_OCTET_STRING) {
+                CYASSL_MSG("\texpected Octet String");
+                return ASN_PARSE_E;
+            }
+
+            if (GetLength(input, &idx, &strLen, sz) < 0) {
+                CYASSL_MSG("\tfailed: str len");
+                return ASN_PARSE_E;
+            }
+
+            cert->hwSerialNum = (byte*)XMALLOC(strLen + 1, cert->heap, 0);
+            if (cert->hwSerialNum == NULL) {
+                CYASSL_MSG("\tOut of Memory");
+                return MEMORY_E;
+            }
+
+            XMEMCPY(cert->hwSerialNum, &input[idx], strLen);
+            cert->hwSerialNum[strLen] = '\0';
+            cert->hwSerialNumSz = strLen;
+            idx += strLen;
+        }
+#endif /* CYASSL_SEP */
+        else {
+            int strLen;
+            word32 lenStartIdx = idx;
+
+            CYASSL_MSG("\tUnsupported name type, skipping");
+
+            if (GetLength(input, &idx, &strLen, sz) < 0) {
+                CYASSL_MSG("\tfail: unsupported name length");
+                return ASN_PARSE_E;
+            }
+            length -= (strLen + idx - lenStartIdx);
+            idx += strLen;
+        }
+    }
+    return 0;
+}
+
+
+static int DecodeBasicCaConstraint(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length = 0;
+
+    CYASSL_ENTER("DecodeBasicCaConstraint");
+    if (GetSequence(input, &idx, &length, sz) < 0) {
+        CYASSL_MSG("\tfail: bad SEQUENCE");
+        return ASN_PARSE_E;
+    }
+
+    if (length == 0)
+        return 0;
+
+    /* If the basic ca constraint is false, this extension may be named, but
+     * left empty. So, if the length is 0, just return. */
+
+    if (input[idx++] != ASN_BOOLEAN)
+    {
+        CYASSL_MSG("\tfail: constraint not BOOLEAN");
+        return ASN_PARSE_E;
+    }
+
+    if (GetLength(input, &idx, &length, sz) < 0)
+    {
+        CYASSL_MSG("\tfail: length");
+        return ASN_PARSE_E;
+    }
+
+    if (input[idx++])
+        cert->isCA = 1;
+
+    #ifdef OPENSSL_EXTRA
+        /* If there isn't any more data, return. */
+        if (idx >= (word32)sz)
+            return 0;
+
+        /* Anything left should be the optional pathlength */
+        if (input[idx++] != ASN_INTEGER) {
+            CYASSL_MSG("\tfail: pathlen not INTEGER");
+            return ASN_PARSE_E;
+        }
+
+        if (input[idx++] != 1) {
+            CYASSL_MSG("\tfail: pathlen too long");
+            return ASN_PARSE_E;
+        }
+
+        cert->pathLength = input[idx];
+        cert->extBasicConstPlSet = 1;
+    #endif /* OPENSSL_EXTRA */
+
+    return 0;
+}
+
+
+#define CRLDP_FULL_NAME 0
+    /* From RFC3280 SS4.2.1.14, Distribution Point Name*/
+#define GENERALNAME_URI 6
+    /* From RFC3280 SS4.2.1.7, GeneralName */
+
+static int DecodeCrlDist(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length = 0;
+
+    CYASSL_ENTER("DecodeCrlDist");
+
+    /* Unwrap the list of Distribution Points*/
+    if (GetSequence(input, &idx, &length, sz) < 0)
+        return ASN_PARSE_E;
+
+    /* Unwrap a single Distribution Point */
+    if (GetSequence(input, &idx, &length, sz) < 0)
+        return ASN_PARSE_E;
+
+    /* The Distribution Point has three explicit optional members
+     *  First check for a DistributionPointName
+     */
+    if (input[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
+    {
+        idx++;
+        if (GetLength(input, &idx, &length, sz) < 0)
+            return ASN_PARSE_E;
+
+        if (input[idx] == 
+                    (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | CRLDP_FULL_NAME))
+        {
+            idx++;
+            if (GetLength(input, &idx, &length, sz) < 0)
+                return ASN_PARSE_E;
+
+            if (input[idx] == (ASN_CONTEXT_SPECIFIC | GENERALNAME_URI))
+            {
+                idx++;
+                if (GetLength(input, &idx, &length, sz) < 0)
+                    return ASN_PARSE_E;
+
+                cert->extCrlInfoSz = length;
+                cert->extCrlInfo = input + idx;
+                idx += length;
+            }
+            else
+                /* This isn't a URI, skip it. */
+                idx += length;
+        }
+        else
+            /* This isn't a FULLNAME, skip it. */
+            idx += length;
+    }
+
+    /* Check for reasonFlags */
+    if (idx < (word32)sz &&
+        input[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1))
+    {
+        idx++;
+        if (GetLength(input, &idx, &length, sz) < 0)
+            return ASN_PARSE_E;
+        idx += length;
+    }
+
+    /* Check for cRLIssuer */
+    if (idx < (word32)sz &&
+        input[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 2))
+    {
+        idx++;
+        if (GetLength(input, &idx, &length, sz) < 0)
+            return ASN_PARSE_E;
+        idx += length;
+    }
+
+    if (idx < (word32)sz)
+    {
+        CYASSL_MSG("\tThere are more CRL Distribution Point records, "
+                   "but we only use the first one.");
+    }
+
+    return 0;
+}
+
+
+static int DecodeAuthInfo(byte* input, int sz, DecodedCert* cert)
+/*
+ *  Read the first of the Authority Information Access records. If there are
+ *  any issues, return without saving the record.
+ */
+{
+    word32 idx = 0;
+    int length = 0;
+    byte b;
+    word32 oid;
+
+    CYASSL_ENTER("DecodeAuthInfo");
+
+    /* Unwrap the list of AIAs */
+    if (GetSequence(input, &idx, &length, sz) < 0)
+        return ASN_PARSE_E;
+
+    while (idx < (word32)sz) {
+        /* Unwrap a single AIA */
+        if (GetSequence(input, &idx, &length, sz) < 0)
+            return ASN_PARSE_E;
+
+        oid = 0;
+        if (GetObjectId(input, &idx, &oid, sz) < 0)
+            return ASN_PARSE_E;
+
+        /* Only supporting URIs right now. */
+        b = input[idx++];
+        if (GetLength(input, &idx, &length, sz) < 0)
+            return ASN_PARSE_E;
+
+        if (b == (ASN_CONTEXT_SPECIFIC | GENERALNAME_URI) &&
+            oid == AIA_OCSP_OID)
+        {
+            cert->extAuthInfoSz = length;
+            cert->extAuthInfo = input + idx;
+            break;
+        }
+        idx += length;
+    }
+
+    return 0;
+}
+
+
+static int DecodeAuthKeyId(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length = 0, ret = 0;
+
+    CYASSL_ENTER("DecodeAuthKeyId");
+
+    if (GetSequence(input, &idx, &length, sz) < 0) {
+        CYASSL_MSG("\tfail: should be a SEQUENCE\n");
+        return ASN_PARSE_E;
+    }
+
+    if (input[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) {
+        CYASSL_MSG("\tfail: wanted OPTIONAL item 0, not available\n");
+        return ASN_PARSE_E;
+    }
+
+    if (GetLength(input, &idx, &length, sz) < 0) {
+        CYASSL_MSG("\tfail: extension data length");
+        return ASN_PARSE_E;
+    }
+
+    #ifdef OPENSSL_EXTRA
+        cert->extAuthKeyIdSrc = &input[idx];
+        cert->extAuthKeyIdSz = length;
+    #endif /* OPENSSL_EXTRA */
+
+    if (length == SHA_SIZE) {
+        XMEMCPY(cert->extAuthKeyId, input + idx, length);
+    }
+    else {
+        Sha sha;
+        ret = InitSha(&sha);
+        if (ret != 0)
+            return ret;
+        ShaUpdate(&sha, input + idx, length);
+        ShaFinal(&sha, cert->extAuthKeyId);
+    }
+
+    return 0;
+}
+
+
+static int DecodeSubjKeyId(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length = 0, ret = 0;
+
+    CYASSL_ENTER("DecodeSubjKeyId");
+
+    if (input[idx++] != ASN_OCTET_STRING) {
+        CYASSL_MSG("\tfail: should be an OCTET STRING");
+        return ASN_PARSE_E;
+    }
+
+    if (GetLength(input, &idx, &length, sz) < 0) {
+        CYASSL_MSG("\tfail: extension data length");
+        return ASN_PARSE_E;
+    }
+
+    #ifdef OPENSSL_EXTRA
+        cert->extSubjKeyIdSrc = &input[idx];
+        cert->extSubjKeyIdSz = length;
+    #endif /* OPENSSL_EXTRA */
+
+    if (length == SIGNER_DIGEST_SIZE) {
+        XMEMCPY(cert->extSubjKeyId, input + idx, length);
+    }
+    else {
+        Sha sha;
+        ret = InitSha(&sha);
+        if (ret != 0)
+            return ret;
+        ShaUpdate(&sha, input + idx, length);
+        ShaFinal(&sha, cert->extSubjKeyId);
+    }
+
+    return ret;
+}
+
+
+static int DecodeKeyUsage(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0;
+    int length;
+    byte unusedBits;
+    CYASSL_ENTER("DecodeKeyUsage");
+
+    if (input[idx++] != ASN_BIT_STRING) {
+        CYASSL_MSG("\tfail: key usage expected bit string");
+        return ASN_PARSE_E;
+    }
+
+    if (GetLength(input, &idx, &length, sz) < 0) {
+        CYASSL_MSG("\tfail: key usage bad length");
+        return ASN_PARSE_E;
+    }
+
+    unusedBits = input[idx++];
+    length--;
+
+    if (length == 2) {
+        cert->extKeyUsage = (word16)((input[idx] << 8) | input[idx+1]);
+        cert->extKeyUsage >>= unusedBits;
+    }
+    else if (length == 1)
+        cert->extKeyUsage = (word16)(input[idx] << 1);
+
+    return 0;
+}
+
+
+static int DecodeExtKeyUsage(byte* input, int sz, DecodedCert* cert)
+{
+    word32 idx = 0, oid;
+    int length;
+
+    CYASSL_ENTER("DecodeExtKeyUsage");
+
+    if (GetSequence(input, &idx, &length, sz) < 0) {
+        CYASSL_MSG("\tfail: should be a SEQUENCE\n");
+        return ASN_PARSE_E;
+    }
+
+    #ifdef OPENSSL_EXTRA
+        cert->extExtKeyUsageSrc = input + idx;
+        cert->extExtKeyUsageSz = length;
+    #endif
+
+    while (idx < (word32)sz) {
+        if (GetObjectId(input, &idx, &oid, sz) < 0)
+            return ASN_PARSE_E;
+
+        switch (oid) {
+            case EKU_ANY_OID:
+                cert->extExtKeyUsage |= EXTKEYUSE_ANY;
+                break;
+            case EKU_SERVER_AUTH_OID:
+                cert->extExtKeyUsage |= EXTKEYUSE_SERVER_AUTH;
+                break;
+            case EKU_CLIENT_AUTH_OID:
+                cert->extExtKeyUsage |= EXTKEYUSE_CLIENT_AUTH;
+                break;
+            case EKU_OCSP_SIGN_OID:
+                cert->extExtKeyUsage |= EXTKEYUSE_OCSP_SIGN;
+                break;
+        }
+
+        #ifdef OPENSSL_EXTRA
+            cert->extExtKeyUsageCount++;
+        #endif
+    }
+
+    return 0;
+}
+
+
+#ifdef CYASSL_SEP
+    static int DecodeCertPolicy(byte* input, int sz, DecodedCert* cert)
+    {
+        word32 idx = 0;
+        int length = 0;
+
+        CYASSL_ENTER("DecodeCertPolicy");
+
+        /* Unwrap certificatePolicies */
+        if (GetSequence(input, &idx, &length, sz) < 0) {
+            CYASSL_MSG("\tdeviceType isn't OID");
+            return ASN_PARSE_E;
+        }
+
+        if (GetSequence(input, &idx, &length, sz) < 0) {
+            CYASSL_MSG("\tdeviceType isn't OID");
+            return ASN_PARSE_E;
+        }
+
+        if (input[idx++] != ASN_OBJECT_ID) {
+            CYASSL_MSG("\tdeviceType isn't OID");
+            return ASN_PARSE_E;
+        }
+
+        if (GetLength(input, &idx, &length, sz) < 0) {
+            CYASSL_MSG("\tCouldn't read length of deviceType");
+            return ASN_PARSE_E;
+        }
+
+        if (length > 0) {
+            cert->deviceType = (byte*)XMALLOC(length, cert->heap, 0);
+            if (cert->deviceType == NULL) {
+                CYASSL_MSG("\tCouldn't alloc memory for deviceType");
+                return MEMORY_E;
+            }
+            cert->deviceTypeSz = length;
+            XMEMCPY(cert->deviceType, input + idx, length);
+        }
+
+        CYASSL_LEAVE("DecodeCertPolicy", 0);
+        return 0;
+    }
+#endif /* CYASSL_SEP */
+
+
+static int DecodeCertExtensions(DecodedCert* cert)
+/*
+ *  Processing the Certificate Extensions. This does not modify the current
+ *  index. It is works starting with the recorded extensions pointer.
+ */
+{
+    word32 idx = 0;
+    int sz = cert->extensionsSz;
+    byte* input = cert->extensions;
+    int length;
+    word32 oid;
+    byte critical = 0;
+    byte criticalFail = 0;
+
+    CYASSL_ENTER("DecodeCertExtensions");
+
+    if (input == NULL || sz == 0)
+        return BAD_FUNC_ARG;
+
+    if (input[idx++] != ASN_EXTENSIONS)
+        return ASN_PARSE_E;
+
+    if (GetLength(input, &idx, &length, sz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetSequence(input, &idx, &length, sz) < 0)
+        return ASN_PARSE_E;
+    
+    while (idx < (word32)sz) {
+        if (GetSequence(input, &idx, &length, sz) < 0) {
+            CYASSL_MSG("\tfail: should be a SEQUENCE");
+            return ASN_PARSE_E;
+        }
+
+        oid = 0;
+        if (GetObjectId(input, &idx, &oid, sz) < 0) {
+            CYASSL_MSG("\tfail: OBJECT ID");
+            return ASN_PARSE_E;
+        }
+
+        /* check for critical flag */
+        critical = 0;
+        if (input[idx] == ASN_BOOLEAN) {
+            int boolLength = 0;
+            idx++;
+            if (GetLength(input, &idx, &boolLength, sz) < 0) {
+                CYASSL_MSG("\tfail: critical boolean length");
+                return ASN_PARSE_E;
+            }
+            if (input[idx++])
+                critical = 1;
+        }
+
+        /* process the extension based on the OID */
+        if (input[idx++] != ASN_OCTET_STRING) {
+            CYASSL_MSG("\tfail: should be an OCTET STRING");
+            return ASN_PARSE_E;
+        }
+
+        if (GetLength(input, &idx, &length, sz) < 0) {
+            CYASSL_MSG("\tfail: extension data length");
+            return ASN_PARSE_E;
+        }
+
+        switch (oid) {
+            case BASIC_CA_OID:
+                #ifdef OPENSSL_EXTRA
+                    cert->extBasicConstSet = 1;
+                    cert->extBasicConstCrit = critical;
+                #endif
+                if (DecodeBasicCaConstraint(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            case CRL_DIST_OID:
+                if (DecodeCrlDist(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            case AUTH_INFO_OID:
+                if (DecodeAuthInfo(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            case ALT_NAMES_OID:
+                #ifdef OPENSSL_EXTRA
+                    cert->extSubjAltNameSet = 1;
+                    cert->extSubjAltNameCrit = critical;
+                #endif
+                if (DecodeAltNames(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            case AUTH_KEY_OID:
+                cert->extAuthKeyIdSet = 1;
+                #ifdef OPENSSL_EXTRA
+                    cert->extAuthKeyIdCrit = critical;
+                #endif
+                if (DecodeAuthKeyId(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            case SUBJ_KEY_OID:
+                cert->extSubjKeyIdSet = 1;
+                #ifdef OPENSSL_EXTRA
+                    cert->extSubjKeyIdCrit = critical;
+                #endif
+                if (DecodeSubjKeyId(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            case CERT_POLICY_OID:
+                CYASSL_MSG("Certificate Policy extension not supported yet.");
+                #ifdef CYASSL_SEP
+                    #ifdef OPENSSL_EXTRA
+                        cert->extCertPolicySet = 1;
+                        cert->extCertPolicyCrit = critical;
+                    #endif
+                    if (DecodeCertPolicy(&input[idx], length, cert) < 0)
+                        return ASN_PARSE_E;
+                #endif
+                break;
+
+            case KEY_USAGE_OID:
+                cert->extKeyUsageSet = 1;
+                #ifdef OPENSSL_EXTRA
+                    cert->extKeyUsageCrit = critical;
+                #endif
+                if (DecodeKeyUsage(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            case EXT_KEY_USAGE_OID:
+                cert->extExtKeyUsageSet = 1;
+                #ifdef OPENSSL_EXTRA
+                    cert->extExtKeyUsageCrit = critical;
+                #endif
+                if (DecodeExtKeyUsage(&input[idx], length, cert) < 0)
+                    return ASN_PARSE_E;
+                break;
+
+            case INHIBIT_ANY_OID:
+                CYASSL_MSG("Inhibit anyPolicy extension not supported yet.");
+                break;
+
+            default:
+                /* While it is a failure to not support critical extensions,
+                 * still parse the certificate ignoring the unsupported
+                 * extention to allow caller to accept it with the verify
+                 * callback. */
+                if (critical)
+                    criticalFail = 1;
+                break;
+        }
+        idx += length;
+    }
+
+    return criticalFail ? ASN_CRIT_EXT_E : 0;
+}
+
+
+int ParseCert(DecodedCert* cert, int type, int verify, void* cm)
+{
+    int   ret;
+    char* ptr;
+
+    ret = ParseCertRelative(cert, type, verify, cm);
+    if (ret < 0)
+        return ret;
+
+    if (cert->subjectCNLen > 0) {
+        ptr = (char*) XMALLOC(cert->subjectCNLen + 1, cert->heap,
+                              DYNAMIC_TYPE_SUBJECT_CN);
+        if (ptr == NULL)
+            return MEMORY_E;
+        XMEMCPY(ptr, cert->subjectCN, cert->subjectCNLen);
+        ptr[cert->subjectCNLen] = '\0';
+        cert->subjectCN = ptr;
+        cert->subjectCNStored = 1;
+    }
+
+    if (cert->keyOID == RSAk &&
+                          cert->publicKey != NULL  && cert->pubKeySize > 0) {
+        ptr = (char*) XMALLOC(cert->pubKeySize, cert->heap,
+                              DYNAMIC_TYPE_PUBLIC_KEY);
+        if (ptr == NULL)
+            return MEMORY_E;
+        XMEMCPY(ptr, cert->publicKey, cert->pubKeySize);
+        cert->publicKey = (byte *)ptr;
+        cert->pubKeyStored = 1;
+    }
+
+    return ret;
+}
+
+
+/* from SSL proper, for locking can't do find here anymore */
+#ifdef __cplusplus
+    extern "C" {
+#endif
+    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;
+    int    criticalExt = 0;
+
+    if ((ret = DecodeToKey(cert, verify)) < 0) {
+        if (ret == ASN_BEFORE_DATE_E || ret == ASN_AFTER_DATE_E)
+            badDate = ret;
+        else
+            return ret;
+    }
+
+    CYASSL_MSG("Parsed Past Key");
+
+    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 */
+        }
+        if ((ret = DecodeCertExtensions(cert)) < 0) {
+            if (ret == ASN_CRIT_EXT_E)
+                criticalExt = ret;
+            else
+                return ret;
+        }
+
+        /* advance past extensions */
+        cert->srcIdx =  cert->sigIndex;
+    }
+
+    if ((ret = GetAlgoId(cert->source, &cert->srcIdx, &confirmOID,
+                         cert->maxIdx)) < 0)
+        return ret;
+
+    if ((ret = GetSignature(cert)) < 0)
+        return ret;
+
+    if (confirmOID != cert->signatureOID)
+        return ASN_SIG_OID_E;
+
+    #ifndef NO_SKID
+        if (cert->extSubjKeyIdSet == 0
+                          && cert->publicKey != NULL && cert->pubKeySize > 0) {
+            Sha sha;
+            ret = InitSha(&sha);
+            if (ret != 0)
+                return ret;
+            ShaUpdate(&sha, cert->publicKey, cert->pubKeySize);
+            ShaFinal(&sha, cert->extSubjKeyId);
+        }
+    #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;
+                ret = InitSha(&sha);
+                if (ret != 0)
+                    return ret;
+                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;
+
+    if (criticalExt != 0)
+        return criticalExt;
+
+    return 0;
+}
+
+
+/* Create and init an new signer */
+Signer* MakeSigner(void* heap)
+{
+    Signer* signer = (Signer*) XMALLOC(sizeof(Signer), heap,
+                                       DYNAMIC_TYPE_SIGNER);
+    if (signer) {
+        signer->pubKeySize = 0;
+        signer->keyOID     = 0;
+        signer->publicKey  = NULL;
+        signer->nameLen    = 0;
+        signer->name       = NULL;
+        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;
+    }
+}
+
+
+CYASSL_LOCAL int SetMyVersion(word32 version, byte* output, int header)
+{
+    int i = 0;
+
+    if (header) {
+        output[i++] = ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED;
+        output[i++] = ASN_BIT_STRING;
+    }
+    output[i++] = ASN_INTEGER;
+    output[i++] = 0x01;
+    output[i++] = (byte)version;
+
+    return i;
+}
+
+
+CYASSL_LOCAL int SetSerialNumber(const byte* sn, word32 snSz, byte* output)
+{
+    int result = 0;
+
+    CYASSL_ENTER("SetSerialNumber");
+
+    if (snSz <= EXTERNAL_SERIAL_SIZE) {
+        output[0] = ASN_INTEGER;
+        /* The serial number is always positive. When encoding the
+         * INTEGER, if the MSB is 1, add a padding zero to keep the
+         * number positive. */
+        if (sn[0] & 0x80) {
+            output[1] = (byte)snSz + 1;
+            output[2] = 0;
+            XMEMCPY(&output[3], sn, snSz);
+            result = snSz + 3;
+        }
+        else {
+            output[1] = (byte)snSz;
+            XMEMCPY(&output[2], sn, snSz);
+            result = snSz + 2;
+        }
+    }
+    return result;
+}
+
+
+
+
+#if defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN)
+
+/* convert der buffer to pem into output, can't do inplace, der and output
+   need to be different */
+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 (der == output)      /* no in place conversion */
+        return BAD_FUNC_ARG;
+
+    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
+    #ifdef CYASSL_CERT_REQ
+    else if (type == CERTREQ_TYPE)
+    {
+        XSTRNCPY(header,
+                       "-----BEGIN CERTIFICATE REQUEST-----\n", sizeof(header));
+        XSTRNCPY(footer, "-----END CERTIFICATE REQUEST-----\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';
+
+#ifdef CYASSL_CERT_REQ
+    cert->challengePw[0] ='\0';
+#endif
+}
+
+
+/* DER encoded x509 Certificate */
+typedef struct DerCert {
+    byte size[MAX_LENGTH_SZ];          /* length encoded */
+    byte version[MAX_VERSION_SZ];      /* version encoded */
+    byte serial[CTC_SERIAL_SIZE + MAX_LENGTH_SZ]; /* serial number encoded */
+    byte sigAlgo[MAX_ALGO_SZ];         /* signature algo encoded */
+    byte issuer[ASN_NAME_MAX];         /* issuer  encoded */
+    byte subject[ASN_NAME_MAX];        /* subject encoded */
+    byte validity[MAX_DATE_SIZE*2 + MAX_SEQ_SZ*2];  /* before and after dates */
+    byte publicKey[MAX_PUBLIC_KEY_SZ]; /* rsa / ntru public key encoded */
+    byte ca[MAX_CA_SZ];                /* basic constraint CA true size */
+    byte extensions[MAX_EXTENSIONS_SZ];  /* all extensions */
+#ifdef CYASSL_CERT_REQ
+    byte attrib[MAX_ATTRIB_SZ];        /* Cert req attributes encoded */
+#endif
+    int  sizeSz;                       /* encoded size length */
+    int  versionSz;                    /* encoded version length */
+    int  serialSz;                     /* encoded serial length */
+    int  sigAlgoSz;                    /* enocded sig alog length */
+    int  issuerSz;                     /* encoded issuer length */
+    int  subjectSz;                    /* encoded subject length */
+    int  validitySz;                   /* encoded validity length */
+    int  publicKeySz;                  /* encoded public key length */
+    int  caSz;                         /* encoded CA extension length */
+    int  extensionsSz;                 /* encoded extensions total length */
+    int  total;                        /* total encoded lengths */
+#ifdef CYASSL_CERT_REQ
+    int  attribSz;
+#endif
+} DerCert;
+
+
+#ifdef CYASSL_CERT_REQ
+
+/* Write a set header to output */
+static word32 SetUTF8String(word32 len, byte* output)
+{
+    output[0] = ASN_UTF8STRING;
+    return SetLength(len, output + 1) + 1;
+}
+
+#endif /* CYASSL_CERT_REQ */
+
+
+/* Write a serial number to output */
+static int SetSerial(const byte* serial, byte* output)
+{
+    int length = 0;
+
+    output[length++] = ASN_INTEGER;
+    length += SetLength(CTC_SERIAL_SIZE, &output[length]);
+    XMEMCPY(&output[length], serial, CTC_SERIAL_SIZE);
+
+    return length + CTC_SERIAL_SIZE;
+}
+
+
+#ifdef HAVE_ECC 
+
+/* Write a public ECC key to output */
+static int SetEccPublicKey(byte* output, ecc_key* key)
+{
+    byte algo[MAX_ALGO_SZ];
+    byte curve[MAX_ALGO_SZ];
+    byte len[MAX_LENGTH_SZ + 1];  /* trailing 0 */
+    byte pub[ECC_BUFSIZE];
+    int  algoSz;
+    int  curveSz;
+    int  lenSz;
+    int  idx;
+    word32 pubSz = sizeof(pub);
+
+    int ret = ecc_export_x963(key, pub, &pubSz);
+    if (ret != 0) return ret;
+
+    /* headers */
+    curveSz = SetCurve(key, curve);
+    if (curveSz <= 0) return curveSz;
+
+    algoSz  = SetAlgoID(ECDSAk, algo, keyType, curveSz);
+    lenSz   = SetLength(pubSz + 1, len);
+    len[lenSz++] = 0;   /* trailing 0 */
+
+    /* write */
+    idx = SetSequence(pubSz + curveSz + lenSz + 1 + algoSz, output);
+        /* 1 is for ASN_BIT_STRING */
+    /* algo */
+    XMEMCPY(output + idx, algo, algoSz);
+    idx += algoSz;
+    /* curve */
+    XMEMCPY(output + idx, curve, curveSz);
+    idx += curveSz;
+    /* bit string */
+    output[idx++] = ASN_BIT_STRING;
+    /* length */
+    XMEMCPY(output + idx, len, lenSz);
+    idx += lenSz;
+    /* pub */
+    XMEMCPY(output + idx, pub, pubSz);
+    idx += pubSz;
+
+    return idx;
+}
+
+
+#endif /* HAVE_ECC */
+
+
+/* Write a public RSA key to output */
+static int SetRsaPublicKey(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;
+    int  leadingBit;
+    int  err;
+
+    /* n */
+    leadingBit = mp_leading_bit(&key->n);
+    rawLen = mp_unsigned_bin_size(&key->n) + leadingBit;
+    n[0] = ASN_INTEGER;
+    nSz  = SetLength(rawLen, n + 1) + 1;  /* int tag */
+
+    if ( (nSz + rawLen) < (int)sizeof(n)) {
+        if (leadingBit)
+            n[nSz] = 0;
+        err = mp_to_unsigned_bin(&key->n, n + nSz + leadingBit);
+        if (err == MP_OKAY)
+            nSz += rawLen;
+        else
+            return MP_TO_E;
+    }
+    else
+        return BUFFER_E;
+
+    /* e */
+    leadingBit = mp_leading_bit(&key->e);
+    rawLen = mp_unsigned_bin_size(&key->e) + leadingBit;
+    e[0] = ASN_INTEGER;
+    eSz  = SetLength(rawLen, e + 1) + 1;  /* int tag */
+
+    if ( (eSz + rawLen) < (int)sizeof(e)) {
+        if (leadingBit)
+            e[eSz] = 0;
+        err = mp_to_unsigned_bin(&key->e, e + eSz + leadingBit);
+        if (err == MP_OKAY)
+            eSz += rawLen;
+        else
+            return MP_TO_E;
+    }
+    else
+        return BUFFER_E;
+
+    /* headers */
+    algoSz = SetAlgoID(RSAk, algo, keyType, 0);
+    seqSz  = SetSequence(nSz + eSz, seq);
+    lenSz  = SetLength(seqSz + nSz + eSz + 1, len);
+    len[lenSz++] = 0;   /* trailing 0 */
+
+    /* write */
+    idx = SetSequence(nSz + eSz + seqSz + lenSz + 1 + algoSz, output);
+        /* 1 is for ASN_BIT_STRING */
+    /* algo */
+    XMEMCPY(output + idx, algo, algoSz);
+    idx += algoSz;
+    /* bit string */
+    output[idx++] = ASN_BIT_STRING;
+    /* length */
+    XMEMCPY(output + idx, len, lenSz);
+    idx += lenSz;
+    /* seq */
+    XMEMCPY(output + idx, seq, seqSz);
+    idx += seqSz;
+    /* n */
+    XMEMCPY(output + idx, n, nSz);
+    idx += nSz;
+    /* e */
+    XMEMCPY(output + idx, e, eSz);
+    idx += eSz;
+
+    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, int header)
+{
+    byte sequence[MAX_SEQ_SZ];
+    byte len[MAX_LENGTH_SZ];
+
+    int sz = 0;
+    int seqSz = SetSequence(extSz, sequence);
+
+    if (header) {
+        int lenSz = SetLength(seqSz + extSz, len);
+        output[0] = ASN_EXTENSIONS; /* extensions id */
+        sz++;
+        XMEMCPY(&output[sz], len, lenSz);  /* length */
+        sz += lenSz;
+    }
+    XMEMCPY(&output[sz], sequence, seqSz);  /* sequence */
+    sz += seqSz;
+    XMEMCPY(&output[sz], ext, extSz);  /* extensions */
+    sz += extSz;
+
+    return sz;
+}
+
+
+/* encode CA basic constraint true, return total bytes written */
+static int SetCa(byte* output)
+{
+    static const byte ca[] = { 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04,
+                               0x05, 0x30, 0x03, 0x01, 0x01, 0xff };
+    
+    XMEMCPY(output, ca, sizeof(ca));
+
+    return (int)sizeof(ca);
+}
+
+
+/* encode CertName into output, return total bytes written */
+static int SetName(byte* output, CertName* name)
+{
+    int         totalBytes = 0, i, idx;
+    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 */
+                byte bType = GetNameId(i);
+                names[i].encoded[idx++] = 0x55;
+                names[i].encoded[idx++] = 0x04;
+                /* id type */
+                names[i].encoded[idx++] = bType; 
+                /* str type */
+                if (bType == ASN_COUNTRY_NAME)
+                    names[i].encoded[idx++] = 0x13;   /* printable */
+                else
+                    names[i].encoded[idx++] = 0x0c;   /* utf8 */
+            }
+            /* 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 encoded format */
+static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey,
+                      RNG* rng, const byte* ntruKey, word16 ntruSz)
+{
+    (void)eccKey;
+    (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, 0);
+    if (der->sigAlgoSz == 0)
+        return ALGO_ID_E;
+
+    /* public key */
+    if (cert->keyType == RSA_KEY) {
+        if (rsaKey == NULL)
+            return PUBLIC_KEY_E;
+        der->publicKeySz = SetRsaPublicKey(der->publicKey, rsaKey);
+        if (der->publicKeySz <= 0)
+            return PUBLIC_KEY_E;
+    }
+
+#ifdef HAVE_ECC
+    if (cert->keyType == ECC_KEY) {
+        if (eccKey == NULL)
+            return PUBLIC_KEY_E;
+        der->publicKeySz = SetEccPublicKey(der->publicKey, eccKey);
+        if (der->publicKeySz <= 0)
+            return PUBLIC_KEY_E;
+    }
+#endif /* HAVE_ECC */
+
+#ifdef HAVE_NTRU
+    if (cert->keyType == NTRU_KEY) {
+        word32 rc;
+        word16 encodedSz;
+
+        rc  = 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 /* HAVE_NTRU */
+
+    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, TRUE);
+        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, TRUE);
+        if (der->extensionsSz == 0)
+            return EXTENSIONS_E;
+    }
+#endif
+
+    der->total = der->versionSz + der->serialSz + der->sigAlgoSz +
+        der->publicKeySz + der->validitySz + der->subjectSz + der->issuerSz +
+        der->extensionsSz;
+
+    return 0;
+}
+
+
+/* write DER encoded cert to buffer, size already checked */
+static int WriteCertBody(DerCert* der, byte* buffer)
+{
+    int idx;
+
+    /* signed part header */
+    idx = SetSequence(der->total, buffer);
+    /* version */
+    XMEMCPY(buffer + idx, der->version, der->versionSz);
+    idx += der->versionSz;
+    /* serial */
+    XMEMCPY(buffer + idx, der->serial, der->serialSz);
+    idx += der->serialSz;
+    /* sig algo */
+    XMEMCPY(buffer + idx, der->sigAlgo, der->sigAlgoSz);
+    idx += der->sigAlgoSz;
+    /* issuer */
+    XMEMCPY(buffer + idx, der->issuer, der->issuerSz);
+    idx += der->issuerSz;
+    /* validity */
+    XMEMCPY(buffer + idx, der->validity, der->validitySz);
+    idx += der->validitySz;
+    /* subject */
+    XMEMCPY(buffer + idx, der->subject, der->subjectSz);
+    idx += der->subjectSz;
+    /* public key */
+    XMEMCPY(buffer + idx, der->publicKey, der->publicKeySz);
+    idx += der->publicKeySz;
+    if (der->extensionsSz) {
+        /* extensions */
+        XMEMCPY(buffer + idx, der->extensions, min(der->extensionsSz,
+                                                   sizeof(der->extensions)));
+        idx += der->extensionsSz;
+    }
+
+    return idx;
+}
+
+
+/* Make RSA signature from buffer (sz), write to sig (sigSz) */
+static int MakeSignature(const byte* buffer, int sz, byte* sig, int sigSz,
+                         RsaKey* rsaKey, ecc_key* eccKey, RNG* rng,
+                         int sigAlgoType)
+{
+    byte    digest[SHA256_DIGEST_SIZE];     /* max size */
+    byte    encSig[MAX_ENCODED_DIG_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ];
+    int     encSigSz, digestSz, typeH, ret = 0;
+
+    (void)eccKey;
+
+    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 || sigAlgoType == CTC_SHAwECDSA) {
+        Sha     sha;
+        ret = InitSha(&sha);
+        if (ret != 0)
+            return ret;
+        ShaUpdate(&sha, buffer, sz);
+        ShaFinal(&sha, digest);
+        digestSz = SHA_DIGEST_SIZE;
+        typeH    = SHAh;
+    }
+    else if (sigAlgoType == CTC_SHA256wRSA || sigAlgoType == CTC_SHA256wECDSA) {
+        Sha256     sha256;
+        ret = InitSha256(&sha256);
+        if (ret != 0)
+            return ret;
+        Sha256Update(&sha256, buffer, sz);
+        Sha256Final(&sha256, digest);
+        digestSz = SHA256_DIGEST_SIZE;
+        typeH    = SHA256h;
+    }
+    else
+        return ALGO_ID_E;
+
+    if (rsaKey) {
+        /* signature */
+        encSigSz = EncodeSignature(encSig, digest, digestSz, typeH);
+        return RsaSSL_Sign(encSig, encSigSz, sig, sigSz, rsaKey, rng);
+    }
+#ifdef HAVE_ECC
+    else if (eccKey) {
+        word32 outSz = sigSz;
+        ret = ecc_sign_hash(digest, digestSz, sig, &outSz, rng, eccKey);
+
+        if (ret != 0)
+            return ret;
+        return outSz;
+    }
+#endif /* HAVE_ECC */
+
+    return ALGO_ID_E;
+}
+
+
+/* add signature to end of buffer, size of buffer assumed checked, return
+   new length */
+static int AddSignature(byte* buffer, int bodySz, const byte* sig, int sigSz,
+                        int sigAlgoType)
+{
+    byte seq[MAX_SEQ_SZ];
+    int  idx = bodySz, seqSz;
+
+    /* algo */
+    idx += SetAlgoID(sigAlgoType, buffer + idx, sigType, 0);
+    /* bit string */
+    buffer[idx++] = ASN_BIT_STRING;
+    /* length */
+    idx += SetLength(sigSz + 1, buffer + idx);
+    buffer[idx++] = 0;   /* trailing 0 */
+    /* signature */
+    XMEMCPY(buffer + idx, sig, sigSz);
+    idx += sigSz;
+
+    /* make room for overall header */
+    seqSz = SetSequence(idx, seq);
+    XMEMMOVE(buffer + seqSz, buffer, idx);
+    XMEMCPY(buffer, seq, seqSz);
+
+    return idx + seqSz;
+}
+
+
+/* Make an x509 Certificate v3 any key type from cert input, write to buffer */
+static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz,
+                       RsaKey* rsaKey, ecc_key* eccKey, RNG* rng,
+                       const byte* ntruKey, word16 ntruSz)
+{
+    DerCert der;
+    int     ret;
+
+    if (eccKey)
+        cert->keyType = ECC_KEY;
+    else
+        cert->keyType = rsaKey ? RSA_KEY : NTRU_KEY;
+    ret = EncodeCert(cert, &der, rsaKey, eccKey, 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 or ECC from cert input, write to buffer */
+int MakeCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey,
+             ecc_key* eccKey, RNG* rng)
+{
+    return MakeAnyCert(cert, derBuffer, derSz, rsaKey, eccKey, rng, NULL, 0);
+}
+
+
+#ifdef HAVE_NTRU
+
+int  MakeNtruCert(Cert* cert, byte* derBuffer, word32 derSz,
+                  const byte* ntruKey, word16 keySz, RNG* rng)
+{
+    return MakeAnyCert(cert, derBuffer, derSz, NULL, NULL, rng, ntruKey, keySz);
+}
+
+#endif /* HAVE_NTRU */
+
+
+#ifdef CYASSL_CERT_REQ
+
+static int SetReqAttrib(byte* output, char* pw, int extSz)
+{
+    static const byte cpOid[] =
+        { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+                         0x09, 0x07 };
+    static const byte erOid[] =
+        { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+                         0x09, 0x0e };
+
+    int sz      = 0; /* overall size */
+    int cpSz    = 0; /* Challenge Password section size */
+    int cpSeqSz = 0;
+    int cpSetSz = 0;
+    int cpStrSz = 0;
+    int pwSz    = 0;
+    int erSz    = 0; /* Extension Request section size */
+    int erSeqSz = 0;
+    int erSetSz = 0;
+    byte cpSeq[MAX_SEQ_SZ];
+    byte cpSet[MAX_SET_SZ];
+    byte cpStr[MAX_PRSTR_SZ];
+    byte erSeq[MAX_SEQ_SZ];
+    byte erSet[MAX_SET_SZ];
+
+    output[0] = 0xa0;
+    sz++;
+
+    if (pw && pw[0]) {
+        pwSz = (int)XSTRLEN(pw);
+        cpStrSz = SetUTF8String(pwSz, cpStr);
+        cpSetSz = SetSet(cpStrSz + pwSz, cpSet);
+        cpSeqSz = SetSequence(sizeof(cpOid) + cpSetSz + cpStrSz + pwSz, cpSeq);
+        cpSz = cpSeqSz + sizeof(cpOid) + cpSetSz + cpStrSz + pwSz;
+    }
+
+    if (extSz) {
+        erSetSz = SetSet(extSz, erSet);
+        erSeqSz = SetSequence(erSetSz + sizeof(erOid) + extSz, erSeq);
+        erSz = extSz + erSetSz + erSeqSz + sizeof(erOid);
+    }
+
+    /* Put the pieces together. */
+    sz += SetLength(cpSz + erSz, &output[sz]);
+
+    if (cpSz) {
+        XMEMCPY(&output[sz], cpSeq, cpSeqSz);
+        sz += cpSeqSz;
+        XMEMCPY(&output[sz], cpOid, sizeof(cpOid));
+        sz += sizeof(cpOid);
+        XMEMCPY(&output[sz], cpSet, cpSetSz);
+        sz += cpSetSz;
+        XMEMCPY(&output[sz], cpStr, cpStrSz);
+        sz += cpStrSz;
+        XMEMCPY(&output[sz], pw, pwSz);
+        sz += pwSz;
+    }
+
+    if (erSz) {
+        XMEMCPY(&output[sz], erSeq, erSeqSz);
+        sz += erSeqSz;
+        XMEMCPY(&output[sz], erOid, sizeof(erOid));
+        sz += sizeof(erOid);
+        XMEMCPY(&output[sz], erSet, erSetSz);
+        sz += erSetSz;
+        /* The actual extension data will be tacked onto the output later. */
+    }
+
+    return sz;
+}
+
+
+/* encode info from cert into DER encoded format */
+static int EncodeCertReq(Cert* cert, DerCert* der,
+                         RsaKey* rsaKey, ecc_key* eccKey)
+{
+    (void)eccKey;
+
+    /* init */
+    XMEMSET(der, 0, sizeof(DerCert));
+
+    /* version */
+    der->versionSz = SetMyVersion(cert->version, der->version, FALSE);
+
+    /* subject name */
+    der->subjectSz = SetName(der->subject, &cert->subject);
+    if (der->subjectSz == 0)
+        return SUBJECT_E;
+
+    /* public key */
+    if (cert->keyType == RSA_KEY) {
+        if (rsaKey == NULL)
+            return PUBLIC_KEY_E;
+        der->publicKeySz = SetRsaPublicKey(der->publicKey, rsaKey);
+        if (der->publicKeySz <= 0)
+            return PUBLIC_KEY_E;
+    }
+
+#ifdef HAVE_ECC
+    if (cert->keyType == ECC_KEY) {
+        if (eccKey == NULL)
+            return PUBLIC_KEY_E;
+        der->publicKeySz = SetEccPublicKey(der->publicKey, eccKey);
+        if (der->publicKeySz <= 0)
+            return PUBLIC_KEY_E;
+    }
+#endif /* HAVE_ECC */
+
+    /* CA */
+    if (cert->isCA) {
+        der->caSz = SetCa(der->ca);
+        if (der->caSz == 0)
+            return CA_TRUE_E;
+    }
+    else
+        der->caSz = 0;
+
+    /* extensions, just CA now */
+    if (cert->isCA) {
+        der->extensionsSz = SetExtensions(der->extensions,
+                                          der->ca, der->caSz, FALSE);
+        if (der->extensionsSz == 0)
+            return EXTENSIONS_E;
+    }
+    else
+        der->extensionsSz = 0;
+
+    der->attribSz = SetReqAttrib(der->attrib,
+                                 cert->challengePw, der->extensionsSz);
+    if (der->attribSz == 0)
+        return REQ_ATTRIBUTE_E;
+
+    der->total = der->versionSz + der->subjectSz + der->publicKeySz +
+        der->extensionsSz + der->attribSz;
+
+    return 0;
+}
+
+
+/* write DER encoded cert req to buffer, size already checked */
+static int WriteCertReqBody(DerCert* der, byte* buffer)
+{
+    int idx;
+
+    /* signed part header */
+    idx = SetSequence(der->total, buffer);
+    /* version */
+    XMEMCPY(buffer + idx, der->version, der->versionSz);
+    idx += der->versionSz;
+    /* subject */
+    XMEMCPY(buffer + idx, der->subject, der->subjectSz);
+    idx += der->subjectSz;
+    /* public key */
+    XMEMCPY(buffer + idx, der->publicKey, der->publicKeySz);
+    idx += der->publicKeySz;
+    /* attributes */
+    XMEMCPY(buffer + idx, der->attrib, der->attribSz);
+    idx += der->attribSz;
+    /* extensions */
+    if (der->extensionsSz) {
+        XMEMCPY(buffer + idx, der->extensions, min(der->extensionsSz,
+                                                   sizeof(der->extensions)));
+        idx += der->extensionsSz;
+    }
+
+    return idx;
+}
+
+
+int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz,
+                RsaKey* rsaKey, ecc_key* eccKey)
+{
+    DerCert der;
+    int     ret;
+
+    cert->keyType = (eccKey != NULL) ? ECC_KEY : RSA_KEY;
+    ret = EncodeCertReq(cert, &der, rsaKey, eccKey);
+    if (ret != 0)
+        return ret;
+
+    if (der.total + MAX_SEQ_SZ * 2 > (int)derSz)
+        return BUFFER_E;
+
+    return cert->bodySz = WriteCertReqBody(&der, derBuffer);
+}
+
+#endif /* CYASSL_CERT_REQ */
+
+
+int SignCert(int requestSz, int sType, byte* buffer, word32 buffSz,
+             RsaKey* rsaKey, ecc_key* eccKey, RNG* rng)
+{
+    byte    sig[MAX_ENCODED_SIG_SZ];
+    int     sigSz;
+
+    if (requestSz < 0)
+        return requestSz;
+
+    sigSz = MakeSignature(buffer, requestSz, sig, sizeof(sig), rsaKey, eccKey,
+                          rng, sType);
+    if (sigSz < 0)
+        return sigSz; 
+
+    if (requestSz + MAX_SEQ_SZ * 2 + sigSz > (int)buffSz)
+        return BUFFER_E; 
+
+    return AddSignature(buffer, requestSz, sig, sigSz, sType);
+}
+
+
+int MakeSelfCert(Cert* cert, byte* buffer, word32 buffSz, RsaKey* key, RNG* rng)
+{
+    int ret = MakeCert(cert, buffer, buffSz, key, NULL, rng);
+
+    if (ret < 0)
+        return ret;
+
+    return SignCert(cert->bodySz, cert->sigType, buffer, buffSz, key, NULL,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) */
+
+    /* If the leading bit on the INTEGER is a 1, add a leading zero */
+    int rLeadingZero = mp_leading_bit(r);
+    int sLeadingZero = mp_leading_bit(s);
+    int rLen = mp_unsigned_bin_size(r);   /* big int size */
+    int sLen = mp_unsigned_bin_size(s);
+    int err;
+
+    if (*outLen < (rLen + rLeadingZero + sLen + sLeadingZero +
+                   headerSz + 2))  /* SEQ_TAG + LEN(ENUM) */
+        return BAD_FUNC_ARG;
+
+    idx = SetSequence(rLen+rLeadingZero+sLen+sLeadingZero+headerSz, out);
+
+    /* store r */
+    out[idx++] = ASN_INTEGER;
+    rSz = SetLength(rLen + rLeadingZero, &out[idx]);
+    idx += rSz;
+    if (rLeadingZero)
+        out[idx++] = 0;
+    err = mp_to_unsigned_bin(r, &out[idx]);
+    if (err != MP_OKAY) return err;
+    idx += rLen;
+
+    /* store s */
+    out[idx++] = ASN_INTEGER;
+    sSz = SetLength(sLen + sLeadingZero, &out[idx]);
+    idx += sSz;
+    if (sLeadingZero)
+        out[idx++] = 0;
+    err = mp_to_unsigned_bin(s, &out[idx]);
+    if (err != MP_OKAY) return err;
+    idx += sLen;
+
+    *outLen = idx;
+
+    return 0;
+}
+
+
+/* Der Decode ECC-DSA Signautre, r & s stored as big ints */
+int DecodeECC_DSA_Sig(const byte* sig, word32 sigLen, mp_int* r, mp_int* s)
+{
+    word32 idx = 0;
+    int    len = 0;
+
+    if (GetSequence(sig, &idx, &len, sigLen) < 0)
+        return ASN_ECC_KEY_E;
+
+    if ((word32)len > (sigLen - idx))
+        return ASN_ECC_KEY_E;
+
+    if (GetInt(r, sig, &idx, sigLen) < 0)
+        return ASN_ECC_KEY_E;
+
+    if (GetInt(s, sig, &idx, sigLen) < 0)
+        return ASN_ECC_KEY_E;
+
+    return 0;
+}
+
+
+int 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 (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0)
+        return BAD_FUNC_ARG;
+
+    if (GetSequence(input, inOutIdx, &length, inSz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetMyVersion(input, inOutIdx, &version) < 0)
+        return ASN_PARSE_E;
+
+    b = input[*inOutIdx];
+    *inOutIdx += 1;
+
+    /* priv type */
+    if (b != 4 && b != 6 && b != 7) 
+        return ASN_PARSE_E;
+
+    if (GetLength(input, inOutIdx, &length, inSz) < 0)
+        return ASN_PARSE_E;
+
+    /* 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 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, 0);
+
+    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;
+    }
+
+    /* Nonces are not critical. The responder may not necessarily add
+     * the nonce to the response. */
+    if (req->useNonce && resp->nonceSz != 0) {
+        cmp = req->nonceSz - resp->nonceSz;
+        if (cmp != 0)
+        {
+            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
+
+
+/* store SHA1 hash of NAME */
+CYASSL_LOCAL int GetNameHash(const byte* source, word32* idx, byte* hash,
+                             int maxIdx)
+{
+    Sha    sha;
+    int    length;  /* length of all distinguished names */
+    int    ret = 0;
+    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;
+
+    ret = InitSha(&sha);
+    if (ret != 0)
+        return ret;
+    ShaUpdate(&sha, source + dummy, length + *idx - dummy);
+    ShaFinal(&sha, hash);
+
+    *idx += length;
+
+    return 0;
+}
+
+
+#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;
+    }
+}
+
+
+/* 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
+
+#ifdef CYASSL_SEP
+
+
+
+#endif /* CYASSL_SEP */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/blake2b.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,388 @@
+/*
+   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;
+}
+
+/* Some helper functions, not necessarily useful */
+static INLINE int blake2b_set_lastblock( blake2b_state *S )
+{
+  if( S->last_node ) blake2b_set_lastnode( S );
+
+  S->f[0] = ~0ULL;
+  return 0;
+}
+
+static INLINE int blake2b_increment_counter( blake2b_state *S, const word64
+                                             inc )
+{
+  S->t[0] += inc;
+  S->t[1] += ( S->t[0] < inc );
+  return 0;
+}
+
+static INLINE int blake2b_init0( blake2b_state *S )
+{
+  int i;
+  XMEMSET( S, 0, sizeof( blake2b_state ) );
+
+  for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
+
+  return 0;
+}
+
+/* init xors IV with input parameter block */
+int blake2b_init_param( blake2b_state *S, const blake2b_param *P )
+{
+  word32 i;
+  blake2b_init0( S );
+  byte *p = ( byte * )( P );
+
+  /* IV XOR ParamBlock */
+  for( i = 0; i < 8; ++i )
+    S->h[i] ^= load64( p + sizeof( S->h[i] ) * i );
+
+  return 0;
+}
+
+
+
+int blake2b_init( blake2b_state *S, const byte outlen )
+{
+  blake2b_param P[1];
+
+  if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
+
+  P->digest_length = outlen;
+  P->key_length    = 0;
+  P->fanout        = 1;
+  P->depth         = 1;
+  store32( &P->leaf_length, 0 );
+  store64( &P->node_offset, 0 );
+  P->node_depth    = 0;
+  P->inner_length  = 0;
+  XMEMSET( P->reserved, 0, sizeof( P->reserved ) );
+  XMEMSET( P->salt,     0, sizeof( P->salt ) );
+  XMEMSET( P->personal, 0, sizeof( P->personal ) );
+  return blake2b_init_param( S, P );
+}
+
+
+int blake2b_init_key( blake2b_state *S, const byte outlen, const void *key,
+                      const byte keylen )
+{
+  blake2b_param P[1];
+
+  if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
+
+  if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
+
+  P->digest_length = outlen;
+  P->key_length    = keylen;
+  P->fanout        = 1;
+  P->depth         = 1;
+  store32( &P->leaf_length, 0 );
+  store64( &P->node_offset, 0 );
+  P->node_depth    = 0;
+  P->inner_length  = 0;
+  XMEMSET( P->reserved, 0, sizeof( P->reserved ) );
+  XMEMSET( P->salt,     0, sizeof( P->salt ) );
+  XMEMSET( P->personal, 0, sizeof( P->personal ) );
+
+  if( blake2b_init_param( S, P ) < 0 ) return -1;
+
+  {
+    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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,1572 @@
+/* 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/error-crypt.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);
+    else
+        XMEMSET(cam->reg,  0, 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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,399 @@
+/* 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/error-crypt.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 = (byte)((e1 << 2) | (e2 >> 4));
+        b2 = (byte)(((e2 & 0xF) << 4) | (e3 >> 2));
+        b3 = (byte)(((e3 & 0x3) << 6) | e4);
+
+        out[i++] = b1;
+        if (!pad3)
+            out[i++] = b2;
+        if (!pad4)
+            out[i++] = b3;
+        else
+            break;
+        
+        inLen -= 4;
+        if (inLen && (in[j] == ' ' || in[j] == '\r' || in[j] == '\n')) {
+            byte endLine = in[j++];
+            inLen--;
+            while (inLen && endLine == ' ') {   /* allow trailing whitespace */
+                endLine = in[j++];
+                inLen--;
+            }
+            if (endLine == '\r') {
+                if (inLen) {
+                    endLine = in[j++];
+                    inLen--;
+                }
+            }
+            if (endLine != '\n') {
+                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',
+                              '+', '/'
+                            };
+
+
+/* make sure *i (idx) won't exceed max, store and possibly escape to out,
+ * raw means use e w/o decode,  0 on success */
+static int CEscape(int escaped, byte e, byte* out, word32* i, word32 max,
+                  int raw)
+{
+    int    doEscape = 0;
+    word32 needed = 1;
+    word32 idx = *i;
+
+    byte basic;
+    byte plus    = 0;
+    byte equals  = 0;
+    byte newline = 0;
+
+    if (raw)
+        basic = e;
+    else
+        basic = base64Encode[e];
+
+    /* check whether to escape */
+    if (escaped) {
+        switch ((char)basic) {
+            case '+' :
+                plus     = 1;
+                doEscape = 1;
+                needed  += 2;
+                break;
+            case '=' :
+                equals   = 1;
+                doEscape = 1;
+                needed  += 2;
+                break;
+            case '\n' :
+                newline  = 1;
+                doEscape = 1;
+                needed  += 2;
+                break;
+            default:
+                /* do nothing */
+                break;
+        }
+    }
+
+    /* check size */
+    if ( (idx+needed) > max) {
+        CYASSL_MSG("Escape buffer max too small");
+        return BUFFER_E;
+    }
+
+    /* store it */
+    if (doEscape == 0) {
+        out[idx++] = basic;
+    }
+    else {
+        out[idx++] = '%';  /* start escape */
+
+        if (plus) {
+            out[idx++] = '2';
+            out[idx++] = 'B';
+        }
+        else if (equals) {
+            out[idx++] = '3';
+            out[idx++] = 'D';
+        }
+        else if (newline) {
+            out[idx++] = '0';
+            out[idx++] = 'A';
+        }
+
+    }
+    *i = idx;
+
+    return 0;
+}
+
+
+/* internal worker, handles both escaped and normal line endings */
+static int DoBase64_Encode(const byte* in, word32 inLen, byte* out,
+                           word32* outLen, int escaped)
+{
+    int    ret = 0;
+    word32 i = 0,
+           j = 0,
+           n = 0;   /* new line counter */
+
+    word32 outSz = (inLen + 3 - 1) / 3 * 4;
+    word32 addSz = (outSz + PEM_LINE_SZ - 1) / PEM_LINE_SZ;  /* new lines */
+
+    if (escaped)
+        addSz *= 3;   /* instead of just \n, we're doing %0A triplet */
+
+    outSz += addSz;
+
+    /* if escaped we can't predetermine size for one pass encoding, but
+     * make sure we have enough if no escapes are in input */
+    if (outSz > *outLen) return BAD_FUNC_ARG;
+    
+    while (inLen > 2) {
+        byte b1 = in[j++];
+        byte b2 = in[j++];
+        byte b3 = in[j++];
+
+        /* encoded idx */
+        byte e1 = b1 >> 2;
+        byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
+        byte e3 = (byte)(((b2 & 0xF) << 2) | (b3 >> 6));
+        byte e4 = b3 & 0x3F;
+
+        /* store */
+        ret = CEscape(escaped, e1, out, &i, *outLen, 0);
+        if (ret != 0) break;
+        ret = CEscape(escaped, e2, out, &i, *outLen, 0);
+        if (ret != 0) break;
+        ret = CEscape(escaped, e3, out, &i, *outLen, 0);
+        if (ret != 0) break;
+        ret = CEscape(escaped, e4, out, &i, *outLen, 0);
+        if (ret != 0) break;
+
+        inLen -= 3;
+
+        if ((++n % (PEM_LINE_SZ / 4)) == 0 && inLen) {
+            ret = CEscape(escaped, '\n', out, &i, *outLen, 1);
+            if (ret != 0) break;
+        }
+    }
+
+    /* last integral */
+    if (inLen && ret == 0) {
+        int twoBytes = (inLen == 2);
+
+        byte b1 = in[j++];
+        byte b2 = (twoBytes) ? in[j++] : 0;
+
+        byte e1 = b1 >> 2;
+        byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
+        byte e3 = (byte)((b2 & 0xF) << 2);
+
+        ret = CEscape(escaped, e1, out, &i, *outLen, 0);
+        if (ret == 0) 
+            ret = CEscape(escaped, e2, out, &i, *outLen, 0);
+        if (ret == 0) {
+            /* third */
+            if (twoBytes)
+                ret = CEscape(escaped, e3, out, &i, *outLen, 0);
+            else 
+                ret = CEscape(escaped, '=', out, &i, *outLen, 1);
+        }
+        /* fourth always pad */
+        if (ret == 0)
+            ret = CEscape(escaped, '=', out, &i, *outLen, 1);
+    } 
+
+    if (ret == 0) 
+        ret = CEscape(escaped, '\n', out, &i, *outLen, 1);
+
+    if (i != outSz && escaped == 0 && ret == 0)
+        return ASN_INPUT_E; 
+
+    *outLen = i;
+    return ret; 
+}
+
+
+/* Base64 Encode, PEM style, with \n line endings */
+int Base64_Encode(const byte* in, word32 inLen, byte* out, word32* outLen)
+{
+    return DoBase64_Encode(in, inLen, out, outLen, 0);
+}
+
+
+/* Base64 Encode, with %0A esacped line endings instead of \n */
+int Base64_EncodeEsc(const byte* in, word32 inLen, byte* out, word32* outLen)
+{
+    return DoBase64_Encode(in, inLen, out, outLen, 1);
+}
+
+
+#endif  /* defined(OPENSSL_EXTRA) || defined (SESSION_CERTS) || defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN) || defined(HAVE_WEBSERVER) */
+
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || defined(HAVE_FIPS)
+
+static
+const byte hexDecode[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+                           BAD, BAD, BAD, BAD, BAD, BAD, BAD,
+                           10, 11, 12, 13, 14, 15,  /* upper case A-F */
+                           BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
+                           BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
+                           BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
+                           BAD, BAD,  /* G - ` */
+                           10, 11, 12, 13, 14, 15   /* lower case a-f */
+                         };  /* A starts at 0x41 not 0x3A */
+
+int Base16_Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
+{
+    word32 inIdx  = 0;
+    word32 outIdx = 0;
+
+    if (inLen == 1 && *outLen && in) {
+        byte b = in[inIdx++] - 0x30;  /* 0 starts at 0x30 */
+
+        /* sanity check */
+        if (b >=  sizeof(hexDecode)/sizeof(hexDecode[0]))
+            return ASN_INPUT_E;
+
+        b  = hexDecode[b];
+
+        if (b == BAD)
+            return ASN_INPUT_E;
+        
+        out[outIdx++] = b;
+
+        *outLen = outIdx;
+        return 0;
+    }
+
+    if (inLen % 2)
+        return BAD_FUNC_ARG;
+
+    if (*outLen < (inLen / 2))
+        return BAD_FUNC_ARG;
+
+    while (inLen) {
+        byte b  = in[inIdx++] - 0x30;  /* 0 starts at 0x30 */
+        byte b2 = in[inIdx++] - 0x30;
+
+        /* sanity checks */
+        if (b >=  sizeof(hexDecode)/sizeof(hexDecode[0]))
+            return ASN_INPUT_E;
+        if (b2 >= sizeof(hexDecode)/sizeof(hexDecode[0]))
+            return ASN_INPUT_E;
+
+        b  = hexDecode[b];
+        b2 = hexDecode[b2];
+
+        if (b == BAD || b2 == BAD)
+            return ASN_INPUT_E;
+        
+        out[outIdx++] = (byte)((b << 4) | b2);
+        inLen -= 2;
+    }
+
+    *outLen = outIdx;
+    return 0;
+}
+
+
+#endif /* (OPENSSL_EXTRA) || (HAVE_WEBSERVER) || (HAVE_FIPS) */
+
+#endif /* NO_CODING */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/compress.c	Sun Apr 20 12:40:57 2014 +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/error-crypt.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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,1416 @@
+/* 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
+
+#ifdef HAVE_FIPS
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+#endif
+
+#include <cyassl/ctaocrypt/des3.h>
+#include <cyassl/ctaocrypt/error-crypt.h>
+
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/src/misc.c>
+#endif
+
+
+#ifdef HAVE_CAVIUM
+    static int Des3_CaviumSetKey(Des3* des3, const byte* key, const byte* iv);
+    static int Des3_CaviumCbcEncrypt(Des3* des3, byte* out, const byte* in,
+                                      word32 length);
+    static int Des3_CaviumCbcDecrypt(Des3* des3, byte* out, const byte* in,
+                                      word32 length);
+#endif
+
+
+
+
+#ifdef STM32F2_CRYPTO
+    /*
+     * STM32F2 hardware DES/3DES support through the STM32F2 standard
+     * peripheral library. Documentation located in STM32F2xx Standard
+     * Peripheral Library document (See note in README).
+     */
+    #include "stm32f2xx.h"
+		#include "stm32f2xx_cryp.h"
+
+    int 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);
+
+        return 0;
+    }
+
+    int Des3_SetKey(Des3* des, const byte* key, const byte* iv, int dir)
+    {
+        word32 *dkey1 = des->key[0];
+        word32 *dkey2 = des->key[1];
+        word32 *dkey3 = des->key[2];
+
+        XMEMCPY(dkey1, key, 8);         /* set key 1 */
+        XMEMCPY(dkey2, key + 8, 8);     /* set key 2 */
+        XMEMCPY(dkey3, key + 16, 8);    /* set key 3 */
+
+        ByteReverseWords(dkey1, dkey1, 8);
+        ByteReverseWords(dkey2, dkey2, 8);
+        ByteReverseWords(dkey3, dkey3, 8);
+
+        return 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);
+
+    }
+
+    int Des3_CbcEncrypt(Des3* des, byte* out, const byte* in, word32 sz)
+    {
+        Des3Crypt(des, out, in, sz, DES_ENCRYPTION);
+        return 0;
+    }
+
+    int Des3_CbcDecrypt(Des3* des, byte* out, const byte* in, word32 sz)
+    {
+        Des3Crypt(des, out, in, sz, DES_DECRYPTION);
+        return 0;
+    }
+
+
+#elif  defined(HAVE_COLDFIRE_SEC)
+
+#include "sec.h"
+#include "mcf548x_sec.h"
+
+#include "memory_pools.h"
+extern TX_BYTE_POOL mp_ncached;  /* Non Cached memory pool */
+#define DES_BUFFER_SIZE (DES_BLOCK_SIZE * 16)
+static unsigned char *DesBuffer = NULL ;
+
+#define SEC_DESC_DES_CBC_ENCRYPT  0x20500010
+#define SEC_DESC_DES_CBC_DECRYPT  0x20400010
+#define SEC_DESC_DES3_CBC_ENCRYPT 0x20700010
+#define SEC_DESC_DES3_CBC_DECRYPT 0x20600010
+
+extern volatile unsigned char __MBAR[];
+
+static void Des_Cbc(Des* des, byte* out, const byte* in, word32 sz, word32 desc)
+{
+    static volatile SECdescriptorType descriptor = {    NULL } ;
+    int ret ; int stat1,stat2 ;
+    int i ; int size ;
+    volatile int v ;
+
+    while(sz) {
+        if((sz%DES_BUFFER_SIZE) == sz) {
+            size = sz ;
+            sz = 0 ;
+        } else {
+            size = DES_BUFFER_SIZE ;
+            sz -= DES_BUFFER_SIZE ;
+        }
+        
+        descriptor.header = desc ;
+        /*
+        escriptor.length1 = 0x0;
+        descriptor.pointer1 = NULL;
+        */
+        descriptor.length2 = des->ivlen ;
+        descriptor.pointer2 = (byte *)des->iv ;
+        descriptor.length3 = des->keylen ;
+        descriptor.pointer3 = (byte *)des->key;
+        descriptor.length4 = size;
+        descriptor.pointer4 = (byte *)in ;
+        descriptor.length5 = size;
+        descriptor.pointer5 = DesBuffer ;
+        /*
+        descriptor.length6 = 0; 
+        descriptor.pointer6 = NULL; 
+        descriptor.length7 = 0x0;
+        descriptor.pointer7 = NULL;
+        descriptor.nextDescriptorPtr = NULL ; 
+        */
+        
+        /* Initialize SEC and wait for encryption to complete */
+        MCF_SEC_CCCR0 = 0x0000001A; //enable channel done notification
+
+        /* Point SEC to the location of the descriptor */
+        MCF_SEC_FR0 = (uint32)&descriptor;  
+                
+        /* poll SISR to determine when channel is complete */
+        while (!(MCF_SEC_SISRL) && !(MCF_SEC_SISRH))
+            ;   
+            
+        for(v=0; v<500; v++) ; 
+
+        ret = MCF_SEC_SISRH;
+        stat1 = MCF_SEC_DSR ;   
+        stat2 = MCF_SEC_DISR ;
+        if(ret & 0xe0000000)
+            db_printf("Des_Cbc(%x):ISRH=%08x, DSR=%08x, DISR=%08x\n", desc, ret, stat1, stat2) ;
+
+        XMEMCPY(out, DesBuffer, size) ;
+
+        if((desc==SEC_DESC_DES3_CBC_ENCRYPT)||(desc==SEC_DESC_DES_CBC_ENCRYPT)) {
+            XMEMCPY((void*)des->iv, (void*)&(out[size-DES_IVLEN]), DES_IVLEN) ;
+        } else {
+            XMEMCPY((void*)des->iv, (void*)&(in[size-DES_IVLEN]), DES_IVLEN) ;
+        }
+        
+        in  += size ;   
+        out += size ;
+                
+    }
+}
+
+
+void Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz)
+{
+    Des_Cbc(des, out, in, sz, SEC_DESC_DES_CBC_ENCRYPT) ;
+}
+
+void Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz)
+{
+    Des_Cbc(des, out, in, sz, SEC_DESC_DES_CBC_DECRYPT) ;
+}
+
+int Des3_CbcEncrypt(Des3* des3, byte* out, const byte* in, word32 sz)
+{
+    Des_Cbc((Des *)des3, out, in, sz, SEC_DESC_DES3_CBC_ENCRYPT) ;
+    return 0;
+}
+
+int Des3_CbcDecrypt(Des3* des3, byte* out, const byte* in, word32 sz)
+{
+    Des_Cbc((Des *)des3, out, in, sz, SEC_DESC_DES3_CBC_DECRYPT) ;
+    return 0;
+}
+
+
+int Des_SetKey(Des* des, const byte* key, const byte* iv, int dir)
+{
+    int i ; int status ;
+    
+    if(DesBuffer == NULL) {
+        status = tx_byte_allocate(&mp_ncached,(void *)&DesBuffer,DES_BUFFER_SIZE,TX_NO_WAIT);       
+    }
+    
+    XMEMCPY(des->key, key, DES_KEYLEN);
+    des->keylen = DES_KEYLEN ;
+    des->ivlen = 0 ;      
+    if (iv) {
+        XMEMCPY(des->iv, iv, DES_IVLEN);
+        des->ivlen = DES_IVLEN ;
+    }   else {
+        for(i=0; i<DES_IVLEN; i++)
+            des->iv[i] = 0x0 ;
+    }
+
+    return 0;
+}
+
+int Des3_SetKey(Des3* des3, const byte* key, const byte* iv, int dir)
+{
+    int i ; int status ;
+    
+    if(DesBuffer == NULL) {
+        status = tx_byte_allocate(&mp_ncached,(void *)&DesBuffer,DES_BUFFER_SIZE,TX_NO_WAIT);       
+    }
+    
+    XMEMCPY(des3->key, key, DES3_KEYLEN);  
+    des3->keylen = DES3_KEYLEN ;   
+    des3->ivlen = 0 ;         
+    if (iv) {
+        XMEMCPY(des3->iv, iv, DES3_IVLEN);
+        des3->ivlen = DES3_IVLEN ;
+    }   else {
+        for(i=0; i<DES_IVLEN; i++)
+            des3->iv[i] = 0x0 ;
+    }
+
+    return 0;
+}
+
+#elif defined FREESCALE_MMCAU
+    /*
+     * Freescale mmCAU hardware DES/3DES support through the CAU/mmCAU library.
+     * Documentation located in ColdFire/ColdFire+ CAU and Kinetis mmCAU
+     * Software Library User Guide (See note in README).
+     */
+    #include "cau_api.h"
+
+    const unsigned char parityLookup[128] =
+    {
+        1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+        0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+        0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+        1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
+     };
+
+    int Des_SetKey(Des* des, const byte* key, const byte* iv, int dir)
+    {
+        int i = 0;
+        byte* dkey = (byte*)des->key;
+
+        XMEMCPY(dkey, key, 8);
+
+        Des_SetIV(des, iv);
+
+        /* fix key parity, if needed */
+        for (i = 0; i < 8; i++) {
+            dkey[i] = ((dkey[i] & 0xFE) | parityLookup[dkey[i] >> 1]);
+        }
+
+        return 0;
+    }
+
+    int Des3_SetKey(Des3* des, const byte* key, const byte* iv, int dir)
+    {
+        int i = 0, ret = 0;
+        byte* dkey1 = (byte*)des->key[0];
+        byte* dkey2 = (byte*)des->key[1];
+        byte* dkey3 = (byte*)des->key[2];
+
+        XMEMCPY(dkey1, key, 8);         /* set key 1 */
+        XMEMCPY(dkey2, key + 8, 8);     /* set key 2 */
+        XMEMCPY(dkey3, key + 16, 8);    /* set key 3 */
+
+        ret = Des3_SetIV(des, iv);
+        if (ret != 0)
+            return ret;
+
+        /* fix key parity if needed */
+        for (i = 0; i < 8; i++)
+           dkey1[i] = ((dkey1[i] & 0xFE) | parityLookup[dkey1[i] >> 1]);
+
+        for (i = 0; i < 8; i++)
+           dkey2[i] = ((dkey2[i] & 0xFE) | parityLookup[dkey2[i] >> 1]);
+
+        for (i = 0; i < 8; i++)
+           dkey3[i] = ((dkey3[i] & 0xFE) | parityLookup[dkey3[i] >> 1]);
+
+        return ret;
+    }
+
+    void Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz)
+    {
+        int i;
+        int offset = 0;
+        int len = sz;
+        byte *iv;
+        byte temp_block[DES_BLOCK_SIZE];
+
+        iv = (byte*)des->reg;
+
+        while (len > 0)
+        {
+            XMEMCPY(temp_block, in + offset, DES_BLOCK_SIZE);
+
+            /* XOR block with IV for CBC */
+            for (i = 0; i < DES_BLOCK_SIZE; i++)
+                temp_block[i] ^= iv[i];
+
+            cau_des_encrypt(temp_block, (byte*)des->key, out + offset);
+
+            len    -= DES_BLOCK_SIZE;
+            offset += DES_BLOCK_SIZE;
+
+            /* store IV for next block */
+            XMEMCPY(iv, out + offset - DES_BLOCK_SIZE, DES_BLOCK_SIZE);
+        }
+
+        return;
+    }
+
+    void Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz)
+    {
+        int i;
+        int offset = 0;
+        int len = sz;
+        byte* iv;
+        byte temp_block[DES_BLOCK_SIZE];
+
+        iv = (byte*)des->reg;
+
+        while (len > 0)
+        {
+            XMEMCPY(temp_block, in + offset, DES_BLOCK_SIZE);
+
+            cau_des_decrypt(in + offset, (byte*)des->key, out + offset);
+
+            /* XOR block with IV for CBC */
+            for (i = 0; i < DES_BLOCK_SIZE; i++)
+                (out + offset)[i] ^= iv[i];
+
+            /* store IV for next block */
+            XMEMCPY(iv, temp_block, DES_BLOCK_SIZE);
+
+            len     -= DES_BLOCK_SIZE;
+            offset += DES_BLOCK_SIZE;
+        }
+
+        return;
+    }
+
+    int Des3_CbcEncrypt(Des3* des, byte* out, const byte* in, word32 sz)
+    {
+        int i;
+        int offset = 0;
+        int len = sz;
+
+        byte *iv;
+        byte temp_block[DES_BLOCK_SIZE];
+
+        iv = (byte*)des->reg;
+
+        while (len > 0)
+        {
+            XMEMCPY(temp_block, in + offset, DES_BLOCK_SIZE);
+
+            /* XOR block with IV for CBC */
+            for (i = 0; i < DES_BLOCK_SIZE; i++)
+                temp_block[i] ^= iv[i];
+
+            cau_des_encrypt(temp_block  , (byte*)des->key[0], out + offset);
+            cau_des_decrypt(out + offset, (byte*)des->key[1], out + offset);
+            cau_des_encrypt(out + offset, (byte*)des->key[2], out + offset);
+
+            len    -= DES_BLOCK_SIZE;
+            offset += DES_BLOCK_SIZE;
+
+            /* store IV for next block */
+            XMEMCPY(iv, out + offset - DES_BLOCK_SIZE, DES_BLOCK_SIZE);
+        }
+
+        return 0;
+    }
+
+    int Des3_CbcDecrypt(Des3* des, byte* out, const byte* in, word32 sz)
+    {
+        int i;
+        int offset = 0;
+        int len = sz;
+
+        byte* iv;
+        byte temp_block[DES_BLOCK_SIZE];
+
+        iv = (byte*)des->reg;
+
+        while (len > 0)
+        {
+            XMEMCPY(temp_block, in + offset, DES_BLOCK_SIZE);
+
+            cau_des_decrypt(in + offset , (byte*)des->key[2], out + offset);
+            cau_des_encrypt(out + offset, (byte*)des->key[1], out + offset);
+            cau_des_decrypt(out + offset, (byte*)des->key[0], out + offset);
+
+            /* XOR block with IV for CBC */
+            for (i = 0; i < DES_BLOCK_SIZE; i++)
+                (out + offset)[i] ^= iv[i];
+
+            /* store IV for next block */
+            XMEMCPY(iv, temp_block, DES_BLOCK_SIZE);
+
+            len    -= DES_BLOCK_SIZE;
+            offset += DES_BLOCK_SIZE;
+        }
+
+        return 0;
+    }
+
+
+#elif defined(CYASSL_PIC32MZ_CRYPT)
+
+    #include "../../cyassl/ctaocrypt/port/pic32/pic32mz-crypt.h"
+
+void Des_SetIV(Des* des, const byte* iv);
+int  Des3_SetIV(Des3* des, const byte* iv);
+
+    int Des_SetKey(Des* des, const byte* key, const byte* iv, int dir)
+    {
+        word32 *dkey = des->key ;
+        word32 *dreg = des->reg ;
+
+        XMEMCPY((byte *)dkey, (byte *)key, 8);
+        ByteReverseWords(dkey, dkey, 8);
+        XMEMCPY((byte *)dreg, (byte *)iv, 8);
+        ByteReverseWords(dreg, dreg, 8);
+
+        return 0;
+    }
+
+    int Des3_SetKey(Des3* des, const byte* key, const byte* iv, int dir)
+    {
+        word32 *dkey1 = des->key[0];
+        word32 *dreg = des->reg ;
+
+        XMEMCPY(dkey1, key, 24);
+        ByteReverseWords(dkey1, dkey1, 24);
+        XMEMCPY(dreg, iv, 8);
+        ByteReverseWords(dreg, dreg, 8) ;
+
+        return 0;
+    }
+
+    void DesCrypt(word32 *key, word32 *iv, byte* out, const byte* in, word32 sz,
+                  int dir, int algo, int cryptoalgo)
+    {
+        securityAssociation *sa_p ;
+        bufferDescriptor *bd_p ;
+        const byte *in_p, *in_l ;
+        byte *out_p, *out_l ;
+        volatile securityAssociation sa __attribute__((aligned (8)));
+        volatile bufferDescriptor bd __attribute__((aligned (8)));
+        volatile int k ;
+        
+        /* get uncached address */
+
+        in_l = in;
+        out_l = out ;
+        sa_p = KVA0_TO_KVA1(&sa) ; 
+        bd_p = KVA0_TO_KVA1(&bd) ;
+        in_p = KVA0_TO_KVA1(in_l) ;
+        out_p= KVA0_TO_KVA1(out_l);
+        
+        if(PIC32MZ_IF_RAM(in_p))
+            XMEMCPY((void *)in_p, (void *)in, sz);
+        XMEMSET((void *)out_p, 0, sz);
+
+        /* Set up the Security Association */
+        XMEMSET((byte *)KVA0_TO_KVA1(&sa), 0, sizeof(sa));
+        sa_p->SA_CTRL.ALGO = algo ; 
+        sa_p->SA_CTRL.LNC = 1;
+        sa_p->SA_CTRL.LOADIV = 1;
+        sa_p->SA_CTRL.FB = 1;
+        sa_p->SA_CTRL.ENCTYPE = dir ; /* Encryption/Decryption */
+        sa_p->SA_CTRL.CRYPTOALGO = cryptoalgo;
+        sa_p->SA_CTRL.KEYSIZE = 1 ; /* KEY is 192 bits */
+        XMEMCPY((byte *)KVA0_TO_KVA1(&sa.SA_ENCKEY[algo==PIC32_ALGO_TDES ? 2 : 6]),
+                (byte *)key, algo==PIC32_ALGO_TDES ? 24 : 8);
+        XMEMCPY((byte *)KVA0_TO_KVA1(&sa.SA_ENCIV[2]), (byte *)iv, 8);
+
+        XMEMSET((byte *)KVA0_TO_KVA1(&bd), 0, sizeof(bd));
+        /* Set up the Buffer Descriptor */
+        bd_p->BD_CTRL.BUFLEN = sz;
+        bd_p->BD_CTRL.LIFM = 1;
+        bd_p->BD_CTRL.SA_FETCH_EN = 1;
+        bd_p->BD_CTRL.LAST_BD = 1;
+        bd_p->BD_CTRL.DESC_EN = 1;
+    
+        bd_p->SA_ADDR = (unsigned int)KVA_TO_PA(&sa) ; // (unsigned int)sa_p  ;
+        bd_p->SRCADDR = (unsigned int)KVA_TO_PA(in) ; // (unsigned int)in_p  ;
+        bd_p->DSTADDR = (unsigned int)KVA_TO_PA(out); // (unsigned int)out_p  ;
+        bd_p->NXTPTR = (unsigned int)KVA_TO_PA(&bd);
+        bd_p->MSGLEN = sz ;
+        
+        /* Fire in the hole! */
+        CECON = 1 << 6;
+        while (CECON);
+        
+        /* Run the engine */
+        CEBDPADDR = (unsigned int)KVA_TO_PA(&bd) ; // (unsigned int)bd_p ;
+        CEINTEN = 0x07;
+        CECON = 0x27;
+
+        WAIT_ENGINE ;
+
+        if((cryptoalgo == PIC32_CRYPTOALGO_CBC) ||
+           (cryptoalgo == PIC32_CRYPTOALGO_TCBC)||
+           (cryptoalgo == PIC32_CRYPTOALGO_RCBC)) {
+            /* set iv for the next call */
+            if(dir == PIC32_ENCRYPTION) {
+	        XMEMCPY((void *)iv, (void*)&(out_p[sz-DES_IVLEN]), DES_IVLEN) ;
+	        } else {
+                ByteReverseWords((word32*)iv, (word32 *)&(in_p[sz-DES_IVLEN]), DES_IVLEN);
+	        }
+
+        }
+
+        ByteReverseWords((word32*)out, (word32 *)KVA0_TO_KVA1(out), sz);
+    }
+
+    void Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz)
+    {
+        DesCrypt(des->key, des->reg, out, in, sz, 
+                PIC32_ENCRYPTION, PIC32_ALGO_DES, PIC32_CRYPTOALGO_CBC );
+    }
+
+    void Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz)
+    {
+        DesCrypt(des->key, des->reg, out, in, sz, 
+                PIC32_DECRYPTION, PIC32_ALGO_DES, PIC32_CRYPTOALGO_CBC);
+    }
+
+    int Des3_CbcEncrypt(Des3* des, byte* out, const byte* in, word32 sz)
+    {
+        DesCrypt(des->key[0], des->reg, out, in, sz, 
+                PIC32_ENCRYPTION, PIC32_ALGO_TDES, PIC32_CRYPTOALGO_TCBC);
+        return 0;
+    }
+
+    int Des3_CbcDecrypt(Des3* des, byte* out, const byte* in, word32 sz)
+    {
+        DesCrypt(des->key[0], des->reg, out, in, sz, 
+                PIC32_DECRYPTION, PIC32_ALGO_TDES, PIC32_CRYPTOALGO_TCBC);
+        return 0;
+    }
+
+#else /* CTaoCrypt software implementation */
+
+/* permuted choice table (key) */
+static const byte pc1[] = {
+       57, 49, 41, 33, 25, 17,  9,
+        1, 58, 50, 42, 34, 26, 18,
+       10,  2, 59, 51, 43, 35, 27,
+       19, 11,  3, 60, 52, 44, 36,
+
+       63, 55, 47, 39, 31, 23, 15,
+        7, 62, 54, 46, 38, 30, 22,
+       14,  6, 61, 53, 45, 37, 29,
+       21, 13,  5, 28, 20, 12,  4
+};
+
+/* number left rotations of pc1 */
+static const byte totrot[] = {
+       1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
+};
+
+/* permuted choice key (table) */
+static const byte pc2[] = {
+       14, 17, 11, 24,  1,  5,
+        3, 28, 15,  6, 21, 10,
+       23, 19, 12,  4, 26,  8,
+       16,  7, 27, 20, 13,  2,
+       41, 52, 31, 37, 47, 55,
+       30, 40, 51, 45, 33, 48,
+       44, 49, 39, 56, 34, 53,
+       46, 42, 50, 36, 29, 32
+};
+
+/* End of DES-defined tables */
+
+/* bit 0 is left-most in byte */
+static const int bytebit[] = {
+       0200,0100,040,020,010,04,02,01
+};
+
+static const word32 Spbox[8][64] = {
+{
+0x01010400,0x00000000,0x00010000,0x01010404,
+0x01010004,0x00010404,0x00000004,0x00010000,
+0x00000400,0x01010400,0x01010404,0x00000400,
+0x01000404,0x01010004,0x01000000,0x00000004,
+0x00000404,0x01000400,0x01000400,0x00010400,
+0x00010400,0x01010000,0x01010000,0x01000404,
+0x00010004,0x01000004,0x01000004,0x00010004,
+0x00000000,0x00000404,0x00010404,0x01000000,
+0x00010000,0x01010404,0x00000004,0x01010000,
+0x01010400,0x01000000,0x01000000,0x00000400,
+0x01010004,0x00010000,0x00010400,0x01000004,
+0x00000400,0x00000004,0x01000404,0x00010404,
+0x01010404,0x00010004,0x01010000,0x01000404,
+0x01000004,0x00000404,0x00010404,0x01010400,
+0x00000404,0x01000400,0x01000400,0x00000000,
+0x00010004,0x00010400,0x00000000,0x01010004},
+{
+0x80108020,0x80008000,0x00008000,0x00108020,
+0x00100000,0x00000020,0x80100020,0x80008020,
+0x80000020,0x80108020,0x80108000,0x80000000,
+0x80008000,0x00100000,0x00000020,0x80100020,
+0x00108000,0x00100020,0x80008020,0x00000000,
+0x80000000,0x00008000,0x00108020,0x80100000,
+0x00100020,0x80000020,0x00000000,0x00108000,
+0x00008020,0x80108000,0x80100000,0x00008020,
+0x00000000,0x00108020,0x80100020,0x00100000,
+0x80008020,0x80100000,0x80108000,0x00008000,
+0x80100000,0x80008000,0x00000020,0x80108020,
+0x00108020,0x00000020,0x00008000,0x80000000,
+0x00008020,0x80108000,0x00100000,0x80000020,
+0x00100020,0x80008020,0x80000020,0x00100020,
+0x00108000,0x00000000,0x80008000,0x00008020,
+0x80000000,0x80100020,0x80108020,0x00108000},
+{
+0x00000208,0x08020200,0x00000000,0x08020008,
+0x08000200,0x00000000,0x00020208,0x08000200,
+0x00020008,0x08000008,0x08000008,0x00020000,
+0x08020208,0x00020008,0x08020000,0x00000208,
+0x08000000,0x00000008,0x08020200,0x00000200,
+0x00020200,0x08020000,0x08020008,0x00020208,
+0x08000208,0x00020200,0x00020000,0x08000208,
+0x00000008,0x08020208,0x00000200,0x08000000,
+0x08020200,0x08000000,0x00020008,0x00000208,
+0x00020000,0x08020200,0x08000200,0x00000000,
+0x00000200,0x00020008,0x08020208,0x08000200,
+0x08000008,0x00000200,0x00000000,0x08020008,
+0x08000208,0x00020000,0x08000000,0x08020208,
+0x00000008,0x00020208,0x00020200,0x08000008,
+0x08020000,0x08000208,0x00000208,0x08020000,
+0x00020208,0x00000008,0x08020008,0x00020200},
+{
+0x00802001,0x00002081,0x00002081,0x00000080,
+0x00802080,0x00800081,0x00800001,0x00002001,
+0x00000000,0x00802000,0x00802000,0x00802081,
+0x00000081,0x00000000,0x00800080,0x00800001,
+0x00000001,0x00002000,0x00800000,0x00802001,
+0x00000080,0x00800000,0x00002001,0x00002080,
+0x00800081,0x00000001,0x00002080,0x00800080,
+0x00002000,0x00802080,0x00802081,0x00000081,
+0x00800080,0x00800001,0x00802000,0x00802081,
+0x00000081,0x00000000,0x00000000,0x00802000,
+0x00002080,0x00800080,0x00800081,0x00000001,
+0x00802001,0x00002081,0x00002081,0x00000080,
+0x00802081,0x00000081,0x00000001,0x00002000,
+0x00800001,0x00002001,0x00802080,0x00800081,
+0x00002001,0x00002080,0x00800000,0x00802001,
+0x00000080,0x00800000,0x00002000,0x00802080},
+{
+0x00000100,0x02080100,0x02080000,0x42000100,
+0x00080000,0x00000100,0x40000000,0x02080000,
+0x40080100,0x00080000,0x02000100,0x40080100,
+0x42000100,0x42080000,0x00080100,0x40000000,
+0x02000000,0x40080000,0x40080000,0x00000000,
+0x40000100,0x42080100,0x42080100,0x02000100,
+0x42080000,0x40000100,0x00000000,0x42000000,
+0x02080100,0x02000000,0x42000000,0x00080100,
+0x00080000,0x42000100,0x00000100,0x02000000,
+0x40000000,0x02080000,0x42000100,0x40080100,
+0x02000100,0x40000000,0x42080000,0x02080100,
+0x40080100,0x00000100,0x02000000,0x42080000,
+0x42080100,0x00080100,0x42000000,0x42080100,
+0x02080000,0x00000000,0x40080000,0x42000000,
+0x00080100,0x02000100,0x40000100,0x00080000,
+0x00000000,0x40080000,0x02080100,0x40000100},
+{
+0x20000010,0x20400000,0x00004000,0x20404010,
+0x20400000,0x00000010,0x20404010,0x00400000,
+0x20004000,0x00404010,0x00400000,0x20000010,
+0x00400010,0x20004000,0x20000000,0x00004010,
+0x00000000,0x00400010,0x20004010,0x00004000,
+0x00404000,0x20004010,0x00000010,0x20400010,
+0x20400010,0x00000000,0x00404010,0x20404000,
+0x00004010,0x00404000,0x20404000,0x20000000,
+0x20004000,0x00000010,0x20400010,0x00404000,
+0x20404010,0x00400000,0x00004010,0x20000010,
+0x00400000,0x20004000,0x20000000,0x00004010,
+0x20000010,0x20404010,0x00404000,0x20400000,
+0x00404010,0x20404000,0x00000000,0x20400010,
+0x00000010,0x00004000,0x20400000,0x00404010,
+0x00004000,0x00400010,0x20004010,0x00000000,
+0x20404000,0x20000000,0x00400010,0x20004010},
+{
+0x00200000,0x04200002,0x04000802,0x00000000,
+0x00000800,0x04000802,0x00200802,0x04200800,
+0x04200802,0x00200000,0x00000000,0x04000002,
+0x00000002,0x04000000,0x04200002,0x00000802,
+0x04000800,0x00200802,0x00200002,0x04000800,
+0x04000002,0x04200000,0x04200800,0x00200002,
+0x04200000,0x00000800,0x00000802,0x04200802,
+0x00200800,0x00000002,0x04000000,0x00200800,
+0x04000000,0x00200800,0x00200000,0x04000802,
+0x04000802,0x04200002,0x04200002,0x00000002,
+0x00200002,0x04000000,0x04000800,0x00200000,
+0x04200800,0x00000802,0x00200802,0x04200800,
+0x00000802,0x04000002,0x04200802,0x04200000,
+0x00200800,0x00000000,0x00000002,0x04200802,
+0x00000000,0x00200802,0x04200000,0x00000800,
+0x04000002,0x04000800,0x00000800,0x00200002},
+{
+0x10001040,0x00001000,0x00040000,0x10041040,
+0x10000000,0x10001040,0x00000040,0x10000000,
+0x00040040,0x10040000,0x10041040,0x00041000,
+0x10041000,0x00041040,0x00001000,0x00000040,
+0x10040000,0x10000040,0x10001000,0x00001040,
+0x00041000,0x00040040,0x10040040,0x10041000,
+0x00001040,0x00000000,0x00000000,0x10040040,
+0x10000040,0x10001000,0x00041040,0x00040000,
+0x00041040,0x00040000,0x10041000,0x00001000,
+0x00000040,0x10040040,0x00001000,0x00041040,
+0x10001000,0x00000040,0x10000040,0x10040000,
+0x10040040,0x10000000,0x00040000,0x10001040,
+0x00000000,0x10041040,0x00040040,0x10000040,
+0x10040000,0x10001000,0x10001040,0x00000000,
+0x10041040,0x00041000,0x00041000,0x00001040,
+0x00001040,0x00040040,0x10000000,0x10041000}
+};
+
+
+static INLINE void IPERM(word32* left, word32* right)
+{
+    word32 work;
+
+    *right = rotlFixed(*right, 4U);
+    work = (*left ^ *right) & 0xf0f0f0f0;
+    *left ^= work;
+
+    *right = rotrFixed(*right^work, 20U);
+    work = (*left ^ *right) & 0xffff0000;
+    *left ^= work;
+
+    *right = rotrFixed(*right^work, 18U);
+    work = (*left ^ *right) & 0x33333333;
+    *left ^= work;
+
+    *right = rotrFixed(*right^work, 6U);
+    work = (*left ^ *right) & 0x00ff00ff;
+    *left ^= work;
+
+    *right = rotlFixed(*right^work, 9U);
+    work = (*left ^ *right) & 0xaaaaaaaa;
+    *left = rotlFixed(*left^work, 1U);
+    *right ^= work;
+}
+
+
+static INLINE void FPERM(word32* left, word32* right)
+{
+    word32 work;
+
+    *right = rotrFixed(*right, 1U);
+    work = (*left ^ *right) & 0xaaaaaaaa;
+    *right ^= work;
+
+    *left = rotrFixed(*left^work, 9U);
+    work = (*left ^ *right) & 0x00ff00ff;
+    *right ^= work;
+
+    *left = rotlFixed(*left^work, 6U);
+    work = (*left ^ *right) & 0x33333333;
+    *right ^= work;
+
+    *left = rotlFixed(*left^work, 18U);
+    work = (*left ^ *right) & 0xffff0000;
+    *right ^= work;
+
+    *left = rotlFixed(*left^work, 20U);
+    work = (*left ^ *right) & 0xf0f0f0f0;
+    *right ^= work;
+
+    *left = rotrFixed(*left^work, 4U);
+}
+
+
+static int DesSetKey(const byte* key, int dir, word32* out)
+{
+    byte* buffer = (byte*)XMALLOC(56+56+8, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    if (!buffer) {
+        return MEMORY_E;
+    }
+    else {
+        byte* const  pc1m = buffer;               /* place to modify pc1 into */
+        byte* const  pcr  = pc1m + 56;            /* place to rotate pc1 into */
+        byte* const  ks   = pcr  + 56;
+        register int i, j, l;
+        int          m;
+
+        for (j = 0; j < 56; j++) {             /* convert pc1 to bits of key  */
+            l = pc1[j] - 1;                    /* integer bit location        */
+            m = l & 07;                        /* find bit                    */
+            pc1m[j] = (key[l >> 3] &           /* find which key byte l is in */
+                bytebit[m])                    /* and which bit of that byte  */
+                ? 1 : 0;                       /* and store 1-bit result      */
+        }
+
+        for (i = 0; i < 16; i++) {            /* key chunk for each iteration */
+            XMEMSET(ks, 0, 8);                /* Clear key schedule */
+
+            for (j = 0; j < 56; j++)          /* rotate pc1 the right amount  */
+                pcr[j] =
+                      pc1m[(l = j + totrot[i]) < (j < 28 ? 28 : 56) ? l : l-28];
+
+            /* rotate left and right halves independently */
+            for (j = 0; j < 48; j++) {        /* select bits individually     */
+                if (pcr[pc2[j] - 1]) {        /* check bit that goes to ks[j] */
+                    l= j % 6;                 /* mask it in if it's there     */
+                    ks[j/6] |= bytebit[l] >> 2;
+                }
+            }
+
+            /* Now convert to odd/even interleaved form for use in F */
+            out[2*i] = ((word32) ks[0] << 24)
+                     | ((word32) ks[2] << 16)
+                     | ((word32) ks[4] << 8)
+                     | ((word32) ks[6]);
+
+            out[2*i + 1] = ((word32) ks[1] << 24)
+                         | ((word32) ks[3] << 16)
+                         | ((word32) ks[5] << 8)
+                         | ((word32) ks[7]);
+        }
+
+        /* reverse key schedule order */
+        if (dir == DES_DECRYPTION) {
+            for (i = 0; i < 16; i += 2) {
+                word32 swap = out[i];
+                out[i] = out[DES_KS_SIZE - 2 - i];
+                out[DES_KS_SIZE - 2 - i] = swap;
+    
+                swap = out[i + 1];
+                out[i + 1] = out[DES_KS_SIZE - 1 - i];
+                out[DES_KS_SIZE - 1 - i] = swap;
+            }
+        }
+
+        XFREE(buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    }
+
+    return 0;
+}
+
+
+static INLINE int Reverse(int dir)
+{
+    return !dir;
+}
+
+
+int Des_SetKey(Des* des, const byte* key, const byte* iv, int dir)
+{
+    Des_SetIV(des, iv);
+
+    return DesSetKey(key, dir, des->key);
+}
+
+
+int Des3_SetKey(Des3* des, const byte* key, const byte* iv, int dir)
+{
+    int ret;
+
+#ifdef HAVE_CAVIUM
+    if (des->magic == CYASSL_3DES_CAVIUM_MAGIC)
+        return Des3_CaviumSetKey(des, key, iv);
+#endif
+
+    ret = DesSetKey(key + (dir == DES_ENCRYPTION ? 0:16), dir, des->key[0]);
+    if (ret != 0)
+        return ret;
+
+    ret = DesSetKey(key + 8, Reverse(dir), des->key[1]);
+    if (ret != 0)
+        return ret;
+
+    ret = DesSetKey(key + (dir == DES_DECRYPTION ? 0:16), dir, des->key[2]);
+    if (ret != 0)
+        return ret;
+
+    return 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; 
+    }
+}
+
+
+int 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; 
+    }
+    return 0;
+}
+
+
+int 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; 
+    }
+    return 0;
+}
+
+#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);
+    else if (des)
+        XMEMSET(des->reg,  0, DES_BLOCK_SIZE);
+}
+
+
+int Des3_SetIV(Des3* des, const byte* iv)
+{
+    if (des && iv)
+        XMEMCPY(des->reg, iv, DES_BLOCK_SIZE);
+    else if (des)
+        XMEMSET(des->reg,  0, DES_BLOCK_SIZE);
+
+    return 0;
+}
+
+
+#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 int Des3_CaviumSetKey(Des3* des3, const byte* key, const byte* iv)
+{
+    if (des3 == NULL)
+        return -1;
+
+    /* key[0] holds key, iv in reg */
+    XMEMCPY(des3->key[0], key, DES_BLOCK_SIZE*3);
+
+    return Des3_SetIV(des3, iv);
+}
+
+
+static int 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");
+            return -1;
+        }
+        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");
+            return -1;
+        }
+        XMEMCPY(des3->reg, out+offset+length - DES_BLOCK_SIZE, DES_BLOCK_SIZE);
+    }
+    return 0;
+}
+
+static int 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");
+            return -1;
+        }
+        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");
+            return -1;
+        }
+        XMEMCPY(des3->reg, des3->tmp, DES_BLOCK_SIZE);
+    }
+    return 0;
+}
+
+#endif /* HAVE_CAVIUM */
+
+#endif /* NO_DES3 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/dh.c	Sun Apr 20 12:40:57 2014 +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/error-crypt.h>
+
+#ifndef USER_MATH_LIB
+    #include <math.h>
+    #define XPOW(x,y) pow((x),(y))
+    #define XLOG(x)   log((x))
+#else
+    /* user's own math lib */
+#endif
+
+
+#ifndef 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	Sun Apr 20 12:40:57 2014 +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/error-crypt.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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,3981 @@
+/* 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/error-crypt.h>
+
+#ifdef HAVE_ECC_ENCRYPT
+    #include <cyassl/ctaocrypt/hmac.h>
+    #include <cyassl/ctaocrypt/aes.h>
+#endif
+
+
+/* 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);
+static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus,
+                      int map);
+#ifdef ECC_SHAMIR
+static int ecc_mul2add(ecc_point* A, mp_int* kA, ecc_point* B, mp_int* kB,
+                       ecc_point* C, mp_int* modulus);
+#endif
+
+
+/* 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];
+}
+
+
+#if defined(USE_FAST_MATH)
+
+/* fast math accelerated version, but not for fp ecc yet */
+
+/**
+   Add two ECC points
+   P        The point to add
+   Q        The point to add
+   R        [out] The destination of the double
+   modulus  The modulus of the field the ECC curve is in
+   mp       The "b" value from montgomery_setup()
+   return   MP_OKAY on success
+*/
+int ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R,
+                             mp_int* modulus, mp_digit* mp)
+{
+   fp_int t1, t2, x, y, z;
+   int    err;
+
+   if (P == NULL || Q == NULL || R == NULL || modulus == NULL || mp == NULL)
+       return ECC_BAD_ARG_E;
+
+   if ((err = mp_init_multi(&t1, &t2, &x, &y, &z, NULL)) != MP_OKAY) {
+      return err;
+   }
+
+   /* should we dbl instead? */
+   fp_sub(modulus, &Q->y, &t1);
+   if ( (fp_cmp(&P->x, &Q->x) == FP_EQ) && 
+        (get_digit_count(&Q->z) && fp_cmp(&P->z, &Q->z) == FP_EQ) &&
+        (fp_cmp(&P->y, &Q->y) == FP_EQ || fp_cmp(&P->y, &t1) == FP_EQ)) {
+        return ecc_projective_dbl_point(P, R, modulus, mp);
+   }
+
+   fp_copy(&P->x, &x);
+   fp_copy(&P->y, &y);
+   fp_copy(&P->z, &z);
+
+   /* if Z is one then these are no-operations */
+   if (get_digit_count(&Q->z)) {
+      /* T1 = Z' * Z' */
+      fp_sqr(&Q->z, &t1);
+      fp_montgomery_reduce(&t1, modulus, *mp);
+      /* X = X * T1 */
+      fp_mul(&t1, &x, &x);
+      fp_montgomery_reduce(&x, modulus, *mp);
+      /* T1 = Z' * T1 */
+      fp_mul(&Q->z, &t1, &t1);
+      fp_montgomery_reduce(&t1, modulus, *mp);
+      /* Y = Y * T1 */
+      fp_mul(&t1, &y, &y);
+      fp_montgomery_reduce(&y, modulus, *mp);
+   }
+
+   /* T1 = Z*Z */
+   fp_sqr(&z, &t1);
+   fp_montgomery_reduce(&t1, modulus, *mp);
+   /* T2 = X' * T1 */
+   fp_mul(&Q->x, &t1, &t2);
+   fp_montgomery_reduce(&t2, modulus, *mp);
+   /* T1 = Z * T1 */
+   fp_mul(&z, &t1, &t1);
+   fp_montgomery_reduce(&t1, modulus, *mp);
+   /* T1 = Y' * T1 */
+   fp_mul(&Q->y, &t1, &t1);
+   fp_montgomery_reduce(&t1, modulus, *mp);
+
+   /* Y = Y - T1 */
+   fp_sub(&y, &t1, &y);
+   if (fp_cmp_d(&y, 0) == FP_LT) {
+      fp_add(&y, modulus, &y);
+   }
+   /* T1 = 2T1 */
+   fp_add(&t1, &t1, &t1);
+   if (fp_cmp(&t1, modulus) != FP_LT) {
+      fp_sub(&t1, modulus, &t1);
+   }
+   /* T1 = Y + T1 */
+   fp_add(&t1, &y, &t1);
+   if (fp_cmp(&t1, modulus) != FP_LT) {
+      fp_sub(&t1, modulus, &t1);
+   }
+   /* X = X - T2 */
+   fp_sub(&x, &t2, &x);
+   if (fp_cmp_d(&x, 0) == FP_LT) {
+      fp_add(&x, modulus, &x);
+   }
+   /* T2 = 2T2 */
+   fp_add(&t2, &t2, &t2);
+   if (fp_cmp(&t2, modulus) != FP_LT) {
+      fp_sub(&t2, modulus, &t2);
+   }
+   /* T2 = X + T2 */
+   fp_add(&t2, &x, &t2);
+   if (fp_cmp(&t2, modulus) != FP_LT) {
+      fp_sub(&t2, modulus, &t2);
+   }
+
+   /* if Z' != 1 */
+   if (get_digit_count(&Q->z)) {
+      /* Z = Z * Z' */
+      fp_mul(&z, &Q->z, &z);
+      fp_montgomery_reduce(&z, modulus, *mp);
+   }
+
+   /* Z = Z * X */
+   fp_mul(&z, &x, &z);
+   fp_montgomery_reduce(&z, modulus, *mp);
+
+   /* T1 = T1 * X  */
+   fp_mul(&t1, &x, &t1);
+   fp_montgomery_reduce(&t1, modulus, *mp);
+   /* X = X * X */
+   fp_sqr(&x, &x);
+   fp_montgomery_reduce(&x, modulus, *mp);
+   /* T2 = T2 * x */
+   fp_mul(&t2, &x, &t2);
+   fp_montgomery_reduce(&t2, modulus, *mp);
+   /* T1 = T1 * X  */
+   fp_mul(&t1, &x, &t1);
+   fp_montgomery_reduce(&t1, modulus, *mp);
+ 
+   /* X = Y*Y */
+   fp_sqr(&y, &x);
+   fp_montgomery_reduce(&x, modulus, *mp);
+   /* X = X - T2 */
+   fp_sub(&x, &t2, &x);
+   if (fp_cmp_d(&x, 0) == FP_LT) {
+      fp_add(&x, modulus, &x);
+   }
+
+   /* T2 = T2 - X */
+   fp_sub(&t2, &x, &t2);
+   if (fp_cmp_d(&t2, 0) == FP_LT) {
+      fp_add(&t2, modulus, &t2);
+   } 
+   /* T2 = T2 - X */
+   fp_sub(&t2, &x, &t2);
+   if (fp_cmp_d(&t2, 0) == FP_LT) {
+      fp_add(&t2, modulus, &t2);
+   }
+   /* T2 = T2 * Y */
+   fp_mul(&t2, &y, &t2);
+   fp_montgomery_reduce(&t2, modulus, *mp);
+   /* Y = T2 - T1 */
+   fp_sub(&t2, &t1, &y);
+   if (fp_cmp_d(&y, 0) == FP_LT) {
+      fp_add(&y, modulus, &y);
+   }
+   /* Y = Y/2 */
+   if (fp_isodd(&y)) {
+      fp_add(&y, modulus, &y);
+   }
+   fp_div_2(&y, &y);
+
+   fp_copy(&x, &R->x);
+   fp_copy(&y, &R->y);
+   fp_copy(&z, &R->z);
+   
+   return MP_OKAY;
+}
+
+
+/**
+   Double an ECC point
+   P   The point to double
+   R   [out] The destination of the double
+   modulus  The modulus of the field the ECC curve is in
+   mp       The "b" value from montgomery_setup()
+   return   MP_OKAY on success
+*/
+int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* modulus,
+                             mp_digit* mp)
+{
+   fp_int   t1, t2;
+   int      err;
+
+   if (P == NULL || R == NULL || modulus == NULL || mp == NULL)
+       return ECC_BAD_ARG_E;
+
+   if (P != R) {
+      fp_copy(&P->x, &R->x);
+      fp_copy(&P->y, &R->y);
+      fp_copy(&P->z, &R->z);
+   }
+
+   if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+      return err;
+   }
+
+   /* t1 = Z * Z */
+   fp_sqr(&R->z, &t1);
+   fp_montgomery_reduce(&t1, modulus, *mp);
+   /* Z = Y * Z */
+   fp_mul(&R->z, &R->y, &R->z);
+   fp_montgomery_reduce(&R->z, modulus, *mp);
+   /* Z = 2Z */
+   fp_add(&R->z, &R->z, &R->z);
+   if (fp_cmp(&R->z, modulus) != FP_LT) {
+      fp_sub(&R->z, modulus, &R->z);
+   }
+   
+   /* &t2 = X - T1 */
+   fp_sub(&R->x, &t1, &t2);
+   if (fp_cmp_d(&t2, 0) == FP_LT) {
+      fp_add(&t2, modulus, &t2);
+   }
+   /* T1 = X + T1 */
+   fp_add(&t1, &R->x, &t1);
+   if (fp_cmp(&t1, modulus) != FP_LT) {
+      fp_sub(&t1, modulus, &t1);
+   }
+   /* T2 = T1 * T2 */
+   fp_mul(&t1, &t2, &t2);
+   fp_montgomery_reduce(&t2, modulus, *mp);
+   /* T1 = 2T2 */
+   fp_add(&t2, &t2, &t1);
+   if (fp_cmp(&t1, modulus) != FP_LT) {
+      fp_sub(&t1, modulus, &t1);
+   }
+   /* T1 = T1 + T2 */
+   fp_add(&t1, &t2, &t1);
+   if (fp_cmp(&t1, modulus) != FP_LT) {
+      fp_sub(&t1, modulus, &t1);
+   }
+
+   /* Y = 2Y */
+   fp_add(&R->y, &R->y, &R->y);
+   if (fp_cmp(&R->y, modulus) != FP_LT) {
+      fp_sub(&R->y, modulus, &R->y);
+   }
+   /* Y = Y * Y */
+   fp_sqr(&R->y, &R->y);
+   fp_montgomery_reduce(&R->y, modulus, *mp);
+   /* T2 = Y * Y */
+   fp_sqr(&R->y, &t2);
+   fp_montgomery_reduce(&t2, modulus, *mp);
+   /* T2 = T2/2 */
+   if (fp_isodd(&t2)) {
+      fp_add(&t2, modulus, &t2);
+   }
+   fp_div_2(&t2, &t2);
+   /* Y = Y * X */
+   fp_mul(&R->y, &R->x, &R->y);
+   fp_montgomery_reduce(&R->y, modulus, *mp);
+
+   /* X  = T1 * T1 */
+   fp_sqr(&t1, &R->x);
+   fp_montgomery_reduce(&R->x, modulus, *mp);
+   /* X = X - Y */
+   fp_sub(&R->x, &R->y, &R->x);
+   if (fp_cmp_d(&R->x, 0) == FP_LT) {
+      fp_add(&R->x, modulus, &R->x);
+   }
+   /* X = X - Y */
+   fp_sub(&R->x, &R->y, &R->x);
+   if (fp_cmp_d(&R->x, 0) == FP_LT) {
+      fp_add(&R->x, modulus, &R->x);
+   }
+
+   /* Y = Y - X */     
+   fp_sub(&R->y, &R->x, &R->y);
+   if (fp_cmp_d(&R->y, 0) == FP_LT) {
+      fp_add(&R->y, modulus, &R->y);
+   }
+   /* Y = Y * T1 */
+   fp_mul(&R->y, &t1, &R->y);
+   fp_montgomery_reduce(&R->y, modulus, *mp);
+   /* Y = Y - T2 */
+   fp_sub(&R->y, &t2, &R->y);
+   if (fp_cmp_d(&R->y, 0) == FP_LT) {
+      fp_add(&R->y, modulus, &R->y);
+   }
+ 
+   return MP_OKAY;
+}
+
+#else /* USE_FAST_MATH */
+
+/**
+   Add two ECC points
+   P        The point to add
+   Q        The point to add
+   R        [out] The destination of the double
+   modulus  The modulus of the field the ECC curve is in
+   mp       The "b" value from montgomery_setup()
+   return   MP_OKAY on success
+*/
+int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R,
+                             mp_int* modulus, mp_digit* mp)
+{
+   mp_int t1;
+   mp_int t2;
+   mp_int x;
+   mp_int y;
+   mp_int z;
+   int    err;
+
+   if (P == NULL || Q == NULL || R == NULL || modulus == NULL || mp == NULL)
+       return ECC_BAD_ARG_E;
+
+   if ((err = mp_init_multi(&t1, &t2, &x, &y, &z, NULL)) != MP_OKAY) {
+      return err;
+   }
+   
+   /* should we dbl instead? */
+   err = mp_sub(modulus, &Q->y, &t1);
+
+   if (err == MP_OKAY) {
+       if ( (mp_cmp(&P->x, &Q->x) == MP_EQ) && 
+            (get_digit_count(&Q->z) && mp_cmp(&P->z, &Q->z) == MP_EQ) &&
+            (mp_cmp(&P->y, &Q->y) == MP_EQ || mp_cmp(&P->y, &t1) == MP_EQ)) {
+                mp_clear(&t1);
+                mp_clear(&t2);
+                mp_clear(&x);
+                mp_clear(&y);
+                mp_clear(&z);
+
+                return ecc_projective_dbl_point(P, R, modulus, mp);
+       }
+   }
+
+   if (err == MP_OKAY)
+       err = mp_copy(&P->x, &x);
+   if (err == MP_OKAY)
+       err = mp_copy(&P->y, &y);
+   if (err == MP_OKAY)
+       err = mp_copy(&P->z, &z);
+
+   /* if Z is one then these are no-operations */
+   if (err == MP_OKAY) {
+       if (get_digit_count(&Q->z)) {
+           /* T1 = Z' * Z' */
+           err = mp_sqr(&Q->z, &t1);
+           if (err == MP_OKAY)
+               err = mp_montgomery_reduce(&t1, modulus, *mp);
+
+           /* X = X * T1 */
+           if (err == MP_OKAY)
+               err = mp_mul(&t1, &x, &x);
+           if (err == MP_OKAY)
+               err = mp_montgomery_reduce(&x, modulus, *mp);
+
+           /* T1 = Z' * T1 */
+           if (err == MP_OKAY)
+               err = mp_mul(&Q->z, &t1, &t1);
+           if (err == MP_OKAY)
+               err = mp_montgomery_reduce(&t1, modulus, *mp);
+
+           /* Y = Y * T1 */
+           if (err == MP_OKAY)
+               err = mp_mul(&t1, &y, &y);
+           if (err == MP_OKAY)
+               err = mp_montgomery_reduce(&y, modulus, *mp);
+       }
+   }
+
+   /* T1 = Z*Z */
+   if (err == MP_OKAY)
+       err = mp_sqr(&z, &t1);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&t1, modulus, *mp);
+
+   /* T2 = X' * T1 */
+   if (err == MP_OKAY)
+       err = mp_mul(&Q->x, &t1, &t2);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&t2, modulus, *mp);
+
+   /* T1 = Z * T1 */
+   if (err == MP_OKAY)
+       err = mp_mul(&z, &t1, &t1);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&t1, modulus, *mp);
+
+   /* T1 = Y' * T1 */
+   if (err == MP_OKAY)
+       err = mp_mul(&Q->y, &t1, &t1);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&t1, modulus, *mp);
+
+   /* Y = Y - T1 */
+   if (err == MP_OKAY)
+       err = mp_sub(&y, &t1, &y);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&y, 0) == MP_LT)
+           err = mp_add(&y, modulus, &y);
+   }
+   /* T1 = 2T1 */
+   if (err == MP_OKAY)
+       err = mp_add(&t1, &t1, &t1);
+   if (err == MP_OKAY) {
+       if (mp_cmp(&t1, modulus) != MP_LT)
+           err = mp_sub(&t1, modulus, &t1);
+   }
+   /* T1 = Y + T1 */
+   if (err == MP_OKAY)
+       err = mp_add(&t1, &y, &t1);
+   if (err == MP_OKAY) {
+       if (mp_cmp(&t1, modulus) != MP_LT)
+           err = mp_sub(&t1, modulus, &t1);
+   }
+   /* X = X - T2 */
+   if (err == MP_OKAY)
+       err = mp_sub(&x, &t2, &x);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&x, 0) == MP_LT)
+           err = mp_add(&x, modulus, &x);
+   }
+   /* T2 = 2T2 */
+   if (err == MP_OKAY)
+       err = mp_add(&t2, &t2, &t2);
+   if (err == MP_OKAY) {
+       if (mp_cmp(&t2, modulus) != MP_LT)
+           err = mp_sub(&t2, modulus, &t2);
+   }
+   /* T2 = X + T2 */
+   if (err == MP_OKAY)
+       err = mp_add(&t2, &x, &t2);
+   if (err == MP_OKAY) {
+       if (mp_cmp(&t2, modulus) != MP_LT)
+           err = mp_sub(&t2, modulus, &t2);
+   }
+
+   if (err == MP_OKAY) {
+       if (get_digit_count(&Q->z)) {
+           /* Z = Z * Z' */
+           err = mp_mul(&z, &Q->z, &z);
+           if (err == MP_OKAY)
+               err = mp_montgomery_reduce(&z, modulus, *mp);
+       }
+   }
+
+   /* Z = Z * X */
+   if (err == MP_OKAY)
+       err = mp_mul(&z, &x, &z);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&z, modulus, *mp);
+
+   /* T1 = T1 * X  */
+   if (err == MP_OKAY)
+       err = mp_mul(&t1, &x, &t1);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&t1, modulus, *mp);
+
+   /* X = X * X */
+   if (err == MP_OKAY)
+       err = mp_sqr(&x, &x);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&x, modulus, *mp);
+   
+   /* T2 = T2 * x */
+   if (err == MP_OKAY)
+       err = mp_mul(&t2, &x, &t2);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&t2, modulus, *mp);
+
+   /* T1 = T1 * X  */
+   if (err == MP_OKAY)
+       err = mp_mul(&t1, &x, &t1);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&t1, modulus, *mp);
+ 
+   /* X = Y*Y */
+   if (err == MP_OKAY)
+       err = mp_sqr(&y, &x);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&x, modulus, *mp);
+
+   /* X = X - T2 */
+   if (err == MP_OKAY)
+       err = mp_sub(&x, &t2, &x);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&x, 0) == MP_LT)
+           err = mp_add(&x, modulus, &x);
+   }
+   /* T2 = T2 - X */
+   if (err == MP_OKAY)
+       err = mp_sub(&t2, &x, &t2);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&t2, 0) == MP_LT)
+           err = mp_add(&t2, modulus, &t2);
+   } 
+   /* T2 = T2 - X */
+   if (err == MP_OKAY)
+       err = mp_sub(&t2, &x, &t2);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&t2, 0) == MP_LT)
+           err = mp_add(&t2, modulus, &t2);
+   }
+   /* T2 = T2 * Y */
+   if (err == MP_OKAY)
+       err = mp_mul(&t2, &y, &t2);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&t2, modulus, *mp);
+
+   /* Y = T2 - T1 */
+   if (err == MP_OKAY)
+       err = mp_sub(&t2, &t1, &y);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&y, 0) == MP_LT)
+           err = mp_add(&y, modulus, &y);
+   }
+   /* Y = Y/2 */
+   if (err == MP_OKAY) {
+       if (mp_isodd(&y))
+           err = mp_add(&y, modulus, &y);
+   }
+   if (err == MP_OKAY)
+       err = mp_div_2(&y, &y);
+
+   if (err == MP_OKAY)
+       err = mp_copy(&x, &R->x);
+   if (err == MP_OKAY)
+       err = mp_copy(&y, &R->y);
+   if (err == MP_OKAY)
+       err = mp_copy(&z, &R->z);
+
+   /* clean up */
+   mp_clear(&t1);
+   mp_clear(&t2);
+   mp_clear(&x);
+   mp_clear(&y);
+   mp_clear(&z);
+
+   return err;
+}
+
+
+/**
+   Double an ECC point
+   P   The point to double
+   R   [out] The destination of the double
+   modulus  The modulus of the field the ECC curve is in
+   mp       The "b" value from montgomery_setup()
+   return   MP_OKAY on success
+*/
+int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* modulus,
+                             mp_digit* mp)
+{
+   mp_int t1;
+   mp_int t2;
+   int    err;
+
+   if (P == NULL || R == NULL || modulus == NULL || mp == NULL)
+       return ECC_BAD_ARG_E;
+
+   if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+      return err;
+   }
+
+   if (P != R) {
+      err = mp_copy(&P->x, &R->x);
+      if (err == MP_OKAY)
+          err = mp_copy(&P->y, &R->y);
+      if (err == MP_OKAY)
+          err = mp_copy(&P->z, &R->z);
+   }
+
+   /* t1 = Z * Z */
+   if (err == MP_OKAY)
+       err = mp_sqr(&R->z, &t1);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&t1, modulus, *mp);
+
+   /* Z = Y * Z */
+   if (err == MP_OKAY)
+       err = mp_mul(&R->z, &R->y, &R->z);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&R->z, modulus, *mp);
+
+   /* Z = 2Z */
+   if (err == MP_OKAY)
+       err = mp_add(&R->z, &R->z, &R->z);
+   if (err == MP_OKAY) {
+       if (mp_cmp(&R->z, modulus) != MP_LT)
+           err = mp_sub(&R->z, modulus, &R->z);
+   }
+
+   /* T2 = X - T1 */
+   if (err == MP_OKAY)
+       err = mp_sub(&R->x, &t1, &t2);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&t2, 0) == MP_LT)
+           err = mp_add(&t2, modulus, &t2);
+   }
+   /* T1 = X + T1 */
+   if (err == MP_OKAY)
+       err = mp_add(&t1, &R->x, &t1);
+   if (err == MP_OKAY) {
+       if (mp_cmp(&t1, modulus) != MP_LT)
+           err = mp_sub(&t1, modulus, &t1);
+   }
+   /* T2 = T1 * T2 */
+   if (err == MP_OKAY)
+       err = mp_mul(&t1, &t2, &t2);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&t2, modulus, *mp);
+
+   /* T1 = 2T2 */
+   if (err == MP_OKAY)
+       err = mp_add(&t2, &t2, &t1);
+   if (err == MP_OKAY) {
+       if (mp_cmp(&t1, modulus) != MP_LT)
+           err = mp_sub(&t1, modulus, &t1);
+   }
+   /* T1 = T1 + T2 */
+   if (err == MP_OKAY)
+       err = mp_add(&t1, &t2, &t1);
+   if (err == MP_OKAY) {
+       if (mp_cmp(&t1, modulus) != MP_LT)
+           err = mp_sub(&t1, modulus, &t1);
+   }
+   /* Y = 2Y */
+   if (err == MP_OKAY)
+       err = mp_add(&R->y, &R->y, &R->y);
+   if (err == MP_OKAY) {
+       if (mp_cmp(&R->y, modulus) != MP_LT)
+           err = mp_sub(&R->y, modulus, &R->y);
+   }
+   /* Y = Y * Y */
+   if (err == MP_OKAY)
+       err = mp_sqr(&R->y, &R->y);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&R->y, modulus, *mp);
+   
+   /* T2 = Y * Y */
+   if (err == MP_OKAY)
+       err = mp_sqr(&R->y, &t2);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&t2, modulus, *mp);
+
+   /* T2 = T2/2 */
+   if (err == MP_OKAY) {
+       if (mp_isodd(&t2))
+           err = mp_add(&t2, modulus, &t2);
+   }
+   if (err == MP_OKAY)
+       err = mp_div_2(&t2, &t2);
+   
+   /* Y = Y * X */
+   if (err == MP_OKAY)
+       err = mp_mul(&R->y, &R->x, &R->y);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&R->y, modulus, *mp);
+
+   /* X  = T1 * T1 */
+   if (err == MP_OKAY)
+       err = mp_sqr(&t1, &R->x);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&R->x, modulus, *mp);
+
+   /* X = X - Y */
+   if (err == MP_OKAY)
+       err = mp_sub(&R->x, &R->y, &R->x);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&R->x, 0) == MP_LT)
+           err = mp_add(&R->x, modulus, &R->x);
+   }
+   /* X = X - Y */
+   if (err == MP_OKAY)
+       err = mp_sub(&R->x, &R->y, &R->x);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&R->x, 0) == MP_LT)
+           err = mp_add(&R->x, modulus, &R->x);
+   }
+   /* Y = Y - X */     
+   if (err == MP_OKAY)
+       err = mp_sub(&R->y, &R->x, &R->y);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&R->y, 0) == MP_LT)
+           err = mp_add(&R->y, modulus, &R->y);
+   }
+   /* Y = Y * T1 */
+   if (err == MP_OKAY)
+       err = mp_mul(&R->y, &t1, &R->y);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&R->y, modulus, *mp);
+
+   /* Y = Y - T2 */
+   if (err == MP_OKAY)
+       err = mp_sub(&R->y, &t2, &R->y);
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&R->y, 0) == MP_LT)
+           err = mp_add(&R->y, modulus, &R->y);
+   }
+
+   /* clean up */ 
+   mp_clear(&t1);
+   mp_clear(&t2);
+
+   return err;
+}
+
+#endif /* USE_FAST_MATH */
+
+/**
+  Map a projective jacbobian point back to affine space
+  P        [in/out] The point to map
+  modulus  The modulus of the field the ECC curve is in
+  mp       The "b" value from montgomery_setup()
+  return   MP_OKAY on success
+*/
+int ecc_map(ecc_point* P, mp_int* modulus, mp_digit* mp)
+{
+   mp_int t1;
+   mp_int t2;
+   int    err;
+
+   if (P == NULL || mp == NULL || modulus == NULL)
+       return ECC_BAD_ARG_E;
+
+   if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+      return MEMORY_E;
+   }
+
+   /* first map z back to normal */
+   err = mp_montgomery_reduce(&P->z, modulus, *mp);
+
+   /* get 1/z */
+   if (err == MP_OKAY)
+       err = mp_invmod(&P->z, modulus, &t1);
+ 
+   /* get 1/z^2 and 1/z^3 */
+   if (err == MP_OKAY)
+       err = mp_sqr(&t1, &t2);
+   if (err == MP_OKAY)
+       err = mp_mod(&t2, modulus, &t2);
+   if (err == MP_OKAY)
+       err = mp_mul(&t1, &t2, &t1);
+   if (err == MP_OKAY)
+       err = mp_mod(&t1, modulus, &t1);
+
+   /* multiply against x/y */
+   if (err == MP_OKAY)
+       err = mp_mul(&P->x, &t2, &P->x);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&P->x, modulus, *mp);
+   if (err == MP_OKAY)
+       err = mp_mul(&P->y, &t1, &P->y);
+   if (err == MP_OKAY)
+       err = mp_montgomery_reduce(&P->y, modulus, *mp);
+   
+   if (err == MP_OKAY)
+       mp_set(&P->z, 1);
+
+   /* clean up */
+   mp_clear(&t1);
+   mp_clear(&t2);
+
+   return err;
+}
+
+
+#ifndef ECC_TIMING_RESISTANT
+
+/* size of sliding window, don't change this! */
+#define WINSIZE 4
+
+/**
+   Perform a point multiplication 
+   k    The scalar to multiply by
+   G    The base point
+   R    [out] Destination for kG
+   modulus  The modulus of the field the ECC curve is in
+   map      Boolean whether to map back to affine or not
+                (1==map, 0 == leave in projective)
+   return MP_OKAY on success
+*/
+#ifdef FP_ECC
+static int normal_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R,
+                             mp_int* modulus, int map)
+#else
+static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus,
+                      int map)
+#endif
+{
+   ecc_point *tG, *M[8];
+   int           i, j, err;
+   mp_int        mu;
+   mp_digit      mp;
+   unsigned long buf;
+   int           first = 1, bitbuf = 0, bitcpy = 0, bitcnt = 0, mode = 0,
+                 digidx = 0;
+
+   if (k == NULL || G == NULL || R == NULL || modulus == NULL)
+       return ECC_BAD_ARG_E;
+
+   /* init montgomery reduction */
+   if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) {
+      return err;
+   }
+   if ((err = mp_init(&mu)) != MP_OKAY) {
+      return err;
+   }
+   if ((err = mp_montgomery_calc_normalization(&mu, modulus)) != MP_OKAY) {
+      mp_clear(&mu);
+      return err;
+   }
+  
+  /* alloc ram for window temps */
+  for (i = 0; i < 8; i++) {
+      M[i] = ecc_new_point();
+      if (M[i] == NULL) {
+         for (j = 0; j < i; j++) {
+             ecc_del_point(M[j]);
+         }
+         mp_clear(&mu);
+         return MEMORY_E;
+      }
+  }
+
+   /* make a copy of G incase R==G */
+   tG = ecc_new_point();
+   if (tG == NULL)
+       err = MEMORY_E;
+
+   /* tG = G  and convert to montgomery */
+   if (err == MP_OKAY) {
+       if (mp_cmp_d(&mu, 1) == MP_EQ) {
+           err = mp_copy(&G->x, &tG->x);
+           if (err == MP_OKAY)
+               err = mp_copy(&G->y, &tG->y);
+           if (err == MP_OKAY)
+               err = mp_copy(&G->z, &tG->z);
+       } else {
+           err = mp_mulmod(&G->x, &mu, modulus, &tG->x);
+           if (err == MP_OKAY)
+               err = mp_mulmod(&G->y, &mu, modulus, &tG->y);
+           if (err == MP_OKAY)
+               err = mp_mulmod(&G->z, &mu, modulus, &tG->z);
+       }
+   }
+   mp_clear(&mu);
+   
+   /* calc the M tab, which holds kG for k==8..15 */
+   /* M[0] == 8G */
+   if (err == MP_OKAY)
+       err = ecc_projective_dbl_point(tG, M[0], modulus, &mp);
+   if (err == MP_OKAY)
+       err = ecc_projective_dbl_point(M[0], M[0], modulus, &mp);
+   if (err == MP_OKAY)
+       err = ecc_projective_dbl_point(M[0], M[0], modulus, &mp);
+
+   /* now find (8+k)G for k=1..7 */
+   if (err == MP_OKAY)
+       for (j = 9; j < 16; j++) {
+           err = ecc_projective_add_point(M[j-9], tG, M[j-8], modulus, &mp);
+           if (err != MP_OKAY) break;
+       }
+
+   /* setup sliding window */
+   if (err == MP_OKAY) {
+       mode   = 0;
+       bitcnt = 1;
+       buf    = 0;
+       digidx = get_digit_count(k) - 1;
+       bitcpy = bitbuf = 0;
+       first  = 1;
+
+       /* perform ops */
+       for (;;) {
+           /* grab next digit as required */
+           if (--bitcnt == 0) {
+               if (digidx == -1) {
+                   break;
+               }
+               buf    = get_digit(k, digidx);
+               bitcnt = (int) DIGIT_BIT; 
+               --digidx;
+           }
+
+           /* grab the next msb from the ltiplicand */
+           i = (int)(buf >> (DIGIT_BIT - 1)) & 1;
+           buf <<= 1;
+
+           /* skip leading zero bits */
+           if (mode == 0 && i == 0)
+               continue;
+
+           /* if the bit is zero and mode == 1 then we double */
+           if (mode == 1 && i == 0) {
+               err = ecc_projective_dbl_point(R, R, modulus, &mp);
+               if (err != MP_OKAY) break;
+               continue;
+           }
+
+           /* else we add it to the window */
+           bitbuf |= (i << (WINSIZE - ++bitcpy));
+           mode = 2;
+
+           if (bitcpy == WINSIZE) {
+               /* if this is the first window we do a simple copy */
+               if (first == 1) {
+                   /* R = kG [k = first window] */
+                   err = mp_copy(&M[bitbuf-8]->x, &R->x);
+                   if (err != MP_OKAY) break;
+
+                   err = mp_copy(&M[bitbuf-8]->y, &R->y);
+                   if (err != MP_OKAY) break;
+
+                   err = mp_copy(&M[bitbuf-8]->z, &R->z);
+                   first = 0;
+               } else {
+                   /* normal window */
+                   /* ok window is filled so double as required and add  */
+                   /* double first */
+                   for (j = 0; j < WINSIZE; j++) {
+                       err = ecc_projective_dbl_point(R, R, modulus, &mp);
+                       if (err != MP_OKAY) break;
+                   }
+                   if (err != MP_OKAY) break;  /* out of first for(;;) */
+
+                   /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranted */
+                   err = ecc_projective_add_point(R,M[bitbuf-8],R,modulus,&mp);
+               }
+               if (err != MP_OKAY) break;
+               /* empty window and reset */
+               bitcpy = bitbuf = 0;
+               mode = 1;
+           }
+       }
+   }
+
+   /* if bits remain then double/add */
+   if (err == MP_OKAY) {
+       if (mode == 2 && bitcpy > 0) {
+           /* double then add */
+           for (j = 0; j < bitcpy; j++) {
+               /* only double if we have had at least one add first */
+               if (first == 0) {
+                   err = ecc_projective_dbl_point(R, R, modulus, &mp);
+                   if (err != MP_OKAY) break;
+               }
+
+               bitbuf <<= 1;
+               if ((bitbuf & (1 << WINSIZE)) != 0) {
+                   if (first == 1) {
+                       /* first add, so copy */
+                       err = mp_copy(&tG->x, &R->x);
+                       if (err != MP_OKAY) break;
+
+                       err = mp_copy(&tG->y, &R->y);
+                       if (err != MP_OKAY) break;
+
+                       err = mp_copy(&tG->z, &R->z);
+                       if (err != MP_OKAY) break;
+                       first = 0;
+                   } else {
+                       /* then add */
+                       err = ecc_projective_add_point(R, tG, R, modulus, &mp);
+                       if (err != MP_OKAY) break;
+                   }
+               }
+           }
+       }
+   }
+
+   /* map R back from projective space */
+   if (err == MP_OKAY && map)
+       err = ecc_map(R, modulus, &mp);
+
+   mp_clear(&mu);
+   ecc_del_point(tG);
+   for (i = 0; i < 8; i++) {
+       ecc_del_point(M[i]);
+   }
+   return err;
+}
+
+#undef WINSIZE
+#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) {
+       /* we may need to truncate if hash is longer than key size */
+       word32 orderBits = mp_count_bits(&p);
+
+       /* truncate down to byte size, may be all that's needed */
+       if ( (CYASSL_BIT_SIZE * inlen) > orderBits)
+           inlen = (orderBits + CYASSL_BIT_SIZE - 1)/CYASSL_BIT_SIZE;
+       err = mp_read_unsigned_bin(&e, (byte*)in, inlen);
+
+       /* may still need bit truncation too */
+       if (err == MP_OKAY && (CYASSL_BIT_SIZE * inlen) > orderBits)
+           mp_rshb(&e, CYASSL_BIT_SIZE - (orderBits & 0x7));
+   }
+
+   /* 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);
+}
+
+
+#ifdef USE_FAST_MATH
+    #define GEN_MEM_ERR FP_MEM
+#else
+    #define GEN_MEM_ERR MP_MEM
+#endif
+
+#ifdef ECC_SHAMIR
+
+/** Computes kA*A + kB*B = C using Shamir's Trick
+  A        First point to multiply
+  kA       What to multiple A by
+  B        Second point to multiply
+  kB       What to multiple B by
+  C        [out] Destination point (can overlap with A or B)
+  modulus  Modulus for curve 
+  return MP_OKAY on success
+*/
+#ifdef FP_ECC
+static int normal_ecc_mul2add(ecc_point* A, mp_int* kA,
+                             ecc_point* B, mp_int* kB,
+                             ecc_point* C, mp_int* modulus)
+#else
+static int ecc_mul2add(ecc_point* A, mp_int* kA,
+                    ecc_point* B, mp_int* kB,
+                    ecc_point* C, mp_int* modulus)
+#endif
+{
+  ecc_point*     precomp[16];
+  unsigned       bitbufA, bitbufB, lenA, lenB, len, x, y, nA, nB, nibble;
+  unsigned char* tA;
+  unsigned char* tB;
+  int            err = MP_OKAY, first;
+  int            muInit    = 0;
+  int            tableInit = 0;
+  mp_digit mp;
+  mp_int   mu;
+ 
+  /* argchks */
+  if (A == NULL || kA == NULL || B == NULL || kB == NULL || C == NULL || 
+                   modulus == NULL)
+    return ECC_BAD_ARG_E;
+
+
+  /* allocate memory */
+  tA = XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+  if (tA == NULL) {
+     return GEN_MEM_ERR;
+  }
+  tB = XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+  if (tB == NULL) {
+     XFREE(tA, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+     return GEN_MEM_ERR;
+  }
+  XMEMSET(tA, 0, ECC_BUFSIZE);
+  XMEMSET(tB, 0, ECC_BUFSIZE);
+
+  /* get sizes */
+  lenA = mp_unsigned_bin_size(kA);
+  lenB = mp_unsigned_bin_size(kB);
+  len  = MAX(lenA, lenB);
+
+  /* sanity check */
+  if ((lenA > ECC_BUFSIZE) || (lenB > ECC_BUFSIZE)) {
+     err = BAD_FUNC_ARG;
+  }
+
+  if (err == MP_OKAY) {
+    /* extract and justify kA */
+    err = mp_to_unsigned_bin(kA, (len - lenA) + tA);
+
+    /* extract and justify kB */
+    if (err == MP_OKAY)
+        err = mp_to_unsigned_bin(kB, (len - lenB) + tB);
+
+    /* allocate the table */
+    if (err == MP_OKAY) {
+        for (x = 0; x < 16; x++) {
+            precomp[x] = ecc_new_point();
+            if (precomp[x] == NULL) {
+                for (y = 0; y < x; ++y) {
+                    ecc_del_point(precomp[y]);
+                }
+                err = GEN_MEM_ERR;
+                break;
+            }
+        }
+    }
+  }
+
+  if (err == MP_OKAY)
+    tableInit = 1;
+
+  if (err == MP_OKAY)
+   /* init montgomery reduction */
+   err = mp_montgomery_setup(modulus, &mp);
+
+  if (err == MP_OKAY)
+    err = mp_init(&mu);
+  if (err == MP_OKAY)
+    muInit = 1;
+
+  if (err == MP_OKAY)
+    err = mp_montgomery_calc_normalization(&mu, modulus);
+
+  if (err == MP_OKAY)
+    /* copy ones ... */
+    err = mp_mulmod(&A->x, &mu, modulus, &precomp[1]->x);
+
+  if (err == MP_OKAY)
+    err = mp_mulmod(&A->y, &mu, modulus, &precomp[1]->y);
+  if (err == MP_OKAY)
+    err = mp_mulmod(&A->z, &mu, modulus, &precomp[1]->z);
+
+  if (err == MP_OKAY)
+    err = mp_mulmod(&B->x, &mu, modulus, &precomp[1<<2]->x);
+  if (err == MP_OKAY)
+    err = mp_mulmod(&B->y, &mu, modulus, &precomp[1<<2]->y);
+  if (err == MP_OKAY)
+    err = mp_mulmod(&B->z, &mu, modulus, &precomp[1<<2]->z);
+
+  if (err == MP_OKAY)
+    /* precomp [i,0](A + B) table */
+    err = ecc_projective_dbl_point(precomp[1], precomp[2], modulus, &mp);
+
+  if (err == MP_OKAY)
+    err = ecc_projective_add_point(precomp[1], precomp[2], precomp[3],
+                                   modulus, &mp);
+  if (err == MP_OKAY)
+    /* precomp [0,i](A + B) table */
+    err = ecc_projective_dbl_point(precomp[1<<2], precomp[2<<2], modulus, &mp);
+
+  if (err == MP_OKAY)
+    err = ecc_projective_add_point(precomp[1<<2], precomp[2<<2], precomp[3<<2],
+                                   modulus, &mp);
+
+  if (err == MP_OKAY) {
+    /* precomp [i,j](A + B) table (i != 0, j != 0) */
+    for (x = 1; x < 4; x++) {
+        for (y = 1; y < 4; y++) {
+            if (err == MP_OKAY)
+                err = ecc_projective_add_point(precomp[x], precomp[(y<<2)],
+                                               precomp[x+(y<<2)], modulus, &mp);
+        }
+    } 
+  }  
+
+  if (err == MP_OKAY) {
+    nibble  = 3;
+    first   = 1;
+    bitbufA = tA[0];
+    bitbufB = tB[0];
+
+    /* for every byte of the multiplicands */
+    for (x = -1;; ) {
+        /* grab a nibble */
+        if (++nibble == 4) {
+            ++x; if (x == len) break;
+            bitbufA = tA[x];
+            bitbufB = tB[x];
+            nibble  = 0;
+        }
+
+        /* extract two bits from both, shift/update */
+        nA = (bitbufA >> 6) & 0x03;
+        nB = (bitbufB >> 6) & 0x03;
+        bitbufA = (bitbufA << 2) & 0xFF;   
+        bitbufB = (bitbufB << 2) & 0xFF;   
+
+        /* if both zero, if first, continue */
+        if ((nA == 0) && (nB == 0) && (first == 1)) {
+            continue;
+        }
+
+        /* double twice, only if this isn't the first */
+        if (first == 0) {
+            /* double twice */
+            if (err == MP_OKAY)
+                err = ecc_projective_dbl_point(C, C, modulus, &mp);
+            if (err == MP_OKAY)
+                err = ecc_projective_dbl_point(C, C, modulus, &mp);
+            else
+                break;
+        }
+
+        /* if not both zero */
+        if ((nA != 0) || (nB != 0)) {
+            if (first == 1) {
+                /* if first, copy from table */
+                first = 0;
+                if (err == MP_OKAY)
+                    err = mp_copy(&precomp[nA + (nB<<2)]->x, &C->x);
+
+                if (err == MP_OKAY)
+                    err = mp_copy(&precomp[nA + (nB<<2)]->y, &C->y);
+
+                if (err == MP_OKAY)
+                    err = mp_copy(&precomp[nA + (nB<<2)]->z, &C->z);
+                else
+                    break;
+            } else {
+                /* if not first, add from table */
+                if (err == MP_OKAY)
+                    err = ecc_projective_add_point(C, precomp[nA + (nB<<2)], C,
+                                                   modulus, &mp);
+                else
+                    break;
+            }
+        }
+    }
+  }
+
+  if (err == MP_OKAY)
+    /* reduce to affine */
+    err = ecc_map(C, modulus, &mp);
+
+  /* clean up */
+  if (muInit)
+    mp_clear(&mu);
+
+  if (tableInit) {
+    for (x = 0; x < 16; x++) {
+       ecc_del_point(precomp[x]);
+    }
+  }
+#ifdef ECC_CLEAN_STACK
+   XMEMSET(tA, 0, ECC_BUF_SIZE);
+   XMEMSET(tB, 0, ECC_BUF_SIZE);
+#endif
+   XFREE(tA, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+   XFREE(tB, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+   return err;
+}
+
+
+#endif /* ECC_SHAMIR */
+
+
+
+/* verify 
+ *
+ * w  = s^-1 mod n
+ * u1 = xw 
+ * u2 = rw
+ * X = u1*G + u2*Q
+ * v = X_x1 mod n
+ * accept if v == r
+ */
+
+/**
+   Verify an ECC signature
+   sig         The signature to verify
+   siglen      The length of the signature (octets)
+   hash        The hash (message digest) that was signed
+   hashlen     The length of the hash (octets)
+   stat        Result of signature, 1==valid, 0==invalid
+   key         The corresponding public ECC key
+   return      MP_OKAY if successful (even if the signature is not valid)
+*/
+int ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash,
+                    word32 hashlen, int* stat, ecc_key* key)
+{
+   ecc_point    *mG, *mQ;
+   mp_int        r;
+   mp_int        s;
+   mp_int        v;
+   mp_int        w;
+   mp_int        u1;
+   mp_int        u2;
+   mp_int        e;
+   mp_int        p;
+   mp_int        m;
+   int           err;
+
+   if (sig == NULL || hash == NULL || stat == NULL || key == NULL)
+       return ECC_BAD_ARG_E; 
+
+   /* default to invalid signature */
+   *stat = 0;
+
+   /* is the IDX valid ?  */
+   if (ecc_is_valid_idx(key->idx) != 1) {
+      return ECC_BAD_ARG_E;
+   }
+
+   /* allocate ints */
+   if ((err = mp_init_multi(&v, &w, &u1, &u2, &p, &e)) != MP_OKAY) {
+      return MEMORY_E;
+   }
+
+   if ((err = mp_init(&m)) != MP_OKAY) {
+      mp_clear(&v);
+      mp_clear(&w);
+      mp_clear(&u1);
+      mp_clear(&u2);
+      mp_clear(&p);
+      mp_clear(&e);
+      return MEMORY_E;
+   }
+
+   /* allocate points */
+   mG = ecc_new_point();
+   mQ = ecc_new_point();
+   if (mQ  == NULL || mG == NULL)
+      err = MEMORY_E;
+
+   /* Note, DecodeECC_DSA_Sig() calls mp_init() on r and s.
+    * If either of those don't allocate correctly, none of
+    * the rest of this function will execute, and everything
+    * gets cleaned up at the end. */
+   XMEMSET(&r, 0, sizeof(r));
+   XMEMSET(&s, 0, sizeof(s));
+   if (err == MP_OKAY) 
+       err = DecodeECC_DSA_Sig(sig, siglen, &r, &s);
+
+   /* get the order */
+   if (err == MP_OKAY)
+       err = mp_read_radix(&p, (char *)key->dp->order, 16);
+
+   /* get the modulus */
+   if (err == MP_OKAY)
+       err = mp_read_radix(&m, (char *)key->dp->prime, 16);
+
+   /* check for zero */
+   if (err == MP_OKAY) {
+       if (mp_iszero(&r) || mp_iszero(&s) || mp_cmp(&r, &p) != MP_LT ||
+                                             mp_cmp(&s, &p) != MP_LT)
+           err = MP_ZERO_E; 
+   }
+   /* read hash */
+   if (err == MP_OKAY) {
+       /* we may need to truncate if hash is longer than key size */
+       unsigned int orderBits = mp_count_bits(&p);
+
+       /* truncate down to byte size, may be all that's needed */
+       if ( (CYASSL_BIT_SIZE * hashlen) > orderBits)
+           hashlen = (orderBits + CYASSL_BIT_SIZE - 1)/CYASSL_BIT_SIZE;
+       err = mp_read_unsigned_bin(&e, hash, hashlen);
+
+       /* may still need bit truncation too */
+       if (err == MP_OKAY && (CYASSL_BIT_SIZE * hashlen) > orderBits)
+           mp_rshb(&e, CYASSL_BIT_SIZE - (orderBits & 0x7));
+   }
+
+   /*  w  = s^-1 mod n */
+   if (err == MP_OKAY)
+       err = mp_invmod(&s, &p, &w);
+
+   /* u1 = ew */
+   if (err == MP_OKAY)
+       err = mp_mulmod(&e, &w, &p, &u1);
+
+   /* u2 = rw */
+   if (err == MP_OKAY)
+       err = mp_mulmod(&r, &w, &p, &u2);
+
+   /* find mG and mQ */
+   if (err == MP_OKAY)
+       err = mp_read_radix(&mG->x, (char *)key->dp->Gx, 16);
+
+   if (err == MP_OKAY)
+       err = mp_read_radix(&mG->y, (char *)key->dp->Gy, 16);
+   if (err == MP_OKAY)
+       mp_set(&mG->z, 1);
+
+   if (err == MP_OKAY)
+       err = mp_copy(&key->pubkey.x, &mQ->x);
+   if (err == MP_OKAY)
+       err = mp_copy(&key->pubkey.y, &mQ->y);
+   if (err == MP_OKAY)
+       err = mp_copy(&key->pubkey.z, &mQ->z);
+
+#ifndef ECC_SHAMIR
+    {
+       mp_digit      mp;
+
+       /* compute u1*mG + u2*mQ = mG */
+       if (err == MP_OKAY)
+           err = ecc_mulmod(&u1, mG, mG, &m, 0);
+       if (err == MP_OKAY)
+           err = ecc_mulmod(&u2, mQ, mQ, &m, 0);
+  
+       /* find the montgomery mp */
+       if (err == MP_OKAY)
+           err = mp_montgomery_setup(&m, &mp);
+
+       /* add them */
+       if (err == MP_OKAY)
+           err = ecc_projective_add_point(mQ, mG, mG, &m, &mp);
+   
+       /* reduce */
+       if (err == MP_OKAY)
+           err = ecc_map(mG, &m, &mp);
+    }
+#else
+       /* use Shamir's trick to compute u1*mG + u2*mQ using half the doubles */
+       if (err == MP_OKAY)
+           err = ecc_mul2add(mG, &u1, mQ, &u2, mG, &m);
+#endif /* ECC_SHAMIR */ 
+
+   /* v = X_x1 mod n */
+   if (err == MP_OKAY)
+       err = mp_mod(&mG->x, &p, &v);
+
+   /* does v == r */
+   if (err == MP_OKAY) {
+       if (mp_cmp(&v, &r) == MP_EQ)
+           *stat = 1;
+   }
+
+   ecc_del_point(mG);
+   ecc_del_point(mQ);
+
+   mp_clear(&r);
+   mp_clear(&s);
+   mp_clear(&v);
+   mp_clear(&w);
+   mp_clear(&u1);
+   mp_clear(&u2);
+   mp_clear(&p);
+   mp_clear(&e);
+   mp_clear(&m);
+
+   return err;
+}
+
+
+/* export public ECC key in ANSI X9.63 format */
+int ecc_export_x963(ecc_key* key, byte* out, word32* outLen)
+{
+   byte   buf[ECC_BUFSIZE];
+   word32 numlen;
+   int    ret = MP_OKAY;
+
+   if (key == NULL || out == NULL || outLen == NULL)
+       return ECC_BAD_ARG_E;
+
+   if (ecc_is_valid_idx(key->idx) == 0) {
+      return ECC_BAD_ARG_E;
+   }
+   numlen = key->dp->size;
+
+   if (*outLen < (1 + 2*numlen)) {
+      *outLen = 1 + 2*numlen;
+      return BUFFER_E;
+   }
+
+   /* store byte 0x04 */
+   out[0] = 0x04;
+
+   /* pad and store x */
+   XMEMSET(buf, 0, sizeof(buf));
+   ret = mp_to_unsigned_bin(&key->pubkey.x,
+                      buf + (numlen - mp_unsigned_bin_size(&key->pubkey.x)));
+   if (ret != MP_OKAY)
+       return ret;
+   XMEMCPY(out+1, buf, numlen);
+
+   /* pad and store y */
+   XMEMSET(buf, 0, sizeof(buf));
+   ret = mp_to_unsigned_bin(&key->pubkey.y,
+                      buf + (numlen - mp_unsigned_bin_size(&key->pubkey.y)));
+   if (ret != MP_OKAY)
+       return ret;
+   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;
+}
+
+
+/* export ecc private key only raw, outLen is in/out size 
+   return MP_OKAY on success */
+int ecc_export_private_only(ecc_key* key, byte* out, word32* outLen)
+{
+   word32 numlen;
+
+   if (key == NULL || out == NULL || outLen == NULL)
+       return ECC_BAD_ARG_E;
+
+   if (ecc_is_valid_idx(key->idx) == 0) {
+      return ECC_BAD_ARG_E;
+   }
+   numlen = key->dp->size;
+
+   if (*outLen < numlen) {
+      *outLen = numlen;
+      return BUFFER_E;
+   }
+   *outLen = numlen; 
+   XMEMSET(out, 0, *outLen);
+   return mp_to_unsigned_bin(&key->k, out + (numlen -
+                                             mp_unsigned_bin_size(&key->k)));
+}
+
+
+/* ecc private key import, public key in ANSI X9.63 format, private raw */
+int 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;
+}
+
+
+/* worst case estimate, check actual return from ecc_sign_hash for actual value
+   of 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 + 4;  /* (4) worst case estimate */
+}
+
+
+#ifdef FP_ECC
+
+/* fixed point ECC cache */
+/* number of entries in the cache */
+#ifndef FP_ENTRIES
+    #define FP_ENTRIES 16
+#endif
+
+/* number of bits in LUT */
+#ifndef FP_LUT
+    #define FP_LUT     8U
+#endif
+
+#ifdef ECC_SHAMIR
+    /* Sharmir requires a bigger LUT, TAO */
+    #if (FP_LUT > 12) || (FP_LUT < 4)
+        #error FP_LUT must be between 4 and 12 inclusively
+    #endif
+#else
+    #if (FP_LUT > 12) || (FP_LUT < 2)
+        #error FP_LUT must be between 2 and 12 inclusively
+    #endif
+#endif
+
+
+/** Our FP cache */
+typedef struct {
+   ecc_point* g;               /* cached COPY of base point */
+   ecc_point* LUT[1U<<FP_LUT]; /* fixed point lookup */ 
+   mp_int     mu;              /* copy of the montgomery constant */
+   int        lru_count;       /* amount of times this entry has been used */
+   int        lock;            /* flag to indicate cache eviction */
+                               /* permitted (0) or not (1) */
+} fp_cache_t;
+
+/* if HAVE_THREAD_LS this cache is per thread, no locking needed */
+static THREAD_LS_T fp_cache_t fp_cache[FP_ENTRIES];
+
+#ifndef HAVE_THREAD_LS
+    static volatile int initMutex = 0;  /* prevent multiple mutex inits */
+    static CyaSSL_Mutex ecc_fp_lock;
+#endif /* HAVE_THREAD_LS */
+
+/* simple table to help direct the generation of the LUT */
+static const struct {
+   int ham, terma, termb;
+} lut_orders[] = {
+   { 0, 0, 0 }, { 1, 0, 0 }, { 1, 0, 0 }, { 2, 1, 2 }, { 1, 0, 0 }, { 2, 1, 4 }, { 2, 2, 4 }, { 3, 3, 4 }, 
+   { 1, 0, 0 }, { 2, 1, 8 }, { 2, 2, 8 }, { 3, 3, 8 }, { 2, 4, 8 }, { 3, 5, 8 }, { 3, 6, 8 }, { 4, 7, 8 }, 
+   { 1, 0, 0 }, { 2, 1, 16 }, { 2, 2, 16 }, { 3, 3, 16 }, { 2, 4, 16 }, { 3, 5, 16 }, { 3, 6, 16 }, { 4, 7, 16 }, 
+   { 2, 8, 16 }, { 3, 9, 16 }, { 3, 10, 16 }, { 4, 11, 16 }, { 3, 12, 16 }, { 4, 13, 16 }, { 4, 14, 16 }, { 5, 15, 16 }, 
+   { 1, 0, 0 }, { 2, 1, 32 }, { 2, 2, 32 }, { 3, 3, 32 }, { 2, 4, 32 }, { 3, 5, 32 }, { 3, 6, 32 }, { 4, 7, 32 }, 
+   { 2, 8, 32 }, { 3, 9, 32 }, { 3, 10, 32 }, { 4, 11, 32 }, { 3, 12, 32 }, { 4, 13, 32 }, { 4, 14, 32 }, { 5, 15, 32 }, 
+   { 2, 16, 32 }, { 3, 17, 32 }, { 3, 18, 32 }, { 4, 19, 32 }, { 3, 20, 32 }, { 4, 21, 32 }, { 4, 22, 32 }, { 5, 23, 32 }, 
+   { 3, 24, 32 }, { 4, 25, 32 }, { 4, 26, 32 }, { 5, 27, 32 }, { 4, 28, 32 }, { 5, 29, 32 }, { 5, 30, 32 }, { 6, 31, 32 }, 
+#if FP_LUT > 6
+   { 1, 0, 0 }, { 2, 1, 64 }, { 2, 2, 64 }, { 3, 3, 64 }, { 2, 4, 64 }, { 3, 5, 64 }, { 3, 6, 64 }, { 4, 7, 64 }, 
+   { 2, 8, 64 }, { 3, 9, 64 }, { 3, 10, 64 }, { 4, 11, 64 }, { 3, 12, 64 }, { 4, 13, 64 }, { 4, 14, 64 }, { 5, 15, 64 }, 
+   { 2, 16, 64 }, { 3, 17, 64 }, { 3, 18, 64 }, { 4, 19, 64 }, { 3, 20, 64 }, { 4, 21, 64 }, { 4, 22, 64 }, { 5, 23, 64 }, 
+   { 3, 24, 64 }, { 4, 25, 64 }, { 4, 26, 64 }, { 5, 27, 64 }, { 4, 28, 64 }, { 5, 29, 64 }, { 5, 30, 64 }, { 6, 31, 64 }, 
+   { 2, 32, 64 }, { 3, 33, 64 }, { 3, 34, 64 }, { 4, 35, 64 }, { 3, 36, 64 }, { 4, 37, 64 }, { 4, 38, 64 }, { 5, 39, 64 }, 
+   { 3, 40, 64 }, { 4, 41, 64 }, { 4, 42, 64 }, { 5, 43, 64 }, { 4, 44, 64 }, { 5, 45, 64 }, { 5, 46, 64 }, { 6, 47, 64 }, 
+   { 3, 48, 64 }, { 4, 49, 64 }, { 4, 50, 64 }, { 5, 51, 64 }, { 4, 52, 64 }, { 5, 53, 64 }, { 5, 54, 64 }, { 6, 55, 64 }, 
+   { 4, 56, 64 }, { 5, 57, 64 }, { 5, 58, 64 }, { 6, 59, 64 }, { 5, 60, 64 }, { 6, 61, 64 }, { 6, 62, 64 }, { 7, 63, 64 }, 
+#if FP_LUT > 7
+   { 1, 0, 0 }, { 2, 1, 128 }, { 2, 2, 128 }, { 3, 3, 128 }, { 2, 4, 128 }, { 3, 5, 128 }, { 3, 6, 128 }, { 4, 7, 128 }, 
+   { 2, 8, 128 }, { 3, 9, 128 }, { 3, 10, 128 }, { 4, 11, 128 }, { 3, 12, 128 }, { 4, 13, 128 }, { 4, 14, 128 }, { 5, 15, 128 }, 
+   { 2, 16, 128 }, { 3, 17, 128 }, { 3, 18, 128 }, { 4, 19, 128 }, { 3, 20, 128 }, { 4, 21, 128 }, { 4, 22, 128 }, { 5, 23, 128 }, 
+   { 3, 24, 128 }, { 4, 25, 128 }, { 4, 26, 128 }, { 5, 27, 128 }, { 4, 28, 128 }, { 5, 29, 128 }, { 5, 30, 128 }, { 6, 31, 128 }, 
+   { 2, 32, 128 }, { 3, 33, 128 }, { 3, 34, 128 }, { 4, 35, 128 }, { 3, 36, 128 }, { 4, 37, 128 }, { 4, 38, 128 }, { 5, 39, 128 }, 
+   { 3, 40, 128 }, { 4, 41, 128 }, { 4, 42, 128 }, { 5, 43, 128 }, { 4, 44, 128 }, { 5, 45, 128 }, { 5, 46, 128 }, { 6, 47, 128 }, 
+   { 3, 48, 128 }, { 4, 49, 128 }, { 4, 50, 128 }, { 5, 51, 128 }, { 4, 52, 128 }, { 5, 53, 128 }, { 5, 54, 128 }, { 6, 55, 128 }, 
+   { 4, 56, 128 }, { 5, 57, 128 }, { 5, 58, 128 }, { 6, 59, 128 }, { 5, 60, 128 }, { 6, 61, 128 }, { 6, 62, 128 }, { 7, 63, 128 }, 
+   { 2, 64, 128 }, { 3, 65, 128 }, { 3, 66, 128 }, { 4, 67, 128 }, { 3, 68, 128 }, { 4, 69, 128 }, { 4, 70, 128 }, { 5, 71, 128 }, 
+   { 3, 72, 128 }, { 4, 73, 128 }, { 4, 74, 128 }, { 5, 75, 128 }, { 4, 76, 128 }, { 5, 77, 128 }, { 5, 78, 128 }, { 6, 79, 128 }, 
+   { 3, 80, 128 }, { 4, 81, 128 }, { 4, 82, 128 }, { 5, 83, 128 }, { 4, 84, 128 }, { 5, 85, 128 }, { 5, 86, 128 }, { 6, 87, 128 }, 
+   { 4, 88, 128 }, { 5, 89, 128 }, { 5, 90, 128 }, { 6, 91, 128 }, { 5, 92, 128 }, { 6, 93, 128 }, { 6, 94, 128 }, { 7, 95, 128 }, 
+   { 3, 96, 128 }, { 4, 97, 128 }, { 4, 98, 128 }, { 5, 99, 128 }, { 4, 100, 128 }, { 5, 101, 128 }, { 5, 102, 128 }, { 6, 103, 128 }, 
+   { 4, 104, 128 }, { 5, 105, 128 }, { 5, 106, 128 }, { 6, 107, 128 }, { 5, 108, 128 }, { 6, 109, 128 }, { 6, 110, 128 }, { 7, 111, 128 }, 
+   { 4, 112, 128 }, { 5, 113, 128 }, { 5, 114, 128 }, { 6, 115, 128 }, { 5, 116, 128 }, { 6, 117, 128 }, { 6, 118, 128 }, { 7, 119, 128 }, 
+   { 5, 120, 128 }, { 6, 121, 128 }, { 6, 122, 128 }, { 7, 123, 128 }, { 6, 124, 128 }, { 7, 125, 128 }, { 7, 126, 128 }, { 8, 127, 128 }, 
+#if FP_LUT > 8
+   { 1, 0, 0 }, { 2, 1, 256 }, { 2, 2, 256 }, { 3, 3, 256 }, { 2, 4, 256 }, { 3, 5, 256 }, { 3, 6, 256 }, { 4, 7, 256 }, 
+   { 2, 8, 256 }, { 3, 9, 256 }, { 3, 10, 256 }, { 4, 11, 256 }, { 3, 12, 256 }, { 4, 13, 256 }, { 4, 14, 256 }, { 5, 15, 256 }, 
+   { 2, 16, 256 }, { 3, 17, 256 }, { 3, 18, 256 }, { 4, 19, 256 }, { 3, 20, 256 }, { 4, 21, 256 }, { 4, 22, 256 }, { 5, 23, 256 }, 
+   { 3, 24, 256 }, { 4, 25, 256 }, { 4, 26, 256 }, { 5, 27, 256 }, { 4, 28, 256 }, { 5, 29, 256 }, { 5, 30, 256 }, { 6, 31, 256 }, 
+   { 2, 32, 256 }, { 3, 33, 256 }, { 3, 34, 256 }, { 4, 35, 256 }, { 3, 36, 256 }, { 4, 37, 256 }, { 4, 38, 256 }, { 5, 39, 256 }, 
+   { 3, 40, 256 }, { 4, 41, 256 }, { 4, 42, 256 }, { 5, 43, 256 }, { 4, 44, 256 }, { 5, 45, 256 }, { 5, 46, 256 }, { 6, 47, 256 }, 
+   { 3, 48, 256 }, { 4, 49, 256 }, { 4, 50, 256 }, { 5, 51, 256 }, { 4, 52, 256 }, { 5, 53, 256 }, { 5, 54, 256 }, { 6, 55, 256 }, 
+   { 4, 56, 256 }, { 5, 57, 256 }, { 5, 58, 256 }, { 6, 59, 256 }, { 5, 60, 256 }, { 6, 61, 256 }, { 6, 62, 256 }, { 7, 63, 256 }, 
+   { 2, 64, 256 }, { 3, 65, 256 }, { 3, 66, 256 }, { 4, 67, 256 }, { 3, 68, 256 }, { 4, 69, 256 }, { 4, 70, 256 }, { 5, 71, 256 }, 
+   { 3, 72, 256 }, { 4, 73, 256 }, { 4, 74, 256 }, { 5, 75, 256 }, { 4, 76, 256 }, { 5, 77, 256 }, { 5, 78, 256 }, { 6, 79, 256 }, 
+   { 3, 80, 256 }, { 4, 81, 256 }, { 4, 82, 256 }, { 5, 83, 256 }, { 4, 84, 256 }, { 5, 85, 256 }, { 5, 86, 256 }, { 6, 87, 256 }, 
+   { 4, 88, 256 }, { 5, 89, 256 }, { 5, 90, 256 }, { 6, 91, 256 }, { 5, 92, 256 }, { 6, 93, 256 }, { 6, 94, 256 }, { 7, 95, 256 }, 
+   { 3, 96, 256 }, { 4, 97, 256 }, { 4, 98, 256 }, { 5, 99, 256 }, { 4, 100, 256 }, { 5, 101, 256 }, { 5, 102, 256 }, { 6, 103, 256 }, 
+   { 4, 104, 256 }, { 5, 105, 256 }, { 5, 106, 256 }, { 6, 107, 256 }, { 5, 108, 256 }, { 6, 109, 256 }, { 6, 110, 256 }, { 7, 111, 256 }, 
+   { 4, 112, 256 }, { 5, 113, 256 }, { 5, 114, 256 }, { 6, 115, 256 }, { 5, 116, 256 }, { 6, 117, 256 }, { 6, 118, 256 }, { 7, 119, 256 }, 
+   { 5, 120, 256 }, { 6, 121, 256 }, { 6, 122, 256 }, { 7, 123, 256 }, { 6, 124, 256 }, { 7, 125, 256 }, { 7, 126, 256 }, { 8, 127, 256 }, 
+   { 2, 128, 256 }, { 3, 129, 256 }, { 3, 130, 256 }, { 4, 131, 256 }, { 3, 132, 256 }, { 4, 133, 256 }, { 4, 134, 256 }, { 5, 135, 256 }, 
+   { 3, 136, 256 }, { 4, 137, 256 }, { 4, 138, 256 }, { 5, 139, 256 }, { 4, 140, 256 }, { 5, 141, 256 }, { 5, 142, 256 }, { 6, 143, 256 }, 
+   { 3, 144, 256 }, { 4, 145, 256 }, { 4, 146, 256 }, { 5, 147, 256 }, { 4, 148, 256 }, { 5, 149, 256 }, { 5, 150, 256 }, { 6, 151, 256 }, 
+   { 4, 152, 256 }, { 5, 153, 256 }, { 5, 154, 256 }, { 6, 155, 256 }, { 5, 156, 256 }, { 6, 157, 256 }, { 6, 158, 256 }, { 7, 159, 256 }, 
+   { 3, 160, 256 }, { 4, 161, 256 }, { 4, 162, 256 }, { 5, 163, 256 }, { 4, 164, 256 }, { 5, 165, 256 }, { 5, 166, 256 }, { 6, 167, 256 }, 
+   { 4, 168, 256 }, { 5, 169, 256 }, { 5, 170, 256 }, { 6, 171, 256 }, { 5, 172, 256 }, { 6, 173, 256 }, { 6, 174, 256 }, { 7, 175, 256 }, 
+   { 4, 176, 256 }, { 5, 177, 256 }, { 5, 178, 256 }, { 6, 179, 256 }, { 5, 180, 256 }, { 6, 181, 256 }, { 6, 182, 256 }, { 7, 183, 256 }, 
+   { 5, 184, 256 }, { 6, 185, 256 }, { 6, 186, 256 }, { 7, 187, 256 }, { 6, 188, 256 }, { 7, 189, 256 }, { 7, 190, 256 }, { 8, 191, 256 }, 
+   { 3, 192, 256 }, { 4, 193, 256 }, { 4, 194, 256 }, { 5, 195, 256 }, { 4, 196, 256 }, { 5, 197, 256 }, { 5, 198, 256 }, { 6, 199, 256 }, 
+   { 4, 200, 256 }, { 5, 201, 256 }, { 5, 202, 256 }, { 6, 203, 256 }, { 5, 204, 256 }, { 6, 205, 256 }, { 6, 206, 256 }, { 7, 207, 256 }, 
+   { 4, 208, 256 }, { 5, 209, 256 }, { 5, 210, 256 }, { 6, 211, 256 }, { 5, 212, 256 }, { 6, 213, 256 }, { 6, 214, 256 }, { 7, 215, 256 }, 
+   { 5, 216, 256 }, { 6, 217, 256 }, { 6, 218, 256 }, { 7, 219, 256 }, { 6, 220, 256 }, { 7, 221, 256 }, { 7, 222, 256 }, { 8, 223, 256 }, 
+   { 4, 224, 256 }, { 5, 225, 256 }, { 5, 226, 256 }, { 6, 227, 256 }, { 5, 228, 256 }, { 6, 229, 256 }, { 6, 230, 256 }, { 7, 231, 256 }, 
+   { 5, 232, 256 }, { 6, 233, 256 }, { 6, 234, 256 }, { 7, 235, 256 }, { 6, 236, 256 }, { 7, 237, 256 }, { 7, 238, 256 }, { 8, 239, 256 }, 
+   { 5, 240, 256 }, { 6, 241, 256 }, { 6, 242, 256 }, { 7, 243, 256 }, { 6, 244, 256 }, { 7, 245, 256 }, { 7, 246, 256 }, { 8, 247, 256 }, 
+   { 6, 248, 256 }, { 7, 249, 256 }, { 7, 250, 256 }, { 8, 251, 256 }, { 7, 252, 256 }, { 8, 253, 256 }, { 8, 254, 256 }, { 9, 255, 256 }, 
+#if FP_LUT > 9
+   { 1, 0, 0 }, { 2, 1, 512 }, { 2, 2, 512 }, { 3, 3, 512 }, { 2, 4, 512 }, { 3, 5, 512 }, { 3, 6, 512 }, { 4, 7, 512 }, 
+   { 2, 8, 512 }, { 3, 9, 512 }, { 3, 10, 512 }, { 4, 11, 512 }, { 3, 12, 512 }, { 4, 13, 512 }, { 4, 14, 512 }, { 5, 15, 512 }, 
+   { 2, 16, 512 }, { 3, 17, 512 }, { 3, 18, 512 }, { 4, 19, 512 }, { 3, 20, 512 }, { 4, 21, 512 }, { 4, 22, 512 }, { 5, 23, 512 }, 
+   { 3, 24, 512 }, { 4, 25, 512 }, { 4, 26, 512 }, { 5, 27, 512 }, { 4, 28, 512 }, { 5, 29, 512 }, { 5, 30, 512 }, { 6, 31, 512 }, 
+   { 2, 32, 512 }, { 3, 33, 512 }, { 3, 34, 512 }, { 4, 35, 512 }, { 3, 36, 512 }, { 4, 37, 512 }, { 4, 38, 512 }, { 5, 39, 512 }, 
+   { 3, 40, 512 }, { 4, 41, 512 }, { 4, 42, 512 }, { 5, 43, 512 }, { 4, 44, 512 }, { 5, 45, 512 }, { 5, 46, 512 }, { 6, 47, 512 }, 
+   { 3, 48, 512 }, { 4, 49, 512 }, { 4, 50, 512 }, { 5, 51, 512 }, { 4, 52, 512 }, { 5, 53, 512 }, { 5, 54, 512 }, { 6, 55, 512 }, 
+   { 4, 56, 512 }, { 5, 57, 512 }, { 5, 58, 512 }, { 6, 59, 512 }, { 5, 60, 512 }, { 6, 61, 512 }, { 6, 62, 512 }, { 7, 63, 512 }, 
+   { 2, 64, 512 }, { 3, 65, 512 }, { 3, 66, 512 }, { 4, 67, 512 }, { 3, 68, 512 }, { 4, 69, 512 }, { 4, 70, 512 }, { 5, 71, 512 }, 
+   { 3, 72, 512 }, { 4, 73, 512 }, { 4, 74, 512 }, { 5, 75, 512 }, { 4, 76, 512 }, { 5, 77, 512 }, { 5, 78, 512 }, { 6, 79, 512 }, 
+   { 3, 80, 512 }, { 4, 81, 512 }, { 4, 82, 512 }, { 5, 83, 512 }, { 4, 84, 512 }, { 5, 85, 512 }, { 5, 86, 512 }, { 6, 87, 512 }, 
+   { 4, 88, 512 }, { 5, 89, 512 }, { 5, 90, 512 }, { 6, 91, 512 }, { 5, 92, 512 }, { 6, 93, 512 }, { 6, 94, 512 }, { 7, 95, 512 }, 
+   { 3, 96, 512 }, { 4, 97, 512 }, { 4, 98, 512 }, { 5, 99, 512 }, { 4, 100, 512 }, { 5, 101, 512 }, { 5, 102, 512 }, { 6, 103, 512 }, 
+   { 4, 104, 512 }, { 5, 105, 512 }, { 5, 106, 512 }, { 6, 107, 512 }, { 5, 108, 512 }, { 6, 109, 512 }, { 6, 110, 512 }, { 7, 111, 512 }, 
+   { 4, 112, 512 }, { 5, 113, 512 }, { 5, 114, 512 }, { 6, 115, 512 }, { 5, 116, 512 }, { 6, 117, 512 }, { 6, 118, 512 }, { 7, 119, 512 }, 
+   { 5, 120, 512 }, { 6, 121, 512 }, { 6, 122, 512 }, { 7, 123, 512 }, { 6, 124, 512 }, { 7, 125, 512 }, { 7, 126, 512 }, { 8, 127, 512 }, 
+   { 2, 128, 512 }, { 3, 129, 512 }, { 3, 130, 512 }, { 4, 131, 512 }, { 3, 132, 512 }, { 4, 133, 512 }, { 4, 134, 512 }, { 5, 135, 512 }, 
+   { 3, 136, 512 }, { 4, 137, 512 }, { 4, 138, 512 }, { 5, 139, 512 }, { 4, 140, 512 }, { 5, 141, 512 }, { 5, 142, 512 }, { 6, 143, 512 }, 
+   { 3, 144, 512 }, { 4, 145, 512 }, { 4, 146, 512 }, { 5, 147, 512 }, { 4, 148, 512 }, { 5, 149, 512 }, { 5, 150, 512 }, { 6, 151, 512 }, 
+   { 4, 152, 512 }, { 5, 153, 512 }, { 5, 154, 512 }, { 6, 155, 512 }, { 5, 156, 512 }, { 6, 157, 512 }, { 6, 158, 512 }, { 7, 159, 512 }, 
+   { 3, 160, 512 }, { 4, 161, 512 }, { 4, 162, 512 }, { 5, 163, 512 }, { 4, 164, 512 }, { 5, 165, 512 }, { 5, 166, 512 }, { 6, 167, 512 }, 
+   { 4, 168, 512 }, { 5, 169, 512 }, { 5, 170, 512 }, { 6, 171, 512 }, { 5, 172, 512 }, { 6, 173, 512 }, { 6, 174, 512 }, { 7, 175, 512 }, 
+   { 4, 176, 512 }, { 5, 177, 512 }, { 5, 178, 512 }, { 6, 179, 512 }, { 5, 180, 512 }, { 6, 181, 512 }, { 6, 182, 512 }, { 7, 183, 512 }, 
+   { 5, 184, 512 }, { 6, 185, 512 }, { 6, 186, 512 }, { 7, 187, 512 }, { 6, 188, 512 }, { 7, 189, 512 }, { 7, 190, 512 }, { 8, 191, 512 }, 
+   { 3, 192, 512 }, { 4, 193, 512 }, { 4, 194, 512 }, { 5, 195, 512 }, { 4, 196, 512 }, { 5, 197, 512 }, { 5, 198, 512 }, { 6, 199, 512 }, 
+   { 4, 200, 512 }, { 5, 201, 512 }, { 5, 202, 512 }, { 6, 203, 512 }, { 5, 204, 512 }, { 6, 205, 512 }, { 6, 206, 512 }, { 7, 207, 512 }, 
+   { 4, 208, 512 }, { 5, 209, 512 }, { 5, 210, 512 }, { 6, 211, 512 }, { 5, 212, 512 }, { 6, 213, 512 }, { 6, 214, 512 }, { 7, 215, 512 }, 
+   { 5, 216, 512 }, { 6, 217, 512 }, { 6, 218, 512 }, { 7, 219, 512 }, { 6, 220, 512 }, { 7, 221, 512 }, { 7, 222, 512 }, { 8, 223, 512 }, 
+   { 4, 224, 512 }, { 5, 225, 512 }, { 5, 226, 512 }, { 6, 227, 512 }, { 5, 228, 512 }, { 6, 229, 512 }, { 6, 230, 512 }, { 7, 231, 512 }, 
+   { 5, 232, 512 }, { 6, 233, 512 }, { 6, 234, 512 }, { 7, 235, 512 }, { 6, 236, 512 }, { 7, 237, 512 }, { 7, 238, 512 }, { 8, 239, 512 }, 
+   { 5, 240, 512 }, { 6, 241, 512 }, { 6, 242, 512 }, { 7, 243, 512 }, { 6, 244, 512 }, { 7, 245, 512 }, { 7, 246, 512 }, { 8, 247, 512 }, 
+   { 6, 248, 512 }, { 7, 249, 512 }, { 7, 250, 512 }, { 8, 251, 512 }, { 7, 252, 512 }, { 8, 253, 512 }, { 8, 254, 512 }, { 9, 255, 512 }, 
+   { 2, 256, 512 }, { 3, 257, 512 }, { 3, 258, 512 }, { 4, 259, 512 }, { 3, 260, 512 }, { 4, 261, 512 }, { 4, 262, 512 }, { 5, 263, 512 }, 
+   { 3, 264, 512 }, { 4, 265, 512 }, { 4, 266, 512 }, { 5, 267, 512 }, { 4, 268, 512 }, { 5, 269, 512 }, { 5, 270, 512 }, { 6, 271, 512 }, 
+   { 3, 272, 512 }, { 4, 273, 512 }, { 4, 274, 512 }, { 5, 275, 512 }, { 4, 276, 512 }, { 5, 277, 512 }, { 5, 278, 512 }, { 6, 279, 512 }, 
+   { 4, 280, 512 }, { 5, 281, 512 }, { 5, 282, 512 }, { 6, 283, 512 }, { 5, 284, 512 }, { 6, 285, 512 }, { 6, 286, 512 }, { 7, 287, 512 }, 
+   { 3, 288, 512 }, { 4, 289, 512 }, { 4, 290, 512 }, { 5, 291, 512 }, { 4, 292, 512 }, { 5, 293, 512 }, { 5, 294, 512 }, { 6, 295, 512 }, 
+   { 4, 296, 512 }, { 5, 297, 512 }, { 5, 298, 512 }, { 6, 299, 512 }, { 5, 300, 512 }, { 6, 301, 512 }, { 6, 302, 512 }, { 7, 303, 512 }, 
+   { 4, 304, 512 }, { 5, 305, 512 }, { 5, 306, 512 }, { 6, 307, 512 }, { 5, 308, 512 }, { 6, 309, 512 }, { 6, 310, 512 }, { 7, 311, 512 }, 
+   { 5, 312, 512 }, { 6, 313, 512 }, { 6, 314, 512 }, { 7, 315, 512 }, { 6, 316, 512 }, { 7, 317, 512 }, { 7, 318, 512 }, { 8, 319, 512 }, 
+   { 3, 320, 512 }, { 4, 321, 512 }, { 4, 322, 512 }, { 5, 323, 512 }, { 4, 324, 512 }, { 5, 325, 512 }, { 5, 326, 512 }, { 6, 327, 512 }, 
+   { 4, 328, 512 }, { 5, 329, 512 }, { 5, 330, 512 }, { 6, 331, 512 }, { 5, 332, 512 }, { 6, 333, 512 }, { 6, 334, 512 }, { 7, 335, 512 }, 
+   { 4, 336, 512 }, { 5, 337, 512 }, { 5, 338, 512 }, { 6, 339, 512 }, { 5, 340, 512 }, { 6, 341, 512 }, { 6, 342, 512 }, { 7, 343, 512 }, 
+   { 5, 344, 512 }, { 6, 345, 512 }, { 6, 346, 512 }, { 7, 347, 512 }, { 6, 348, 512 }, { 7, 349, 512 }, { 7, 350, 512 }, { 8, 351, 512 }, 
+   { 4, 352, 512 }, { 5, 353, 512 }, { 5, 354, 512 }, { 6, 355, 512 }, { 5, 356, 512 }, { 6, 357, 512 }, { 6, 358, 512 }, { 7, 359, 512 }, 
+   { 5, 360, 512 }, { 6, 361, 512 }, { 6, 362, 512 }, { 7, 363, 512 }, { 6, 364, 512 }, { 7, 365, 512 }, { 7, 366, 512 }, { 8, 367, 512 }, 
+   { 5, 368, 512 }, { 6, 369, 512 }, { 6, 370, 512 }, { 7, 371, 512 }, { 6, 372, 512 }, { 7, 373, 512 }, { 7, 374, 512 }, { 8, 375, 512 }, 
+   { 6, 376, 512 }, { 7, 377, 512 }, { 7, 378, 512 }, { 8, 379, 512 }, { 7, 380, 512 }, { 8, 381, 512 }, { 8, 382, 512 }, { 9, 383, 512 }, 
+   { 3, 384, 512 }, { 4, 385, 512 }, { 4, 386, 512 }, { 5, 387, 512 }, { 4, 388, 512 }, { 5, 389, 512 }, { 5, 390, 512 }, { 6, 391, 512 }, 
+   { 4, 392, 512 }, { 5, 393, 512 }, { 5, 394, 512 }, { 6, 395, 512 }, { 5, 396, 512 }, { 6, 397, 512 }, { 6, 398, 512 }, { 7, 399, 512 }, 
+   { 4, 400, 512 }, { 5, 401, 512 }, { 5, 402, 512 }, { 6, 403, 512 }, { 5, 404, 512 }, { 6, 405, 512 }, { 6, 406, 512 }, { 7, 407, 512 }, 
+   { 5, 408, 512 }, { 6, 409, 512 }, { 6, 410, 512 }, { 7, 411, 512 }, { 6, 412, 512 }, { 7, 413, 512 }, { 7, 414, 512 }, { 8, 415, 512 }, 
+   { 4, 416, 512 }, { 5, 417, 512 }, { 5, 418, 512 }, { 6, 419, 512 }, { 5, 420, 512 }, { 6, 421, 512 }, { 6, 422, 512 }, { 7, 423, 512 }, 
+   { 5, 424, 512 }, { 6, 425, 512 }, { 6, 426, 512 }, { 7, 427, 512 }, { 6, 428, 512 }, { 7, 429, 512 }, { 7, 430, 512 }, { 8, 431, 512 }, 
+   { 5, 432, 512 }, { 6, 433, 512 }, { 6, 434, 512 }, { 7, 435, 512 }, { 6, 436, 512 }, { 7, 437, 512 }, { 7, 438, 512 }, { 8, 439, 512 }, 
+   { 6, 440, 512 }, { 7, 441, 512 }, { 7, 442, 512 }, { 8, 443, 512 }, { 7, 444, 512 }, { 8, 445, 512 }, { 8, 446, 512 }, { 9, 447, 512 }, 
+   { 4, 448, 512 }, { 5, 449, 512 }, { 5, 450, 512 }, { 6, 451, 512 }, { 5, 452, 512 }, { 6, 453, 512 }, { 6, 454, 512 }, { 7, 455, 512 }, 
+   { 5, 456, 512 }, { 6, 457, 512 }, { 6, 458, 512 }, { 7, 459, 512 }, { 6, 460, 512 }, { 7, 461, 512 }, { 7, 462, 512 }, { 8, 463, 512 }, 
+   { 5, 464, 512 }, { 6, 465, 512 }, { 6, 466, 512 }, { 7, 467, 512 }, { 6, 468, 512 }, { 7, 469, 512 }, { 7, 470, 512 }, { 8, 471, 512 }, 
+   { 6, 472, 512 }, { 7, 473, 512 }, { 7, 474, 512 }, { 8, 475, 512 }, { 7, 476, 512 }, { 8, 477, 512 }, { 8, 478, 512 }, { 9, 479, 512 }, 
+   { 5, 480, 512 }, { 6, 481, 512 }, { 6, 482, 512 }, { 7, 483, 512 }, { 6, 484, 512 }, { 7, 485, 512 }, { 7, 486, 512 }, { 8, 487, 512 }, 
+   { 6, 488, 512 }, { 7, 489, 512 }, { 7, 490, 512 }, { 8, 491, 512 }, { 7, 492, 512 }, { 8, 493, 512 }, { 8, 494, 512 }, { 9, 495, 512 }, 
+   { 6, 496, 512 }, { 7, 497, 512 }, { 7, 498, 512 }, { 8, 499, 512 }, { 7, 500, 512 }, { 8, 501, 512 }, { 8, 502, 512 }, { 9, 503, 512 }, 
+   { 7, 504, 512 }, { 8, 505, 512 }, { 8, 506, 512 }, { 9, 507, 512 }, { 8, 508, 512 }, { 9, 509, 512 }, { 9, 510, 512 }, { 10, 511, 512 }, 
+#if FP_LUT > 10
+   { 1, 0, 0 }, { 2, 1, 1024 }, { 2, 2, 1024 }, { 3, 3, 1024 }, { 2, 4, 1024 }, { 3, 5, 1024 }, { 3, 6, 1024 }, { 4, 7, 1024 }, 
+   { 2, 8, 1024 }, { 3, 9, 1024 }, { 3, 10, 1024 }, { 4, 11, 1024 }, { 3, 12, 1024 }, { 4, 13, 1024 }, { 4, 14, 1024 }, { 5, 15, 1024 }, 
+   { 2, 16, 1024 }, { 3, 17, 1024 }, { 3, 18, 1024 }, { 4, 19, 1024 }, { 3, 20, 1024 }, { 4, 21, 1024 }, { 4, 22, 1024 }, { 5, 23, 1024 }, 
+   { 3, 24, 1024 }, { 4, 25, 1024 }, { 4, 26, 1024 }, { 5, 27, 1024 }, { 4, 28, 1024 }, { 5, 29, 1024 }, { 5, 30, 1024 }, { 6, 31, 1024 }, 
+   { 2, 32, 1024 }, { 3, 33, 1024 }, { 3, 34, 1024 }, { 4, 35, 1024 }, { 3, 36, 1024 }, { 4, 37, 1024 }, { 4, 38, 1024 }, { 5, 39, 1024 }, 
+   { 3, 40, 1024 }, { 4, 41, 1024 }, { 4, 42, 1024 }, { 5, 43, 1024 }, { 4, 44, 1024 }, { 5, 45, 1024 }, { 5, 46, 1024 }, { 6, 47, 1024 }, 
+   { 3, 48, 1024 }, { 4, 49, 1024 }, { 4, 50, 1024 }, { 5, 51, 1024 }, { 4, 52, 1024 }, { 5, 53, 1024 }, { 5, 54, 1024 }, { 6, 55, 1024 }, 
+   { 4, 56, 1024 }, { 5, 57, 1024 }, { 5, 58, 1024 }, { 6, 59, 1024 }, { 5, 60, 1024 }, { 6, 61, 1024 }, { 6, 62, 1024 }, { 7, 63, 1024 }, 
+   { 2, 64, 1024 }, { 3, 65, 1024 }, { 3, 66, 1024 }, { 4, 67, 1024 }, { 3, 68, 1024 }, { 4, 69, 1024 }, { 4, 70, 1024 }, { 5, 71, 1024 }, 
+   { 3, 72, 1024 }, { 4, 73, 1024 }, { 4, 74, 1024 }, { 5, 75, 1024 }, { 4, 76, 1024 }, { 5, 77, 1024 }, { 5, 78, 1024 }, { 6, 79, 1024 }, 
+   { 3, 80, 1024 }, { 4, 81, 1024 }, { 4, 82, 1024 }, { 5, 83, 1024 }, { 4, 84, 1024 }, { 5, 85, 1024 }, { 5, 86, 1024 }, { 6, 87, 1024 }, 
+   { 4, 88, 1024 }, { 5, 89, 1024 }, { 5, 90, 1024 }, { 6, 91, 1024 }, { 5, 92, 1024 }, { 6, 93, 1024 }, { 6, 94, 1024 }, { 7, 95, 1024 }, 
+   { 3, 96, 1024 }, { 4, 97, 1024 }, { 4, 98, 1024 }, { 5, 99, 1024 }, { 4, 100, 1024 }, { 5, 101, 1024 }, { 5, 102, 1024 }, { 6, 103, 1024 }, 
+   { 4, 104, 1024 }, { 5, 105, 1024 }, { 5, 106, 1024 }, { 6, 107, 1024 }, { 5, 108, 1024 }, { 6, 109, 1024 }, { 6, 110, 1024 }, { 7, 111, 1024 }, 
+   { 4, 112, 1024 }, { 5, 113, 1024 }, { 5, 114, 1024 }, { 6, 115, 1024 }, { 5, 116, 1024 }, { 6, 117, 1024 }, { 6, 118, 1024 }, { 7, 119, 1024 }, 
+   { 5, 120, 1024 }, { 6, 121, 1024 }, { 6, 122, 1024 }, { 7, 123, 1024 }, { 6, 124, 1024 }, { 7, 125, 1024 }, { 7, 126, 1024 }, { 8, 127, 1024 }, 
+   { 2, 128, 1024 }, { 3, 129, 1024 }, { 3, 130, 1024 }, { 4, 131, 1024 }, { 3, 132, 1024 }, { 4, 133, 1024 }, { 4, 134, 1024 }, { 5, 135, 1024 }, 
+   { 3, 136, 1024 }, { 4, 137, 1024 }, { 4, 138, 1024 }, { 5, 139, 1024 }, { 4, 140, 1024 }, { 5, 141, 1024 }, { 5, 142, 1024 }, { 6, 143, 1024 }, 
+   { 3, 144, 1024 }, { 4, 145, 1024 }, { 4, 146, 1024 }, { 5, 147, 1024 }, { 4, 148, 1024 }, { 5, 149, 1024 }, { 5, 150, 1024 }, { 6, 151, 1024 }, 
+   { 4, 152, 1024 }, { 5, 153, 1024 }, { 5, 154, 1024 }, { 6, 155, 1024 }, { 5, 156, 1024 }, { 6, 157, 1024 }, { 6, 158, 1024 }, { 7, 159, 1024 }, 
+   { 3, 160, 1024 }, { 4, 161, 1024 }, { 4, 162, 1024 }, { 5, 163, 1024 }, { 4, 164, 1024 }, { 5, 165, 1024 }, { 5, 166, 1024 }, { 6, 167, 1024 }, 
+   { 4, 168, 1024 }, { 5, 169, 1024 }, { 5, 170, 1024 }, { 6, 171, 1024 }, { 5, 172, 1024 }, { 6, 173, 1024 }, { 6, 174, 1024 }, { 7, 175, 1024 }, 
+   { 4, 176, 1024 }, { 5, 177, 1024 }, { 5, 178, 1024 }, { 6, 179, 1024 }, { 5, 180, 1024 }, { 6, 181, 1024 }, { 6, 182, 1024 }, { 7, 183, 1024 }, 
+   { 5, 184, 1024 }, { 6, 185, 1024 }, { 6, 186, 1024 }, { 7, 187, 1024 }, { 6, 188, 1024 }, { 7, 189, 1024 }, { 7, 190, 1024 }, { 8, 191, 1024 }, 
+   { 3, 192, 1024 }, { 4, 193, 1024 }, { 4, 194, 1024 }, { 5, 195, 1024 }, { 4, 196, 1024 }, { 5, 197, 1024 }, { 5, 198, 1024 }, { 6, 199, 1024 }, 
+   { 4, 200, 1024 }, { 5, 201, 1024 }, { 5, 202, 1024 }, { 6, 203, 1024 }, { 5, 204, 1024 }, { 6, 205, 1024 }, { 6, 206, 1024 }, { 7, 207, 1024 }, 
+   { 4, 208, 1024 }, { 5, 209, 1024 }, { 5, 210, 1024 }, { 6, 211, 1024 }, { 5, 212, 1024 }, { 6, 213, 1024 }, { 6, 214, 1024 }, { 7, 215, 1024 }, 
+   { 5, 216, 1024 }, { 6, 217, 1024 }, { 6, 218, 1024 }, { 7, 219, 1024 }, { 6, 220, 1024 }, { 7, 221, 1024 }, { 7, 222, 1024 }, { 8, 223, 1024 }, 
+   { 4, 224, 1024 }, { 5, 225, 1024 }, { 5, 226, 1024 }, { 6, 227, 1024 }, { 5, 228, 1024 }, { 6, 229, 1024 }, { 6, 230, 1024 }, { 7, 231, 1024 }, 
+   { 5, 232, 1024 }, { 6, 233, 1024 }, { 6, 234, 1024 }, { 7, 235, 1024 }, { 6, 236, 1024 }, { 7, 237, 1024 }, { 7, 238, 1024 }, { 8, 239, 1024 }, 
+   { 5, 240, 1024 }, { 6, 241, 1024 }, { 6, 242, 1024 }, { 7, 243, 1024 }, { 6, 244, 1024 }, { 7, 245, 1024 }, { 7, 246, 1024 }, { 8, 247, 1024 }, 
+   { 6, 248, 1024 }, { 7, 249, 1024 }, { 7, 250, 1024 }, { 8, 251, 1024 }, { 7, 252, 1024 }, { 8, 253, 1024 }, { 8, 254, 1024 }, { 9, 255, 1024 }, 
+   { 2, 256, 1024 }, { 3, 257, 1024 }, { 3, 258, 1024 }, { 4, 259, 1024 }, { 3, 260, 1024 }, { 4, 261, 1024 }, { 4, 262, 1024 }, { 5, 263, 1024 }, 
+   { 3, 264, 1024 }, { 4, 265, 1024 }, { 4, 266, 1024 }, { 5, 267, 1024 }, { 4, 268, 1024 }, { 5, 269, 1024 }, { 5, 270, 1024 }, { 6, 271, 1024 }, 
+   { 3, 272, 1024 }, { 4, 273, 1024 }, { 4, 274, 1024 }, { 5, 275, 1024 }, { 4, 276, 1024 }, { 5, 277, 1024 }, { 5, 278, 1024 }, { 6, 279, 1024 }, 
+   { 4, 280, 1024 }, { 5, 281, 1024 }, { 5, 282, 1024 }, { 6, 283, 1024 }, { 5, 284, 1024 }, { 6, 285, 1024 }, { 6, 286, 1024 }, { 7, 287, 1024 }, 
+   { 3, 288, 1024 }, { 4, 289, 1024 }, { 4, 290, 1024 }, { 5, 291, 1024 }, { 4, 292, 1024 }, { 5, 293, 1024 }, { 5, 294, 1024 }, { 6, 295, 1024 }, 
+   { 4, 296, 1024 }, { 5, 297, 1024 }, { 5, 298, 1024 }, { 6, 299, 1024 }, { 5, 300, 1024 }, { 6, 301, 1024 }, { 6, 302, 1024 }, { 7, 303, 1024 }, 
+   { 4, 304, 1024 }, { 5, 305, 1024 }, { 5, 306, 1024 }, { 6, 307, 1024 }, { 5, 308, 1024 }, { 6, 309, 1024 }, { 6, 310, 1024 }, { 7, 311, 1024 }, 
+   { 5, 312, 1024 }, { 6, 313, 1024 }, { 6, 314, 1024 }, { 7, 315, 1024 }, { 6, 316, 1024 }, { 7, 317, 1024 }, { 7, 318, 1024 }, { 8, 319, 1024 }, 
+   { 3, 320, 1024 }, { 4, 321, 1024 }, { 4, 322, 1024 }, { 5, 323, 1024 }, { 4, 324, 1024 }, { 5, 325, 1024 }, { 5, 326, 1024 }, { 6, 327, 1024 }, 
+   { 4, 328, 1024 }, { 5, 329, 1024 }, { 5, 330, 1024 }, { 6, 331, 1024 }, { 5, 332, 1024 }, { 6, 333, 1024 }, { 6, 334, 1024 }, { 7, 335, 1024 }, 
+   { 4, 336, 1024 }, { 5, 337, 1024 }, { 5, 338, 1024 }, { 6, 339, 1024 }, { 5, 340, 1024 }, { 6, 341, 1024 }, { 6, 342, 1024 }, { 7, 343, 1024 }, 
+   { 5, 344, 1024 }, { 6, 345, 1024 }, { 6, 346, 1024 }, { 7, 347, 1024 }, { 6, 348, 1024 }, { 7, 349, 1024 }, { 7, 350, 1024 }, { 8, 351, 1024 }, 
+   { 4, 352, 1024 }, { 5, 353, 1024 }, { 5, 354, 1024 }, { 6, 355, 1024 }, { 5, 356, 1024 }, { 6, 357, 1024 }, { 6, 358, 1024 }, { 7, 359, 1024 }, 
+   { 5, 360, 1024 }, { 6, 361, 1024 }, { 6, 362, 1024 }, { 7, 363, 1024 }, { 6, 364, 1024 }, { 7, 365, 1024 }, { 7, 366, 1024 }, { 8, 367, 1024 }, 
+   { 5, 368, 1024 }, { 6, 369, 1024 }, { 6, 370, 1024 }, { 7, 371, 1024 }, { 6, 372, 1024 }, { 7, 373, 1024 }, { 7, 374, 1024 }, { 8, 375, 1024 }, 
+   { 6, 376, 1024 }, { 7, 377, 1024 }, { 7, 378, 1024 }, { 8, 379, 1024 }, { 7, 380, 1024 }, { 8, 381, 1024 }, { 8, 382, 1024 }, { 9, 383, 1024 }, 
+   { 3, 384, 1024 }, { 4, 385, 1024 }, { 4, 386, 1024 }, { 5, 387, 1024 }, { 4, 388, 1024 }, { 5, 389, 1024 }, { 5, 390, 1024 }, { 6, 391, 1024 }, 
+   { 4, 392, 1024 }, { 5, 393, 1024 }, { 5, 394, 1024 }, { 6, 395, 1024 }, { 5, 396, 1024 }, { 6, 397, 1024 }, { 6, 398, 1024 }, { 7, 399, 1024 }, 
+   { 4, 400, 1024 }, { 5, 401, 1024 }, { 5, 402, 1024 }, { 6, 403, 1024 }, { 5, 404, 1024 }, { 6, 405, 1024 }, { 6, 406, 1024 }, { 7, 407, 1024 }, 
+   { 5, 408, 1024 }, { 6, 409, 1024 }, { 6, 410, 1024 }, { 7, 411, 1024 }, { 6, 412, 1024 }, { 7, 413, 1024 }, { 7, 414, 1024 }, { 8, 415, 1024 }, 
+   { 4, 416, 1024 }, { 5, 417, 1024 }, { 5, 418, 1024 }, { 6, 419, 1024 }, { 5, 420, 1024 }, { 6, 421, 1024 }, { 6, 422, 1024 }, { 7, 423, 1024 }, 
+   { 5, 424, 1024 }, { 6, 425, 1024 }, { 6, 426, 1024 }, { 7, 427, 1024 }, { 6, 428, 1024 }, { 7, 429, 1024 }, { 7, 430, 1024 }, { 8, 431, 1024 }, 
+   { 5, 432, 1024 }, { 6, 433, 1024 }, { 6, 434, 1024 }, { 7, 435, 1024 }, { 6, 436, 1024 }, { 7, 437, 1024 }, { 7, 438, 1024 }, { 8, 439, 1024 }, 
+   { 6, 440, 1024 }, { 7, 441, 1024 }, { 7, 442, 1024 }, { 8, 443, 1024 }, { 7, 444, 1024 }, { 8, 445, 1024 }, { 8, 446, 1024 }, { 9, 447, 1024 }, 
+   { 4, 448, 1024 }, { 5, 449, 1024 }, { 5, 450, 1024 }, { 6, 451, 1024 }, { 5, 452, 1024 }, { 6, 453, 1024 }, { 6, 454, 1024 }, { 7, 455, 1024 }, 
+   { 5, 456, 1024 }, { 6, 457, 1024 }, { 6, 458, 1024 }, { 7, 459, 1024 }, { 6, 460, 1024 }, { 7, 461, 1024 }, { 7, 462, 1024 }, { 8, 463, 1024 }, 
+   { 5, 464, 1024 }, { 6, 465, 1024 }, { 6, 466, 1024 }, { 7, 467, 1024 }, { 6, 468, 1024 }, { 7, 469, 1024 }, { 7, 470, 1024 }, { 8, 471, 1024 }, 
+   { 6, 472, 1024 }, { 7, 473, 1024 }, { 7, 474, 1024 }, { 8, 475, 1024 }, { 7, 476, 1024 }, { 8, 477, 1024 }, { 8, 478, 1024 }, { 9, 479, 1024 }, 
+   { 5, 480, 1024 }, { 6, 481, 1024 }, { 6, 482, 1024 }, { 7, 483, 1024 }, { 6, 484, 1024 }, { 7, 485, 1024 }, { 7, 486, 1024 }, { 8, 487, 1024 }, 
+   { 6, 488, 1024 }, { 7, 489, 1024 }, { 7, 490, 1024 }, { 8, 491, 1024 }, { 7, 492, 1024 }, { 8, 493, 1024 }, { 8, 494, 1024 }, { 9, 495, 1024 }, 
+   { 6, 496, 1024 }, { 7, 497, 1024 }, { 7, 498, 1024 }, { 8, 499, 1024 }, { 7, 500, 1024 }, { 8, 501, 1024 }, { 8, 502, 1024 }, { 9, 503, 1024 }, 
+   { 7, 504, 1024 }, { 8, 505, 1024 }, { 8, 506, 1024 }, { 9, 507, 1024 }, { 8, 508, 1024 }, { 9, 509, 1024 }, { 9, 510, 1024 }, { 10, 511, 1024 }, 
+   { 2, 512, 1024 }, { 3, 513, 1024 }, { 3, 514, 1024 }, { 4, 515, 1024 }, { 3, 516, 1024 }, { 4, 517, 1024 }, { 4, 518, 1024 }, { 5, 519, 1024 }, 
+   { 3, 520, 1024 }, { 4, 521, 1024 }, { 4, 522, 1024 }, { 5, 523, 1024 }, { 4, 524, 1024 }, { 5, 525, 1024 }, { 5, 526, 1024 }, { 6, 527, 1024 }, 
+   { 3, 528, 1024 }, { 4, 529, 1024 }, { 4, 530, 1024 }, { 5, 531, 1024 }, { 4, 532, 1024 }, { 5, 533, 1024 }, { 5, 534, 1024 }, { 6, 535, 1024 }, 
+   { 4, 536, 1024 }, { 5, 537, 1024 }, { 5, 538, 1024 }, { 6, 539, 1024 }, { 5, 540, 1024 }, { 6, 541, 1024 }, { 6, 542, 1024 }, { 7, 543, 1024 }, 
+   { 3, 544, 1024 }, { 4, 545, 1024 }, { 4, 546, 1024 }, { 5, 547, 1024 }, { 4, 548, 1024 }, { 5, 549, 1024 }, { 5, 550, 1024 }, { 6, 551, 1024 }, 
+   { 4, 552, 1024 }, { 5, 553, 1024 }, { 5, 554, 1024 }, { 6, 555, 1024 }, { 5, 556, 1024 }, { 6, 557, 1024 }, { 6, 558, 1024 }, { 7, 559, 1024 }, 
+   { 4, 560, 1024 }, { 5, 561, 1024 }, { 5, 562, 1024 }, { 6, 563, 1024 }, { 5, 564, 1024 }, { 6, 565, 1024 }, { 6, 566, 1024 }, { 7, 567, 1024 }, 
+   { 5, 568, 1024 }, { 6, 569, 1024 }, { 6, 570, 1024 }, { 7, 571, 1024 }, { 6, 572, 1024 }, { 7, 573, 1024 }, { 7, 574, 1024 }, { 8, 575, 1024 }, 
+   { 3, 576, 1024 }, { 4, 577, 1024 }, { 4, 578, 1024 }, { 5, 579, 1024 }, { 4, 580, 1024 }, { 5, 581, 1024 }, { 5, 582, 1024 }, { 6, 583, 1024 }, 
+   { 4, 584, 1024 }, { 5, 585, 1024 }, { 5, 586, 1024 }, { 6, 587, 1024 }, { 5, 588, 1024 }, { 6, 589, 1024 }, { 6, 590, 1024 }, { 7, 591, 1024 }, 
+   { 4, 592, 1024 }, { 5, 593, 1024 }, { 5, 594, 1024 }, { 6, 595, 1024 }, { 5, 596, 1024 }, { 6, 597, 1024 }, { 6, 598, 1024 }, { 7, 599, 1024 }, 
+   { 5, 600, 1024 }, { 6, 601, 1024 }, { 6, 602, 1024 }, { 7, 603, 1024 }, { 6, 604, 1024 }, { 7, 605, 1024 }, { 7, 606, 1024 }, { 8, 607, 1024 }, 
+   { 4, 608, 1024 }, { 5, 609, 1024 }, { 5, 610, 1024 }, { 6, 611, 1024 }, { 5, 612, 1024 }, { 6, 613, 1024 }, { 6, 614, 1024 }, { 7, 615, 1024 }, 
+   { 5, 616, 1024 }, { 6, 617, 1024 }, { 6, 618, 1024 }, { 7, 619, 1024 }, { 6, 620, 1024 }, { 7, 621, 1024 }, { 7, 622, 1024 }, { 8, 623, 1024 }, 
+   { 5, 624, 1024 }, { 6, 625, 1024 }, { 6, 626, 1024 }, { 7, 627, 1024 }, { 6, 628, 1024 }, { 7, 629, 1024 }, { 7, 630, 1024 }, { 8, 631, 1024 }, 
+   { 6, 632, 1024 }, { 7, 633, 1024 }, { 7, 634, 1024 }, { 8, 635, 1024 }, { 7, 636, 1024 }, { 8, 637, 1024 }, { 8, 638, 1024 }, { 9, 639, 1024 }, 
+   { 3, 640, 1024 }, { 4, 641, 1024 }, { 4, 642, 1024 }, { 5, 643, 1024 }, { 4, 644, 1024 }, { 5, 645, 1024 }, { 5, 646, 1024 }, { 6, 647, 1024 }, 
+   { 4, 648, 1024 }, { 5, 649, 1024 }, { 5, 650, 1024 }, { 6, 651, 1024 }, { 5, 652, 1024 }, { 6, 653, 1024 }, { 6, 654, 1024 }, { 7, 655, 1024 }, 
+   { 4, 656, 1024 }, { 5, 657, 1024 }, { 5, 658, 1024 }, { 6, 659, 1024 }, { 5, 660, 1024 }, { 6, 661, 1024 }, { 6, 662, 1024 }, { 7, 663, 1024 }, 
+   { 5, 664, 1024 }, { 6, 665, 1024 }, { 6, 666, 1024 }, { 7, 667, 1024 }, { 6, 668, 1024 }, { 7, 669, 1024 }, { 7, 670, 1024 }, { 8, 671, 1024 }, 
+   { 4, 672, 1024 }, { 5, 673, 1024 }, { 5, 674, 1024 }, { 6, 675, 1024 }, { 5, 676, 1024 }, { 6, 677, 1024 }, { 6, 678, 1024 }, { 7, 679, 1024 }, 
+   { 5, 680, 1024 }, { 6, 681, 1024 }, { 6, 682, 1024 }, { 7, 683, 1024 }, { 6, 684, 1024 }, { 7, 685, 1024 }, { 7, 686, 1024 }, { 8, 687, 1024 }, 
+   { 5, 688, 1024 }, { 6, 689, 1024 }, { 6, 690, 1024 }, { 7, 691, 1024 }, { 6, 692, 1024 }, { 7, 693, 1024 }, { 7, 694, 1024 }, { 8, 695, 1024 }, 
+   { 6, 696, 1024 }, { 7, 697, 1024 }, { 7, 698, 1024 }, { 8, 699, 1024 }, { 7, 700, 1024 }, { 8, 701, 1024 }, { 8, 702, 1024 }, { 9, 703, 1024 }, 
+   { 4, 704, 1024 }, { 5, 705, 1024 }, { 5, 706, 1024 }, { 6, 707, 1024 }, { 5, 708, 1024 }, { 6, 709, 1024 }, { 6, 710, 1024 }, { 7, 711, 1024 }, 
+   { 5, 712, 1024 }, { 6, 713, 1024 }, { 6, 714, 1024 }, { 7, 715, 1024 }, { 6, 716, 1024 }, { 7, 717, 1024 }, { 7, 718, 1024 }, { 8, 719, 1024 }, 
+   { 5, 720, 1024 }, { 6, 721, 1024 }, { 6, 722, 1024 }, { 7, 723, 1024 }, { 6, 724, 1024 }, { 7, 725, 1024 }, { 7, 726, 1024 }, { 8, 727, 1024 }, 
+   { 6, 728, 1024 }, { 7, 729, 1024 }, { 7, 730, 1024 }, { 8, 731, 1024 }, { 7, 732, 1024 }, { 8, 733, 1024 }, { 8, 734, 1024 }, { 9, 735, 1024 }, 
+   { 5, 736, 1024 }, { 6, 737, 1024 }, { 6, 738, 1024 }, { 7, 739, 1024 }, { 6, 740, 1024 }, { 7, 741, 1024 }, { 7, 742, 1024 }, { 8, 743, 1024 }, 
+   { 6, 744, 1024 }, { 7, 745, 1024 }, { 7, 746, 1024 }, { 8, 747, 1024 }, { 7, 748, 1024 }, { 8, 749, 1024 }, { 8, 750, 1024 }, { 9, 751, 1024 }, 
+   { 6, 752, 1024 }, { 7, 753, 1024 }, { 7, 754, 1024 }, { 8, 755, 1024 }, { 7, 756, 1024 }, { 8, 757, 1024 }, { 8, 758, 1024 }, { 9, 759, 1024 }, 
+   { 7, 760, 1024 }, { 8, 761, 1024 }, { 8, 762, 1024 }, { 9, 763, 1024 }, { 8, 764, 1024 }, { 9, 765, 1024 }, { 9, 766, 1024 }, { 10, 767, 1024 }, 
+   { 3, 768, 1024 }, { 4, 769, 1024 }, { 4, 770, 1024 }, { 5, 771, 1024 }, { 4, 772, 1024 }, { 5, 773, 1024 }, { 5, 774, 1024 }, { 6, 775, 1024 }, 
+   { 4, 776, 1024 }, { 5, 777, 1024 }, { 5, 778, 1024 }, { 6, 779, 1024 }, { 5, 780, 1024 }, { 6, 781, 1024 }, { 6, 782, 1024 }, { 7, 783, 1024 }, 
+   { 4, 784, 1024 }, { 5, 785, 1024 }, { 5, 786, 1024 }, { 6, 787, 1024 }, { 5, 788, 1024 }, { 6, 789, 1024 }, { 6, 790, 1024 }, { 7, 791, 1024 }, 
+   { 5, 792, 1024 }, { 6, 793, 1024 }, { 6, 794, 1024 }, { 7, 795, 1024 }, { 6, 796, 1024 }, { 7, 797, 1024 }, { 7, 798, 1024 }, { 8, 799, 1024 }, 
+   { 4, 800, 1024 }, { 5, 801, 1024 }, { 5, 802, 1024 }, { 6, 803, 1024 }, { 5, 804, 1024 }, { 6, 805, 1024 }, { 6, 806, 1024 }, { 7, 807, 1024 }, 
+   { 5, 808, 1024 }, { 6, 809, 1024 }, { 6, 810, 1024 }, { 7, 811, 1024 }, { 6, 812, 1024 }, { 7, 813, 1024 }, { 7, 814, 1024 }, { 8, 815, 1024 }, 
+   { 5, 816, 1024 }, { 6, 817, 1024 }, { 6, 818, 1024 }, { 7, 819, 1024 }, { 6, 820, 1024 }, { 7, 821, 1024 }, { 7, 822, 1024 }, { 8, 823, 1024 }, 
+   { 6, 824, 1024 }, { 7, 825, 1024 }, { 7, 826, 1024 }, { 8, 827, 1024 }, { 7, 828, 1024 }, { 8, 829, 1024 }, { 8, 830, 1024 }, { 9, 831, 1024 }, 
+   { 4, 832, 1024 }, { 5, 833, 1024 }, { 5, 834, 1024 }, { 6, 835, 1024 }, { 5, 836, 1024 }, { 6, 837, 1024 }, { 6, 838, 1024 }, { 7, 839, 1024 }, 
+   { 5, 840, 1024 }, { 6, 841, 1024 }, { 6, 842, 1024 }, { 7, 843, 1024 }, { 6, 844, 1024 }, { 7, 845, 1024 }, { 7, 846, 1024 }, { 8, 847, 1024 }, 
+   { 5, 848, 1024 }, { 6, 849, 1024 }, { 6, 850, 1024 }, { 7, 851, 1024 }, { 6, 852, 1024 }, { 7, 853, 1024 }, { 7, 854, 1024 }, { 8, 855, 1024 }, 
+   { 6, 856, 1024 }, { 7, 857, 1024 }, { 7, 858, 1024 }, { 8, 859, 1024 }, { 7, 860, 1024 }, { 8, 861, 1024 }, { 8, 862, 1024 }, { 9, 863, 1024 }, 
+   { 5, 864, 1024 }, { 6, 865, 1024 }, { 6, 866, 1024 }, { 7, 867, 1024 }, { 6, 868, 1024 }, { 7, 869, 1024 }, { 7, 870, 1024 }, { 8, 871, 1024 }, 
+   { 6, 872, 1024 }, { 7, 873, 1024 }, { 7, 874, 1024 }, { 8, 875, 1024 }, { 7, 876, 1024 }, { 8, 877, 1024 }, { 8, 878, 1024 }, { 9, 879, 1024 }, 
+   { 6, 880, 1024 }, { 7, 881, 1024 }, { 7, 882, 1024 }, { 8, 883, 1024 }, { 7, 884, 1024 }, { 8, 885, 1024 }, { 8, 886, 1024 }, { 9, 887, 1024 }, 
+   { 7, 888, 1024 }, { 8, 889, 1024 }, { 8, 890, 1024 }, { 9, 891, 1024 }, { 8, 892, 1024 }, { 9, 893, 1024 }, { 9, 894, 1024 }, { 10, 895, 1024 }, 
+   { 4, 896, 1024 }, { 5, 897, 1024 }, { 5, 898, 1024 }, { 6, 899, 1024 }, { 5, 900, 1024 }, { 6, 901, 1024 }, { 6, 902, 1024 }, { 7, 903, 1024 }, 
+   { 5, 904, 1024 }, { 6, 905, 1024 }, { 6, 906, 1024 }, { 7, 907, 1024 }, { 6, 908, 1024 }, { 7, 909, 1024 }, { 7, 910, 1024 }, { 8, 911, 1024 }, 
+   { 5, 912, 1024 }, { 6, 913, 1024 }, { 6, 914, 1024 }, { 7, 915, 1024 }, { 6, 916, 1024 }, { 7, 917, 1024 }, { 7, 918, 1024 }, { 8, 919, 1024 }, 
+   { 6, 920, 1024 }, { 7, 921, 1024 }, { 7, 922, 1024 }, { 8, 923, 1024 }, { 7, 924, 1024 }, { 8, 925, 1024 }, { 8, 926, 1024 }, { 9, 927, 1024 }, 
+   { 5, 928, 1024 }, { 6, 929, 1024 }, { 6, 930, 1024 }, { 7, 931, 1024 }, { 6, 932, 1024 }, { 7, 933, 1024 }, { 7, 934, 1024 }, { 8, 935, 1024 }, 
+   { 6, 936, 1024 }, { 7, 937, 1024 }, { 7, 938, 1024 }, { 8, 939, 1024 }, { 7, 940, 1024 }, { 8, 941, 1024 }, { 8, 942, 1024 }, { 9, 943, 1024 }, 
+   { 6, 944, 1024 }, { 7, 945, 1024 }, { 7, 946, 1024 }, { 8, 947, 1024 }, { 7, 948, 1024 }, { 8, 949, 1024 }, { 8, 950, 1024 }, { 9, 951, 1024 }, 
+   { 7, 952, 1024 }, { 8, 953, 1024 }, { 8, 954, 1024 }, { 9, 955, 1024 }, { 8, 956, 1024 }, { 9, 957, 1024 }, { 9, 958, 1024 }, { 10, 959, 1024 }, 
+   { 5, 960, 1024 }, { 6, 961, 1024 }, { 6, 962, 1024 }, { 7, 963, 1024 }, { 6, 964, 1024 }, { 7, 965, 1024 }, { 7, 966, 1024 }, { 8, 967, 1024 }, 
+   { 6, 968, 1024 }, { 7, 969, 1024 }, { 7, 970, 1024 }, { 8, 971, 1024 }, { 7, 972, 1024 }, { 8, 973, 1024 }, { 8, 974, 1024 }, { 9, 975, 1024 }, 
+   { 6, 976, 1024 }, { 7, 977, 1024 }, { 7, 978, 1024 }, { 8, 979, 1024 }, { 7, 980, 1024 }, { 8, 981, 1024 }, { 8, 982, 1024 }, { 9, 983, 1024 }, 
+   { 7, 984, 1024 }, { 8, 985, 1024 }, { 8, 986, 1024 }, { 9, 987, 1024 }, { 8, 988, 1024 }, { 9, 989, 1024 }, { 9, 990, 1024 }, { 10, 991, 1024 }, 
+   { 6, 992, 1024 }, { 7, 993, 1024 }, { 7, 994, 1024 }, { 8, 995, 1024 }, { 7, 996, 1024 }, { 8, 997, 1024 }, { 8, 998, 1024 }, { 9, 999, 1024 }, 
+   { 7, 1000, 1024 }, { 8, 1001, 1024 }, { 8, 1002, 1024 }, { 9, 1003, 1024 }, { 8, 1004, 1024 }, { 9, 1005, 1024 }, { 9, 1006, 1024 }, { 10, 1007, 1024 }, 
+   { 7, 1008, 1024 }, { 8, 1009, 1024 }, { 8, 1010, 1024 }, { 9, 1011, 1024 }, { 8, 1012, 1024 }, { 9, 1013, 1024 }, { 9, 1014, 1024 }, { 10, 1015, 1024 }, 
+   { 8, 1016, 1024 }, { 9, 1017, 1024 }, { 9, 1018, 1024 }, { 10, 1019, 1024 }, { 9, 1020, 1024 }, { 10, 1021, 1024 }, { 10, 1022, 1024 }, { 11, 1023, 1024 }, 
+#if FP_LUT > 11
+   { 1, 0, 0 }, { 2, 1, 2048 }, { 2, 2, 2048 }, { 3, 3, 2048 }, { 2, 4, 2048 }, { 3, 5, 2048 }, { 3, 6, 2048 }, { 4, 7, 2048 }, 
+   { 2, 8, 2048 }, { 3, 9, 2048 }, { 3, 10, 2048 }, { 4, 11, 2048 }, { 3, 12, 2048 }, { 4, 13, 2048 }, { 4, 14, 2048 }, { 5, 15, 2048 }, 
+   { 2, 16, 2048 }, { 3, 17, 2048 }, { 3, 18, 2048 }, { 4, 19, 2048 }, { 3, 20, 2048 }, { 4, 21, 2048 }, { 4, 22, 2048 }, { 5, 23, 2048 }, 
+   { 3, 24, 2048 }, { 4, 25, 2048 }, { 4, 26, 2048 }, { 5, 27, 2048 }, { 4, 28, 2048 }, { 5, 29, 2048 }, { 5, 30, 2048 }, { 6, 31, 2048 }, 
+   { 2, 32, 2048 }, { 3, 33, 2048 }, { 3, 34, 2048 }, { 4, 35, 2048 }, { 3, 36, 2048 }, { 4, 37, 2048 }, { 4, 38, 2048 }, { 5, 39, 2048 }, 
+   { 3, 40, 2048 }, { 4, 41, 2048 }, { 4, 42, 2048 }, { 5, 43, 2048 }, { 4, 44, 2048 }, { 5, 45, 2048 }, { 5, 46, 2048 }, { 6, 47, 2048 }, 
+   { 3, 48, 2048 }, { 4, 49, 2048 }, { 4, 50, 2048 }, { 5, 51, 2048 }, { 4, 52, 2048 }, { 5, 53, 2048 }, { 5, 54, 2048 }, { 6, 55, 2048 }, 
+   { 4, 56, 2048 }, { 5, 57, 2048 }, { 5, 58, 2048 }, { 6, 59, 2048 }, { 5, 60, 2048 }, { 6, 61, 2048 }, { 6, 62, 2048 }, { 7, 63, 2048 }, 
+   { 2, 64, 2048 }, { 3, 65, 2048 }, { 3, 66, 2048 }, { 4, 67, 2048 }, { 3, 68, 2048 }, { 4, 69, 2048 }, { 4, 70, 2048 }, { 5, 71, 2048 }, 
+   { 3, 72, 2048 }, { 4, 73, 2048 }, { 4, 74, 2048 }, { 5, 75, 2048 }, { 4, 76, 2048 }, { 5, 77, 2048 }, { 5, 78, 2048 }, { 6, 79, 2048 }, 
+   { 3, 80, 2048 }, { 4, 81, 2048 }, { 4, 82, 2048 }, { 5, 83, 2048 }, { 4, 84, 2048 }, { 5, 85, 2048 }, { 5, 86, 2048 }, { 6, 87, 2048 }, 
+   { 4, 88, 2048 }, { 5, 89, 2048 }, { 5, 90, 2048 }, { 6, 91, 2048 }, { 5, 92, 2048 }, { 6, 93, 2048 }, { 6, 94, 2048 }, { 7, 95, 2048 }, 
+   { 3, 96, 2048 }, { 4, 97, 2048 }, { 4, 98, 2048 }, { 5, 99, 2048 }, { 4, 100, 2048 }, { 5, 101, 2048 }, { 5, 102, 2048 }, { 6, 103, 2048 }, 
+   { 4, 104, 2048 }, { 5, 105, 2048 }, { 5, 106, 2048 }, { 6, 107, 2048 }, { 5, 108, 2048 }, { 6, 109, 2048 }, { 6, 110, 2048 }, { 7, 111, 2048 }, 
+   { 4, 112, 2048 }, { 5, 113, 2048 }, { 5, 114, 2048 }, { 6, 115, 2048 }, { 5, 116, 2048 }, { 6, 117, 2048 }, { 6, 118, 2048 }, { 7, 119, 2048 }, 
+   { 5, 120, 2048 }, { 6, 121, 2048 }, { 6, 122, 2048 }, { 7, 123, 2048 }, { 6, 124, 2048 }, { 7, 125, 2048 }, { 7, 126, 2048 }, { 8, 127, 2048 }, 
+   { 2, 128, 2048 }, { 3, 129, 2048 }, { 3, 130, 2048 }, { 4, 131, 2048 }, { 3, 132, 2048 }, { 4, 133, 2048 }, { 4, 134, 2048 }, { 5, 135, 2048 }, 
+   { 3, 136, 2048 }, { 4, 137, 2048 }, { 4, 138, 2048 }, { 5, 139, 2048 }, { 4, 140, 2048 }, { 5, 141, 2048 }, { 5, 142, 2048 }, { 6, 143, 2048 }, 
+   { 3, 144, 2048 }, { 4, 145, 2048 }, { 4, 146, 2048 }, { 5, 147, 2048 }, { 4, 148, 2048 }, { 5, 149, 2048 }, { 5, 150, 2048 }, { 6, 151, 2048 }, 
+   { 4, 152, 2048 }, { 5, 153, 2048 }, { 5, 154, 2048 }, { 6, 155, 2048 }, { 5, 156, 2048 }, { 6, 157, 2048 }, { 6, 158, 2048 }, { 7, 159, 2048 }, 
+   { 3, 160, 2048 }, { 4, 161, 2048 }, { 4, 162, 2048 }, { 5, 163, 2048 }, { 4, 164, 2048 }, { 5, 165, 2048 }, { 5, 166, 2048 }, { 6, 167, 2048 }, 
+   { 4, 168, 2048 }, { 5, 169, 2048 }, { 5, 170, 2048 }, { 6, 171, 2048 }, { 5, 172, 2048 }, { 6, 173, 2048 }, { 6, 174, 2048 }, { 7, 175, 2048 }, 
+   { 4, 176, 2048 }, { 5, 177, 2048 }, { 5, 178, 2048 }, { 6, 179, 2048 }, { 5, 180, 2048 }, { 6, 181, 2048 }, { 6, 182, 2048 }, { 7, 183, 2048 }, 
+   { 5, 184, 2048 }, { 6, 185, 2048 }, { 6, 186, 2048 }, { 7, 187, 2048 }, { 6, 188, 2048 }, { 7, 189, 2048 }, { 7, 190, 2048 }, { 8, 191, 2048 }, 
+   { 3, 192, 2048 }, { 4, 193, 2048 }, { 4, 194, 2048 }, { 5, 195, 2048 }, { 4, 196, 2048 }, { 5, 197, 2048 }, { 5, 198, 2048 }, { 6, 199, 2048 }, 
+   { 4, 200, 2048 }, { 5, 201, 2048 }, { 5, 202, 2048 }, { 6, 203, 2048 }, { 5, 204, 2048 }, { 6, 205, 2048 }, { 6, 206, 2048 }, { 7, 207, 2048 }, 
+   { 4, 208, 2048 }, { 5, 209, 2048 }, { 5, 210, 2048 }, { 6, 211, 2048 }, { 5, 212, 2048 }, { 6, 213, 2048 }, { 6, 214, 2048 }, { 7, 215, 2048 }, 
+   { 5, 216, 2048 }, { 6, 217, 2048 }, { 6, 218, 2048 }, { 7, 219, 2048 }, { 6, 220, 2048 }, { 7, 221, 2048 }, { 7, 222, 2048 }, { 8, 223, 2048 }, 
+   { 4, 224, 2048 }, { 5, 225, 2048 }, { 5, 226, 2048 }, { 6, 227, 2048 }, { 5, 228, 2048 }, { 6, 229, 2048 }, { 6, 230, 2048 }, { 7, 231, 2048 }, 
+   { 5, 232, 2048 }, { 6, 233, 2048 }, { 6, 234, 2048 }, { 7, 235, 2048 }, { 6, 236, 2048 }, { 7, 237, 2048 }, { 7, 238, 2048 }, { 8, 239, 2048 }, 
+   { 5, 240, 2048 }, { 6, 241, 2048 }, { 6, 242, 2048 }, { 7, 243, 2048 }, { 6, 244, 2048 }, { 7, 245, 2048 }, { 7, 246, 2048 }, { 8, 247, 2048 }, 
+   { 6, 248, 2048 }, { 7, 249, 2048 }, { 7, 250, 2048 }, { 8, 251, 2048 }, { 7, 252, 2048 }, { 8, 253, 2048 }, { 8, 254, 2048 }, { 9, 255, 2048 }, 
+   { 2, 256, 2048 }, { 3, 257, 2048 }, { 3, 258, 2048 }, { 4, 259, 2048 }, { 3, 260, 2048 }, { 4, 261, 2048 }, { 4, 262, 2048 }, { 5, 263, 2048 }, 
+   { 3, 264, 2048 }, { 4, 265, 2048 }, { 4, 266, 2048 }, { 5, 267, 2048 }, { 4, 268, 2048 }, { 5, 269, 2048 }, { 5, 270, 2048 }, { 6, 271, 2048 }, 
+   { 3, 272, 2048 }, { 4, 273, 2048 }, { 4, 274, 2048 }, { 5, 275, 2048 }, { 4, 276, 2048 }, { 5, 277, 2048 }, { 5, 278, 2048 }, { 6, 279, 2048 }, 
+   { 4, 280, 2048 }, { 5, 281, 2048 }, { 5, 282, 2048 }, { 6, 283, 2048 }, { 5, 284, 2048 }, { 6, 285, 2048 }, { 6, 286, 2048 }, { 7, 287, 2048 }, 
+   { 3, 288, 2048 }, { 4, 289, 2048 }, { 4, 290, 2048 }, { 5, 291, 2048 }, { 4, 292, 2048 }, { 5, 293, 2048 }, { 5, 294, 2048 }, { 6, 295, 2048 }, 
+   { 4, 296, 2048 }, { 5, 297, 2048 }, { 5, 298, 2048 }, { 6, 299, 2048 }, { 5, 300, 2048 }, { 6, 301, 2048 }, { 6, 302, 2048 }, { 7, 303, 2048 }, 
+   { 4, 304, 2048 }, { 5, 305, 2048 }, { 5, 306, 2048 }, { 6, 307, 2048 }, { 5, 308, 2048 }, { 6, 309, 2048 }, { 6, 310, 2048 }, { 7, 311, 2048 }, 
+   { 5, 312, 2048 }, { 6, 313, 2048 }, { 6, 314, 2048 }, { 7, 315, 2048 }, { 6, 316, 2048 }, { 7, 317, 2048 }, { 7, 318, 2048 }, { 8, 319, 2048 }, 
+   { 3, 320, 2048 }, { 4, 321, 2048 }, { 4, 322, 2048 }, { 5, 323, 2048 }, { 4, 324, 2048 }, { 5, 325, 2048 }, { 5, 326, 2048 }, { 6, 327, 2048 }, 
+   { 4, 328, 2048 }, { 5, 329, 2048 }, { 5, 330, 2048 }, { 6, 331, 2048 }, { 5, 332, 2048 }, { 6, 333, 2048 }, { 6, 334, 2048 }, { 7, 335, 2048 }, 
+   { 4, 336, 2048 }, { 5, 337, 2048 }, { 5, 338, 2048 }, { 6, 339, 2048 }, { 5, 340, 2048 }, { 6, 341, 2048 }, { 6, 342, 2048 }, { 7, 343, 2048 }, 
+   { 5, 344, 2048 }, { 6, 345, 2048 }, { 6, 346, 2048 }, { 7, 347, 2048 }, { 6, 348, 2048 }, { 7, 349, 2048 }, { 7, 350, 2048 }, { 8, 351, 2048 }, 
+   { 4, 352, 2048 }, { 5, 353, 2048 }, { 5, 354, 2048 }, { 6, 355, 2048 }, { 5, 356, 2048 }, { 6, 357, 2048 }, { 6, 358, 2048 }, { 7, 359, 2048 }, 
+   { 5, 360, 2048 }, { 6, 361, 2048 }, { 6, 362, 2048 }, { 7, 363, 2048 }, { 6, 364, 2048 }, { 7, 365, 2048 }, { 7, 366, 2048 }, { 8, 367, 2048 }, 
+   { 5, 368, 2048 }, { 6, 369, 2048 }, { 6, 370, 2048 }, { 7, 371, 2048 }, { 6, 372, 2048 }, { 7, 373, 2048 }, { 7, 374, 2048 }, { 8, 375, 2048 }, 
+   { 6, 376, 2048 }, { 7, 377, 2048 }, { 7, 378, 2048 }, { 8, 379, 2048 }, { 7, 380, 2048 }, { 8, 381, 2048 }, { 8, 382, 2048 }, { 9, 383, 2048 }, 
+   { 3, 384, 2048 }, { 4, 385, 2048 }, { 4, 386, 2048 }, { 5, 387, 2048 }, { 4, 388, 2048 }, { 5, 389, 2048 }, { 5, 390, 2048 }, { 6, 391, 2048 }, 
+   { 4, 392, 2048 }, { 5, 393, 2048 }, { 5, 394, 2048 }, { 6, 395, 2048 }, { 5, 396, 2048 }, { 6, 397, 2048 }, { 6, 398, 2048 }, { 7, 399, 2048 }, 
+   { 4, 400, 2048 }, { 5, 401, 2048 }, { 5, 402, 2048 }, { 6, 403, 2048 }, { 5, 404, 2048 }, { 6, 405, 2048 }, { 6, 406, 2048 }, { 7, 407, 2048 }, 
+   { 5, 408, 2048 }, { 6, 409, 2048 }, { 6, 410, 2048 }, { 7, 411, 2048 }, { 6, 412, 2048 }, { 7, 413, 2048 }, { 7, 414, 2048 }, { 8, 415, 2048 }, 
+   { 4, 416, 2048 }, { 5, 417, 2048 }, { 5, 418, 2048 }, { 6, 419, 2048 }, { 5, 420, 2048 }, { 6, 421, 2048 }, { 6, 422, 2048 }, { 7, 423, 2048 }, 
+   { 5, 424, 2048 }, { 6, 425, 2048 }, { 6, 426, 2048 }, { 7, 427, 2048 }, { 6, 428, 2048 }, { 7, 429, 2048 }, { 7, 430, 2048 }, { 8, 431, 2048 }, 
+   { 5, 432, 2048 }, { 6, 433, 2048 }, { 6, 434, 2048 }, { 7, 435, 2048 }, { 6, 436, 2048 }, { 7, 437, 2048 }, { 7, 438, 2048 }, { 8, 439, 2048 }, 
+   { 6, 440, 2048 }, { 7, 441, 2048 }, { 7, 442, 2048 }, { 8, 443, 2048 }, { 7, 444, 2048 }, { 8, 445, 2048 }, { 8, 446, 2048 }, { 9, 447, 2048 }, 
+   { 4, 448, 2048 }, { 5, 449, 2048 }, { 5, 450, 2048 }, { 6, 451, 2048 }, { 5, 452, 2048 }, { 6, 453, 2048 }, { 6, 454, 2048 }, { 7, 455, 2048 }, 
+   { 5, 456, 2048 }, { 6, 457, 2048 }, { 6, 458, 2048 }, { 7, 459, 2048 }, { 6, 460, 2048 }, { 7, 461, 2048 }, { 7, 462, 2048 }, { 8, 463, 2048 }, 
+   { 5, 464, 2048 }, { 6, 465, 2048 }, { 6, 466, 2048 }, { 7, 467, 2048 }, { 6, 468, 2048 }, { 7, 469, 2048 }, { 7, 470, 2048 }, { 8, 471, 2048 }, 
+   { 6, 472, 2048 }, { 7, 473, 2048 }, { 7, 474, 2048 }, { 8, 475, 2048 }, { 7, 476, 2048 }, { 8, 477, 2048 }, { 8, 478, 2048 }, { 9, 479, 2048 }, 
+   { 5, 480, 2048 }, { 6, 481, 2048 }, { 6, 482, 2048 }, { 7, 483, 2048 }, { 6, 484, 2048 }, { 7, 485, 2048 }, { 7, 486, 2048 }, { 8, 487, 2048 }, 
+   { 6, 488, 2048 }, { 7, 489, 2048 }, { 7, 490, 2048 }, { 8, 491, 2048 }, { 7, 492, 2048 }, { 8, 493, 2048 }, { 8, 494, 2048 }, { 9, 495, 2048 }, 
+   { 6, 496, 2048 }, { 7, 497, 2048 }, { 7, 498, 2048 }, { 8, 499, 2048 }, { 7, 500, 2048 }, { 8, 501, 2048 }, { 8, 502, 2048 }, { 9, 503, 2048 }, 
+   { 7, 504, 2048 }, { 8, 505, 2048 }, { 8, 506, 2048 }, { 9, 507, 2048 }, { 8, 508, 2048 }, { 9, 509, 2048 }, { 9, 510, 2048 }, { 10, 511, 2048 }, 
+   { 2, 512, 2048 }, { 3, 513, 2048 }, { 3, 514, 2048 }, { 4, 515, 2048 }, { 3, 516, 2048 }, { 4, 517, 2048 }, { 4, 518, 2048 }, { 5, 519, 2048 }, 
+   { 3, 520, 2048 }, { 4, 521, 2048 }, { 4, 522, 2048 }, { 5, 523, 2048 }, { 4, 524, 2048 }, { 5, 525, 2048 }, { 5, 526, 2048 }, { 6, 527, 2048 }, 
+   { 3, 528, 2048 }, { 4, 529, 2048 }, { 4, 530, 2048 }, { 5, 531, 2048 }, { 4, 532, 2048 }, { 5, 533, 2048 }, { 5, 534, 2048 }, { 6, 535, 2048 }, 
+   { 4, 536, 2048 }, { 5, 537, 2048 }, { 5, 538, 2048 }, { 6, 539, 2048 }, { 5, 540, 2048 }, { 6, 541, 2048 }, { 6, 542, 2048 }, { 7, 543, 2048 }, 
+   { 3, 544, 2048 }, { 4, 545, 2048 }, { 4, 546, 2048 }, { 5, 547, 2048 }, { 4, 548, 2048 }, { 5, 549, 2048 }, { 5, 550, 2048 }, { 6, 551, 2048 }, 
+   { 4, 552, 2048 }, { 5, 553, 2048 }, { 5, 554, 2048 }, { 6, 555, 2048 }, { 5, 556, 2048 }, { 6, 557, 2048 }, { 6, 558, 2048 }, { 7, 559, 2048 }, 
+   { 4, 560, 2048 }, { 5, 561, 2048 }, { 5, 562, 2048 }, { 6, 563, 2048 }, { 5, 564, 2048 }, { 6, 565, 2048 }, { 6, 566, 2048 }, { 7, 567, 2048 }, 
+   { 5, 568, 2048 }, { 6, 569, 2048 }, { 6, 570, 2048 }, { 7, 571, 2048 }, { 6, 572, 2048 }, { 7, 573, 2048 }, { 7, 574, 2048 }, { 8, 575, 2048 }, 
+   { 3, 576, 2048 }, { 4, 577, 2048 }, { 4, 578, 2048 }, { 5, 579, 2048 }, { 4, 580, 2048 }, { 5, 581, 2048 }, { 5, 582, 2048 }, { 6, 583, 2048 }, 
+   { 4, 584, 2048 }, { 5, 585, 2048 }, { 5, 586, 2048 }, { 6, 587, 2048 }, { 5, 588, 2048 }, { 6, 589, 2048 }, { 6, 590, 2048 }, { 7, 591, 2048 }, 
+   { 4, 592, 2048 }, { 5, 593, 2048 }, { 5, 594, 2048 }, { 6, 595, 2048 }, { 5, 596, 2048 }, { 6, 597, 2048 }, { 6, 598, 2048 }, { 7, 599, 2048 }, 
+   { 5, 600, 2048 }, { 6, 601, 2048 }, { 6, 602, 2048 }, { 7, 603, 2048 }, { 6, 604, 2048 }, { 7, 605, 2048 }, { 7, 606, 2048 }, { 8, 607, 2048 }, 
+   { 4, 608, 2048 }, { 5, 609, 2048 }, { 5, 610, 2048 }, { 6, 611, 2048 }, { 5, 612, 2048 }, { 6, 613, 2048 }, { 6, 614, 2048 }, { 7, 615, 2048 }, 
+   { 5, 616, 2048 }, { 6, 617, 2048 }, { 6, 618, 2048 }, { 7, 619, 2048 }, { 6, 620, 2048 }, { 7, 621, 2048 }, { 7, 622, 2048 }, { 8, 623, 2048 }, 
+   { 5, 624, 2048 }, { 6, 625, 2048 }, { 6, 626, 2048 }, { 7, 627, 2048 }, { 6, 628, 2048 }, { 7, 629, 2048 }, { 7, 630, 2048 }, { 8, 631, 2048 }, 
+   { 6, 632, 2048 }, { 7, 633, 2048 }, { 7, 634, 2048 }, { 8, 635, 2048 }, { 7, 636, 2048 }, { 8, 637, 2048 }, { 8, 638, 2048 }, { 9, 639, 2048 }, 
+   { 3, 640, 2048 }, { 4, 641, 2048 }, { 4, 642, 2048 }, { 5, 643, 2048 }, { 4, 644, 2048 }, { 5, 645, 2048 }, { 5, 646, 2048 }, { 6, 647, 2048 }, 
+   { 4, 648, 2048 }, { 5, 649, 2048 }, { 5, 650, 2048 }, { 6, 651, 2048 }, { 5, 652, 2048 }, { 6, 653, 2048 }, { 6, 654, 2048 }, { 7, 655, 2048 }, 
+   { 4, 656, 2048 }, { 5, 657, 2048 }, { 5, 658, 2048 }, { 6, 659, 2048 }, { 5, 660, 2048 }, { 6, 661, 2048 }, { 6, 662, 2048 }, { 7, 663, 2048 }, 
+   { 5, 664, 2048 }, { 6, 665, 2048 }, { 6, 666, 2048 }, { 7, 667, 2048 }, { 6, 668, 2048 }, { 7, 669, 2048 }, { 7, 670, 2048 }, { 8, 671, 2048 }, 
+   { 4, 672, 2048 }, { 5, 673, 2048 }, { 5, 674, 2048 }, { 6, 675, 2048 }, { 5, 676, 2048 }, { 6, 677, 2048 }, { 6, 678, 2048 }, { 7, 679, 2048 }, 
+   { 5, 680, 2048 }, { 6, 681, 2048 }, { 6, 682, 2048 }, { 7, 683, 2048 }, { 6, 684, 2048 }, { 7, 685, 2048 }, { 7, 686, 2048 }, { 8, 687, 2048 }, 
+   { 5, 688, 2048 }, { 6, 689, 2048 }, { 6, 690, 2048 }, { 7, 691, 2048 }, { 6, 692, 2048 }, { 7, 693, 2048 }, { 7, 694, 2048 }, { 8, 695, 2048 }, 
+   { 6, 696, 2048 }, { 7, 697, 2048 }, { 7, 698, 2048 }, { 8, 699, 2048 }, { 7, 700, 2048 }, { 8, 701, 2048 }, { 8, 702, 2048 }, { 9, 703, 2048 }, 
+   { 4, 704, 2048 }, { 5, 705, 2048 }, { 5, 706, 2048 }, { 6, 707, 2048 }, { 5, 708, 2048 }, { 6, 709, 2048 }, { 6, 710, 2048 }, { 7, 711, 2048 }, 
+   { 5, 712, 2048 }, { 6, 713, 2048 }, { 6, 714, 2048 }, { 7, 715, 2048 }, { 6, 716, 2048 }, { 7, 717, 2048 }, { 7, 718, 2048 }, { 8, 719, 2048 }, 
+   { 5, 720, 2048 }, { 6, 721, 2048 }, { 6, 722, 2048 }, { 7, 723, 2048 }, { 6, 724, 2048 }, { 7, 725, 2048 }, { 7, 726, 2048 }, { 8, 727, 2048 }, 
+   { 6, 728, 2048 }, { 7, 729, 2048 }, { 7, 730, 2048 }, { 8, 731, 2048 }, { 7, 732, 2048 }, { 8, 733, 2048 }, { 8, 734, 2048 }, { 9, 735, 2048 }, 
+   { 5, 736, 2048 }, { 6, 737, 2048 }, { 6, 738, 2048 }, { 7, 739, 2048 }, { 6, 740, 2048 }, { 7, 741, 2048 }, { 7, 742, 2048 }, { 8, 743, 2048 }, 
+   { 6, 744, 2048 }, { 7, 745, 2048 }, { 7, 746, 2048 }, { 8, 747, 2048 }, { 7, 748, 2048 }, { 8, 749, 2048 }, { 8, 750, 2048 }, { 9, 751, 2048 }, 
+   { 6, 752, 2048 }, { 7, 753, 2048 }, { 7, 754, 2048 }, { 8, 755, 2048 }, { 7, 756, 2048 }, { 8, 757, 2048 }, { 8, 758, 2048 }, { 9, 759, 2048 }, 
+   { 7, 760, 2048 }, { 8, 761, 2048 }, { 8, 762, 2048 }, { 9, 763, 2048 }, { 8, 764, 2048 }, { 9, 765, 2048 }, { 9, 766, 2048 }, { 10, 767, 2048 }, 
+   { 3, 768, 2048 }, { 4, 769, 2048 }, { 4, 770, 2048 }, { 5, 771, 2048 }, { 4, 772, 2048 }, { 5, 773, 2048 }, { 5, 774, 2048 }, { 6, 775, 2048 }, 
+   { 4, 776, 2048 }, { 5, 777, 2048 }, { 5, 778, 2048 }, { 6, 779, 2048 }, { 5, 780, 2048 }, { 6, 781, 2048 }, { 6, 782, 2048 }, { 7, 783, 2048 }, 
+   { 4, 784, 2048 }, { 5, 785, 2048 }, { 5, 786, 2048 }, { 6, 787, 2048 }, { 5, 788, 2048 }, { 6, 789, 2048 }, { 6, 790, 2048 }, { 7, 791, 2048 }, 
+   { 5, 792, 2048 }, { 6, 793, 2048 }, { 6, 794, 2048 }, { 7, 795, 2048 }, { 6, 796, 2048 }, { 7, 797, 2048 }, { 7, 798, 2048 }, { 8, 799, 2048 }, 
+   { 4, 800, 2048 }, { 5, 801, 2048 }, { 5, 802, 2048 }, { 6, 803, 2048 }, { 5, 804, 2048 }, { 6, 805, 2048 }, { 6, 806, 2048 }, { 7, 807, 2048 }, 
+   { 5, 808, 2048 }, { 6, 809, 2048 }, { 6, 810, 2048 }, { 7, 811, 2048 }, { 6, 812, 2048 }, { 7, 813, 2048 }, { 7, 814, 2048 }, { 8, 815, 2048 }, 
+   { 5, 816, 2048 }, { 6, 817, 2048 }, { 6, 818, 2048 }, { 7, 819, 2048 }, { 6, 820, 2048 }, { 7, 821, 2048 }, { 7, 822, 2048 }, { 8, 823, 2048 }, 
+   { 6, 824, 2048 }, { 7, 825, 2048 }, { 7, 826, 2048 }, { 8, 827, 2048 }, { 7, 828, 2048 }, { 8, 829, 2048 }, { 8, 830, 2048 }, { 9, 831, 2048 }, 
+   { 4, 832, 2048 }, { 5, 833, 2048 }, { 5, 834, 2048 }, { 6, 835, 2048 }, { 5, 836, 2048 }, { 6, 837, 2048 }, { 6, 838, 2048 }, { 7, 839, 2048 }, 
+   { 5, 840, 2048 }, { 6, 841, 2048 }, { 6, 842, 2048 }, { 7, 843, 2048 }, { 6, 844, 2048 }, { 7, 845, 2048 }, { 7, 846, 2048 }, { 8, 847, 2048 }, 
+   { 5, 848, 2048 }, { 6, 849, 2048 }, { 6, 850, 2048 }, { 7, 851, 2048 }, { 6, 852, 2048 }, { 7, 853, 2048 }, { 7, 854, 2048 }, { 8, 855, 2048 }, 
+   { 6, 856, 2048 }, { 7, 857, 2048 }, { 7, 858, 2048 }, { 8, 859, 2048 }, { 7, 860, 2048 }, { 8, 861, 2048 }, { 8, 862, 2048 }, { 9, 863, 2048 }, 
+   { 5, 864, 2048 }, { 6, 865, 2048 }, { 6, 866, 2048 }, { 7, 867, 2048 }, { 6, 868, 2048 }, { 7, 869, 2048 }, { 7, 870, 2048 }, { 8, 871, 2048 }, 
+   { 6, 872, 2048 }, { 7, 873, 2048 }, { 7, 874, 2048 }, { 8, 875, 2048 }, { 7, 876, 2048 }, { 8, 877, 2048 }, { 8, 878, 2048 }, { 9, 879, 2048 }, 
+   { 6, 880, 2048 }, { 7, 881, 2048 }, { 7, 882, 2048 }, { 8, 883, 2048 }, { 7, 884, 2048 }, { 8, 885, 2048 }, { 8, 886, 2048 }, { 9, 887, 2048 }, 
+   { 7, 888, 2048 }, { 8, 889, 2048 }, { 8, 890, 2048 }, { 9, 891, 2048 }, { 8, 892, 2048 }, { 9, 893, 2048 }, { 9, 894, 2048 }, { 10, 895, 2048 }, 
+   { 4, 896, 2048 }, { 5, 897, 2048 }, { 5, 898, 2048 }, { 6, 899, 2048 }, { 5, 900, 2048 }, { 6, 901, 2048 }, { 6, 902, 2048 }, { 7, 903, 2048 }, 
+   { 5, 904, 2048 }, { 6, 905, 2048 }, { 6, 906, 2048 }, { 7, 907, 2048 }, { 6, 908, 2048 }, { 7, 909, 2048 }, { 7, 910, 2048 }, { 8, 911, 2048 }, 
+   { 5, 912, 2048 }, { 6, 913, 2048 }, { 6, 914, 2048 }, { 7, 915, 2048 }, { 6, 916, 2048 }, { 7, 917, 2048 }, { 7, 918, 2048 }, { 8, 919, 2048 }, 
+   { 6, 920, 2048 }, { 7, 921, 2048 }, { 7, 922, 2048 }, { 8, 923, 2048 }, { 7, 924, 2048 }, { 8, 925, 2048 }, { 8, 926, 2048 }, { 9, 927, 2048 }, 
+   { 5, 928, 2048 }, { 6, 929, 2048 }, { 6, 930, 2048 }, { 7, 931, 2048 }, { 6, 932, 2048 }, { 7, 933, 2048 }, { 7, 934, 2048 }, { 8, 935, 2048 }, 
+   { 6, 936, 2048 }, { 7, 937, 2048 }, { 7, 938, 2048 }, { 8, 939, 2048 }, { 7, 940, 2048 }, { 8, 941, 2048 }, { 8, 942, 2048 }, { 9, 943, 2048 }, 
+   { 6, 944, 2048 }, { 7, 945, 2048 }, { 7, 946, 2048 }, { 8, 947, 2048 }, { 7, 948, 2048 }, { 8, 949, 2048 }, { 8, 950, 2048 }, { 9, 951, 2048 }, 
+   { 7, 952, 2048 }, { 8, 953, 2048 }, { 8, 954, 2048 }, { 9, 955, 2048 }, { 8, 956, 2048 }, { 9, 957, 2048 }, { 9, 958, 2048 }, { 10, 959, 2048 }, 
+   { 5, 960, 2048 }, { 6, 961, 2048 }, { 6, 962, 2048 }, { 7, 963, 2048 }, { 6, 964, 2048 }, { 7, 965, 2048 }, { 7, 966, 2048 }, { 8, 967, 2048 }, 
+   { 6, 968, 2048 }, { 7, 969, 2048 }, { 7, 970, 2048 }, { 8, 971, 2048 }, { 7, 972, 2048 }, { 8, 973, 2048 }, { 8, 974, 2048 }, { 9, 975, 2048 }, 
+   { 6, 976, 2048 }, { 7, 977, 2048 }, { 7, 978, 2048 }, { 8, 979, 2048 }, { 7, 980, 2048 }, { 8, 981, 2048 }, { 8, 982, 2048 }, { 9, 983, 2048 }, 
+   { 7, 984, 2048 }, { 8, 985, 2048 }, { 8, 986, 2048 }, { 9, 987, 2048 }, { 8, 988, 2048 }, { 9, 989, 2048 }, { 9, 990, 2048 }, { 10, 991, 2048 }, 
+   { 6, 992, 2048 }, { 7, 993, 2048 }, { 7, 994, 2048 }, { 8, 995, 2048 }, { 7, 996, 2048 }, { 8, 997, 2048 }, { 8, 998, 2048 }, { 9, 999, 2048 }, 
+   { 7, 1000, 2048 }, { 8, 1001, 2048 }, { 8, 1002, 2048 }, { 9, 1003, 2048 }, { 8, 1004, 2048 }, { 9, 1005, 2048 }, { 9, 1006, 2048 }, { 10, 1007, 2048 }, 
+   { 7, 1008, 2048 }, { 8, 1009, 2048 }, { 8, 1010, 2048 }, { 9, 1011, 2048 }, { 8, 1012, 2048 }, { 9, 1013, 2048 }, { 9, 1014, 2048 }, { 10, 1015, 2048 }, 
+   { 8, 1016, 2048 }, { 9, 1017, 2048 }, { 9, 1018, 2048 }, { 10, 1019, 2048 }, { 9, 1020, 2048 }, { 10, 1021, 2048 }, { 10, 1022, 2048 }, { 11, 1023, 2048 }, 
+   { 2, 1024, 2048 }, { 3, 1025, 2048 }, { 3, 1026, 2048 }, { 4, 1027, 2048 }, { 3, 1028, 2048 }, { 4, 1029, 2048 }, { 4, 1030, 2048 }, { 5, 1031, 2048 }, 
+   { 3, 1032, 2048 }, { 4, 1033, 2048 }, { 4, 1034, 2048 }, { 5, 1035, 2048 }, { 4, 1036, 2048 }, { 5, 1037, 2048 }, { 5, 1038, 2048 }, { 6, 1039, 2048 }, 
+   { 3, 1040, 2048 }, { 4, 1041, 2048 }, { 4, 1042, 2048 }, { 5, 1043, 2048 }, { 4, 1044, 2048 }, { 5, 1045, 2048 }, { 5, 1046, 2048 }, { 6, 1047, 2048 }, 
+   { 4, 1048, 2048 }, { 5, 1049, 2048 }, { 5, 1050, 2048 }, { 6, 1051, 2048 }, { 5, 1052, 2048 }, { 6, 1053, 2048 }, { 6, 1054, 2048 }, { 7, 1055, 2048 }, 
+   { 3, 1056, 2048 }, { 4, 1057, 2048 }, { 4, 1058, 2048 }, { 5, 1059, 2048 }, { 4, 1060, 2048 }, { 5, 1061, 2048 }, { 5, 1062, 2048 }, { 6, 1063, 2048 }, 
+   { 4, 1064, 2048 }, { 5, 1065, 2048 }, { 5, 1066, 2048 }, { 6, 1067, 2048 }, { 5, 1068, 2048 }, { 6, 1069, 2048 }, { 6, 1070, 2048 }, { 7, 1071, 2048 }, 
+   { 4, 1072, 2048 }, { 5, 1073, 2048 }, { 5, 1074, 2048 }, { 6, 1075, 2048 }, { 5, 1076, 2048 }, { 6, 1077, 2048 }, { 6, 1078, 2048 }, { 7, 1079, 2048 }, 
+   { 5, 1080, 2048 }, { 6, 1081, 2048 }, { 6, 1082, 2048 }, { 7, 1083, 2048 }, { 6, 1084, 2048 }, { 7, 1085, 2048 }, { 7, 1086, 2048 }, { 8, 1087, 2048 }, 
+   { 3, 1088, 2048 }, { 4, 1089, 2048 }, { 4, 1090, 2048 }, { 5, 1091, 2048 }, { 4, 1092, 2048 }, { 5, 1093, 2048 }, { 5, 1094, 2048 }, { 6, 1095, 2048 }, 
+   { 4, 1096, 2048 }, { 5, 1097, 2048 }, { 5, 1098, 2048 }, { 6, 1099, 2048 }, { 5, 1100, 2048 }, { 6, 1101, 2048 }, { 6, 1102, 2048 }, { 7, 1103, 2048 }, 
+   { 4, 1104, 2048 }, { 5, 1105, 2048 }, { 5, 1106, 2048 }, { 6, 1107, 2048 }, { 5, 1108, 2048 }, { 6, 1109, 2048 }, { 6, 1110, 2048 }, { 7, 1111, 2048 }, 
+   { 5, 1112, 2048 }, { 6, 1113, 2048 }, { 6, 1114, 2048 }, { 7, 1115, 2048 }, { 6, 1116, 2048 }, { 7, 1117, 2048 }, { 7, 1118, 2048 }, { 8, 1119, 2048 }, 
+   { 4, 1120, 2048 }, { 5, 1121, 2048 }, { 5, 1122, 2048 }, { 6, 1123, 2048 }, { 5, 1124, 2048 }, { 6, 1125, 2048 }, { 6, 1126, 2048 }, { 7, 1127, 2048 }, 
+   { 5, 1128, 2048 }, { 6, 1129, 2048 }, { 6, 1130, 2048 }, { 7, 1131, 2048 }, { 6, 1132, 2048 }, { 7, 1133, 2048 }, { 7, 1134, 2048 }, { 8, 1135, 2048 }, 
+   { 5, 1136, 2048 }, { 6, 1137, 2048 }, { 6, 1138, 2048 }, { 7, 1139, 2048 }, { 6, 1140, 2048 }, { 7, 1141, 2048 }, { 7, 1142, 2048 }, { 8, 1143, 2048 }, 
+   { 6, 1144, 2048 }, { 7, 1145, 2048 }, { 7, 1146, 2048 }, { 8, 1147, 2048 }, { 7, 1148, 2048 }, { 8, 1149, 2048 }, { 8, 1150, 2048 }, { 9, 1151, 2048 }, 
+   { 3, 1152, 2048 }, { 4, 1153, 2048 }, { 4, 1154, 2048 }, { 5, 1155, 2048 }, { 4, 1156, 2048 }, { 5, 1157, 2048 }, { 5, 1158, 2048 }, { 6, 1159, 2048 }, 
+   { 4, 1160, 2048 }, { 5, 1161, 2048 }, { 5, 1162, 2048 }, { 6, 1163, 2048 }, { 5, 1164, 2048 }, { 6, 1165, 2048 }, { 6, 1166, 2048 }, { 7, 1167, 2048 }, 
+   { 4, 1168, 2048 }, { 5, 1169, 2048 }, { 5, 1170, 2048 }, { 6, 1171, 2048 }, { 5, 1172, 2048 }, { 6, 1173, 2048 }, { 6, 1174, 2048 }, { 7, 1175, 2048 }, 
+   { 5, 1176, 2048 }, { 6, 1177, 2048 }, { 6, 1178, 2048 }, { 7, 1179, 2048 }, { 6, 1180, 2048 }, { 7, 1181, 2048 }, { 7, 1182, 2048 }, { 8, 1183, 2048 }, 
+   { 4, 1184, 2048 }, { 5, 1185, 2048 }, { 5, 1186, 2048 }, { 6, 1187, 2048 }, { 5, 1188, 2048 }, { 6, 1189, 2048 }, { 6, 1190, 2048 }, { 7, 1191, 2048 }, 
+   { 5, 1192, 2048 }, { 6, 1193, 2048 }, { 6, 1194, 2048 }, { 7, 1195, 2048 }, { 6, 1196, 2048 }, { 7, 1197, 2048 }, { 7, 1198, 2048 }, { 8, 1199, 2048 }, 
+   { 5, 1200, 2048 }, { 6, 1201, 2048 }, { 6, 1202, 2048 }, { 7, 1203, 2048 }, { 6, 1204, 2048 }, { 7, 1205, 2048 }, { 7, 1206, 2048 }, { 8, 1207, 2048 }, 
+   { 6, 1208, 2048 }, { 7, 1209, 2048 }, { 7, 1210, 2048 }, { 8, 1211, 2048 }, { 7, 1212, 2048 }, { 8, 1213, 2048 }, { 8, 1214, 2048 }, { 9, 1215, 2048 }, 
+   { 4, 1216, 2048 }, { 5, 1217, 2048 }, { 5, 1218, 2048 }, { 6, 1219, 2048 }, { 5, 1220, 2048 }, { 6, 1221, 2048 }, { 6, 1222, 2048 }, { 7, 1223, 2048 }, 
+   { 5, 1224, 2048 }, { 6, 1225, 2048 }, { 6, 1226, 2048 }, { 7, 1227, 2048 }, { 6, 1228, 2048 }, { 7, 1229, 2048 }, { 7, 1230, 2048 }, { 8, 1231, 2048 }, 
+   { 5, 1232, 2048 }, { 6, 1233, 2048 }, { 6, 1234, 2048 }, { 7, 1235, 2048 }, { 6, 1236, 2048 }, { 7, 1237, 2048 }, { 7, 1238, 2048 }, { 8, 1239, 2048 }, 
+   { 6, 1240, 2048 }, { 7, 1241, 2048 }, { 7, 1242, 2048 }, { 8, 1243, 2048 }, { 7, 1244, 2048 }, { 8, 1245, 2048 }, { 8, 1246, 2048 }, { 9, 1247, 2048 }, 
+   { 5, 1248, 2048 }, { 6, 1249, 2048 }, { 6, 1250, 2048 }, { 7, 1251, 2048 }, { 6, 1252, 2048 }, { 7, 1253, 2048 }, { 7, 1254, 2048 }, { 8, 1255, 2048 }, 
+   { 6, 1256, 2048 }, { 7, 1257, 2048 }, { 7, 1258, 2048 }, { 8, 1259, 2048 }, { 7, 1260, 2048 }, { 8, 1261, 2048 }, { 8, 1262, 2048 }, { 9, 1263, 2048 }, 
+   { 6, 1264, 2048 }, { 7, 1265, 2048 }, { 7, 1266, 2048 }, { 8, 1267, 2048 }, { 7, 1268, 2048 }, { 8, 1269, 2048 }, { 8, 1270, 2048 }, { 9, 1271, 2048 }, 
+   { 7, 1272, 2048 }, { 8, 1273, 2048 }, { 8, 1274, 2048 }, { 9, 1275, 2048 }, { 8, 1276, 2048 }, { 9, 1277, 2048 }, { 9, 1278, 2048 }, { 10, 1279, 2048 }, 
+   { 3, 1280, 2048 }, { 4, 1281, 2048 }, { 4, 1282, 2048 }, { 5, 1283, 2048 }, { 4, 1284, 2048 }, { 5, 1285, 2048 }, { 5, 1286, 2048 }, { 6, 1287, 2048 }, 
+   { 4, 1288, 2048 }, { 5, 1289, 2048 }, { 5, 1290, 2048 }, { 6, 1291, 2048 }, { 5, 1292, 2048 }, { 6, 1293, 2048 }, { 6, 1294, 2048 }, { 7, 1295, 2048 }, 
+   { 4, 1296, 2048 }, { 5, 1297, 2048 }, { 5, 1298, 2048 }, { 6, 1299, 2048 }, { 5, 1300, 2048 }, { 6, 1301, 2048 }, { 6, 1302, 2048 }, { 7, 1303, 2048 }, 
+   { 5, 1304, 2048 }, { 6, 1305, 2048 }, { 6, 1306, 2048 }, { 7, 1307, 2048 }, { 6, 1308, 2048 }, { 7, 1309, 2048 }, { 7, 1310, 2048 }, { 8, 1311, 2048 }, 
+   { 4, 1312, 2048 }, { 5, 1313, 2048 }, { 5, 1314, 2048 }, { 6, 1315, 2048 }, { 5, 1316, 2048 }, { 6, 1317, 2048 }, { 6, 1318, 2048 }, { 7, 1319, 2048 }, 
+   { 5, 1320, 2048 }, { 6, 1321, 2048 }, { 6, 1322, 2048 }, { 7, 1323, 2048 }, { 6, 1324, 2048 }, { 7, 1325, 2048 }, { 7, 1326, 2048 }, { 8, 1327, 2048 }, 
+   { 5, 1328, 2048 }, { 6, 1329, 2048 }, { 6, 1330, 2048 }, { 7, 1331, 2048 }, { 6, 1332, 2048 }, { 7, 1333, 2048 }, { 7, 1334, 2048 }, { 8, 1335, 2048 }, 
+   { 6, 1336, 2048 }, { 7, 1337, 2048 }, { 7, 1338, 2048 }, { 8, 1339, 2048 }, { 7, 1340, 2048 }, { 8, 1341, 2048 }, { 8, 1342, 2048 }, { 9, 1343, 2048 }, 
+   { 4, 1344, 2048 }, { 5, 1345, 2048 }, { 5, 1346, 2048 }, { 6, 1347, 2048 }, { 5, 1348, 2048 }, { 6, 1349, 2048 }, { 6, 1350, 2048 }, { 7, 1351, 2048 }, 
+   { 5, 1352, 2048 }, { 6, 1353, 2048 }, { 6, 1354, 2048 }, { 7, 1355, 2048 }, { 6, 1356, 2048 }, { 7, 1357, 2048 }, { 7, 1358, 2048 }, { 8, 1359, 2048 }, 
+   { 5, 1360, 2048 }, { 6, 1361, 2048 }, { 6, 1362, 2048 }, { 7, 1363, 2048 }, { 6, 1364, 2048 }, { 7, 1365, 2048 }, { 7, 1366, 2048 }, { 8, 1367, 2048 }, 
+   { 6, 1368, 2048 }, { 7, 1369, 2048 }, { 7, 1370, 2048 }, { 8, 1371, 2048 }, { 7, 1372, 2048 }, { 8, 1373, 2048 }, { 8, 1374, 2048 }, { 9, 1375, 2048 }, 
+   { 5, 1376, 2048 }, { 6, 1377, 2048 }, { 6, 1378, 2048 }, { 7, 1379, 2048 }, { 6, 1380, 2048 }, { 7, 1381, 2048 }, { 7, 1382, 2048 }, { 8, 1383, 2048 }, 
+   { 6, 1384, 2048 }, { 7, 1385, 2048 }, { 7, 1386, 2048 }, { 8, 1387, 2048 }, { 7, 1388, 2048 }, { 8, 1389, 2048 }, { 8, 1390, 2048 }, { 9, 1391, 2048 }, 
+   { 6, 1392, 2048 }, { 7, 1393, 2048 }, { 7, 1394, 2048 }, { 8, 1395, 2048 }, { 7, 1396, 2048 }, { 8, 1397, 2048 }, { 8, 1398, 2048 }, { 9, 1399, 2048 }, 
+   { 7, 1400, 2048 }, { 8, 1401, 2048 }, { 8, 1402, 2048 }, { 9, 1403, 2048 }, { 8, 1404, 2048 }, { 9, 1405, 2048 }, { 9, 1406, 2048 }, { 10, 1407, 2048 }, 
+   { 4, 1408, 2048 }, { 5, 1409, 2048 }, { 5, 1410, 2048 }, { 6, 1411, 2048 }, { 5, 1412, 2048 }, { 6, 1413, 2048 }, { 6, 1414, 2048 }, { 7, 1415, 2048 }, 
+   { 5, 1416, 2048 }, { 6, 1417, 2048 }, { 6, 1418, 2048 }, { 7, 1419, 2048 }, { 6, 1420, 2048 }, { 7, 1421, 2048 }, { 7, 1422, 2048 }, { 8, 1423, 2048 }, 
+   { 5, 1424, 2048 }, { 6, 1425, 2048 }, { 6, 1426, 2048 }, { 7, 1427, 2048 }, { 6, 1428, 2048 }, { 7, 1429, 2048 }, { 7, 1430, 2048 }, { 8, 1431, 2048 }, 
+   { 6, 1432, 2048 }, { 7, 1433, 2048 }, { 7, 1434, 2048 }, { 8, 1435, 2048 }, { 7, 1436, 2048 }, { 8, 1437, 2048 }, { 8, 1438, 2048 }, { 9, 1439, 2048 }, 
+   { 5, 1440, 2048 }, { 6, 1441, 2048 }, { 6, 1442, 2048 }, { 7, 1443, 2048 }, { 6, 1444, 2048 }, { 7, 1445, 2048 }, { 7, 1446, 2048 }, { 8, 1447, 2048 }, 
+   { 6, 1448, 2048 }, { 7, 1449, 2048 }, { 7, 1450, 2048 }, { 8, 1451, 2048 }, { 7, 1452, 2048 }, { 8, 1453, 2048 }, { 8, 1454, 2048 }, { 9, 1455, 2048 }, 
+   { 6, 1456, 2048 }, { 7, 1457, 2048 }, { 7, 1458, 2048 }, { 8, 1459, 2048 }, { 7, 1460, 2048 }, { 8, 1461, 2048 }, { 8, 1462, 2048 }, { 9, 1463, 2048 }, 
+   { 7, 1464, 2048 }, { 8, 1465, 2048 }, { 8, 1466, 2048 }, { 9, 1467, 2048 }, { 8, 1468, 2048 }, { 9, 1469, 2048 }, { 9, 1470, 2048 }, { 10, 1471, 2048 }, 
+   { 5, 1472, 2048 }, { 6, 1473, 2048 }, { 6, 1474, 2048 }, { 7, 1475, 2048 }, { 6, 1476, 2048 }, { 7, 1477, 2048 }, { 7, 1478, 2048 }, { 8, 1479, 2048 }, 
+   { 6, 1480, 2048 }, { 7, 1481, 2048 }, { 7, 1482, 2048 }, { 8, 1483, 2048 }, { 7, 1484, 2048 }, { 8, 1485, 2048 }, { 8, 1486, 2048 }, { 9, 1487, 2048 }, 
+   { 6, 1488, 2048 }, { 7, 1489, 2048 }, { 7, 1490, 2048 }, { 8, 1491, 2048 }, { 7, 1492, 2048 }, { 8, 1493, 2048 }, { 8, 1494, 2048 }, { 9, 1495, 2048 }, 
+   { 7, 1496, 2048 }, { 8, 1497, 2048 }, { 8, 1498, 2048 }, { 9, 1499, 2048 }, { 8, 1500, 2048 }, { 9, 1501, 2048 }, { 9, 1502, 2048 }, { 10, 1503, 2048 }, 
+   { 6, 1504, 2048 }, { 7, 1505, 2048 }, { 7, 1506, 2048 }, { 8, 1507, 2048 }, { 7, 1508, 2048 }, { 8, 1509, 2048 }, { 8, 1510, 2048 }, { 9, 1511, 2048 }, 
+   { 7, 1512, 2048 }, { 8, 1513, 2048 }, { 8, 1514, 2048 }, { 9, 1515, 2048 }, { 8, 1516, 2048 }, { 9, 1517, 2048 }, { 9, 1518, 2048 }, { 10, 1519, 2048 }, 
+   { 7, 1520, 2048 }, { 8, 1521, 2048 }, { 8, 1522, 2048 }, { 9, 1523, 2048 }, { 8, 1524, 2048 }, { 9, 1525, 2048 }, { 9, 1526, 2048 }, { 10, 1527, 2048 }, 
+   { 8, 1528, 2048 }, { 9, 1529, 2048 }, { 9, 1530, 2048 }, { 10, 1531, 2048 }, { 9, 1532, 2048 }, { 10, 1533, 2048 }, { 10, 1534, 2048 }, { 11, 1535, 2048 }, 
+   { 3, 1536, 2048 }, { 4, 1537, 2048 }, { 4, 1538, 2048 }, { 5, 1539, 2048 }, { 4, 1540, 2048 }, { 5, 1541, 2048 }, { 5, 1542, 2048 }, { 6, 1543, 2048 }, 
+   { 4, 1544, 2048 }, { 5, 1545, 2048 }, { 5, 1546, 2048 }, { 6, 1547, 2048 }, { 5, 1548, 2048 }, { 6, 1549, 2048 }, { 6, 1550, 2048 }, { 7, 1551, 2048 }, 
+   { 4, 1552, 2048 }, { 5, 1553, 2048 }, { 5, 1554, 2048 }, { 6, 1555, 2048 }, { 5, 1556, 2048 }, { 6, 1557, 2048 }, { 6, 1558, 2048 }, { 7, 1559, 2048 }, 
+   { 5, 1560, 2048 }, { 6, 1561, 2048 }, { 6, 1562, 2048 }, { 7, 1563, 2048 }, { 6, 1564, 2048 }, { 7, 1565, 2048 }, { 7, 1566, 2048 }, { 8, 1567, 2048 }, 
+   { 4, 1568, 2048 }, { 5, 1569, 2048 }, { 5, 1570, 2048 }, { 6, 1571, 2048 }, { 5, 1572, 2048 }, { 6, 1573, 2048 }, { 6, 1574, 2048 }, { 7, 1575, 2048 }, 
+   { 5, 1576, 2048 }, { 6, 1577, 2048 }, { 6, 1578, 2048 }, { 7, 1579, 2048 }, { 6, 1580, 2048 }, { 7, 1581, 2048 }, { 7, 1582, 2048 }, { 8, 1583, 2048 }, 
+   { 5, 1584, 2048 }, { 6, 1585, 2048 }, { 6, 1586, 2048 }, { 7, 1587, 2048 }, { 6, 1588, 2048 }, { 7, 1589, 2048 }, { 7, 1590, 2048 }, { 8, 1591, 2048 }, 
+   { 6, 1592, 2048 }, { 7, 1593, 2048 }, { 7, 1594, 2048 }, { 8, 1595, 2048 }, { 7, 1596, 2048 }, { 8, 1597, 2048 }, { 8, 1598, 2048 }, { 9, 1599, 2048 }, 
+   { 4, 1600, 2048 }, { 5, 1601, 2048 }, { 5, 1602, 2048 }, { 6, 1603, 2048 }, { 5, 1604, 2048 }, { 6, 1605, 2048 }, { 6, 1606, 2048 }, { 7, 1607, 2048 }, 
+   { 5, 1608, 2048 }, { 6, 1609, 2048 }, { 6, 1610, 2048 }, { 7, 1611, 2048 }, { 6, 1612, 2048 }, { 7, 1613, 2048 }, { 7, 1614, 2048 }, { 8, 1615, 2048 }, 
+   { 5, 1616, 2048 }, { 6, 1617, 2048 }, { 6, 1618, 2048 }, { 7, 1619, 2048 }, { 6, 1620, 2048 }, { 7, 1621, 2048 }, { 7, 1622, 2048 }, { 8, 1623, 2048 }, 
+   { 6, 1624, 2048 }, { 7, 1625, 2048 }, { 7, 1626, 2048 }, { 8, 1627, 2048 }, { 7, 1628, 2048 }, { 8, 1629, 2048 }, { 8, 1630, 2048 }, { 9, 1631, 2048 }, 
+   { 5, 1632, 2048 }, { 6, 1633, 2048 }, { 6, 1634, 2048 }, { 7, 1635, 2048 }, { 6, 1636, 2048 }, { 7, 1637, 2048 }, { 7, 1638, 2048 }, { 8, 1639, 2048 }, 
+   { 6, 1640, 2048 }, { 7, 1641, 2048 }, { 7, 1642, 2048 }, { 8, 1643, 2048 }, { 7, 1644, 2048 }, { 8, 1645, 2048 }, { 8, 1646, 2048 }, { 9, 1647, 2048 }, 
+   { 6, 1648, 2048 }, { 7, 1649, 2048 }, { 7, 1650, 2048 }, { 8, 1651, 2048 }, { 7, 1652, 2048 }, { 8, 1653, 2048 }, { 8, 1654, 2048 }, { 9, 1655, 2048 }, 
+   { 7, 1656, 2048 }, { 8, 1657, 2048 }, { 8, 1658, 2048 }, { 9, 1659, 2048 }, { 8, 1660, 2048 }, { 9, 1661, 2048 }, { 9, 1662, 2048 }, { 10, 1663, 2048 }, 
+   { 4, 1664, 2048 }, { 5, 1665, 2048 }, { 5, 1666, 2048 }, { 6, 1667, 2048 }, { 5, 1668, 2048 }, { 6, 1669, 2048 }, { 6, 1670, 2048 }, { 7, 1671, 2048 }, 
+   { 5, 1672, 2048 }, { 6, 1673, 2048 }, { 6, 1674, 2048 }, { 7, 1675, 2048 }, { 6, 1676, 2048 }, { 7, 1677, 2048 }, { 7, 1678, 2048 }, { 8, 1679, 2048 }, 
+   { 5, 1680, 2048 }, { 6, 1681, 2048 }, { 6, 1682, 2048 }, { 7, 1683, 2048 }, { 6, 1684, 2048 }, { 7, 1685, 2048 }, { 7, 1686, 2048 }, { 8, 1687, 2048 }, 
+   { 6, 1688, 2048 }, { 7, 1689, 2048 }, { 7, 1690, 2048 }, { 8, 1691, 2048 }, { 7, 1692, 2048 }, { 8, 1693, 2048 }, { 8, 1694, 2048 }, { 9, 1695, 2048 }, 
+   { 5, 1696, 2048 }, { 6, 1697, 2048 }, { 6, 1698, 2048 }, { 7, 1699, 2048 }, { 6, 1700, 2048 }, { 7, 1701, 2048 }, { 7, 1702, 2048 }, { 8, 1703, 2048 }, 
+   { 6, 1704, 2048 }, { 7, 1705, 2048 }, { 7, 1706, 2048 }, { 8, 1707, 2048 }, { 7, 1708, 2048 }, { 8, 1709, 2048 }, { 8, 1710, 2048 }, { 9, 1711, 2048 }, 
+   { 6, 1712, 2048 }, { 7, 1713, 2048 }, { 7, 1714, 2048 }, { 8, 1715, 2048 }, { 7, 1716, 2048 }, { 8, 1717, 2048 }, { 8, 1718, 2048 }, { 9, 1719, 2048 }, 
+   { 7, 1720, 2048 }, { 8, 1721, 2048 }, { 8, 1722, 2048 }, { 9, 1723, 2048 }, { 8, 1724, 2048 }, { 9, 1725, 2048 }, { 9, 1726, 2048 }, { 10, 1727, 2048 }, 
+   { 5, 1728, 2048 }, { 6, 1729, 2048 }, { 6, 1730, 2048 }, { 7, 1731, 2048 }, { 6, 1732, 2048 }, { 7, 1733, 2048 }, { 7, 1734, 2048 }, { 8, 1735, 2048 }, 
+   { 6, 1736, 2048 }, { 7, 1737, 2048 }, { 7, 1738, 2048 }, { 8, 1739, 2048 }, { 7, 1740, 2048 }, { 8, 1741, 2048 }, { 8, 1742, 2048 }, { 9, 1743, 2048 }, 
+   { 6, 1744, 2048 }, { 7, 1745, 2048 }, { 7, 1746, 2048 }, { 8, 1747, 2048 }, { 7, 1748, 2048 }, { 8, 1749, 2048 }, { 8, 1750, 2048 }, { 9, 1751, 2048 }, 
+   { 7, 1752, 2048 }, { 8, 1753, 2048 }, { 8, 1754, 2048 }, { 9, 1755, 2048 }, { 8, 1756, 2048 }, { 9, 1757, 2048 }, { 9, 1758, 2048 }, { 10, 1759, 2048 }, 
+   { 6, 1760, 2048 }, { 7, 1761, 2048 }, { 7, 1762, 2048 }, { 8, 1763, 2048 }, { 7, 1764, 2048 }, { 8, 1765, 2048 }, { 8, 1766, 2048 }, { 9, 1767, 2048 }, 
+   { 7, 1768, 2048 }, { 8, 1769, 2048 }, { 8, 1770, 2048 }, { 9, 1771, 2048 }, { 8, 1772, 2048 }, { 9, 1773, 2048 }, { 9, 1774, 2048 }, { 10, 1775, 2048 }, 
+   { 7, 1776, 2048 }, { 8, 1777, 2048 }, { 8, 1778, 2048 }, { 9, 1779, 2048 }, { 8, 1780, 2048 }, { 9, 1781, 2048 }, { 9, 1782, 2048 }, { 10, 1783, 2048 }, 
+   { 8, 1784, 2048 }, { 9, 1785, 2048 }, { 9, 1786, 2048 }, { 10, 1787, 2048 }, { 9, 1788, 2048 }, { 10, 1789, 2048 }, { 10, 1790, 2048 }, { 11, 1791, 2048 }, 
+   { 4, 1792, 2048 }, { 5, 1793, 2048 }, { 5, 1794, 2048 }, { 6, 1795, 2048 }, { 5, 1796, 2048 }, { 6, 1797, 2048 }, { 6, 1798, 2048 }, { 7, 1799, 2048 }, 
+   { 5, 1800, 2048 }, { 6, 1801, 2048 }, { 6, 1802, 2048 }, { 7, 1803, 2048 }, { 6, 1804, 2048 }, { 7, 1805, 2048 }, { 7, 1806, 2048 }, { 8, 1807, 2048 }, 
+   { 5, 1808, 2048 }, { 6, 1809, 2048 }, { 6, 1810, 2048 }, { 7, 1811, 2048 }, { 6, 1812, 2048 }, { 7, 1813, 2048 }, { 7, 1814, 2048 }, { 8, 1815, 2048 }, 
+   { 6, 1816, 2048 }, { 7, 1817, 2048 }, { 7, 1818, 2048 }, { 8, 1819, 2048 }, { 7, 1820, 2048 }, { 8, 1821, 2048 }, { 8, 1822, 2048 }, { 9, 1823, 2048 }, 
+   { 5, 1824, 2048 }, { 6, 1825, 2048 }, { 6, 1826, 2048 }, { 7, 1827, 2048 }, { 6, 1828, 2048 }, { 7, 1829, 2048 }, { 7, 1830, 2048 }, { 8, 1831, 2048 }, 
+   { 6, 1832, 2048 }, { 7, 1833, 2048 }, { 7, 1834, 2048 }, { 8, 1835, 2048 }, { 7, 1836, 2048 }, { 8, 1837, 2048 }, { 8, 1838, 2048 }, { 9, 1839, 2048 }, 
+   { 6, 1840, 2048 }, { 7, 1841, 2048 }, { 7, 1842, 2048 }, { 8, 1843, 2048 }, { 7, 1844, 2048 }, { 8, 1845, 2048 }, { 8, 1846, 2048 }, { 9, 1847, 2048 }, 
+   { 7, 1848, 2048 }, { 8, 1849, 2048 }, { 8, 1850, 2048 }, { 9, 1851, 2048 }, { 8, 1852, 2048 }, { 9, 1853, 2048 }, { 9, 1854, 2048 }, { 10, 1855, 2048 }, 
+   { 5, 1856, 2048 }, { 6, 1857, 2048 }, { 6, 1858, 2048 }, { 7, 1859, 2048 }, { 6, 1860, 2048 }, { 7, 1861, 2048 }, { 7, 1862, 2048 }, { 8, 1863, 2048 }, 
+   { 6, 1864, 2048 }, { 7, 1865, 2048 }, { 7, 1866, 2048 }, { 8, 1867, 2048 }, { 7, 1868, 2048 }, { 8, 1869, 2048 }, { 8, 1870, 2048 }, { 9, 1871, 2048 }, 
+   { 6, 1872, 2048 }, { 7, 1873, 2048 }, { 7, 1874, 2048 }, { 8, 1875, 2048 }, { 7, 1876, 2048 }, { 8, 1877, 2048 }, { 8, 1878, 2048 }, { 9, 1879, 2048 }, 
+   { 7, 1880, 2048 }, { 8, 1881, 2048 }, { 8, 1882, 2048 }, { 9, 1883, 2048 }, { 8, 1884, 2048 }, { 9, 1885, 2048 }, { 9, 1886, 2048 }, { 10, 1887, 2048 }, 
+   { 6, 1888, 2048 }, { 7, 1889, 2048 }, { 7, 1890, 2048 }, { 8, 1891, 2048 }, { 7, 1892, 2048 }, { 8, 1893, 2048 }, { 8, 1894, 2048 }, { 9, 1895, 2048 }, 
+   { 7, 1896, 2048 }, { 8, 1897, 2048 }, { 8, 1898, 2048 }, { 9, 1899, 2048 }, { 8, 1900, 2048 }, { 9, 1901, 2048 }, { 9, 1902, 2048 }, { 10, 1903, 2048 }, 
+   { 7, 1904, 2048 }, { 8, 1905, 2048 }, { 8, 1906, 2048 }, { 9, 1907, 2048 }, { 8, 1908, 2048 }, { 9, 1909, 2048 }, { 9, 1910, 2048 }, { 10, 1911, 2048 }, 
+   { 8, 1912, 2048 }, { 9, 1913, 2048 }, { 9, 1914, 2048 }, { 10, 1915, 2048 }, { 9, 1916, 2048 }, { 10, 1917, 2048 }, { 10, 1918, 2048 }, { 11, 1919, 2048 }, 
+   { 5, 1920, 2048 }, { 6, 1921, 2048 }, { 6, 1922, 2048 }, { 7, 1923, 2048 }, { 6, 1924, 2048 }, { 7, 1925, 2048 }, { 7, 1926, 2048 }, { 8, 1927, 2048 }, 
+   { 6, 1928, 2048 }, { 7, 1929, 2048 }, { 7, 1930, 2048 }, { 8, 1931, 2048 }, { 7, 1932, 2048 }, { 8, 1933, 2048 }, { 8, 1934, 2048 }, { 9, 1935, 2048 }, 
+   { 6, 1936, 2048 }, { 7, 1937, 2048 }, { 7, 1938, 2048 }, { 8, 1939, 2048 }, { 7, 1940, 2048 }, { 8, 1941, 2048 }, { 8, 1942, 2048 }, { 9, 1943, 2048 }, 
+   { 7, 1944, 2048 }, { 8, 1945, 2048 }, { 8, 1946, 2048 }, { 9, 1947, 2048 }, { 8, 1948, 2048 }, { 9, 1949, 2048 }, { 9, 1950, 2048 }, { 10, 1951, 2048 }, 
+   { 6, 1952, 2048 }, { 7, 1953, 2048 }, { 7, 1954, 2048 }, { 8, 1955, 2048 }, { 7, 1956, 2048 }, { 8, 1957, 2048 }, { 8, 1958, 2048 }, { 9, 1959, 2048 }, 
+   { 7, 1960, 2048 }, { 8, 1961, 2048 }, { 8, 1962, 2048 }, { 9, 1963, 2048 }, { 8, 1964, 2048 }, { 9, 1965, 2048 }, { 9, 1966, 2048 }, { 10, 1967, 2048 }, 
+   { 7, 1968, 2048 }, { 8, 1969, 2048 }, { 8, 1970, 2048 }, { 9, 1971, 2048 }, { 8, 1972, 2048 }, { 9, 1973, 2048 }, { 9, 1974, 2048 }, { 10, 1975, 2048 }, 
+   { 8, 1976, 2048 }, { 9, 1977, 2048 }, { 9, 1978, 2048 }, { 10, 1979, 2048 }, { 9, 1980, 2048 }, { 10, 1981, 2048 }, { 10, 1982, 2048 }, { 11, 1983, 2048 }, 
+   { 6, 1984, 2048 }, { 7, 1985, 2048 }, { 7, 1986, 2048 }, { 8, 1987, 2048 }, { 7, 1988, 2048 }, { 8, 1989, 2048 }, { 8, 1990, 2048 }, { 9, 1991, 2048 }, 
+   { 7, 1992, 2048 }, { 8, 1993, 2048 }, { 8, 1994, 2048 }, { 9, 1995, 2048 }, { 8, 1996, 2048 }, { 9, 1997, 2048 }, { 9, 1998, 2048 }, { 10, 1999, 2048 }, 
+   { 7, 2000, 2048 }, { 8, 2001, 2048 }, { 8, 2002, 2048 }, { 9, 2003, 2048 }, { 8, 2004, 2048 }, { 9, 2005, 2048 }, { 9, 2006, 2048 }, { 10, 2007, 2048 }, 
+   { 8, 2008, 2048 }, { 9, 2009, 2048 }, { 9, 2010, 2048 }, { 10, 2011, 2048 }, { 9, 2012, 2048 }, { 10, 2013, 2048 }, { 10, 2014, 2048 }, { 11, 2015, 2048 }, 
+   { 7, 2016, 2048 }, { 8, 2017, 2048 }, { 8, 2018, 2048 }, { 9, 2019, 2048 }, { 8, 2020, 2048 }, { 9, 2021, 2048 }, { 9, 2022, 2048 }, { 10, 2023, 2048 }, 
+   { 8, 2024, 2048 }, { 9, 2025, 2048 }, { 9, 2026, 2048 }, { 10, 2027, 2048 }, { 9, 2028, 2048 }, { 10, 2029, 2048 }, { 10, 2030, 2048 }, { 11, 2031, 2048 }, 
+   { 8, 2032, 2048 }, { 9, 2033, 2048 }, { 9, 2034, 2048 }, { 10, 2035, 2048 }, { 9, 2036, 2048 }, { 10, 2037, 2048 }, { 10, 2038, 2048 }, { 11, 2039, 2048 }, 
+   { 9, 2040, 2048 }, { 10, 2041, 2048 }, { 10, 2042, 2048 }, { 11, 2043, 2048 }, { 10, 2044, 2048 }, { 11, 2045, 2048 }, { 11, 2046, 2048 }, { 12, 2047, 2048 }, 
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+};
+
+/* find a hole and free as required, return -1 if no hole found */
+static int find_hole(void)
+{
+   unsigned x;
+   int      y, z;
+   for (z = -1, y = INT_MAX, x = 0; x < FP_ENTRIES; x++) {
+       if (fp_cache[x].lru_count < y && fp_cache[x].lock == 0) {
+          z = x;
+          y = fp_cache[x].lru_count;
+       }
+   }
+
+   /* decrease all */
+   for (x = 0; x < FP_ENTRIES; x++) {
+      if (fp_cache[x].lru_count > 3) {
+         --(fp_cache[x].lru_count);
+      }
+   }
+
+   /* free entry z */
+   if (z >= 0 && fp_cache[z].g) {
+      mp_clear(&fp_cache[z].mu);
+      ecc_del_point(fp_cache[z].g);
+      fp_cache[z].g  = NULL;
+      for (x = 0; x < (1U<<FP_LUT); x++) {
+         ecc_del_point(fp_cache[z].LUT[x]);
+         fp_cache[z].LUT[x] = NULL;
+      }
+      fp_cache[z].lru_count = 0;
+   }
+   return z;
+}
+
+/* determine if a base is already in the cache and if so, where */
+static int find_base(ecc_point* g)
+{
+   int x;
+   for (x = 0; x < FP_ENTRIES; x++) {
+      if (fp_cache[x].g != NULL && 
+          mp_cmp(&fp_cache[x].g->x, &g->x) == MP_EQ && 
+          mp_cmp(&fp_cache[x].g->y, &g->y) == MP_EQ && 
+          mp_cmp(&fp_cache[x].g->z, &g->z) == MP_EQ) {
+         break;
+      }
+   }
+   if (x == FP_ENTRIES) {
+      x = -1;
+   }
+   return x;
+}
+
+/* add a new base to the cache */
+static int add_entry(int idx, ecc_point *g)
+{
+   unsigned x, y;
+
+   /* allocate base and LUT */
+   fp_cache[idx].g = ecc_new_point();
+   if (fp_cache[idx].g == NULL) {
+      return GEN_MEM_ERR;
+   }
+
+   /* copy x and y */
+   if ((mp_copy(&g->x, &fp_cache[idx].g->x) != MP_OKAY) ||
+       (mp_copy(&g->y, &fp_cache[idx].g->y) != MP_OKAY) ||
+       (mp_copy(&g->z, &fp_cache[idx].g->z) != MP_OKAY)) {
+      ecc_del_point(fp_cache[idx].g);
+      fp_cache[idx].g = NULL;
+      return GEN_MEM_ERR;
+   }              
+
+   for (x = 0; x < (1U<<FP_LUT); x++) {
+      fp_cache[idx].LUT[x] = ecc_new_point();
+      if (fp_cache[idx].LUT[x] == NULL) {
+         for (y = 0; y < x; y++) {
+            ecc_del_point(fp_cache[idx].LUT[y]);
+            fp_cache[idx].LUT[y] = NULL;
+         }
+         ecc_del_point(fp_cache[idx].g);
+         fp_cache[idx].g         = NULL;
+         fp_cache[idx].lru_count = 0;
+         return GEN_MEM_ERR;
+      }
+   }
+   
+   fp_cache[idx].lru_count = 0;
+
+   return MP_OKAY;
+}
+
+/* build the LUT by spacing the bits of the input by #modulus/FP_LUT bits apart 
+ * 
+ * The algorithm builds patterns in increasing bit order by first making all 
+ * single bit input patterns, then all two bit input patterns and so on
+ */
+static int build_lut(int idx, mp_int* modulus, mp_digit* mp, mp_int* mu)
+{ 
+   unsigned x, y, err, bitlen, lut_gap;
+   mp_int tmp;
+
+   if (mp_init(&tmp) != MP_OKAY)
+       return GEN_MEM_ERR;
+
+   /* sanity check to make sure lut_order table is of correct size,
+      should compile out to a NOP if true */
+   if ((sizeof(lut_orders) / sizeof(lut_orders[0])) < (1U<<FP_LUT)) {
+       err = BAD_FUNC_ARG;
+   }
+   else {   
+    /* get bitlen and round up to next multiple of FP_LUT */
+    bitlen  = mp_unsigned_bin_size(modulus) << 3;
+    x       = bitlen % FP_LUT;
+    if (x) {
+      bitlen += FP_LUT - x;
+    }  
+    lut_gap = bitlen / FP_LUT;
+
+    /* init the mu */
+    err = mp_init_copy(&fp_cache[idx].mu, mu);
+   }
+   
+   /* copy base */
+   if (err == MP_OKAY) {
+     if ((mp_mulmod(&fp_cache[idx].g->x, mu, modulus,
+                  &fp_cache[idx].LUT[1]->x) != MP_OKAY) || 
+         (mp_mulmod(&fp_cache[idx].g->y, mu, modulus,
+                  &fp_cache[idx].LUT[1]->y) != MP_OKAY) || 
+         (mp_mulmod(&fp_cache[idx].g->z, mu, modulus,
+                  &fp_cache[idx].LUT[1]->z) != MP_OKAY)) {
+       err = MP_MULMOD_E; 
+     }
+   }
+       
+   /* make all single bit entries */
+   for (x = 1; x < FP_LUT; x++) {
+      if (err != MP_OKAY)
+          break;
+      if ((mp_copy(&fp_cache[idx].LUT[1<<(x-1)]->x,
+                   &fp_cache[idx].LUT[1<<x]->x) != MP_OKAY) || 
+          (mp_copy(&fp_cache[idx].LUT[1<<(x-1)]->y,
+                   &fp_cache[idx].LUT[1<<x]->y) != MP_OKAY) || 
+          (mp_copy(&fp_cache[idx].LUT[1<<(x-1)]->z,
+                   &fp_cache[idx].LUT[1<<x]->z) != MP_OKAY)){
+          err = MP_INIT_E;
+          break;
+      } else {
+          
+         /* now double it bitlen/FP_LUT times */
+         for (y = 0; y < lut_gap; y++) {
+             if ((err = ecc_projective_dbl_point(fp_cache[idx].LUT[1<<x],
+                            fp_cache[idx].LUT[1<<x], modulus, mp)) != MP_OKAY) {
+                 break;
+             }
+         }
+     }
+  }
+      
+   /* now make all entries in increase order of hamming weight */
+   for (x = 2; x <= FP_LUT; x++) {
+       if (err != MP_OKAY)
+           break;
+       for (y = 0; y < (1UL<<FP_LUT); y++) {
+           if (err != MP_OKAY)
+             break;
+           if (lut_orders[y].ham != (int)x) continue;
+                     
+           /* perform the add */
+           if ((err = ecc_projective_add_point(
+                           fp_cache[idx].LUT[lut_orders[y].terma],
+                           fp_cache[idx].LUT[lut_orders[y].termb],
+                           fp_cache[idx].LUT[y], modulus, mp)) != MP_OKAY) {
+              break;
+           }
+       }
+   }
+      
+   /* now map all entries back to affine space to make point addition faster */
+   for (x = 1; x < (1UL<<FP_LUT); x++) {
+       if (err != MP_OKAY)
+           break;
+
+       /* convert z to normal from montgomery */
+       err = mp_montgomery_reduce(&fp_cache[idx].LUT[x]->z, modulus, *mp);
+ 
+       /* invert it */
+       if (err == MP_OKAY)
+         err = mp_invmod(&fp_cache[idx].LUT[x]->z, modulus,
+                         &fp_cache[idx].LUT[x]->z);
+
+       if (err == MP_OKAY)
+         /* now square it */
+         err = mp_sqrmod(&fp_cache[idx].LUT[x]->z, modulus, &tmp);
+       
+       if (err == MP_OKAY)
+         /* fix x */
+         err = mp_mulmod(&fp_cache[idx].LUT[x]->x, &tmp, modulus,
+                         &fp_cache[idx].LUT[x]->x);
+
+       if (err == MP_OKAY)
+         /* get 1/z^3 */
+         err = mp_mulmod(&tmp, &fp_cache[idx].LUT[x]->z, modulus, &tmp);
+
+       if (err == MP_OKAY)
+         /* fix y */
+         err = mp_mulmod(&fp_cache[idx].LUT[x]->y, &tmp, modulus,
+                         &fp_cache[idx].LUT[x]->y);
+
+       if (err == MP_OKAY)
+         /* free z */
+         mp_clear(&fp_cache[idx].LUT[x]->z);
+   }
+   mp_clear(&tmp);
+
+   if (err == MP_OKAY)
+     return MP_OKAY;
+
+   /* err cleanup */
+   for (y = 0; y < (1U<<FP_LUT); y++) {
+      ecc_del_point(fp_cache[idx].LUT[y]);
+      fp_cache[idx].LUT[y] = NULL;
+   }
+   ecc_del_point(fp_cache[idx].g);
+   fp_cache[idx].g         = NULL;
+   fp_cache[idx].lru_count = 0;
+   mp_clear(&fp_cache[idx].mu);
+   mp_clear(&tmp);
+
+   return err;
+}
+
+/* perform a fixed point ECC mulmod */
+static int accel_fp_mul(int idx, mp_int* k, ecc_point *R, mp_int* modulus,
+                        mp_digit* mp, int map)
+{
+   unsigned char kb[128];
+   int      x;
+   unsigned y, z, err, bitlen, bitpos, lut_gap, first;
+   mp_int   tk;
+
+   if (mp_init(&tk) != MP_OKAY)
+       return MP_INIT_E;
+
+   /* if it's smaller than modulus we fine */
+   if (mp_unsigned_bin_size(k) > mp_unsigned_bin_size(modulus)) {
+      mp_int order;
+      if (mp_init(&order) != MP_OKAY) {
+        mp_clear(&tk);
+        return MP_INIT_E;
+      }
+
+      /* find order */
+      y = mp_unsigned_bin_size(modulus);
+      for (x = 0; ecc_sets[x].size; x++) {
+         if (y <= (unsigned)ecc_sets[x].size) break;
+      }
+   
+      /* back off if we are on the 521 bit curve */
+      if (y == 66) --x;
+      
+      if ((err = mp_read_radix(&order, ecc_sets[x].order, 16)) != MP_OKAY) {
+         mp_clear(&order);
+         mp_clear(&tk);
+         return err;
+      }
+
+      /* k must be less than modulus */
+      if (mp_cmp(k, &order) != MP_LT) {
+         if ((err = mp_mod(k, &order, &tk)) != MP_OKAY) {
+            mp_clear(&tk);
+            mp_clear(&order);
+            return err;
+         }
+      } else {
+         mp_copy(k, &tk);
+      }
+      mp_clear(&order);
+   } else {
+      mp_copy(k, &tk);
+   }       
+   
+   /* get bitlen and round up to next multiple of FP_LUT */
+   bitlen  = mp_unsigned_bin_size(modulus) << 3;
+   x       = bitlen % FP_LUT;
+   if (x) {
+      bitlen += FP_LUT - x;
+   }  
+   lut_gap = bitlen / FP_LUT;
+        
+   /* get the k value */
+   if (mp_unsigned_bin_size(&tk) > (int)(sizeof(kb) - 2)) {
+      mp_clear(&tk);
+      return BUFFER_E;
+   }
+   
+   /* store k */
+   XMEMSET(kb, 0, sizeof(kb));
+   if ((err = mp_to_unsigned_bin(&tk, kb)) != MP_OKAY) {
+      mp_clear(&tk);
+      return err;
+   }
+   
+   /* let's reverse kb so it's little endian */
+   x = 0;
+   y = mp_unsigned_bin_size(&tk) - 1;
+   mp_clear(&tk);
+
+   while ((unsigned)x < y) {
+      z = kb[x]; kb[x] = kb[y]; kb[y] = z;
+      ++x; --y;
+   }      
+   
+   /* at this point we can start, yipee */
+   first = 1;
+   for (x = lut_gap-1; x >= 0; x--) {
+       /* extract FP_LUT bits from kb spread out by lut_gap bits and offset
+          by x bits from the start */
+       bitpos = x;
+       for (y = z = 0; y < FP_LUT; y++) {
+          z |= ((kb[bitpos>>3] >> (bitpos&7)) & 1) << y;
+          bitpos += lut_gap;  /* it's y*lut_gap + x, but here we can avoid
+                                 the mult in each loop */
+       }
+              
+       /* double if not first */
+       if (!first) {
+          if ((err = ecc_projective_dbl_point(R, R, modulus, mp)) != MP_OKAY) {
+             return err;
+          }
+       }
+       
+       /* add if not first, otherwise copy */          
+       if (!first && z) {
+          if ((err = ecc_projective_add_point(R, fp_cache[idx].LUT[z], R,
+                                              modulus, mp)) != MP_OKAY) {
+             return err;
+          }
+       } else if (z) {
+          if ((mp_copy(&fp_cache[idx].LUT[z]->x, &R->x) != MP_OKAY) || 
+              (mp_copy(&fp_cache[idx].LUT[z]->y, &R->y) != MP_OKAY) || 
+              (mp_copy(&fp_cache[idx].mu,        &R->z) != MP_OKAY)) {
+              return GEN_MEM_ERR;
+          }
+              first = 0;              
+       }
+   }     
+   z = 0;
+   XMEMSET(kb, 0, sizeof(kb));
+   /* map R back from projective space */
+   if (map) {
+      err = ecc_map(R, modulus, mp);
+   } else {
+      err = MP_OKAY;
+   }
+
+   return err;
+}
+
+#ifdef ECC_SHAMIR
+/* perform a fixed point ECC mulmod */
+static int accel_fp_mul2add(int idx1, int idx2, 
+                            mp_int* kA, mp_int* kB,
+                            ecc_point *R, mp_int* modulus, mp_digit* mp)
+{
+   unsigned char kb[2][128];
+   int      x;
+   unsigned y, z, err, bitlen, bitpos, lut_gap, first, zA, zB;
+   mp_int tka;
+   mp_int tkb;
+   mp_int order;
+
+   if (mp_init_multi(&tka, &tkb, 0, 0, 0, 0) != MP_OKAY)
+       return MP_INIT_E;
+
+   /* if it's smaller than modulus we fine */
+   if (mp_unsigned_bin_size(kA) > mp_unsigned_bin_size(modulus)) {
+      /* find order */
+      y = mp_unsigned_bin_size(modulus);
+      for (x = 0; ecc_sets[x].size; x++) {
+         if (y <= (unsigned)ecc_sets[x].size) break;
+      }
+   
+      /* back off if we are on the 521 bit curve */
+      if (y == 66) --x;
+      
+      if ((err = mp_init(&order)) != MP_OKAY) {
+         mp_clear(&tkb);
+         mp_clear(&tka);
+         return err;
+      }      
+      if ((err = mp_read_radix(&order, ecc_sets[x].order, 16)) != MP_OKAY) {
+         mp_clear(&tkb);
+         mp_clear(&tka);
+         mp_clear(&order);
+         return err;
+      }
+
+      /* kA must be less than modulus */
+      if (mp_cmp(kA, &order) != MP_LT) {
+         if ((err = mp_mod(kA, &order, &tka)) != MP_OKAY) {
+            mp_clear(&tkb);
+            mp_clear(&tka);
+            mp_clear(&order);
+            return err;
+         }
+      } else {
+         mp_copy(kA, &tka);
+      }
+      mp_clear(&order);
+   } else {
+      mp_copy(kA, &tka);
+   }       
+
+   /* if it's smaller than modulus we fine */
+   if (mp_unsigned_bin_size(kB) > mp_unsigned_bin_size(modulus)) {
+      /* find order */
+      y = mp_unsigned_bin_size(modulus);
+      for (x = 0; ecc_sets[x].size; x++) {
+         if (y <= (unsigned)ecc_sets[x].size) break;
+      }
+   
+      /* back off if we are on the 521 bit curve */
+      if (y == 66) --x;
+      
+      if ((err = mp_init(&order)) != MP_OKAY) {
+         mp_clear(&tkb);
+         mp_clear(&tka);
+         return err;
+      }      
+      if ((err = mp_read_radix(&order, ecc_sets[x].order, 16)) != MP_OKAY) {
+         mp_clear(&tkb);
+         mp_clear(&tka);
+         mp_clear(&order);
+         return err;
+      }
+
+      /* kB must be less than modulus */
+      if (mp_cmp(kB, &order) != MP_LT) {
+         if ((err = mp_mod(kB, &order, &tkb)) != MP_OKAY) {
+            mp_clear(&tkb);
+            mp_clear(&tka);
+            mp_clear(&order);
+            return err;
+         }
+      } else {
+         mp_copy(kB, &tkb);
+      }
+      mp_clear(&order);
+   } else {
+      mp_copy(kB, &tkb);
+   }     
+
+   /* get bitlen and round up to next multiple of FP_LUT */
+   bitlen  = mp_unsigned_bin_size(modulus) << 3;
+   x       = bitlen % FP_LUT;
+   if (x) {
+      bitlen += FP_LUT - x;
+   }  
+   lut_gap = bitlen / FP_LUT;
+        
+   /* get the k value */
+   if ((mp_unsigned_bin_size(&tka) > (int)(sizeof(kb[0]) - 2)) ||
+       (mp_unsigned_bin_size(&tkb) > (int)(sizeof(kb[0]) - 2))  ) {
+      mp_clear(&tka);
+      mp_clear(&tkb);
+      return BUFFER_E;
+   }
+   
+   /* store k */
+   XMEMSET(kb, 0, sizeof(kb));
+   if ((err = mp_to_unsigned_bin(&tka, kb[0])) != MP_OKAY) {
+      mp_clear(&tka);
+      mp_clear(&tkb);
+      return err;
+   }
+   
+   /* let's reverse kb so it's little endian */
+   x = 0;
+   y = mp_unsigned_bin_size(&tka) - 1;
+   mp_clear(&tka);
+   while ((unsigned)x < y) {
+      z = kb[0][x]; kb[0][x] = kb[0][y]; kb[0][y] = z;
+      ++x; --y;
+   }      
+   
+   /* store b */
+   if ((err = mp_to_unsigned_bin(&tkb, kb[1])) != MP_OKAY) {
+      mp_clear(&tkb);
+      return err;
+   }
+
+   x = 0;
+   y = mp_unsigned_bin_size(&tkb) - 1;
+   mp_clear(&tkb);
+   while ((unsigned)x < y) {
+      z = kb[1][x]; kb[1][x] = kb[1][y]; kb[1][y] = z;
+      ++x; --y;
+   }      
+
+   /* at this point we can start, yipee */
+   first = 1;
+   for (x = lut_gap-1; x >= 0; x--) {
+       /* extract FP_LUT bits from kb spread out by lut_gap bits and
+          offset by x bits from the start */
+       bitpos = x;
+       for (y = zA = zB = 0; y < FP_LUT; y++) {
+          zA |= ((kb[0][bitpos>>3] >> (bitpos&7)) & 1) << y;
+          zB |= ((kb[1][bitpos>>3] >> (bitpos&7)) & 1) << y;
+          bitpos += lut_gap;    /* it's y*lut_gap + x, but here we can avoid
+                                   the mult in each loop */
+       }
+              
+       /* double if not first */
+       if (!first) {
+          if ((err = ecc_projective_dbl_point(R, R, modulus, mp)) != MP_OKAY) {
+             return err;
+          }
+       }
+       
+       /* add if not first, otherwise copy */          
+       if (!first) {
+          if (zA) {
+             if ((err = ecc_projective_add_point(R, fp_cache[idx1].LUT[zA],
+                                                 R, modulus, mp)) != MP_OKAY) {
+                return err;
+             }
+          }
+          if (zB) {
+             if ((err = ecc_projective_add_point(R, fp_cache[idx2].LUT[zB],
+                                                 R, modulus, mp)) != MP_OKAY) {
+                return err;
+             }
+          }
+       } else {
+          if (zA) {
+              if ((mp_copy(&fp_cache[idx1].LUT[zA]->x, &R->x) != MP_OKAY) || 
+                 (mp_copy(&fp_cache[idx1].LUT[zA]->y, &R->y) != MP_OKAY) || 
+                 (mp_copy(&fp_cache[idx1].mu,        &R->z) != MP_OKAY)) {
+                  return GEN_MEM_ERR;
+              }
+                 first = 0;              
+          }
+          if (zB && first == 0) {
+             if (zB) {
+                if ((err = ecc_projective_add_point(R, fp_cache[idx2].LUT[zB],
+                                                   R, modulus, mp)) != MP_OKAY){
+                   return err;
+                }
+             }
+          } else if (zB && first == 1) {
+              if ((mp_copy(&fp_cache[idx2].LUT[zB]->x, &R->x) != MP_OKAY) || 
+                 (mp_copy(&fp_cache[idx2].LUT[zB]->y, &R->y) != MP_OKAY) || 
+                 (mp_copy(&fp_cache[idx2].mu,        &R->z) != MP_OKAY)) {
+                  return GEN_MEM_ERR;
+              }
+                 first = 0;              
+          }
+       }
+   }     
+   XMEMSET(kb, 0, sizeof(kb));
+
+   return ecc_map(R, modulus, mp);
+}
+
+/** ECC Fixed Point mulmod global
+  Computes kA*A + kB*B = C using Shamir's Trick
+  A        First point to multiply
+  kA       What to multiple A by
+  B        Second point to multiply
+  kB       What to multiple B by
+  C        [out] Destination point (can overlap with A or B)
+  modulus  Modulus for curve 
+  return MP_OKAY on success
+*/ 
+int ecc_mul2add(ecc_point* A, mp_int* kA,
+                ecc_point* B, mp_int* kB,
+                ecc_point* C, mp_int* modulus)
+{
+   int  idx1 = -1, idx2 = -1, err = MP_OKAY, mpInit = 0;
+   mp_digit mp;
+   mp_int   mu;
+  
+   err = mp_init(&mu);
+   if (err != MP_OKAY)
+       return err;
+
+#ifndef HAVE_THREAD_LS
+   if (initMutex == 0) {
+        InitMutex(&ecc_fp_lock);
+        initMutex = 1;
+   }
+   if (LockMutex(&ecc_fp_lock) != 0)
+      return BAD_MUTEX_E;
+#endif /* HAVE_THREAD_LS */
+
+      /* find point */
+      idx1 = find_base(A);
+
+      /* no entry? */
+      if (idx1 == -1) {
+         /* find hole and add it */
+         if ((idx1 = find_hole()) >= 0) {
+            err = add_entry(idx1, A);
+         }
+      }
+      if (err == MP_OKAY && idx1 != -1) {
+         /* increment LRU */
+         ++(fp_cache[idx1].lru_count);
+      }
+
+      if (err == MP_OKAY)
+        /* find point */
+        idx2 = find_base(B);
+
+      if (err == MP_OKAY) {
+        /* no entry? */
+        if (idx2 == -1) {
+           /* find hole and add it */
+           if ((idx2 = find_hole()) >= 0)
+              err = add_entry(idx2, B);
+         }
+      }
+
+      if (err == MP_OKAY && idx2 != -1) {
+         /* increment LRU */
+         ++(fp_cache[idx2].lru_count);
+      }
+
+      if (err == MP_OKAY) {
+        /* if it's 2 build the LUT, if it's higher just use the LUT */
+        if (idx1 >= 0 && fp_cache[idx1].lru_count == 2) {
+           /* compute mp */
+           err = mp_montgomery_setup(modulus, &mp);
+
+           if (err == MP_OKAY) {
+             mpInit = 1;
+             err = mp_montgomery_calc_normalization(&mu, modulus);
+           }
+                 
+           if (err == MP_OKAY)
+             /* build the LUT */
+               err = build_lut(idx1, modulus, &mp, &mu);
+        }
+      }
+
+      if (err == MP_OKAY) {
+        /* if it's 2 build the LUT, if it's higher just use the LUT */
+        if (idx2 >= 0 && fp_cache[idx2].lru_count == 2) {
+           if (mpInit == 0) {
+                /* compute mp */
+                err = mp_montgomery_setup(modulus, &mp);
+                if (err == MP_OKAY) {
+                    mpInit = 1;
+                    err = mp_montgomery_calc_normalization(&mu, modulus);
+                }
+            }
+                 
+            if (err == MP_OKAY) 
+            /* build the LUT */
+              err = build_lut(idx2, modulus, &mp, &mu);
+        }
+      }
+
+
+      if (err == MP_OKAY) {
+        if (idx1 >=0 && idx2 >= 0 && fp_cache[idx1].lru_count >= 2 &&
+                                     fp_cache[idx2].lru_count >= 2) {
+           if (mpInit == 0) {
+              /* compute mp */
+              err = mp_montgomery_setup(modulus, &mp);
+           }
+           if (err == MP_OKAY)
+             err = accel_fp_mul2add(idx1, idx2, kA, kB, C, modulus, &mp);
+        } else {
+           err = normal_ecc_mul2add(A, kA, B, kB, C, modulus);
+        }
+    }
+
+#ifndef HAVE_THREAD_LS
+    UnLockMutex(&ecc_fp_lock);
+#endif /* HAVE_THREAD_LS */
+    mp_clear(&mu);
+
+    return err;
+}
+#endif
+
+/** ECC Fixed Point mulmod global
+    k        The multiplicand
+    G        Base point to multiply
+    R        [out] Destination of product
+    modulus  The modulus for the curve
+    map      [boolean] If non-zero maps the point back to affine co-ordinates,
+             otherwise it's left in jacobian-montgomery form
+    return MP_OKAY if successful
+*/   
+int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus,
+               int map)
+{
+   int   idx, err = MP_OKAY;
+   mp_digit mp;
+   mp_int   mu;
+   int      mpSetup = 0;
+
+   if (mp_init(&mu) != MP_OKAY)
+       return MP_INIT_E;
+   
+#ifndef HAVE_THREAD_LS
+   if (initMutex == 0) {
+        InitMutex(&ecc_fp_lock);
+        initMutex = 1;
+   }
+   
+   if (LockMutex(&ecc_fp_lock) != 0)
+      return BAD_MUTEX_E;
+#endif /* HAVE_THREAD_LS */
+
+      /* find point */
+      idx = find_base(G);
+
+      /* no entry? */
+      if (idx == -1) {
+         /* find hole and add it */
+         idx = find_hole();
+
+         if (idx >= 0)
+            err = add_entry(idx, G);
+      }
+      if (err == MP_OKAY && idx != -1) {
+         /* increment LRU */
+         ++(fp_cache[idx].lru_count);
+      }
+
+
+      if (err == MP_OKAY) { 
+        /* if it's 2 build the LUT, if it's higher just use the LUT */
+        if (idx >= 0 && fp_cache[idx].lru_count == 2) {
+           /* compute mp */
+           err = mp_montgomery_setup(modulus, &mp);
+
+           if (err == MP_OKAY) {
+             /* compute mu */
+             mpSetup = 1;
+             err = mp_montgomery_calc_normalization(&mu, modulus);
+           }
+                 
+           if (err == MP_OKAY) 
+             /* build the LUT */
+             err = build_lut(idx, modulus, &mp, &mu);
+        }
+      }
+
+      if (err == MP_OKAY) { 
+        if (idx >= 0 && fp_cache[idx].lru_count >= 2) {
+           if (mpSetup == 0) {
+              /* compute mp */
+              err = mp_montgomery_setup(modulus, &mp);
+           }
+           if (err == MP_OKAY)
+             err = accel_fp_mul(idx, k, R, modulus, &mp, map);
+        } else {
+           err = normal_ecc_mulmod(k, G, R, modulus, map);
+        }
+     }
+
+#ifndef HAVE_THREAD_LS
+    UnLockMutex(&ecc_fp_lock);
+#endif /* HAVE_THREAD_LS */
+    mp_clear(&mu);
+
+    return err;
+}
+
+/* helper function for freeing the cache ...
+   must be called with the cache mutex locked */
+static void ecc_fp_free_cache(void)
+{
+   unsigned x, y;
+   for (x = 0; x < FP_ENTRIES; x++) {
+      if (fp_cache[x].g != NULL) {
+         for (y = 0; y < (1U<<FP_LUT); y++) {
+            ecc_del_point(fp_cache[x].LUT[y]);
+            fp_cache[x].LUT[y] = NULL;
+         }
+         ecc_del_point(fp_cache[x].g);
+         fp_cache[x].g         = NULL;
+         mp_clear(&fp_cache[x].mu);
+         fp_cache[x].lru_count = 0;
+         fp_cache[x].lock = 0;
+      }         
+   }
+}         
+
+/** Free the Fixed Point cache */
+void ecc_fp_free(void)
+{
+#ifndef HAVE_THREAD_LS
+   if (initMutex == 0) {
+        InitMutex(&ecc_fp_lock);
+        initMutex = 1;
+   }
+   
+   if (LockMutex(&ecc_fp_lock) == 0) {
+#endif /* HAVE_THREAD_LS */
+
+       ecc_fp_free_cache();
+
+#ifndef HAVE_THREAD_LS
+       UnLockMutex(&ecc_fp_lock);
+       FreeMutex(&ecc_fp_lock);
+       initMutex = 0;
+   }
+#endif /* HAVE_THREAD_LS */
+}
+
+
+#endif /* FP_ECC */
+
+#ifdef HAVE_ECC_ENCRYPT
+
+
+enum ecCliState {
+    ecCLI_INIT      = 1,    
+    ecCLI_SALT_GET  = 2,    
+    ecCLI_SALT_SET  = 3,    
+    ecCLI_SENT_REQ  = 4,    
+    ecCLI_RECV_RESP = 5,    
+    ecCLI_BAD_STATE = 99    
+};
+
+enum ecSrvState {
+    ecSRV_INIT      = 1,    
+    ecSRV_SALT_GET  = 2,    
+    ecSRV_SALT_SET  = 3,    
+    ecSRV_RECV_REQ  = 4,    
+    ecSRV_SENT_RESP = 5,    
+    ecSRV_BAD_STATE = 99    
+};
+
+
+struct ecEncCtx {
+    byte*     kdfSalt;     /* optional salt for kdf */
+    byte*     kdfInfo;     /* optional info for kdf */
+    byte*     macSalt;     /* optional salt for mac */
+    word32    kdfSaltSz;   /* size of kdfSalt */
+    word32    kdfInfoSz;   /* size of kdfInfo */
+    word32    macSaltSz;   /* size of macSalt */
+    byte      clientSalt[EXCHANGE_SALT_SZ];  /* for msg exchange */
+    byte      serverSalt[EXCHANGE_SALT_SZ];  /* for msg exchange */
+    byte      encAlgo;     /* which encryption type */
+    byte      kdfAlgo;     /* which key derivation function type */
+    byte      macAlgo;     /* which mac function type */
+    byte      protocol;    /* are we REQ_RESP client or server ? */
+    byte      cliSt;       /* protocol state, for sanity checks */
+    byte      srvSt;       /* protocol state, for sanity checks */
+};
+
+
+const byte* ecc_ctx_get_own_salt(ecEncCtx* ctx)
+{
+    if (ctx == NULL || ctx->protocol == 0)
+        return NULL;
+
+    if (ctx->protocol == REQ_RESP_CLIENT) {
+        if (ctx->cliSt == ecCLI_INIT) {
+            ctx->cliSt =  ecCLI_SALT_GET;
+            return ctx->clientSalt;
+        }
+        else {
+            ctx->cliSt = ecCLI_BAD_STATE;
+            return NULL;
+        }
+    }
+    else if (ctx->protocol == REQ_RESP_SERVER) {
+        if (ctx->srvSt == ecSRV_INIT) {
+            ctx->srvSt =  ecSRV_SALT_GET;
+            return ctx->serverSalt;
+        }
+        else {
+            ctx->srvSt = ecSRV_BAD_STATE;
+            return NULL;
+        }
+    }
+
+    return NULL;
+}
+
+
+static const char* exchange_info = "Secure Message Exchange";
+
+int ecc_ctx_set_peer_salt(ecEncCtx* ctx, const byte* salt)
+{
+    byte tmp[EXCHANGE_SALT_SZ/2];
+    int  halfSz = EXCHANGE_SALT_SZ/2;
+
+    if (ctx == NULL || ctx->protocol == 0 || salt == NULL)
+        return BAD_FUNC_ARG;
+
+    if (ctx->protocol == REQ_RESP_CLIENT) {
+        XMEMCPY(ctx->serverSalt, salt, EXCHANGE_SALT_SZ);
+        if (ctx->cliSt == ecCLI_SALT_GET)
+            ctx->cliSt =  ecCLI_SALT_SET;
+        else {
+            ctx->cliSt =  ecCLI_BAD_STATE;
+            return BAD_ENC_STATE_E;
+        }
+    }
+    else {
+        XMEMCPY(ctx->clientSalt, salt, EXCHANGE_SALT_SZ);
+        if (ctx->srvSt == ecSRV_SALT_GET)
+            ctx->srvSt =  ecSRV_SALT_SET;
+        else {
+            ctx->srvSt =  ecSRV_BAD_STATE;
+            return BAD_ENC_STATE_E;
+        }
+    }
+
+    /* mix half and half */
+    /* tmp stores 2nd half of client before overwrite */
+    XMEMCPY(tmp, ctx->clientSalt + halfSz, halfSz);
+    XMEMCPY(ctx->clientSalt + halfSz, ctx->serverSalt, halfSz);
+    XMEMCPY(ctx->serverSalt, tmp, halfSz);
+
+    ctx->kdfSalt   = ctx->clientSalt;
+    ctx->kdfSaltSz = EXCHANGE_SALT_SZ;
+
+    ctx->macSalt   = ctx->serverSalt;
+    ctx->macSaltSz = EXCHANGE_SALT_SZ;
+
+    ctx->kdfInfo   = (byte*)exchange_info;
+    ctx->kdfInfoSz = EXCHANGE_INFO_SZ;
+
+    return 0;
+}
+
+
+static int ecc_ctx_set_salt(ecEncCtx* ctx, int flags, RNG* rng)
+{
+    byte* saltBuffer = NULL;
+
+    if (ctx == NULL || rng == NULL || flags == 0) 
+        return BAD_FUNC_ARG;
+
+    saltBuffer = (flags == REQ_RESP_CLIENT) ? ctx->clientSalt : ctx->serverSalt;
+    RNG_GenerateBlock(rng, saltBuffer, EXCHANGE_SALT_SZ);
+
+    return 0;
+}
+
+
+static void ecc_ctx_init(ecEncCtx* ctx, int flags)
+{
+    if (ctx) {
+        XMEMSET(ctx, 0, sizeof(ecEncCtx));
+
+        ctx->encAlgo  = ecAES_128_CBC;
+        ctx->kdfAlgo  = ecHKDF_SHA256;
+        ctx->macAlgo  = ecHMAC_SHA256;
+        ctx->protocol = (byte)flags;
+
+        if (flags == REQ_RESP_CLIENT)
+            ctx->cliSt = ecCLI_INIT;
+        if (flags == REQ_RESP_SERVER)
+            ctx->srvSt = ecSRV_INIT;
+    }
+}
+
+
+/* allow ecc context reset so user doesn't have to init/free for resue */
+int ecc_ctx_reset(ecEncCtx* ctx, RNG* rng)
+{
+    if (ctx == NULL || rng == NULL)
+        return BAD_FUNC_ARG;
+
+    ecc_ctx_init(ctx, ctx->protocol);
+    return ecc_ctx_set_salt(ctx, ctx->protocol, rng);
+}
+
+
+/* alloc/init and set defaults, return new Context  */
+ecEncCtx* ecc_ctx_new(int flags, RNG* rng)
+{
+    int       ret = 0;
+    ecEncCtx* ctx = (ecEncCtx*)XMALLOC(sizeof(ecEncCtx), 0, DYNAMIC_TYPE_ECC);
+
+    if (ctx)
+        ctx->protocol = (byte)flags;
+
+    ret = ecc_ctx_reset(ctx, rng);
+    if (ret != 0) {
+        ecc_ctx_free(ctx);
+        ctx = NULL;
+    }
+
+    return ctx;
+}
+
+
+/* free any resources, clear any keys */
+void ecc_ctx_free(ecEncCtx* ctx)
+{
+    if (ctx) {
+        XMEMSET(ctx, 0, sizeof(ecEncCtx));
+        XFREE(ctx, 0, DYNAMIC_TYPE_ECC);
+    }
+}
+
+
+static int ecc_get_key_sizes(ecEncCtx* ctx, int* encKeySz, int* ivSz,
+                             int* keysLen, word32* digestSz, word32* blockSz)
+{
+    if (ctx) {
+        switch (ctx->encAlgo) {
+            case ecAES_128_CBC:
+                *encKeySz = KEY_SIZE_128;
+                *ivSz     = IV_SIZE_64;
+                *blockSz  = AES_BLOCK_SIZE;
+                break;
+            default:
+                return BAD_FUNC_ARG;
+        }
+
+        switch (ctx->macAlgo) {
+            case ecHMAC_SHA256:
+                *digestSz = SHA256_DIGEST_SIZE;
+                break;
+            default:
+                return BAD_FUNC_ARG;
+        }
+    } else
+        return BAD_FUNC_ARG;
+
+    *keysLen  = *encKeySz + *ivSz + *digestSz;
+
+    return 0;
+}
+
+
+/* ecc encrypt with shared secret run through kdf
+   ctx holds non default algos and inputs
+   msgSz should be the right size for encAlgo, i.e., already padded 
+   return 0 on success */
+int ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
+                word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx)
+{
+    int          ret;
+    word32       blockSz;
+    word32       digestSz;
+    ecEncCtx     localCtx;
+    byte         sharedSecret[ECC_MAXSIZE];  /* 521 max size */
+    byte         keys[ECC_BUFSIZE];         /* max size */
+    word32       sharedSz = sizeof(sharedSecret);
+    int          keysLen;
+    int          encKeySz;
+    int          ivSz;
+    int          offset = 0;         /* keys offset if doing msg exchange */
+    byte*        encKey;
+    byte*        encIv;
+    byte*        macKey;
+
+    if (privKey == NULL || pubKey == NULL || msg == NULL || out == NULL ||
+                           outSz  == NULL)
+        return BAD_FUNC_ARG;
+
+    if (ctx == NULL) {  /* use defaults */
+        ecc_ctx_init(&localCtx, 0);
+        ctx = &localCtx;  
+    }
+        
+    ret = ecc_get_key_sizes(ctx, &encKeySz, &ivSz, &keysLen, &digestSz,
+                            &blockSz);
+    if (ret != 0)
+        return ret;
+
+    if (ctx->protocol == REQ_RESP_SERVER) {
+        offset = keysLen;
+        keysLen *= 2;
+
+        if (ctx->srvSt != ecSRV_RECV_REQ)
+            return BAD_ENC_STATE_E;
+
+        ctx->srvSt = ecSRV_BAD_STATE; /* we're done no more ops allowed */
+    }
+    else if (ctx->protocol == REQ_RESP_CLIENT) {
+        if (ctx->cliSt != ecCLI_SALT_SET)
+            return BAD_ENC_STATE_E;
+
+        ctx->cliSt = ecCLI_SENT_REQ; /* only do this once */
+    }
+        
+    if (keysLen > (int)sizeof(keys))
+        return BUFFER_E;
+        
+    if ( (msgSz%blockSz) != 0)
+        return BAD_PADDING_E;
+
+    if (*outSz < (msgSz + digestSz))
+        return BUFFER_E;
+
+    ret = ecc_shared_secret(privKey, pubKey, sharedSecret, &sharedSz); 
+    if (ret != 0)
+        return ret;
+
+    switch (ctx->kdfAlgo) {
+        case ecHKDF_SHA256 :
+                ret = HKDF(SHA256, sharedSecret, sharedSz, ctx->kdfSalt,
+                           ctx->kdfSaltSz, ctx->kdfInfo,
+                           ctx->kdfInfoSz, keys, keysLen);
+                if (ret != 0)
+                    return ret;
+            break;
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    encKey = keys + offset;
+    encIv  = encKey + encKeySz;
+    macKey = encKey + encKeySz + ivSz;
+
+    switch (ctx->encAlgo) {
+        case ecAES_128_CBC:
+            {
+                Aes aes;
+                ret = AesSetKey(&aes, encKey,KEY_SIZE_128,encIv,AES_ENCRYPTION);
+                if (ret != 0)
+                    return ret;
+                ret = AesCbcEncrypt(&aes, out, msg, msgSz);
+                if (ret != 0)
+                    return ret;
+            }
+            break;
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    switch (ctx->macAlgo) {
+        case ecHMAC_SHA256:
+            {
+                Hmac hmac;
+                ret = HmacSetKey(&hmac, SHA256, macKey, SHA256_DIGEST_SIZE);
+                if (ret != 0)
+                    return ret;
+                HmacUpdate(&hmac, out, msgSz);
+                HmacUpdate(&hmac, ctx->macSalt, ctx->macSaltSz);
+                HmacFinal(&hmac, out+msgSz);
+            }
+            break;
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    *outSz = msgSz + digestSz;
+
+    return 0;
+}
+
+
+/* ecc decrypt with shared secret run through kdf
+   ctx holds non default algos and inputs
+   return 0 on success */
+int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
+                word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx)
+{
+    int          ret;
+    word32       blockSz;
+    word32       digestSz;
+    ecEncCtx     localCtx;
+    byte         sharedSecret[ECC_MAXSIZE];  /* 521 max size */
+    byte         keys[ECC_BUFSIZE];         /* max size */
+    word32       sharedSz = sizeof(sharedSecret);
+    int          keysLen;
+    int          encKeySz;
+    int          ivSz;
+    int          offset = 0;       /* in case using msg exchange */
+    byte*        encKey;
+    byte*        encIv;
+    byte*        macKey;
+
+    if (privKey == NULL || pubKey == NULL || msg == NULL || out == NULL ||
+                           outSz  == NULL)
+        return BAD_FUNC_ARG;
+
+    if (ctx == NULL) {  /* use defaults */
+        ecc_ctx_init(&localCtx, 0);
+        ctx = &localCtx;  
+    }
+        
+    ret = ecc_get_key_sizes(ctx, &encKeySz, &ivSz, &keysLen, &digestSz,
+                            &blockSz);
+    if (ret != 0)
+        return ret;
+        
+    if (ctx->protocol == REQ_RESP_CLIENT) {
+        offset = keysLen;
+        keysLen *= 2;
+
+        if (ctx->cliSt != ecCLI_SENT_REQ)
+            return BAD_ENC_STATE_E;
+
+        ctx->cliSt = ecSRV_BAD_STATE; /* we're done no more ops allowed */
+    }
+    else if (ctx->protocol == REQ_RESP_SERVER) {
+        if (ctx->srvSt != ecSRV_SALT_SET)
+            return BAD_ENC_STATE_E;
+
+        ctx->srvSt = ecSRV_RECV_REQ; /* only do this once */
+    }
+        
+    if (keysLen > (int)sizeof(keys))
+        return BUFFER_E;
+        
+    if ( ((msgSz-digestSz) % blockSz) != 0)
+        return BAD_PADDING_E;
+
+    if (*outSz < (msgSz - digestSz))
+        return BUFFER_E;
+
+    ret = ecc_shared_secret(privKey, pubKey, sharedSecret, &sharedSz); 
+    if (ret != 0)
+        return ret;
+
+    switch (ctx->kdfAlgo) {
+        case ecHKDF_SHA256 :
+                ret = HKDF(SHA256, sharedSecret, sharedSz, ctx->kdfSalt,
+                           ctx->kdfSaltSz, ctx->kdfInfo,
+                           ctx->kdfInfoSz, keys, keysLen);
+                if (ret != 0)
+                    return ret;
+            break;
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    encKey = keys + offset;
+    encIv  = encKey + encKeySz;
+    macKey = encKey + encKeySz + ivSz;
+
+    switch (ctx->macAlgo) {
+        case ecHMAC_SHA256:
+            {
+                byte verify[SHA256_DIGEST_SIZE];
+                Hmac hmac;
+                ret = HmacSetKey(&hmac, SHA256, macKey, SHA256_DIGEST_SIZE);
+                if (ret != 0)
+                    return ret;
+                HmacUpdate(&hmac, msg, msgSz-digestSz);
+                HmacUpdate(&hmac, ctx->macSalt, ctx->macSaltSz);
+                HmacFinal(&hmac, verify);
+
+                if (memcmp(verify, msg + msgSz - digestSz, digestSz) != 0) {
+                    return -1;
+                }
+            }
+            break;
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    switch (ctx->encAlgo) {
+        case ecAES_128_CBC:
+            {
+                Aes aes;
+                ret = AesSetKey(&aes, encKey,KEY_SIZE_128,encIv,AES_DECRYPTION);
+                if (ret != 0)
+                    return ret;
+                ret = AesCbcDecrypt(&aes, out, msg, msgSz-digestSz);
+                if (ret != 0)
+                    return ret;
+            }
+            break;
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    *outSz = msgSz - digestSz;
+
+    return 0;
+}
+
+
+#endif /* HAVE_ECC_ENCRYPT */
+
+#endif /* HAVE_ECC */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/ecc_fp.c	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,361 @@
+/* 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/error-crypt.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 = CYASSL_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 BAD_MUTEX_E : 
+        XSTRNCPY(buffer, "Bad mutex, operation failed", 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 ASN_CRIT_EXT_E:
+        XSTRNCPY(buffer, "X.509 Critical extension ignored", 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;
+
+    case BAD_ENC_STATE_E:
+        XSTRNCPY(buffer, "Bad ecc encrypt state operation", max);
+        break;
+
+    case BAD_PADDING_E:
+        XSTRNCPY(buffer, "Bad padding, message wrong length", max);
+        break;
+
+    case REQ_ATTRIBUTE_E:
+        XSTRNCPY(buffer, "Setting cert request attributes error", max);
+        break;
+
+    case PKCS7_OID_E:
+        XSTRNCPY(buffer, "PKCS#7 error: mismatched OID value", max);
+        break;
+
+    case PKCS7_RECIP_E:
+        XSTRNCPY(buffer, "PKCS#7 error: no matching recipient found", max);
+        break;
+
+    case FIPS_NOT_ALLOWED_E:
+        XSTRNCPY(buffer, "FIPS mode not allowed error", 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/fips.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,1 @@
+/* fips.c */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/fips_test.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,1 @@
+/* fips_test.c */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/hc128.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,398 @@
+/* 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/error-crypt.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* inIv)
+{ 
+    word32 i;
+    word32 iv[4];
+
+    if (inIv)
+        XMEMCPY(iv, inIv, sizeof(iv));
+    else
+        XMEMSET(iv,    0, sizeof(iv));
+    
+	for (i = 0; i < (128 >> 5); i++)
+        ctx->iv[i] = LITTLE32(iv[i]);
+	
+    for (; i < 8; i++) ctx->iv[i] = ctx->iv[i-4];
+  
+    /* expand the key and IV into the table T */ 
+    /* (expand the key and IV into the table P and Q) */ 
+	
+	for (i = 0; i < 8;  i++)   ctx->T[i] = ctx->key[i];
+	for (i = 8; i < 16; i++)   ctx->T[i] = ctx->iv[i-8];
+
+    for (i = 16; i < (256+16); i++) 
+		ctx->T[i] = f2(ctx->T[i-2]) + ctx->T[i-7] + f1(ctx->T[i-15]) +
+                                                       ctx->T[i-16]+i;
+    
+	for (i = 0; i < 16;  i++)  ctx->T[i] = ctx->T[256+i];
+
+	for (i = 16; i < 1024; i++) 
+		ctx->T[i] = f2(ctx->T[i-2]) + ctx->T[i-7] + f1(ctx->T[i-15]) +
+                                                       ctx->T[i-16]+256+i;
+    
+    /* initialize counter1024, X and Y */
+	ctx->counter1024 = 0;
+	for (i = 0; i < 16; i++) ctx->X[i] = ctx->T[512-16+i];
+    for (i = 0; i < 16; i++) ctx->Y[i] = ctx->T[512+512-16+i];
+    
+    /* run the cipher 1024 steps before generating the output */
+	for (i = 0; i < 64; i++)  setup_update(ctx);  
+}
+
+
+static INLINE int DoKey(HC128* ctx, const byte* key, const byte* iv)
+{ 
+  word32 i;  
+
+  /* Key size in bits 128 */ 
+  for (i = 0; i < (128 >> 5); i++)
+      ctx->key[i] = LITTLE32(((word32*)key)[i]);
+ 
+  for ( ; i < 8 ; i++) ctx->key[i] = ctx->key[i-4];
+
+  Hc128_SetIV(ctx, iv);
+
+  return 0;
+}
+
+
+/* Key setup */
+int Hc128_SetKey(HC128* ctx, const byte* key, const byte* iv)
+{
+#ifdef XSTREAM_ALIGN
+    if ((word)key % 4) {
+        int alignKey[4];
+
+        /* iv gets aligned in SetIV */
+        CYASSL_MSG("Hc128SetKey unaligned key");
+
+        XMEMCPY(alignKey, key, sizeof(alignKey));
+
+        return DoKey(ctx, (const byte*)alignKey, iv);
+    }
+#endif /* XSTREAM_ALIGN */
+
+    return DoKey(ctx, key, iv);
+}
+
+
+
+/* The following defines the encryption of data stream */
+static INLINE int DoProcess(HC128* ctx, byte* output, const byte* input,
+                            word32 msglen)
+{
+  word32 i, keystream[16];
+
+  for ( ; msglen >= 64; msglen -= 64, input += 64, output += 64)
+  {
+	  generate_keystream(ctx, keystream);
+
+      /* unroll loop */
+	  ((word32*)output)[0]  = ((word32*)input)[0]  ^ LITTLE32(keystream[0]);
+	  ((word32*)output)[1]  = ((word32*)input)[1]  ^ LITTLE32(keystream[1]);
+	  ((word32*)output)[2]  = ((word32*)input)[2]  ^ LITTLE32(keystream[2]);
+	  ((word32*)output)[3]  = ((word32*)input)[3]  ^ LITTLE32(keystream[3]);
+	  ((word32*)output)[4]  = ((word32*)input)[4]  ^ LITTLE32(keystream[4]);
+	  ((word32*)output)[5]  = ((word32*)input)[5]  ^ LITTLE32(keystream[5]);
+	  ((word32*)output)[6]  = ((word32*)input)[6]  ^ LITTLE32(keystream[6]);
+	  ((word32*)output)[7]  = ((word32*)input)[7]  ^ LITTLE32(keystream[7]);
+	  ((word32*)output)[8]  = ((word32*)input)[8]  ^ LITTLE32(keystream[8]);
+	  ((word32*)output)[9]  = ((word32*)input)[9]  ^ LITTLE32(keystream[9]);
+	  ((word32*)output)[10] = ((word32*)input)[10] ^ LITTLE32(keystream[10]);
+	  ((word32*)output)[11] = ((word32*)input)[11] ^ LITTLE32(keystream[11]);
+	  ((word32*)output)[12] = ((word32*)input)[12] ^ LITTLE32(keystream[12]);
+	  ((word32*)output)[13] = ((word32*)input)[13] ^ LITTLE32(keystream[13]);
+	  ((word32*)output)[14] = ((word32*)input)[14] ^ LITTLE32(keystream[14]);
+	  ((word32*)output)[15] = ((word32*)input)[15] ^ LITTLE32(keystream[15]);
+  }
+
+  if (msglen > 0)
+  {
+      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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,691 @@
+/* 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
+
+#ifdef CYASSL_PIC32MZ_HASH
+
+#define InitMd5   InitMd5_sw
+#define Md5Update Md5Update_sw
+#define Md5Final  Md5Final_sw
+
+#define InitSha   InitSha_sw
+#define ShaUpdate ShaUpdate_sw
+#define ShaFinal  ShaFinal_sw
+
+#define InitSha256   InitSha256_sw
+#define Sha256Update Sha256Update_sw
+#define Sha256Final  Sha256Final_sw
+
+#endif
+
+#ifdef HAVE_FIPS
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+#endif
+
+#include <cyassl/ctaocrypt/hmac.h>
+#include <cyassl/ctaocrypt/error-crypt.h>
+
+
+#ifdef HAVE_CAVIUM
+    static void HmacCaviumFinal(Hmac* hmac, byte* hash);
+    static void HmacCaviumUpdate(Hmac* hmac, const byte* msg, word32 length);
+    static void HmacCaviumSetKey(Hmac* hmac, int type, const byte* key,
+                                 word32 length);
+#endif
+
+static int InitHmac(Hmac* hmac, int type)
+{
+    int ret = 0;
+
+    hmac->innerHashKeyed = 0;
+    hmac->macType = (byte)type;
+
+    if (!(type == MD5 || type == SHA    || type == SHA256 || type == SHA384
+                      || type == SHA512 || type == BLAKE2B_ID))
+        return BAD_FUNC_ARG;
+
+    switch (type) {
+        #ifndef NO_MD5
+        case MD5:
+            InitMd5(&hmac->hash.md5);
+        break;
+        #endif
+
+        #ifndef NO_SHA
+        case SHA:
+            ret = InitSha(&hmac->hash.sha);
+        break;
+        #endif
+        
+        #ifndef NO_SHA256
+        case SHA256:
+            ret = InitSha256(&hmac->hash.sha256);
+        break;
+        #endif
+        
+        #ifdef CYASSL_SHA384
+        case SHA384:
+            ret = InitSha384(&hmac->hash.sha384);
+        break;
+        #endif
+        
+        #ifdef CYASSL_SHA512
+        case SHA512:
+            ret = InitSha512(&hmac->hash.sha512);
+        break;
+        #endif
+        
+        #ifdef HAVE_BLAKE2 
+        case BLAKE2B_ID:
+            InitBlake2b(&hmac->hash.blake2b, BLAKE2B_256);
+        break;
+        #endif
+        
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    return ret;
+}
+
+
+int HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length)
+{
+    byte*  ip = (byte*) hmac->ipad;
+    byte*  op = (byte*) hmac->opad;
+    word32 i, hmac_block_size = 0;
+    int    ret;
+
+#ifdef HAVE_CAVIUM
+    if (hmac->magic == CYASSL_HMAC_CAVIUM_MAGIC)
+        return HmacCaviumSetKey(hmac, type, key, length);
+#endif
+
+    ret = InitHmac(hmac, type);
+    if (ret != 0)
+        return ret;
+
+    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
+
+        #ifdef HAVE_BLAKE2 
+        case BLAKE2B_ID:
+        {
+            hmac_block_size = BLAKE2B_BLOCKBYTES;
+            if (length <= BLAKE2B_BLOCKBYTES) {
+                XMEMCPY(ip, key, length);
+            }
+            else {
+                Blake2bUpdate(&hmac->hash.blake2b, key, length);
+                Blake2bFinal(&hmac->hash.blake2b, ip, BLAKE2B_256);
+                length = BLAKE2B_256;
+            }
+        }
+        break;
+        #endif
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+    if (length < hmac_block_size)
+        XMEMSET(ip + length, 0, hmac_block_size - length);
+
+    for(i = 0; i < hmac_block_size; i++) {
+        op[i] = ip[i] ^ OPAD;
+        ip[i] ^= IPAD;
+    }
+    return 0;
+}
+
+
+static 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
+
+        #ifdef HAVE_BLAKE2 
+        case BLAKE2B_ID:
+            Blake2bUpdate(&hmac->hash.blake2b,
+                                         (byte*) hmac->ipad,BLAKE2B_BLOCKBYTES);
+        break;
+        #endif
+
+        default:
+        break;
+    }
+
+    hmac->innerHashKeyed = 1;
+}
+
+
+int 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
+
+        #ifdef HAVE_BLAKE2 
+        case BLAKE2B_ID:
+            Blake2bUpdate(&hmac->hash.blake2b, msg, length);
+        break;
+        #endif
+
+        default:
+        break;
+    }
+
+    return 0;
+}
+
+
+int 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
+
+        #ifdef HAVE_BLAKE2 
+        case BLAKE2B_ID:
+        {
+            Blake2bFinal(&hmac->hash.blake2b, (byte*) hmac->innerHash,
+                         BLAKE2B_256);
+            Blake2bUpdate(&hmac->hash.blake2b,
+                                 (byte*) hmac->opad, BLAKE2B_BLOCKBYTES);
+            Blake2bUpdate(&hmac->hash.blake2b,
+                                 (byte*) hmac->innerHash, BLAKE2B_256);
+            Blake2bFinal(&hmac->hash.blake2b, hash, BLAKE2B_256);
+        }
+        break;
+        #endif
+
+        default:
+        break;
+    }
+
+    hmac->innerHashKeyed = 0;
+
+    return 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 */
+
+int CyaSSL_GetHmacMaxSize(void)
+{
+    return MAX_DIGEST_SIZE;
+}
+
+#ifdef HAVE_HKDF
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+static INLINE int GetHashSizeByType(int type)
+{
+    if (!(type == MD5 || type == SHA    || type == SHA256 || type == SHA384
+                      || type == SHA512 || type == BLAKE2B_ID))
+        return BAD_FUNC_ARG;
+
+    switch (type) {
+        #ifndef NO_MD5
+        case MD5:
+            return MD5_DIGEST_SIZE;
+        break;
+        #endif
+
+        #ifndef NO_SHA
+        case SHA:
+            return SHA_DIGEST_SIZE;
+        break;
+        #endif
+        
+        #ifndef NO_SHA256
+        case SHA256:
+            return SHA256_DIGEST_SIZE;
+        break;
+        #endif
+        
+        #ifdef CYASSL_SHA384
+        case SHA384:
+            return SHA384_DIGEST_SIZE;
+        break;
+        #endif
+        
+        #ifdef CYASSL_SHA512
+        case SHA512:
+            return SHA512_DIGEST_SIZE;
+        break;
+        #endif
+        
+        #ifdef HAVE_BLAKE2 
+        case BLAKE2B_ID:
+            return BLAKE2B_OUTBYTES;
+        break;
+        #endif
+        
+        default:
+            return BAD_FUNC_ARG;
+        break;
+    }
+}
+
+
+/* HMAC-KDF with hash type, optional salt and info, return 0 on success */
+int HKDF(int type, const byte* inKey, word32 inKeySz,
+                   const byte* salt,  word32 saltSz,
+                   const byte* info,  word32 infoSz,
+                   byte* out,         word32 outSz)
+{
+    Hmac   myHmac;
+    byte   tmp[MAX_DIGEST_SIZE]; /* localSalt helper and T */
+    byte   prk[MAX_DIGEST_SIZE];
+    const  byte* localSalt;  /* either points to user input or tmp */
+    int    hashSz = GetHashSizeByType(type);
+    word32 outIdx = 0;
+    byte   n = 0x1;
+
+    if (hashSz < 0)
+        return BAD_FUNC_ARG;
+
+    localSalt = salt;
+    if (localSalt == NULL) {
+        XMEMSET(tmp, 0, hashSz);
+        localSalt = tmp;
+        saltSz    = hashSz;
+    }
+    
+    if (HmacSetKey(&myHmac, type, localSalt, saltSz) != 0)
+        return BAD_FUNC_ARG;
+
+    HmacUpdate(&myHmac, inKey, inKeySz);
+    HmacFinal(&myHmac,  prk);
+
+    while (outIdx < outSz) {
+        int    tmpSz = (n == 1) ? 0 : hashSz;
+        word32 left = outSz - outIdx;
+
+        if (HmacSetKey(&myHmac, type, prk, hashSz) != 0)
+            return BAD_FUNC_ARG;
+
+        HmacUpdate(&myHmac, tmp, tmpSz);
+        HmacUpdate(&myHmac, info, infoSz);
+        HmacUpdate(&myHmac, &n, 1);
+        HmacFinal(&myHmac, tmp);
+
+        left = min(left, (word32)hashSz);
+        XMEMCPY(out+outIdx, tmp, left);
+
+        outIdx += hashSz;
+        n++;
+    }
+
+    return 0;
+}
+
+#endif /* HAVE_HKDF */
+
+#endif /* NO_HMAC */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/integer.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,4488 @@
+/* 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;
+}
+
+
+int mp_leading_bit (mp_int * a)
+{
+    int bit = 0;
+    mp_int t;
+
+    if (mp_init_copy(&t, a) != MP_OKAY)
+        return 0;
+
+    while (mp_iszero(&t) == 0) {
+#ifndef MP_8BIT
+        bit = (t.dp[0] & 0x80) != 0;
+#else
+        bit = (t.dp[0] | ((t.dp[1] & 0x01) << 7)) & 0x80 != 0;
+#endif
+        if (mp_div_2d (&t, 8, &t, NULL) != MP_OKAY)
+            break;
+    }
+    mp_clear(&t);
+    return bit;
+}
+
+
+/* store in unsigned [big endian] format */
+int mp_to_unsigned_bin (mp_int * a, unsigned char *b)
+{
+  int     x, res;
+  mp_int  t;
+
+  if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
+    return res;
+  }
+
+  x = 0;
+  while (mp_iszero (&t) == 0) {
+#ifndef MP_8BIT
+      b[x++] = (unsigned char) (t.dp[0] & 255);
+#else
+      b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
+#endif
+    if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) {
+      mp_clear (&t);
+      return res;
+    }
+  }
+  bn_reverse (b, x);
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+/* creates "a" then copies b into it */
+int mp_init_copy (mp_int * a, mp_int * b)
+{
+  int     res;
+
+  if ((res = mp_init (a)) != MP_OKAY) {
+    return res;
+  }
+  return mp_copy (b, a);
+}
+
+
+/* copy, b = a */
+int
+mp_copy (mp_int * a, mp_int * b)
+{
+  int     res, n;
+
+  /* if dst == src do nothing */
+  if (a == b) {
+    return MP_OKAY;
+  }
+
+  /* grow dest */
+  if (b->alloc < a->used) {
+     if ((res = mp_grow (b, a->used)) != MP_OKAY) {
+        return res;
+     }
+  }
+
+  /* zero b and copy the parameters over */
+  {
+    register mp_digit *tmpa, *tmpb;
+
+    /* pointer aliases */
+
+    /* source */
+    tmpa = a->dp;
+
+    /* destination */
+    tmpb = b->dp;
+
+    /* copy all the digits */
+    for (n = 0; n < a->used; n++) {
+      *tmpb++ = *tmpa++;
+    }
+
+    /* clear high digits */
+    for (; n < b->used; n++) {
+      *tmpb++ = 0;
+    }
+  }
+
+  /* copy used count and sign */
+  b->used = a->used;
+  b->sign = a->sign;
+  return MP_OKAY;
+}
+
+
+/* grow as required */
+int mp_grow (mp_int * a, int size)
+{
+  int     i;
+  mp_digit *tmp;
+
+  /* if the alloc size is smaller alloc more ram */
+  if (a->alloc < size) {
+    /* ensure there are always at least MP_PREC digits extra on top */
+    size += (MP_PREC * 2) - (size % MP_PREC);
+
+    /* reallocate the array a->dp
+     *
+     * We store the return in a temporary variable
+     * in case the operation failed we don't want
+     * to overwrite the dp member of a.
+     */
+    tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size, 0,
+                                       DYNAMIC_TYPE_BIGINT);
+    if (tmp == NULL) {
+      /* reallocation failed but "a" is still valid [can be freed] */
+      return MP_MEM;
+    }
+
+    /* reallocation succeeded so set a->dp */
+    a->dp = tmp;
+
+    /* zero excess digits */
+    i        = a->alloc;
+    a->alloc = size;
+    for (; i < a->alloc; i++) {
+      a->dp[i] = 0;
+    }
+  }
+  return MP_OKAY;
+}
+
+
+/* reverse an array, used for radix code */
+void
+bn_reverse (unsigned char *s, int len)
+{
+  int     ix, iy;
+  unsigned char t;
+
+  ix = 0;
+  iy = len - 1;
+  while (ix < iy) {
+    t     = s[ix];
+    s[ix] = s[iy];
+    s[iy] = t;
+    ++ix;
+    --iy;
+  }
+}
+
+
+/* shift right by a certain bit count (store quotient in c, optional
+   remainder in d) */
+int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
+{
+  int     D, res;
+  mp_int  t;
+
+
+  /* if the shift count is <= 0 then we do no work */
+  if (b <= 0) {
+    res = mp_copy (a, c);
+    if (d != NULL) {
+      mp_zero (d);
+    }
+    return res;
+  }
+
+  if ((res = mp_init (&t)) != MP_OKAY) {
+    return res;
+  }
+
+  /* get the remainder */
+  if (d != NULL) {
+    if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
+      mp_clear (&t);
+      return res;
+    }
+  }
+
+  /* copy */
+  if ((res = mp_copy (a, c)) != MP_OKAY) {
+    mp_clear (&t);
+    return res;
+  }
+
+  /* shift by as many digits in the bit count */
+  if (b >= (int)DIGIT_BIT) {
+    mp_rshd (c, b / DIGIT_BIT);
+  }
+
+  /* shift any bit count < DIGIT_BIT */
+  D = (b % DIGIT_BIT);
+  if (D != 0) {
+    mp_rshb(c, D);
+  }
+  mp_clamp (c);
+  if (d != NULL) {
+    mp_exch (&t, d);
+  }
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+/* set to zero */
+void mp_zero (mp_int * a)
+{
+  int       n;
+  mp_digit *tmp;
+
+  a->sign = MP_ZPOS;
+  a->used = 0;
+
+  tmp = a->dp;
+  for (n = 0; n < a->alloc; n++) {
+     *tmp++ = 0;
+  }
+}
+
+
+/* trim unused digits 
+ *
+ * This is used to ensure that leading zero digits are
+ * trimed and the leading "used" digit will be non-zero
+ * Typically very fast.  Also fixes the sign if there
+ * are no more leading digits
+ */
+void
+mp_clamp (mp_int * a)
+{
+  /* decrease used while the most significant digit is
+   * zero.
+   */
+  while (a->used > 0 && a->dp[a->used - 1] == 0) {
+    --(a->used);
+  }
+
+  /* reset the sign flag if used == 0 */
+  if (a->used == 0) {
+    a->sign = MP_ZPOS;
+  }
+}
+
+
+/* swap the elements of two integers, for cases where you can't simply swap the 
+ * mp_int pointers around
+ */
+void
+mp_exch (mp_int * a, mp_int * b)
+{
+  mp_int  t;
+
+  t  = *a;
+  *a = *b;
+  *b = t;
+}
+
+
+/* shift right a certain number of bits */
+void mp_rshb (mp_int *c, int x)
+{
+    register mp_digit *tmpc, mask, shift;
+    mp_digit r, rr;
+    mp_digit D = x;
+
+    /* mask */
+    mask = (((mp_digit)1) << D) - 1;
+
+    /* shift for lsb */
+    shift = DIGIT_BIT - D;
+
+    /* alias */
+    tmpc = c->dp + (c->used - 1);
+
+    /* carry */
+    r = 0;
+    for (x = c->used - 1; x >= 0; x--) {
+      /* get the lower  bits of this word in a temp */
+      rr = *tmpc & mask;
+
+      /* shift the current word and mix in the carry bits from previous word */
+      *tmpc = (*tmpc >> D) | (r << shift);
+      --tmpc;
+
+      /* set the carry to the carry bits of the current word found above */
+      r = rr;
+    }
+}
+
+
+/* shift right a certain amount of digits */
+void mp_rshd (mp_int * a, int b)
+{
+  int     x;
+
+  /* if b <= 0 then ignore it */
+  if (b <= 0) {
+    return;
+  }
+
+  /* if b > used then simply zero it and return */
+  if (a->used <= b) {
+    mp_zero (a);
+    return;
+  }
+
+  {
+    register mp_digit *bottom, *top;
+
+    /* shift the digits down */
+
+    /* bottom */
+    bottom = a->dp;
+
+    /* top [offset into digits] */
+    top = a->dp + b;
+
+    /* this is implemented as a sliding window where 
+     * the window is b-digits long and digits from 
+     * the top of the window are copied to the bottom
+     *
+     * e.g.
+
+     b-2 | b-1 | b0 | b1 | b2 | ... | bb |   ---->
+                 /\                   |      ---->
+                  \-------------------/      ---->
+     */
+    for (x = 0; x < (a->used - b); x++) {
+      *bottom++ = *top++;
+    }
+
+    /* zero the top digits */
+    for (; x < a->used; x++) {
+      *bottom++ = 0;
+    }
+  }
+  
+  /* remove excess digits */
+  a->used -= b;
+}
+
+
+/* calc a value mod 2**b */
+int
+mp_mod_2d (mp_int * a, int b, mp_int * c)
+{
+  int     x, res;
+
+  /* if b is <= 0 then zero the int */
+  if (b <= 0) {
+    mp_zero (c);
+    return MP_OKAY;
+  }
+
+  /* if the modulus is larger than the value than return */
+  if (b >= (int) (a->used * DIGIT_BIT)) {
+    res = mp_copy (a, c);
+    return res;
+  }
+
+  /* copy */
+  if ((res = mp_copy (a, c)) != MP_OKAY) {
+    return res;
+  }
+
+  /* zero digits above the last digit of the modulus */
+  for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
+    c->dp[x] = 0;
+  }
+  /* clear the digit that is not completely outside/inside the modulus */
+  c->dp[b / DIGIT_BIT] &= (mp_digit) ((((mp_digit) 1) <<
+              (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+/* reads a unsigned char array, assumes the msb is stored first [big endian] */
+int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
+{
+  int     res;
+
+  /* make sure there are at least two digits */
+  if (a->alloc < 2) {
+     if ((res = mp_grow(a, 2)) != MP_OKAY) {
+        return res;
+     }
+  }
+
+  /* zero the int */
+  mp_zero (a);
+
+  /* read the bytes in */
+  while (c-- > 0) {
+    if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
+      return res;
+    }
+
+#ifndef MP_8BIT
+      a->dp[0] |= *b++;
+      a->used += 1;
+#else
+      a->dp[0] = (*b & MP_MASK);
+      a->dp[1] |= ((*b++ >> 7U) & 1);
+      a->used += 2;
+#endif
+  }
+  mp_clamp (a);
+  return MP_OKAY;
+}
+
+
+/* shift left by a certain bit count */
+int mp_mul_2d (mp_int * a, int b, mp_int * c)
+{
+  mp_digit d;
+  int      res;
+
+  /* copy */
+  if (a != c) {
+     if ((res = mp_copy (a, c)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
+     if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  /* shift by as many digits in the bit count */
+  if (b >= (int)DIGIT_BIT) {
+    if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* shift any bit count < DIGIT_BIT */
+  d = (mp_digit) (b % DIGIT_BIT);
+  if (d != 0) {
+    register mp_digit *tmpc, shift, mask, r, rr;
+    register int x;
+
+    /* bitmask for carries */
+    mask = (((mp_digit)1) << d) - 1;
+
+    /* shift for msbs */
+    shift = DIGIT_BIT - d;
+
+    /* alias */
+    tmpc = c->dp;
+
+    /* carry */
+    r    = 0;
+    for (x = 0; x < c->used; x++) {
+      /* get the higher bits of the current word */
+      rr = (*tmpc >> shift) & mask;
+
+      /* shift the current word and OR in the carry */
+      *tmpc = ((*tmpc << d) | r) & MP_MASK;
+      ++tmpc;
+
+      /* set the carry to the carry bits of the current word */
+      r = rr;
+    }
+    
+    /* set final carry */
+    if (r != 0) {
+       c->dp[(c->used)++] = r;
+    }
+  }
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+/* shift left a certain amount of digits */
+int mp_lshd (mp_int * a, int b)
+{
+  int     x, res;
+
+  /* if its less than zero return */
+  if (b <= 0) {
+    return MP_OKAY;
+  }
+
+  /* grow to fit the new digits */
+  if (a->alloc < a->used + b) {
+     if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  {
+    register mp_digit *top, *bottom;
+
+    /* increment the used by the shift amount then copy upwards */
+    a->used += b;
+
+    /* top */
+    top = a->dp + a->used - 1;
+
+    /* base */
+    bottom = a->dp + a->used - 1 - b;
+
+    /* much like mp_rshd this is implemented using a sliding window
+     * except the window goes the otherway around.  Copying from
+     * the bottom to the top.  see bn_mp_rshd.c for more info.
+     */
+    for (x = a->used - 1; x >= b; x--) {
+      *top-- = *bottom--;
+    }
+
+    /* zero the lower digits */
+    top = a->dp;
+    for (x = 0; x < b; x++) {
+      *top++ = 0;
+    }
+  }
+  return MP_OKAY;
+}
+
+
+/* this is a shell function that calls either the normal or Montgomery
+ * exptmod functions.  Originally the call to the montgomery code was
+ * embedded in the normal function but that wasted alot of stack space
+ * for nothing (since 99% of the time the Montgomery code would be called)
+ */
+int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
+{
+  int dr;
+
+  /* modulus P must be positive */
+  if (P->sign == MP_NEG) {
+     return MP_VAL;
+  }
+
+  /* if exponent X is negative we have to recurse */
+  if (X->sign == MP_NEG) {
+#ifdef BN_MP_INVMOD_C
+     mp_int tmpG, tmpX;
+     int err;
+
+     /* first compute 1/G mod P */
+     if ((err = mp_init(&tmpG)) != MP_OKAY) {
+        return err;
+     }
+     if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
+        mp_clear(&tmpG);
+        return err;
+     }
+
+     /* now get |X| */
+     if ((err = mp_init(&tmpX)) != MP_OKAY) {
+        mp_clear(&tmpG);
+        return err;
+     }
+     if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
+        mp_clear(&tmpG);
+        mp_clear(&tmpX);
+        return err;
+     }
+
+     /* and now compute (1/G)**|X| instead of G**X [X < 0] */
+     err = mp_exptmod(&tmpG, &tmpX, P, Y);
+     mp_clear(&tmpG);
+     mp_clear(&tmpX);
+     return err;
+#else 
+     /* no invmod */
+     return MP_VAL;
+#endif
+  }
+
+/* modified diminished radix reduction */
+#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && \
+  defined(BN_S_MP_EXPTMOD_C)
+  if (mp_reduce_is_2k_l(P) == MP_YES) {
+     return s_mp_exptmod(G, X, P, Y, 1);
+  }
+#endif
+
+#ifdef BN_MP_DR_IS_MODULUS_C
+  /* is it a DR modulus? */
+  dr = mp_dr_is_modulus(P);
+#else
+  /* default to no */
+  dr = 0;
+#endif
+
+#ifdef BN_MP_REDUCE_IS_2K_C
+  /* if not, is it a unrestricted DR modulus? */
+  if (dr == 0) {
+     dr = mp_reduce_is_2k(P) << 1;
+  }
+#endif
+    
+  /* if the modulus is odd or dr != 0 use the montgomery method */
+#ifdef BN_MP_EXPTMOD_FAST_C
+  if (mp_isodd (P) == 1 || dr !=  0) {
+    return mp_exptmod_fast (G, X, P, Y, dr);
+  } else {
+#endif
+#ifdef BN_S_MP_EXPTMOD_C
+    /* otherwise use the generic Barrett reduction technique */
+    return s_mp_exptmod (G, X, P, Y, 0);
+#else
+    /* no exptmod for evens */
+    return MP_VAL;
+#endif
+#ifdef BN_MP_EXPTMOD_FAST_C
+  }
+#endif
+}
+
+
+/* b = |a| 
+ *
+ * Simple function copies the input and fixes the sign to positive
+ */
+int
+mp_abs (mp_int * a, mp_int * b)
+{
+  int     res;
+
+  /* copy a to b */
+  if (a != b) {
+     if ((res = mp_copy (a, b)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  /* force the sign of b to positive */
+  b->sign = MP_ZPOS;
+
+  return MP_OKAY;
+}
+
+
+/* hac 14.61, pp608 */
+int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
+{
+  /* b cannot be negative */
+  if (b->sign == MP_NEG || mp_iszero(b) == 1) {
+    return MP_VAL;
+  }
+
+#ifdef BN_FAST_MP_INVMOD_C
+  /* if the modulus is odd we can use a faster routine instead */
+  if (mp_isodd (b) == 1) {
+    return fast_mp_invmod (a, b, c);
+  }
+#endif
+
+#ifdef BN_MP_INVMOD_SLOW_C
+  return mp_invmod_slow(a, b, c);
+#endif
+}
+
+
+/* computes the modular inverse via binary extended euclidean algorithm, 
+ * that is c = 1/a mod b 
+ *
+ * Based on slow invmod except this is optimized for the case where b is 
+ * odd as per HAC Note 14.64 on pp. 610
+ */
+int fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c)
+{
+  mp_int  x, y, u, v, B, D;
+  int     res, neg;
+
+  /* 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) || defined(CYASSL_SNIFFER) || defined(CYASSL_HAVE_WOLFSCEP)
+
+/* 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	Sun Apr 20 12:40:57 2014 +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/error-crypt.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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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
+                ByteReverseWords(md4->buffer, md4->buffer, 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
+            ByteReverseWords(md4->buffer, md4->buffer, MD4_BLOCK_SIZE);
+        #endif
+        Transform(md4);
+        md4->buffLen = 0;
+    }
+    XMEMSET(&local[md4->buffLen], 0, MD4_PAD_SIZE - md4->buffLen);
+   
+    /* put lengths in bits */
+    md4->hiLen = (md4->loLen >> (8*sizeof(md4->loLen) - 3)) + 
+                 (md4->hiLen << 3);
+    md4->loLen = md4->loLen << 3;
+
+    /* store lengths */
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseWords(md4->buffer, md4->buffer, MD4_BLOCK_SIZE);
+    #endif
+    /* ! length ordering dependent on digest endian type ! */
+    XMEMCPY(&local[MD4_PAD_SIZE], &md4->loLen, sizeof(word32));
+    XMEMCPY(&local[MD4_PAD_SIZE + sizeof(word32)], &md4->hiLen, sizeof(word32));
+
+    Transform(md4);
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseWords(md4->digest, md4->digest, MD4_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, md4->digest, MD4_DIGEST_SIZE);
+
+    InitMd4(md4);  /* reset state */
+}
+
+
+#endif /* NO_MD4 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/md5.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,364 @@
+/* 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>
+
+#if !defined(NO_MD5)
+
+#ifdef CYASSL_PIC32MZ_HASH
+#define InitMd5   InitMd5_sw
+#define Md5Update Md5Update_sw
+#define Md5Final  Md5Final_sw
+#endif
+
+#include <cyassl/ctaocrypt/md5.h>
+
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/src/misc.c>
+#endif
+
+#ifdef FREESCALE_MMCAU
+    #include "cau_api.h"
+    #define XTRANSFORM(S,B)  cau_md5_hash_n((B), 1, (unsigned char*)(S)->digest)
+#else
+    #define XTRANSFORM(S,B)  Transform((S))
+#endif
+
+
+#ifdef STM32F2_HASH
+    /*
+     * STM32F2 hardware MD5 support through the STM32F2 standard peripheral
+     * library. Documentation located in STM32F2xx Standard Peripheral Library
+     * document (See note in README).
+     */
+    #include "stm32f2xx.h"
+
+    void 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;
+}
+
+#ifndef FREESCALE_MMCAU
+
+static void Transform(Md5* md5)
+{
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+#define MD5STEP(f, w, x, y, z, data, s) \
+    w = rotlFixed(w + f(x, y, z) + data, s) + x
+
+    /* Copy context->state[] to working vars  */
+    word32 a = md5->digest[0];
+    word32 b = md5->digest[1];
+    word32 c = md5->digest[2];
+    word32 d = md5->digest[3];
+
+    MD5STEP(F1, a, b, c, d, md5->buffer[0]  + 0xd76aa478,  7);
+    MD5STEP(F1, d, a, b, c, md5->buffer[1]  + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, md5->buffer[2]  + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, md5->buffer[3]  + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, md5->buffer[4]  + 0xf57c0faf,  7);
+    MD5STEP(F1, d, a, b, c, md5->buffer[5]  + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, md5->buffer[6]  + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, md5->buffer[7]  + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, md5->buffer[8]  + 0x698098d8,  7);
+    MD5STEP(F1, d, a, b, c, md5->buffer[9]  + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, md5->buffer[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, md5->buffer[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, md5->buffer[12] + 0x6b901122,  7);
+    MD5STEP(F1, d, a, b, c, md5->buffer[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, md5->buffer[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, md5->buffer[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, md5->buffer[1]  + 0xf61e2562,  5);
+    MD5STEP(F2, d, a, b, c, md5->buffer[6]  + 0xc040b340,  9);
+    MD5STEP(F2, c, d, a, b, md5->buffer[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, md5->buffer[0]  + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, md5->buffer[5]  + 0xd62f105d,  5);
+    MD5STEP(F2, d, a, b, c, md5->buffer[10] + 0x02441453,  9);
+    MD5STEP(F2, c, d, a, b, md5->buffer[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, md5->buffer[4]  + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, md5->buffer[9]  + 0x21e1cde6,  5);
+    MD5STEP(F2, d, a, b, c, md5->buffer[14] + 0xc33707d6,  9);
+    MD5STEP(F2, c, d, a, b, md5->buffer[3]  + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, md5->buffer[8]  + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, md5->buffer[13] + 0xa9e3e905,  5);
+    MD5STEP(F2, d, a, b, c, md5->buffer[2]  + 0xfcefa3f8,  9);
+    MD5STEP(F2, c, d, a, b, md5->buffer[7]  + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, md5->buffer[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, md5->buffer[5]  + 0xfffa3942,  4);
+    MD5STEP(F3, d, a, b, c, md5->buffer[8]  + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, md5->buffer[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, md5->buffer[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, md5->buffer[1]  + 0xa4beea44,  4);
+    MD5STEP(F3, d, a, b, c, md5->buffer[4]  + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, md5->buffer[7]  + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, md5->buffer[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, md5->buffer[13] + 0x289b7ec6,  4);
+    MD5STEP(F3, d, a, b, c, md5->buffer[0]  + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, md5->buffer[3]  + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, md5->buffer[6]  + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, md5->buffer[9]  + 0xd9d4d039,  4);
+    MD5STEP(F3, d, a, b, c, md5->buffer[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, md5->buffer[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, md5->buffer[2]  + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, md5->buffer[0]  + 0xf4292244,  6);
+    MD5STEP(F4, d, a, b, c, md5->buffer[7]  + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, md5->buffer[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, md5->buffer[5]  + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, md5->buffer[12] + 0x655b59c3,  6);
+    MD5STEP(F4, d, a, b, c, md5->buffer[3]  + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, md5->buffer[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, md5->buffer[1]  + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, md5->buffer[8]  + 0x6fa87e4f,  6);
+    MD5STEP(F4, d, a, b, c, md5->buffer[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, md5->buffer[6]  + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, md5->buffer[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, md5->buffer[4]  + 0xf7537e82,  6);
+    MD5STEP(F4, d, a, b, c, md5->buffer[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, md5->buffer[2]  + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, md5->buffer[9]  + 0xeb86d391, 21);
+    
+    /* Add the working vars back into digest state[]  */
+    md5->digest[0] += a;
+    md5->digest[1] += b;
+    md5->digest[2] += c;
+    md5->digest[3] += d;
+}
+
+#endif /* FREESCALE_MMCAU */
+
+
+static INLINE void AddLength(Md5* md5, word32 len)
+{
+    word32 tmp = md5->loLen;
+    if ( (md5->loLen += len) < tmp)
+        md5->hiLen++;                       /* carry low to high */
+}
+
+
+void Md5Update(Md5* md5, const byte* data, word32 len)
+{
+    /* do block size increments */
+    byte* local = (byte*)md5->buffer;
+
+    while (len) {
+        word32 add = min(len, MD5_BLOCK_SIZE - md5->buffLen);
+        XMEMCPY(&local[md5->buffLen], data, add);
+
+        md5->buffLen += add;
+        data         += add;
+        len          -= add;
+
+        if (md5->buffLen == MD5_BLOCK_SIZE) {
+            #if defined(BIG_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+                ByteReverseWords(md5->buffer, md5->buffer, MD5_BLOCK_SIZE);
+            #endif
+            XTRANSFORM(md5, local);
+            AddLength(md5, MD5_BLOCK_SIZE);
+            md5->buffLen = 0;
+        }
+    }
+}
+
+
+void Md5Final(Md5* md5, byte* hash)
+{
+    byte* local = (byte*)md5->buffer;
+
+    AddLength(md5, md5->buffLen);  /* before adding pads */
+
+    local[md5->buffLen++] = 0x80;  /* add 1 */
+
+    /* pad with zeros */
+    if (md5->buffLen > MD5_PAD_SIZE) {
+        XMEMSET(&local[md5->buffLen], 0, MD5_BLOCK_SIZE - md5->buffLen);
+        md5->buffLen += MD5_BLOCK_SIZE - md5->buffLen;
+
+        #if defined(BIG_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+            ByteReverseWords(md5->buffer, md5->buffer, MD5_BLOCK_SIZE);
+        #endif
+        XTRANSFORM(md5, local);
+        md5->buffLen = 0;
+    }
+    XMEMSET(&local[md5->buffLen], 0, MD5_PAD_SIZE - md5->buffLen);
+   
+    /* put lengths in bits */
+    md5->hiLen = (md5->loLen >> (8*sizeof(md5->loLen) - 3)) + 
+                 (md5->hiLen << 3);
+    md5->loLen = md5->loLen << 3;
+
+    /* store lengths */
+    #if defined(BIG_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+        ByteReverseWords(md5->buffer, md5->buffer, MD5_BLOCK_SIZE);
+    #endif
+    /* ! length ordering dependent on digest endian type ! */
+    XMEMCPY(&local[MD5_PAD_SIZE], &md5->loLen, sizeof(word32));
+    XMEMCPY(&local[MD5_PAD_SIZE + sizeof(word32)], &md5->hiLen, sizeof(word32));
+
+    XTRANSFORM(md5, local);
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseWords(md5->digest, md5->digest, MD5_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, md5->digest, MD5_DIGEST_SIZE);
+
+    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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,183 @@
+/* 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/error-crypt.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)
+            puts("CyaSSL_malloc failed");
+    #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 */
+
+
+#ifdef HAVE_IO_POOL
+
+/* Example for user io pool, shared build may need definitions in lib proper */
+
+#include <cyassl/ctaocrypt/types.h>
+#include <stdlib.h>
+
+#ifndef HAVE_THREAD_LS
+    #error "Oops, simple I/O pool example needs thread local storage"
+#endif
+
+
+/* allow simple per thread in and out pools */
+/* use 17k size sense max record size is 16k plus overhead */
+static THREAD_LS_T byte pool_in[17*1024];
+static THREAD_LS_T byte pool_out[17*1024];
+
+
+void* XMALLOC(size_t n, void* heap, int type)
+{
+    (void)heap;
+
+    if (type == DYNAMIC_TYPE_IN_BUFFER) {
+        if (n < sizeof(pool_in))
+            return pool_in;
+        else
+            return NULL;
+    }
+
+    if (type == DYNAMIC_TYPE_OUT_BUFFER) {
+        if (n < sizeof(pool_out))
+            return pool_out;
+        else
+            return NULL;
+    }
+
+    return malloc(n);
+}
+
+void* XREALLOC(void *p, size_t n, void* heap, int type)
+{
+    (void)heap;
+
+    if (type == DYNAMIC_TYPE_IN_BUFFER) {
+        if (n < sizeof(pool_in))
+            return pool_in;
+        else
+            return NULL;
+    }
+
+    if (type == DYNAMIC_TYPE_OUT_BUFFER) {
+        if (n < sizeof(pool_out))
+            return pool_out;
+        else
+            return NULL;
+    }
+
+    return realloc(p, n);
+}
+
+
+/* unit api calls, let's make sure visisble with CYASSL_API */
+CYASSL_API void XFREE(void *p, void* heap, int type)
+{
+    (void)heap;
+
+    if (type == DYNAMIC_TYPE_IN_BUFFER)
+        return;  /* do nothing, static pool */
+
+    if (type == DYNAMIC_TYPE_OUT_BUFFER)
+        return;  /* do nothing, static pool */
+
+    free(p);
+}
+
+#endif /* HAVE_IO_POOL */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/misc.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,170 @@
+/* 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 XorWords(word* r, const word* a, word32 n)
+{
+    word32 i;
+
+    for (i = 0; i < n; i++) r[i] ^= a[i];
+}
+
+
+STATIC INLINE void xorbuf(void* buf, const void* mask, word32 count)
+{
+    if (((word)buf | (word)mask | count) % CYASSL_WORD_SIZE == 0)
+        XorWords( (word*)buf, (const word*)mask, count / CYASSL_WORD_SIZE);
+    else {
+        word32 i;
+        byte*       b = (byte*)buf;
+        const byte* m = (const byte*)mask;
+
+        for (i = 0; i < count; i++) b[i] ^= m[i];
+    }
+}
+#undef STATIC
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/pkcs7.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,1392 @@
+/* pkcs7.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_PKCS7
+
+#include <cyassl/ctaocrypt/pkcs7.h>
+#include <cyassl/ctaocrypt/error-crypt.h>
+#include <cyassl/ctaocrypt/logging.h>
+
+#ifndef min
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+#endif
+
+
+/* placed ASN.1 contentType OID into *output, return idx on success,
+ * 0 upon failure */
+CYASSL_LOCAL int SetContentType(int pkcs7TypeOID, byte* output)
+{
+    /* PKCS#7 content types, RFC 2315, section 14 */
+    static const byte pkcs7[]              = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                               0x0D, 0x01, 0x07 };
+    static const byte data[]               = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                               0x0D, 0x01, 0x07, 0x01 };
+    static const byte signedData[]         = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                               0x0D, 0x01, 0x07, 0x02};
+    static const byte envelopedData[]      = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                               0x0D, 0x01, 0x07, 0x03 };
+    static const byte signedAndEnveloped[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                               0x0D, 0x01, 0x07, 0x04 };
+    static const byte digestedData[]       = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                               0x0D, 0x01, 0x07, 0x05 };
+    static const byte encryptedData[]      = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+                                               0x0D, 0x01, 0x07, 0x06 };
+
+    int idSz;
+    int typeSz = 0, idx = 0;
+    const byte* typeName = 0;
+    byte ID_Length[MAX_LENGTH_SZ];
+
+    switch (pkcs7TypeOID) {
+        case PKCS7_MSG:
+            typeSz = sizeof(pkcs7);
+            typeName = pkcs7;
+            break;
+
+        case DATA:
+            typeSz = sizeof(data);
+            typeName = data;
+            break;
+
+        case SIGNED_DATA:
+            typeSz = sizeof(signedData);
+            typeName = signedData;
+            break;
+        
+        case ENVELOPED_DATA:
+            typeSz = sizeof(envelopedData);
+            typeName = envelopedData;
+            break;
+
+        case SIGNED_AND_ENVELOPED_DATA:
+            typeSz = sizeof(signedAndEnveloped);
+            typeName = signedAndEnveloped;
+            break;
+
+        case DIGESTED_DATA:
+            typeSz = sizeof(digestedData);
+            typeName = digestedData;
+            break;
+
+        case ENCRYPTED_DATA:
+            typeSz = sizeof(encryptedData);
+            typeName = encryptedData;
+            break;
+
+        default:
+            CYASSL_MSG("Unknown PKCS#7 Type");
+            return 0;
+    };
+
+    idSz  = SetLength(typeSz, ID_Length);
+    output[idx++] = ASN_OBJECT_ID;
+    XMEMCPY(output + idx, ID_Length, idSz);
+    idx += idSz;
+    XMEMCPY(output + idx, typeName, typeSz);
+    idx += typeSz;
+
+    return idx;
+
+}
+
+
+/* get ASN.1 contentType OID sum, return 0 on success, <0 on failure */
+int GetContentType(const byte* input, word32* inOutIdx, word32* oid,
+                   word32 maxIdx)
+{
+    int length;
+    word32 i = *inOutIdx;
+    byte b;
+    *oid = 0;
+
+    CYASSL_ENTER("GetContentType");
+
+    b = input[i++];
+    if (b != ASN_OBJECT_ID)
+        return ASN_OBJECT_ID_E;
+
+    if (GetLength(input, &i, &length, maxIdx) < 0)
+        return ASN_PARSE_E;
+
+    while(length--) {
+        *oid += input[i];
+        i++;
+    }
+
+    *inOutIdx = i;
+
+    return 0;
+}
+
+
+/* init PKCS7 struct with recipient cert, decode into DecodedCert */
+int PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz)
+{
+    int ret = 0;
+
+    XMEMSET(pkcs7, 0, sizeof(PKCS7));
+    if (cert != NULL && certSz > 0) {
+        DecodedCert dCert;
+
+        pkcs7->singleCert = cert;
+        pkcs7->singleCertSz = certSz;
+        InitDecodedCert(&dCert, cert, certSz, 0);
+
+        ret = ParseCert(&dCert, CA_TYPE, NO_VERIFY, 0);
+        if (ret < 0) {
+            FreeDecodedCert(&dCert);
+            return ret;
+        }
+        XMEMCPY(pkcs7->publicKey, dCert.publicKey, dCert.pubKeySize);
+        pkcs7->publicKeySz = dCert.pubKeySize;
+        XMEMCPY(pkcs7->issuerHash, dCert.issuerHash, SHA_SIZE);
+        pkcs7->issuer = dCert.issuerRaw;
+        pkcs7->issuerSz = dCert.issuerRawLen;
+        XMEMCPY(pkcs7->issuerSn, dCert.serial, dCert.serialSz);
+        pkcs7->issuerSnSz = dCert.serialSz;
+        FreeDecodedCert(&dCert);
+    }
+
+    return ret;
+}
+
+
+/* releases any memory allocated by a PKCS7 initializer */
+void PKCS7_Free(PKCS7* pkcs7)
+{
+    (void)pkcs7;
+}
+
+
+/* build PKCS#7 data content type */
+int PKCS7_EncodeData(PKCS7* pkcs7, byte* output, word32 outputSz)
+{
+    static const byte oid[] =
+        { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
+                         0x07, 0x01 };
+    byte seq[MAX_SEQ_SZ];
+    byte octetStr[MAX_OCTET_STR_SZ];
+    word32 seqSz;
+    word32 octetStrSz;
+    word32 oidSz = (word32)sizeof(oid);
+    int idx = 0;
+
+    octetStrSz = SetOctetString(pkcs7->contentSz, octetStr);
+    seqSz = SetSequence(pkcs7->contentSz + octetStrSz + oidSz, seq);
+
+    if (outputSz < pkcs7->contentSz + octetStrSz + oidSz + seqSz)
+        return BUFFER_E;
+
+    XMEMCPY(output, seq, seqSz);
+    idx += seqSz;
+    XMEMCPY(output + idx, oid, oidSz);
+    idx += oidSz;
+    XMEMCPY(output + idx, octetStr, octetStrSz);
+    idx += octetStrSz;
+    XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz);
+    idx += pkcs7->contentSz;
+
+    return idx;
+}
+
+
+typedef struct EncodedAttrib {
+    byte valueSeq[MAX_SEQ_SZ];
+        const byte* oid;
+        byte valueSet[MAX_SET_SZ];
+        const byte* value;
+    word32 valueSeqSz, oidSz, idSz, valueSetSz, valueSz, totalSz;
+} EncodedAttrib;
+
+
+typedef struct ESD {
+    Sha sha;
+    byte contentDigest[SHA_DIGEST_SIZE + 2]; /* content only + ASN.1 heading */
+    byte contentAttribsDigest[SHA_DIGEST_SIZE];
+    byte encContentDigest[512];
+
+    byte outerSeq[MAX_SEQ_SZ];
+        byte outerContent[MAX_EXP_SZ];
+            byte innerSeq[MAX_SEQ_SZ];
+                byte version[MAX_VERSION_SZ];
+                byte digAlgoIdSet[MAX_SET_SZ];
+                    byte singleDigAlgoId[MAX_ALGO_SZ];
+
+                byte contentInfoSeq[MAX_SEQ_SZ];
+                    byte innerContSeq[MAX_EXP_SZ];
+                        byte innerOctets[MAX_OCTET_STR_SZ];
+
+                byte certsSet[MAX_SET_SZ];
+
+                byte signerInfoSet[MAX_SET_SZ];
+                    byte signerInfoSeq[MAX_SEQ_SZ];
+                        byte signerVersion[MAX_VERSION_SZ];
+                        byte issuerSnSeq[MAX_SEQ_SZ];
+                            byte issuerName[MAX_SEQ_SZ];
+                            byte issuerSn[MAX_SN_SZ];
+                        byte signerDigAlgoId[MAX_ALGO_SZ];
+                        byte digEncAlgoId[MAX_ALGO_SZ];
+                        byte signedAttribSet[MAX_SET_SZ];
+                            EncodedAttrib signedAttribs[6];
+                        byte signerDigest[MAX_OCTET_STR_SZ];
+    word32 innerOctetsSz, innerContSeqSz, contentInfoSeqSz;
+    word32 outerSeqSz, outerContentSz, innerSeqSz, versionSz, digAlgoIdSetSz,
+           singleDigAlgoIdSz, certsSetSz;
+    word32 signerInfoSetSz, signerInfoSeqSz, signerVersionSz,
+           issuerSnSeqSz, issuerNameSz, issuerSnSz,
+           signerDigAlgoIdSz, digEncAlgoIdSz, signerDigestSz;
+    word32 encContentDigestSz, signedAttribsSz, signedAttribsCount,
+           signedAttribSetSz;
+} ESD;
+
+
+static int EncodeAttributes(EncodedAttrib* ea, int eaSz,
+                                            PKCS7Attrib* attribs, int attribsSz)
+{
+    int i;
+    int maxSz = min(eaSz, attribsSz);
+    int allAttribsSz = 0;
+
+    for (i = 0; i < maxSz; i++)
+    {
+        int attribSz = 0;
+
+        ea[i].value = attribs[i].value;
+        ea[i].valueSz = attribs[i].valueSz;
+        attribSz += ea[i].valueSz;
+        ea[i].valueSetSz = SetSet(attribSz, ea[i].valueSet);
+        attribSz += ea[i].valueSetSz;
+        ea[i].oid = attribs[i].oid;
+        ea[i].oidSz = attribs[i].oidSz;
+        attribSz += ea[i].oidSz;
+        ea[i].valueSeqSz = SetSequence(attribSz, ea[i].valueSeq);
+        attribSz += ea[i].valueSeqSz;
+        ea[i].totalSz = attribSz;
+
+        allAttribsSz += attribSz;
+    }
+    return allAttribsSz;
+}
+
+
+static int FlattenAttributes(byte* output, EncodedAttrib* ea, int eaSz)
+{
+    int i, idx;
+
+    idx = 0;
+    for (i = 0; i < eaSz; i++) {
+        XMEMCPY(output + idx, ea[i].valueSeq, ea[i].valueSeqSz);
+        idx += ea[i].valueSeqSz;
+        XMEMCPY(output + idx, ea[i].oid, ea[i].oidSz);
+        idx += ea[i].oidSz;
+        XMEMCPY(output + idx, ea[i].valueSet, ea[i].valueSetSz);
+        idx += ea[i].valueSetSz;
+        XMEMCPY(output + idx, ea[i].value, ea[i].valueSz);
+        idx += ea[i].valueSz;
+    }
+    return 0;
+}
+
+
+/* build PKCS#7 signedData content type */
+int PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz)
+{
+    static const byte outerOid[] =
+        { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
+                         0x07, 0x02 };
+    static const byte innerOid[] =
+        { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
+                         0x07, 0x01 };
+
+    ESD esd;
+    word32 signerInfoSz = 0;
+    word32 totalSz = 0;
+    int idx = 0, ret = 0;
+    byte* flatSignedAttribs = NULL;
+    word32 flatSignedAttribsSz = 0;
+    word32 innerOidSz = sizeof(innerOid);
+    word32 outerOidSz = sizeof(outerOid);
+
+    if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 ||
+        pkcs7->encryptOID == 0 || pkcs7->hashOID == 0 || pkcs7->rng == 0 ||
+        pkcs7->singleCert == NULL || pkcs7->singleCertSz == 0 ||
+        pkcs7->privateKey == NULL || pkcs7->privateKeySz == 0 ||
+        output == NULL || outputSz == 0)
+        return BAD_FUNC_ARG;
+
+    XMEMSET(&esd, 0, sizeof(esd));
+    ret = InitSha(&esd.sha);
+    if (ret != 0)
+        return ret;
+
+    if (pkcs7->contentSz != 0)
+    {
+        ShaUpdate(&esd.sha, pkcs7->content, pkcs7->contentSz);
+        esd.contentDigest[0] = ASN_OCTET_STRING;
+        esd.contentDigest[1] = SHA_DIGEST_SIZE;
+        ShaFinal(&esd.sha, &esd.contentDigest[2]);
+    }
+
+    esd.innerOctetsSz = SetOctetString(pkcs7->contentSz, esd.innerOctets);
+    esd.innerContSeqSz = SetExplicit(0, esd.innerOctetsSz + pkcs7->contentSz,
+                                esd.innerContSeq);
+    esd.contentInfoSeqSz = SetSequence(pkcs7->contentSz + esd.innerOctetsSz +
+                                    innerOidSz + esd.innerContSeqSz,
+                                    esd.contentInfoSeq);
+
+    esd.issuerSnSz = SetSerialNumber(pkcs7->issuerSn, pkcs7->issuerSnSz,
+                                     esd.issuerSn);
+    signerInfoSz += esd.issuerSnSz;
+    esd.issuerNameSz = SetSequence(pkcs7->issuerSz, esd.issuerName);
+    signerInfoSz += esd.issuerNameSz + pkcs7->issuerSz;
+    esd.issuerSnSeqSz = SetSequence(signerInfoSz, esd.issuerSnSeq);
+    signerInfoSz += esd.issuerSnSeqSz;
+    esd.signerVersionSz = SetMyVersion(1, esd.signerVersion, 0);
+    signerInfoSz += esd.signerVersionSz;
+    esd.signerDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd.signerDigAlgoId,
+                                      hashType, 0);
+    signerInfoSz += esd.signerDigAlgoIdSz;
+    esd.digEncAlgoIdSz = SetAlgoID(pkcs7->encryptOID, esd.digEncAlgoId,
+                                   keyType, 0);
+    signerInfoSz += esd.digEncAlgoIdSz;
+
+    if (pkcs7->signedAttribsSz != 0) {
+        byte contentTypeOid[] =
+                { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0d, 0x01,
+                                 0x09, 0x03 };
+        byte contentType[] =
+                { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+                                 0x07, 0x01 };
+        byte messageDigestOid[] =
+                { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+                                 0x09, 0x04 };
+
+        PKCS7Attrib cannedAttribs[2] =
+        {
+            { contentTypeOid, sizeof(contentTypeOid),
+                             contentType, sizeof(contentType) },
+            { messageDigestOid, sizeof(messageDigestOid),
+                             esd.contentDigest, sizeof(esd.contentDigest) }
+        };
+        word32 cannedAttribsCount = sizeof(cannedAttribs)/sizeof(PKCS7Attrib);
+
+        esd.signedAttribsCount += cannedAttribsCount;
+        esd.signedAttribsSz += EncodeAttributes(&esd.signedAttribs[0], 2,
+                                             cannedAttribs, cannedAttribsCount);
+
+        esd.signedAttribsCount += pkcs7->signedAttribsSz;
+        esd.signedAttribsSz += EncodeAttributes(&esd.signedAttribs[2], 4,
+                                  pkcs7->signedAttribs, pkcs7->signedAttribsSz);
+
+        flatSignedAttribs = (byte*)XMALLOC(esd.signedAttribsSz, 0, NULL);
+        flatSignedAttribsSz = esd.signedAttribsSz;
+        if (flatSignedAttribs == NULL)
+            return MEMORY_E;
+        FlattenAttributes(flatSignedAttribs,
+                                     esd.signedAttribs, esd.signedAttribsCount);
+        esd.signedAttribSetSz = SetImplicit(ASN_SET, 0, esd.signedAttribsSz,
+                                                           esd.signedAttribSet);
+    }
+    /* Calculate the final hash and encrypt it. */
+    {
+        RsaKey privKey;
+        int result;
+        word32 scratch = 0;
+
+        byte digestInfo[MAX_SEQ_SZ + MAX_ALGO_SZ +
+                        MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE];
+        byte digestInfoSeq[MAX_SEQ_SZ];
+        byte digestStr[MAX_OCTET_STR_SZ];
+        word32 digestInfoSeqSz, digestStrSz;
+        int digIdx = 0;
+
+        if (pkcs7->signedAttribsSz != 0) {
+            byte attribSet[MAX_SET_SZ];
+            word32 attribSetSz;
+
+            attribSetSz = SetSet(flatSignedAttribsSz, attribSet);
+
+            ret = InitSha(&esd.sha);
+            if (ret < 0) {
+                XFREE(flatSignedAttribs, 0, NULL);
+                return ret;
+            }
+            ShaUpdate(&esd.sha, attribSet, attribSetSz);
+            ShaUpdate(&esd.sha, flatSignedAttribs, flatSignedAttribsSz);
+        }
+        ShaFinal(&esd.sha, esd.contentAttribsDigest);
+
+        digestStrSz = SetOctetString(SHA_DIGEST_SIZE, digestStr);
+        digestInfoSeqSz = SetSequence(esd.signerDigAlgoIdSz +
+                                      digestStrSz + SHA_DIGEST_SIZE,
+                                      digestInfoSeq);
+
+        XMEMCPY(digestInfo + digIdx, digestInfoSeq, digestInfoSeqSz);
+        digIdx += digestInfoSeqSz;
+        XMEMCPY(digestInfo + digIdx,
+                                    esd.signerDigAlgoId, esd.signerDigAlgoIdSz);
+        digIdx += esd.signerDigAlgoIdSz;
+        XMEMCPY(digestInfo + digIdx, digestStr, digestStrSz);
+        digIdx += digestStrSz;
+        XMEMCPY(digestInfo + digIdx, esd.contentAttribsDigest, SHA_DIGEST_SIZE);
+        digIdx += SHA_DIGEST_SIZE;
+
+        result = InitRsaKey(&privKey, NULL);
+        if (result == 0)
+            result = RsaPrivateKeyDecode(pkcs7->privateKey, &scratch, &privKey,
+                                         pkcs7->privateKeySz);
+        if (result < 0) {
+            XFREE(flatSignedAttribs, 0, NULL);
+            return PUBLIC_KEY_E;
+        }
+        result = RsaSSL_Sign(digestInfo, digIdx,
+                             esd.encContentDigest, sizeof(esd.encContentDigest),
+                             &privKey, pkcs7->rng);
+        FreeRsaKey(&privKey);
+        if (result < 0) {
+            XFREE(flatSignedAttribs, 0, NULL);
+            return result;
+        }
+        esd.encContentDigestSz = (word32)result;
+    }
+    signerInfoSz += flatSignedAttribsSz + esd.signedAttribSetSz;
+
+    esd.signerDigestSz = SetOctetString(esd.encContentDigestSz,
+                                                              esd.signerDigest);
+    signerInfoSz += esd.signerDigestSz + esd.encContentDigestSz;
+
+    esd.signerInfoSeqSz = SetSequence(signerInfoSz, esd.signerInfoSeq);
+    signerInfoSz += esd.signerInfoSeqSz;
+    esd.signerInfoSetSz = SetSet(signerInfoSz, esd.signerInfoSet);
+    signerInfoSz += esd.signerInfoSetSz;
+
+    esd.certsSetSz = SetImplicit(ASN_SET, 0, pkcs7->singleCertSz, esd.certsSet);
+
+    esd.singleDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd.singleDigAlgoId,
+                                      hashType, 0);
+    esd.digAlgoIdSetSz = SetSet(esd.singleDigAlgoIdSz, esd.digAlgoIdSet);
+
+
+    esd.versionSz = SetMyVersion(1, esd.version, 0);
+
+    totalSz = esd.versionSz + esd.singleDigAlgoIdSz + esd.digAlgoIdSetSz +
+              esd.contentInfoSeqSz + esd.certsSetSz + pkcs7->singleCertSz +
+              esd.innerOctetsSz + esd.innerContSeqSz +
+              innerOidSz + pkcs7->contentSz +
+              signerInfoSz;
+    esd.innerSeqSz = SetSequence(totalSz, esd.innerSeq);
+    totalSz += esd.innerSeqSz;
+    esd.outerContentSz = SetExplicit(0, totalSz, esd.outerContent);
+    totalSz += esd.outerContentSz + outerOidSz;
+    esd.outerSeqSz = SetSequence(totalSz, esd.outerSeq);
+    totalSz += esd.outerSeqSz;
+
+    if (outputSz < totalSz)
+        return BUFFER_E;
+
+    idx = 0;
+    XMEMCPY(output + idx, esd.outerSeq, esd.outerSeqSz);
+    idx += esd.outerSeqSz;
+    XMEMCPY(output + idx, outerOid, outerOidSz);
+    idx += outerOidSz;
+    XMEMCPY(output + idx, esd.outerContent, esd.outerContentSz);
+    idx += esd.outerContentSz;
+    XMEMCPY(output + idx, esd.innerSeq, esd.innerSeqSz);
+    idx += esd.innerSeqSz;
+    XMEMCPY(output + idx, esd.version, esd.versionSz);
+    idx += esd.versionSz;
+    XMEMCPY(output + idx, esd.digAlgoIdSet, esd.digAlgoIdSetSz);
+    idx += esd.digAlgoIdSetSz;
+    XMEMCPY(output + idx, esd.singleDigAlgoId, esd.singleDigAlgoIdSz);
+    idx += esd.singleDigAlgoIdSz;
+    XMEMCPY(output + idx, esd.contentInfoSeq, esd.contentInfoSeqSz);
+    idx += esd.contentInfoSeqSz;
+    XMEMCPY(output + idx, innerOid, innerOidSz);
+    idx += innerOidSz;
+    XMEMCPY(output + idx, esd.innerContSeq, esd.innerContSeqSz);
+    idx += esd.innerContSeqSz;
+    XMEMCPY(output + idx, esd.innerOctets, esd.innerOctetsSz);
+    idx += esd.innerOctetsSz;
+    XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz);
+    idx += pkcs7->contentSz;
+    XMEMCPY(output + idx, esd.certsSet, esd.certsSetSz);
+    idx += esd.certsSetSz;
+    XMEMCPY(output + idx, pkcs7->singleCert, pkcs7->singleCertSz);
+    idx += pkcs7->singleCertSz;
+    XMEMCPY(output + idx, esd.signerInfoSet, esd.signerInfoSetSz);
+    idx += esd.signerInfoSetSz;
+    XMEMCPY(output + idx, esd.signerInfoSeq, esd.signerInfoSeqSz);
+    idx += esd.signerInfoSeqSz;
+    XMEMCPY(output + idx, esd.signerVersion, esd.signerVersionSz);
+    idx += esd.signerVersionSz;
+    XMEMCPY(output + idx, esd.issuerSnSeq, esd.issuerSnSeqSz);
+    idx += esd.issuerSnSeqSz;
+    XMEMCPY(output + idx, esd.issuerName, esd.issuerNameSz);
+    idx += esd.issuerNameSz;
+    XMEMCPY(output + idx, pkcs7->issuer, pkcs7->issuerSz);
+    idx += pkcs7->issuerSz;
+    XMEMCPY(output + idx, esd.issuerSn, esd.issuerSnSz);
+    idx += esd.issuerSnSz;
+    XMEMCPY(output + idx, esd.signerDigAlgoId, esd.signerDigAlgoIdSz);
+    idx += esd.signerDigAlgoIdSz;
+
+    /* SignerInfo:Attributes */
+    if (pkcs7->signedAttribsSz != 0) {
+        XMEMCPY(output + idx, esd.signedAttribSet, esd.signedAttribSetSz);
+        idx += esd.signedAttribSetSz;
+        XMEMCPY(output + idx, flatSignedAttribs, flatSignedAttribsSz);
+        idx += flatSignedAttribsSz;
+        XFREE(flatSignedAttribs, 0, NULL);
+    }
+
+    XMEMCPY(output + idx, esd.digEncAlgoId, esd.digEncAlgoIdSz);
+    idx += esd.digEncAlgoIdSz;
+    XMEMCPY(output + idx, esd.signerDigest, esd.signerDigestSz);
+    idx += esd.signerDigestSz;
+    XMEMCPY(output + idx, esd.encContentDigest, esd.encContentDigestSz);
+    idx += esd.encContentDigestSz;
+
+    return idx;
+}
+
+
+/* Finds the certificates in the message and saves it. */
+int PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz)
+{
+    word32 idx, contentType;
+    int length, version, ret;
+    byte* content = NULL;
+    byte* sig = NULL;
+    byte* cert = NULL;
+    byte* signedAttr = NULL;
+    int contentSz = 0, sigSz = 0, certSz = 0, signedAttrSz = 0;
+
+    (void)signedAttr;    /* not used yet, just set */
+    (void)signedAttrSz;
+
+    if (pkcs7 == NULL || pkiMsg == NULL || pkiMsgSz == 0)
+        return BAD_FUNC_ARG;
+
+    idx = 0;
+
+    /* Get the contentInfo sequence */
+    if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    /* Get the contentInfo contentType */
+    if (GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (contentType != SIGNED_DATA) {
+        CYASSL_MSG("PKCS#7 input not of type SignedData");
+        return PKCS7_OID_E;
+    }
+
+    /* get the ContentInfo content */
+    if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
+        return ASN_PARSE_E;
+
+    if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    /* Get the signedData sequence */
+    if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    /* Get the version */
+    if (GetMyVersion(pkiMsg, &idx, &version) < 0)
+        return ASN_PARSE_E;
+
+    if (version != 1) {
+        CYASSL_MSG("PKCS#7 signedData needs to be of version 1");
+        return ASN_VERSION_E;
+    }
+
+    /* Get the set of DigestAlgorithmIdentifiers */
+    if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    /* Skip the set. */
+    idx += length;
+
+    /* Get the inner ContentInfo sequence */
+    if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    /* Get the inner ContentInfo contentType */
+    if (GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (contentType != DATA) {
+        CYASSL_MSG("PKCS#7 inner input not of type Data");
+        return PKCS7_OID_E;
+    }
+
+    if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
+        return ASN_PARSE_E;
+
+    if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (pkiMsg[idx++] != ASN_OCTET_STRING)
+        return ASN_PARSE_E;
+
+    if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    /* Save the inner data as the content. */
+    if (length > 0) {
+        /* Local pointer for calculating hashes later */
+        pkcs7->content = content = &pkiMsg[idx];
+        pkcs7->contentSz = contentSz = length;
+        idx += length;
+    }
+
+    /* Get the implicit[0] set of certificates */
+    if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
+        idx++;
+        if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        if (length > 0) {
+            /* At this point, idx is at the first certificate in
+             * a set of certificates. There may be more than one,
+             * or none, or they may be a PKCS 6 extended
+             * certificate. We want to save the first cert if it
+             * is X.509. */
+
+            word32 certIdx = idx;
+
+            if (pkiMsg[certIdx++] == (ASN_CONSTRUCTED | ASN_SEQUENCE)) {
+                if (GetLength(pkiMsg, &certIdx, &certSz, pkiMsgSz) < 0)
+                    return ASN_PARSE_E;
+
+                cert = &pkiMsg[idx];
+                certSz += (certIdx - idx);
+            }
+            PKCS7_InitWithCert(pkcs7, cert, certSz);
+        }
+        idx += length;
+    }
+
+    /* Get the implicit[1] set of crls */
+    if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) {
+        idx++;
+        if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        /* Skip the set */
+        idx += length;
+    }
+
+    /* Get the set of signerInfos */
+    if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (length > 0) {
+        RsaKey key;
+        word32 scratch = 0;
+        int plainSz = 0;
+        byte digest[MAX_SEQ_SZ+MAX_ALGO_SZ+MAX_OCTET_STR_SZ+SHA_DIGEST_SIZE];
+
+        /* Get the sequence of the first signerInfo */
+        if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        /* Get the version */
+        if (GetMyVersion(pkiMsg, &idx, &version) < 0)
+            return ASN_PARSE_E;
+
+        if (version != 1) {
+            CYASSL_MSG("PKCS#7 signerInfo needs to be of version 1");
+            return ASN_VERSION_E;
+        }
+
+        /* Get the sequence of IssuerAndSerialNumber */
+        if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        /* Skip it */
+        idx += length;
+
+        /* Get the sequence of digestAlgorithm */
+        if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        /* Skip it */
+        idx += length;
+
+        /* Get the IMPLICIT[0] SET OF signedAttributes */
+        if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
+            idx++;
+
+            if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+                return ASN_PARSE_E;
+
+            /* save pointer and length */
+            signedAttr = &pkiMsg[idx];
+            signedAttrSz = length;
+
+            idx += length;
+        }
+
+        /* Get the sequence of digestEncryptionAlgorithm */
+        if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        /* Skip it */
+        idx += length;
+
+        /* Get the signature */
+        if (pkiMsg[idx] == ASN_OCTET_STRING) {
+            idx++;
+
+            if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+                return ASN_PARSE_E;
+
+            /* save pointer and length */
+            sig = &pkiMsg[idx];
+            sigSz = length;
+
+            idx += length;
+        }
+
+        XMEMSET(digest, 0, sizeof(digest));
+        pkcs7->content = content;
+        pkcs7->contentSz = contentSz;
+
+        ret = InitRsaKey(&key, NULL);
+        if (ret != 0) return ret;
+        if (RsaPublicKeyDecode(pkcs7->publicKey, &scratch, &key,
+                               pkcs7->publicKeySz) < 0) {
+            CYASSL_MSG("ASN RSA key decode error");
+            return PUBLIC_KEY_E;
+        }
+        plainSz = RsaSSL_Verify(sig, sigSz, digest, sizeof(digest), &key);
+        FreeRsaKey(&key);
+        if (plainSz < 0)
+            return plainSz;
+    }
+
+    return 0;
+}
+
+
+/* create ASN.1 fomatted RecipientInfo structure, returns sequence size */
+CYASSL_LOCAL int CreateRecipientInfo(const byte* cert, word32 certSz,
+                                     int keyEncAlgo, int blockKeySz,
+                                     RNG* rng, byte* contentKeyPlain,
+                                     byte* contentKeyEnc,
+                                     int* keyEncSz, byte* out, word32 outSz)
+{
+    word32 idx = 0;
+    int ret = 0, totalSz = 0;
+    int verSz, issuerSz, snSz, keyEncAlgSz;
+    int issuerSeqSz, recipSeqSz, issuerSerialSeqSz;
+    int encKeyOctetStrSz;
+
+    byte ver[MAX_VERSION_SZ];
+    byte serial[MAX_SN_SZ];
+    byte issuerSerialSeq[MAX_SEQ_SZ];
+    byte recipSeq[MAX_SEQ_SZ];
+    byte issuerSeq[MAX_SEQ_SZ];
+    byte keyAlgArray[MAX_ALGO_SZ];
+    byte encKeyOctetStr[MAX_OCTET_STR_SZ];
+
+    RsaKey pubKey;
+    DecodedCert decoded;
+
+    InitDecodedCert(&decoded, (byte*)cert, certSz, 0);
+    ret = ParseCert(&decoded, CA_TYPE, NO_VERIFY, 0);
+    if (ret < 0) {
+        FreeDecodedCert(&decoded);
+        return ret;
+    }
+
+    /* version */
+    verSz = SetMyVersion(0, ver, 0);
+
+    /* IssuerAndSerialNumber */
+    if (decoded.issuerRaw == NULL || decoded.issuerRawLen == 0) {
+        CYASSL_MSG("DecodedCert lacks raw issuer pointer and length");
+        FreeDecodedCert(&decoded);
+        return -1;
+    }
+    issuerSz    = decoded.issuerRawLen;
+    issuerSeqSz = SetSequence(issuerSz, issuerSeq);
+
+    if (decoded.serial == NULL || decoded.serialSz == 0) {
+        CYASSL_MSG("DecodedCert missing serial number");
+        FreeDecodedCert(&decoded);
+        return -1;
+    }
+    snSz = SetSerialNumber(decoded.serial, decoded.serialSz, serial);
+
+    issuerSerialSeqSz = SetSequence(issuerSeqSz + issuerSz + snSz,
+                                    issuerSerialSeq);
+
+    /* KeyEncryptionAlgorithmIdentifier, only support RSA now */
+    if (keyEncAlgo != RSAk)
+        return ALGO_ID_E;
+
+    keyEncAlgSz = SetAlgoID(keyEncAlgo, keyAlgArray, keyType, 0);
+    if (keyEncAlgSz == 0)
+        return BAD_FUNC_ARG;
+
+    /* EncryptedKey */
+    ret = InitRsaKey(&pubKey, 0);
+    if (ret != 0) return ret;
+    if (RsaPublicKeyDecode(decoded.publicKey, &idx, &pubKey,
+                           decoded.pubKeySize) < 0) {
+        CYASSL_MSG("ASN RSA key decode error");
+        return PUBLIC_KEY_E;
+    }
+
+    *keyEncSz = RsaPublicEncrypt(contentKeyPlain, blockKeySz, contentKeyEnc,
+                                 MAX_ENCRYPTED_KEY_SZ, &pubKey, rng);
+    FreeRsaKey(&pubKey);
+    if (*keyEncSz < 0) {
+        CYASSL_MSG("RSA Public Encrypt failed");
+        return *keyEncSz;
+    }
+
+    encKeyOctetStrSz = SetOctetString(*keyEncSz, encKeyOctetStr);
+
+    /* RecipientInfo */
+    recipSeqSz = SetSequence(verSz + issuerSerialSeqSz + issuerSeqSz +
+                             issuerSz + snSz + keyEncAlgSz + encKeyOctetStrSz +
+                             *keyEncSz, recipSeq);
+
+    if (recipSeqSz + verSz + issuerSerialSeqSz + issuerSeqSz + snSz +
+        keyEncAlgSz + encKeyOctetStrSz + *keyEncSz > (int)outSz) {
+        CYASSL_MSG("RecipientInfo output buffer too small");
+        return BUFFER_E;
+    }
+
+    XMEMCPY(out + totalSz, recipSeq, recipSeqSz);
+    totalSz += recipSeqSz;
+    XMEMCPY(out + totalSz, ver, verSz);
+    totalSz += verSz;
+    XMEMCPY(out + totalSz, issuerSerialSeq, issuerSerialSeqSz);
+    totalSz += issuerSerialSeqSz;
+    XMEMCPY(out + totalSz, issuerSeq, issuerSeqSz);
+    totalSz += issuerSeqSz;
+    XMEMCPY(out + totalSz, decoded.issuerRaw, issuerSz);
+    totalSz += issuerSz;
+    XMEMCPY(out + totalSz, serial, snSz);
+    totalSz += snSz;
+    XMEMCPY(out + totalSz, keyAlgArray, keyEncAlgSz);
+    totalSz += keyEncAlgSz;
+    XMEMCPY(out + totalSz, encKeyOctetStr, encKeyOctetStrSz);
+    totalSz += encKeyOctetStrSz;
+    XMEMCPY(out + totalSz, contentKeyEnc, *keyEncSz);
+    totalSz += *keyEncSz;
+
+    FreeDecodedCert(&decoded);
+
+    return totalSz;
+}
+
+
+/* build PKCS#7 envelopedData content type, return enveloped size */
+int PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz)
+{
+    int i, ret = 0, idx = 0;
+    int totalSz = 0, padSz = 0, desOutSz = 0;
+
+    int contentInfoSeqSz, outerContentTypeSz, outerContentSz;
+    byte contentInfoSeq[MAX_SEQ_SZ];
+    byte outerContentType[MAX_ALGO_SZ];
+    byte outerContent[MAX_SEQ_SZ];
+
+    int envDataSeqSz, verSz;
+    byte envDataSeq[MAX_SEQ_SZ];
+    byte ver[MAX_VERSION_SZ];
+
+    RNG rng;
+    int contentKeyEncSz, blockKeySz;
+    int dynamicFlag = 0;
+    byte contentKeyPlain[MAX_CONTENT_KEY_LEN];
+    byte contentKeyEnc[MAX_ENCRYPTED_KEY_SZ];
+    byte* plain;
+    byte* encryptedContent;
+
+    int recipSz, recipSetSz;
+    byte recip[MAX_RECIP_SZ];
+    byte recipSet[MAX_SET_SZ];
+
+    int encContentOctetSz, encContentSeqSz, contentTypeSz;
+    int contentEncAlgoSz, ivOctetStringSz;
+    byte encContentSeq[MAX_SEQ_SZ];
+    byte contentType[MAX_ALGO_SZ];
+    byte contentEncAlgo[MAX_ALGO_SZ];
+    byte tmpIv[DES_BLOCK_SIZE];
+    byte ivOctetString[MAX_OCTET_STR_SZ];
+    byte encContentOctet[MAX_OCTET_STR_SZ];
+
+    if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 ||
+        pkcs7->encryptOID == 0 || pkcs7->singleCert == NULL)
+        return BAD_FUNC_ARG;
+
+    if (output == NULL || outputSz == 0)
+        return BAD_FUNC_ARG;
+
+    /* PKCS#7 only supports DES, 3DES for now */
+    switch (pkcs7->encryptOID) {
+        case DESb:
+            blockKeySz = DES_KEYLEN;
+            break;
+
+        case DES3b:
+            blockKeySz = DES3_KEYLEN;
+            break;
+
+        default:
+            CYASSL_MSG("Unsupported content cipher type");
+            return ALGO_ID_E;
+    };
+
+    /* outer content type */
+    outerContentTypeSz = SetContentType(ENVELOPED_DATA, outerContentType);
+
+    /* version, defined as 0 in RFC 2315 */
+    verSz = SetMyVersion(0, ver, 0);
+
+    /* generate random content encryption key */
+    InitRng(&rng);
+    RNG_GenerateBlock(&rng, contentKeyPlain, blockKeySz);
+
+    /* build RecipientInfo, only handle 1 for now */
+    recipSz = CreateRecipientInfo(pkcs7->singleCert, pkcs7->singleCertSz, RSAk,
+                                  blockKeySz, &rng, contentKeyPlain,
+                                  contentKeyEnc, &contentKeyEncSz, recip,
+                                  MAX_RECIP_SZ);
+
+    if (recipSz < 0) {
+        CYASSL_MSG("Failed to create RecipientInfo");
+        return recipSz;
+    }
+    recipSetSz = SetSet(recipSz, recipSet);
+
+    /* EncryptedContentInfo */
+    contentTypeSz = SetContentType(pkcs7->contentOID, contentType);
+    if (contentTypeSz == 0)
+        return BAD_FUNC_ARG;
+
+    /* allocate encrypted content buffer, pad if necessary, PKCS#7 padding */
+    padSz = DES_BLOCK_SIZE - (pkcs7->contentSz % DES_BLOCK_SIZE);
+    desOutSz = pkcs7->contentSz + padSz;
+
+    if (padSz != 0) {
+        plain = XMALLOC(desOutSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (plain == NULL) {
+            return MEMORY_E;
+        }
+        XMEMCPY(plain, pkcs7->content, pkcs7->contentSz);
+        dynamicFlag = 1;
+
+        for (i = 0; i < padSz; i++) {
+            plain[pkcs7->contentSz + i] = padSz;
+        }
+
+    } else {
+        plain = pkcs7->content;
+        desOutSz = pkcs7->contentSz;
+    }
+
+    encryptedContent = XMALLOC(desOutSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (encryptedContent == NULL) {
+        if (dynamicFlag)
+            XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+
+    /* generate IV for block cipher */
+    RNG_GenerateBlock(&rng, tmpIv, DES_BLOCK_SIZE);
+
+    /* put together IV OCTET STRING */
+    ivOctetStringSz = SetOctetString(DES_BLOCK_SIZE, ivOctetString);
+
+    /* build up our ContentEncryptionAlgorithmIdentifier sequence,
+     * adding (ivOctetStringSz + DES_BLOCK_SIZE) for IV OCTET STRING */
+    contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo,
+                                 blkType, ivOctetStringSz + DES_BLOCK_SIZE);
+    if (contentEncAlgoSz == 0)
+        return BAD_FUNC_ARG;
+
+    /* encrypt content */
+    if (pkcs7->encryptOID == DESb) {
+        Des des;
+
+        ret = Des_SetKey(&des, contentKeyPlain, tmpIv, DES_ENCRYPTION);
+
+        if (ret == 0)
+            Des_CbcEncrypt(&des, encryptedContent, plain, desOutSz);
+
+        if (ret != 0) {
+            XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            if (dynamicFlag)
+                XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            return ret;
+        }
+    }
+    else if (pkcs7->encryptOID == DES3b) {
+        Des3 des3;
+
+        ret = Des3_SetKey(&des3, contentKeyPlain, tmpIv, DES_ENCRYPTION);
+
+        if (ret == 0)
+            ret = Des3_CbcEncrypt(&des3, encryptedContent, plain, desOutSz);
+
+        if (ret != 0) {
+            XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            if (dynamicFlag)
+                XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            return ret;
+        }
+    }
+
+    encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0,
+                                    desOutSz, encContentOctet);
+
+    encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz +
+                                  ivOctetStringSz + DES_BLOCK_SIZE +
+                                  encContentOctetSz + desOutSz, encContentSeq);
+
+    /* keep track of sizes for outer wrapper layering */
+    totalSz = verSz + recipSetSz + recipSz + encContentSeqSz + contentTypeSz +
+              contentEncAlgoSz + ivOctetStringSz + DES_BLOCK_SIZE +
+              encContentOctetSz + desOutSz;
+
+    /* EnvelopedData */
+    envDataSeqSz = SetSequence(totalSz, envDataSeq);
+    totalSz += envDataSeqSz;
+
+    /* outer content */
+    outerContentSz = SetExplicit(0, totalSz, outerContent);
+    totalSz += outerContentTypeSz;
+    totalSz += outerContentSz;
+
+    /* ContentInfo */
+    contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq);
+    totalSz += contentInfoSeqSz;
+
+    if (totalSz > (int)outputSz) {
+        CYASSL_MSG("Pkcs7_encrypt output buffer too small");
+        XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        if (dynamicFlag)
+            XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return BUFFER_E;
+    }
+
+    XMEMCPY(output + idx, contentInfoSeq, contentInfoSeqSz);
+    idx += contentInfoSeqSz;
+    XMEMCPY(output + idx, outerContentType, outerContentTypeSz);
+    idx += outerContentTypeSz;
+    XMEMCPY(output + idx, outerContent, outerContentSz);
+    idx += outerContentSz;
+    XMEMCPY(output + idx, envDataSeq, envDataSeqSz);
+    idx += envDataSeqSz;
+    XMEMCPY(output + idx, ver, verSz);
+    idx += verSz;
+    XMEMCPY(output + idx, recipSet, recipSetSz);
+    idx += recipSetSz;
+    XMEMCPY(output + idx, recip, recipSz);
+    idx += recipSz;
+    XMEMCPY(output + idx, encContentSeq, encContentSeqSz);
+    idx += encContentSeqSz;
+    XMEMCPY(output + idx, contentType, contentTypeSz);
+    idx += contentTypeSz;
+    XMEMCPY(output + idx, contentEncAlgo, contentEncAlgoSz);
+    idx += contentEncAlgoSz;
+    XMEMCPY(output + idx, ivOctetString, ivOctetStringSz);
+    idx += ivOctetStringSz;
+    XMEMCPY(output + idx, tmpIv, DES_BLOCK_SIZE);
+    idx += DES_BLOCK_SIZE;
+    XMEMCPY(output + idx, encContentOctet, encContentOctetSz);
+    idx += encContentOctetSz;
+    XMEMCPY(output + idx, encryptedContent, desOutSz);
+    idx += desOutSz;
+
+#ifdef NO_RC4
+    FreeRng(&rng);
+#endif
+
+    XMEMSET(contentKeyPlain, 0, MAX_CONTENT_KEY_LEN);
+    XMEMSET(contentKeyEnc,   0, MAX_ENCRYPTED_KEY_SZ);
+
+    if (dynamicFlag)
+        XFREE(plain, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+    XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    return idx;
+}
+
+/* unwrap and decrypt PKCS#7 envelopedData object, return decoded size */
+CYASSL_API int PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg,
+                                         word32 pkiMsgSz, byte* output,
+                                         word32 outputSz)
+{
+    int recipFound = 0;
+    int ret, version, length;
+    word32 savedIdx = 0, idx = 0;
+    word32 contentType, encOID;
+    byte   issuerHash[SHA_DIGEST_SIZE];
+    mp_int serialNum;
+
+    int encryptedKeySz, keySz;
+    byte tmpIv[DES_BLOCK_SIZE];
+    byte encryptedKey[MAX_ENCRYPTED_KEY_SZ];
+    byte* decryptedKey = NULL;
+
+    RsaKey privKey;
+    int encryptedContentSz;
+    byte padLen;
+    byte* encryptedContent = NULL;
+
+    if (pkcs7 == NULL || pkcs7->singleCert == NULL ||
+        pkcs7->singleCertSz == 0 || pkcs7->privateKey == NULL ||
+        pkcs7->privateKeySz == 0)
+        return BAD_FUNC_ARG;
+
+    if (pkiMsg == NULL || pkiMsgSz == 0 ||
+        output == NULL || outputSz == 0)
+        return BAD_FUNC_ARG;
+
+    /* load private key */
+    ret = InitRsaKey(&privKey, 0);
+    if (ret != 0) return ret;
+    ret = RsaPrivateKeyDecode(pkcs7->privateKey, &idx, &privKey,
+                              pkcs7->privateKeySz);
+    if (ret != 0) {
+        CYASSL_MSG("Failed to decode RSA private key");
+        return ret;
+    }
+
+    idx = 0;
+
+    /* read past ContentInfo, verify type is envelopedData */
+    if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (contentType != ENVELOPED_DATA) {
+        CYASSL_MSG("PKCS#7 input not of type EnvelopedData");
+        return PKCS7_OID_E;
+    }
+
+    if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
+        return ASN_PARSE_E;
+
+    if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    /* remove EnvelopedData and version */
+    if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetMyVersion(pkiMsg, &idx, &version) < 0)
+        return ASN_PARSE_E;
+
+    if (version != 0) {
+        CYASSL_MSG("PKCS#7 envelopedData needs to be of version 0");
+        return ASN_VERSION_E;
+    }
+
+    /* walk through RecipientInfo set, find correct recipient */
+    if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    savedIdx = idx;
+    recipFound = 0;
+
+    /* when looking for next recipient, use first sequence and version to
+     * indicate there is another, if not, move on */
+    while(recipFound == 0) {
+
+        /* remove RecipientInfo, if we don't have a SEQUENCE, back up idx to
+         * last good saved one */
+        if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) {
+            idx = savedIdx;
+            break;
+        }
+
+        if (GetMyVersion(pkiMsg, &idx, &version) < 0) {
+            idx = savedIdx;
+            break;
+        }
+
+        if (version != 0)
+            return ASN_VERSION_E;
+
+        /* remove IssuerAndSerialNumber */
+        if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        if (GetNameHash(pkiMsg, &idx, issuerHash, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        /* if we found correct recipient, issuer hashes will match */
+        if (XMEMCMP(issuerHash, pkcs7->issuerHash, SHA_DIGEST_SIZE) == 0) {
+            recipFound = 1;
+        }
+
+        if (GetInt(&serialNum, pkiMsg, &idx, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+        mp_clear(&serialNum);
+
+        if (GetAlgoId(pkiMsg, &idx, &encOID, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        /* key encryption algorithm must be RSA for now */
+        if (encOID != RSAk)
+            return ALGO_ID_E;
+
+        /* read encryptedKey */
+        if (pkiMsg[idx++] != ASN_OCTET_STRING)
+            return ASN_PARSE_E;
+
+        if (GetLength(pkiMsg, &idx, &encryptedKeySz, pkiMsgSz) < 0)
+            return ASN_PARSE_E;
+
+        if (recipFound == 1)
+            XMEMCPY(encryptedKey, &pkiMsg[idx], encryptedKeySz);
+        idx += encryptedKeySz;
+
+        /* update good idx */
+        savedIdx = idx;
+    }
+
+    if (recipFound == 0) {
+        CYASSL_MSG("No recipient found in envelopedData that matches input");
+        return PKCS7_RECIP_E;
+    }
+
+    /* remove EncryptedContentInfo */
+    if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (GetAlgoId(pkiMsg, &idx, &encOID, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */
+    if (pkiMsg[idx++] != ASN_OCTET_STRING)
+        return ASN_PARSE_E;
+
+    if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    if (length != DES_BLOCK_SIZE) {
+        CYASSL_MSG("Incorrect IV length, must be of DES_BLOCK_SIZE");
+        return ASN_PARSE_E;
+    }
+
+    XMEMCPY(tmpIv, &pkiMsg[idx], length);
+    idx += length;
+
+    /* read encryptedContent, cont[0] */
+    if (pkiMsg[idx++] != (ASN_CONTEXT_SPECIFIC | 0))
+        return ASN_PARSE_E;
+
+    if (GetLength(pkiMsg, &idx, &encryptedContentSz, pkiMsgSz) < 0)
+        return ASN_PARSE_E;
+
+    encryptedContent = XMALLOC(encryptedContentSz, NULL,
+                               DYNAMIC_TYPE_TMP_BUFFER);
+
+    XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz);
+
+    /* decrypt encryptedKey */
+    keySz = RsaPrivateDecryptInline(encryptedKey, encryptedKeySz,
+                                    &decryptedKey, &privKey);
+    FreeRsaKey(&privKey);
+    if (keySz <= 0)
+        return keySz;
+
+    /* decrypt encryptedContent */
+    if (encOID == DESb) {
+        Des des;
+        ret = Des_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION);
+
+        if (ret == 0)
+            Des_CbcDecrypt(&des, encryptedContent, encryptedContent,
+                                 encryptedContentSz);
+
+        if (ret != 0) {
+            XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            return ret;
+        }
+    }
+    else if (encOID == DES3b) {
+        Des3 des;
+        ret = Des3_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION);
+        if (ret == 0)
+            ret = Des3_CbcDecrypt(&des, encryptedContent, encryptedContent,
+                                  encryptedContentSz);
+
+        if (ret != 0) {
+            XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            return ret;
+        }
+    } else {
+        CYASSL_MSG("Unsupported content encryption OID type");
+        return ALGO_ID_E;
+    }
+
+    padLen = encryptedContent[encryptedContentSz-1];
+
+    /* copy plaintext to output */
+    XMEMCPY(output, encryptedContent, encryptedContentSz - padLen);
+
+    /* free memory, zero out keys */
+    XMEMSET(encryptedKey, 0, MAX_ENCRYPTED_KEY_SZ);
+    XMEMSET(encryptedContent, 0, encryptedContentSz);
+    XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    return encryptedContentSz - padLen;
+}
+
+
+#else  /* HAVE_PKCS7 */
+
+
+#ifdef _MSC_VER
+    /* 4206 warning for blank file */
+    #pragma warning(disable: 4206)
+#endif
+
+
+#endif /* HAVE_PKCS7 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/port.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,436 @@
+/* port.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/types.h>
+#include <cyassl/ctaocrypt/error-crypt.h>
+
+
+#ifdef _MSC_VER
+    /* 4996 warning to use MS extensions e.g., strcpy_s instead of strncpy */
+    #pragma warning(disable: 4996)
+#endif
+
+
+
+#ifdef SINGLE_THREADED
+
+int InitMutex(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_E;
+
+            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_E;
+
+            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_E;
+        }
+
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            if (pthread_mutex_destroy(m) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            if (pthread_mutex_lock(m) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            if (pthread_mutex_unlock(m) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+    #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_E;
+        }
+
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            if (tx_mutex_delete(m) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            if (tx_mutex_get(m, TX_WAIT_FOREVER) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            if (tx_mutex_put(m) == 0)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+    #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_E;
+            #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_E;
+            #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_E;
+            #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_E;
+            #else
+                return 0;
+            #endif
+
+        }
+
+    #elif defined(EBSNET)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            if (rtp_sig_mutex_alloc(m, "CyaSSL Mutex") == -1)
+                return BAD_MUTEX_E;
+            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_E;
+        }
+
+        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_E;
+        }
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            if (_mutex_destroy(m) == MQX_EOK)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            if (_mutex_lock(m) == MQX_EOK)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            if (_mutex_unlock(m) == MQX_EOK)
+                return 0;
+            else
+                return BAD_MUTEX_E;
+        }
+        
+    #elif defined(CYASSL_MDK_ARM)|| defined(CYASSL_CMSIS_RTOS)
+    
+        #if defined(CYASSL_CMSIS_RTOS)
+            #include "cmsis_os.h"
+            #define CMSIS_NMUTEX 10
+            osMutexDef(CyaSSL_mt0) ;  osMutexDef(CyaSSL_mt1) ;  osMutexDef(CyaSSL_mt2) ;
+            osMutexDef(CyaSSL_mt3) ;  osMutexDef(CyaSSL_mt4) ;  osMutexDef(CyaSSL_mt5) ;  
+            osMutexDef(CyaSSL_mt6) ;  osMutexDef(CyaSSL_mt7) ;  osMutexDef(CyaSSL_mt8) ;  
+            osMutexDef(CyaSSL_mt9) ;  
+            
+            static const osMutexDef_t *CMSIS_mutex[] = { osMutex(CyaSSL_mt0),   
+                osMutex(CyaSSL_mt1),    osMutex(CyaSSL_mt2),   osMutex(CyaSSL_mt3),    
+                osMutex(CyaSSL_mt4),    osMutex(CyaSSL_mt5),   osMutex(CyaSSL_mt6),
+                osMutex(CyaSSL_mt7),    osMutex(CyaSSL_mt8),    osMutex(CyaSSL_mt9) } ;                 
+            
+            static osMutexId CMSIS_mutexID[CMSIS_NMUTEX] = {0} ;
+
+            int InitMutex(CyaSSL_Mutex* m)
+            {
+                int i ;
+                for (i=0; i<CMSIS_NMUTEX; i++) {
+                    if(CMSIS_mutexID[i] == 0) {
+                        CMSIS_mutexID[i] = osMutexCreate(CMSIS_mutex[i]) ;
+                        (*m) = CMSIS_mutexID[i] ;
+                    return 0 ;
+                    }
+                }
+                return -1 ;
+            }
+
+            int FreeMutex(CyaSSL_Mutex* m)
+            {
+                int i ;
+                osMutexDelete   (*m) ;
+                for (i=0; i<CMSIS_NMUTEX; i++) {
+                    if(CMSIS_mutexID[i] == (*m)) {
+                        CMSIS_mutexID[i] = 0 ;
+                        return(0) ;
+                    }
+                }
+                return(-1) ;
+            }
+            
+            int LockMutex(CyaSSL_Mutex* m)
+            {
+                osMutexWait(*m, osWaitForever) ;
+                return(0) ;
+            }
+
+            int UnLockMutex(CyaSSL_Mutex* m)
+            {
+                osMutexRelease (*m);
+                return 0;
+            }
+        #else
+
+        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
+    #endif /* USE_WINDOWS_API */
+#endif /* SINGLE_THREADED */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/pwdbased.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,382 @@
+/* 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
+
+#ifdef CYASSL_PIC32MZ_HASH
+
+#define InitMd5   InitMd5_sw
+#define Md5Update Md5Update_sw
+#define Md5Final  Md5Final_sw
+
+#define InitSha   InitSha_sw
+#define ShaUpdate ShaUpdate_sw
+#define ShaFinal  ShaFinal_sw
+
+#define InitSha256   InitSha256_sw
+#define Sha256Update Sha256Update_sw
+#define Sha256Final  Sha256Final_sw
+
+#endif
+
+#include <cyassl/ctaocrypt/pwdbased.h>
+#include <cyassl/ctaocrypt/hmac.h>
+#include <cyassl/ctaocrypt/integer.h>
+#include <cyassl/ctaocrypt/error-crypt.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, ret = 0;
+    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 {
+        ret = InitSha(&sha);
+        if (ret != 0)
+            return ret;
+        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, ret;
+    Hmac   hmac;
+    byte   buffer[MAX_DIGEST_SIZE];
+
+    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;
+
+    ret = HmacSetKey(&hmac, hashType, passwd, pLen);
+    if (ret != 0)
+        return ret;
+
+    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;
+
+            ret = InitSha(&sha);
+            if (ret != 0)
+                break;
+            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;
+
+            ret = InitSha256(&sha256);
+            if (ret != 0)
+                break;
+            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;
+
+            ret = InitSha512(&sha512);
+            if (ret != 0)
+                break;
+            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];
+                    ret = mp_to_unsigned_bin(&res, tmp);
+                    XMEMCPY(I + i, tmp + 1, v);
+                }
+                else if (outSz < (int)v) {
+                    XMEMSET(I + i, 0, v - outSz);
+                    ret = mp_to_unsigned_bin(&res, I + i + v - outSz);
+                }
+                else
+                    ret = mp_to_unsigned_bin(&res, I + i);
+            }
+
+            mp_clear(&i1);
+            mp_clear(&res);
+            if (ret < 0) break;
+        }
+
+        currentLen = min(kLen, (int)u);
+        XMEMCPY(output, Ai, currentLen);
+        output += currentLen;
+        kLen   -= currentLen;
+        mp_clear(&B1);
+    }
+
+    if (dynamic) XFREE(buffer, 0, DYNAMIC_TYPE_KEY);
+    return ret;
+}
+
+#endif /* NO_PWDBASED */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/rabbit.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,310 @@
+/* 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/error-crypt.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* inIv)
+{
+    /* Temporary variables */
+    word32 i0, i1, i2, i3, i;
+    word32 iv[2];
+
+    if (inIv)
+        XMEMCPY(iv, inIv, sizeof(iv));
+    else
+        XMEMSET(iv,    0, sizeof(iv));
+      
+    /* Generate four subvectors */
+    i0 = LITTLE32(iv[0]);
+    i2 = LITTLE32(iv[1]);
+    i1 = (i0>>16) | (i2&0xFFFF0000);
+    i3 = (i2<<16) | (i0&0x0000FFFF);
+
+    /* Modify counter values */
+    ctx->workCtx.c[0] = ctx->masterCtx.c[0] ^ i0;
+    ctx->workCtx.c[1] = ctx->masterCtx.c[1] ^ i1;
+    ctx->workCtx.c[2] = ctx->masterCtx.c[2] ^ i2;
+    ctx->workCtx.c[3] = ctx->masterCtx.c[3] ^ i3;
+    ctx->workCtx.c[4] = ctx->masterCtx.c[4] ^ i0;
+    ctx->workCtx.c[5] = ctx->masterCtx.c[5] ^ i1;
+    ctx->workCtx.c[6] = ctx->masterCtx.c[6] ^ i2;
+    ctx->workCtx.c[7] = ctx->masterCtx.c[7] ^ i3;
+
+    /* Copy state variables */
+    for (i=0; i<8; i++)
+        ctx->workCtx.x[i] = ctx->masterCtx.x[i];
+    ctx->workCtx.carry = ctx->masterCtx.carry;
+
+    /* Iterate the system four times */
+    for (i=0; i<4; i++)
+        RABBIT_next_state(&(ctx->workCtx));
+}
+
+
+/* Key setup */
+static INLINE int DoKey(Rabbit* ctx, const byte* key, const byte* iv)
+{
+    /* Temporary variables */
+    word32 k0, k1, k2, k3, i;
+
+    /* Generate four subkeys */
+    k0 = LITTLE32(*(word32*)(key+ 0));
+    k1 = LITTLE32(*(word32*)(key+ 4));
+    k2 = LITTLE32(*(word32*)(key+ 8));
+    k3 = LITTLE32(*(word32*)(key+12));
+
+    /* Generate initial state variables */
+    ctx->masterCtx.x[0] = k0;
+    ctx->masterCtx.x[2] = k1;
+    ctx->masterCtx.x[4] = k2;
+    ctx->masterCtx.x[6] = k3;
+    ctx->masterCtx.x[1] = U32V(k3<<16) | (k2>>16);
+    ctx->masterCtx.x[3] = U32V(k0<<16) | (k3>>16);
+    ctx->masterCtx.x[5] = U32V(k1<<16) | (k0>>16);
+    ctx->masterCtx.x[7] = U32V(k2<<16) | (k1>>16);
+
+    /* Generate initial counter values */
+    ctx->masterCtx.c[0] = rotlFixed(k2, 16);
+    ctx->masterCtx.c[2] = rotlFixed(k3, 16);
+    ctx->masterCtx.c[4] = rotlFixed(k0, 16);
+    ctx->masterCtx.c[6] = rotlFixed(k1, 16);
+    ctx->masterCtx.c[1] = (k0&0xFFFF0000) | (k1&0xFFFF);
+    ctx->masterCtx.c[3] = (k1&0xFFFF0000) | (k2&0xFFFF);
+    ctx->masterCtx.c[5] = (k2&0xFFFF0000) | (k3&0xFFFF);
+    ctx->masterCtx.c[7] = (k3&0xFFFF0000) | (k0&0xFFFF);
+
+    /* Clear carry bit */
+    ctx->masterCtx.carry = 0;
+
+    /* Iterate the system four times */
+    for (i=0; i<4; i++)
+        RABBIT_next_state(&(ctx->masterCtx));
+
+    /* Modify the counters */
+    for (i=0; i<8; i++)
+        ctx->masterCtx.c[i] ^= ctx->masterCtx.x[(i+4)&0x7];
+
+    /* Copy master instance to work instance */
+    for (i=0; i<8; i++) {
+        ctx->workCtx.x[i] = ctx->masterCtx.x[i];
+        ctx->workCtx.c[i] = ctx->masterCtx.c[i];
+    }
+    ctx->workCtx.carry = ctx->masterCtx.carry;
+
+    RabbitSetIV(ctx, iv);
+
+    return 0;
+}
+
+
+/* Key setup */
+int RabbitSetKey(Rabbit* ctx, const byte* key, const byte* iv)
+{
+#ifdef XSTREAM_ALIGN
+    if ((word)key % 4) {
+        int alignKey[4];
+
+        /* iv aligned in SetIV */
+        CYASSL_MSG("RabbitSetKey unaligned key");
+
+        XMEMCPY(alignKey, key, sizeof(alignKey));
+
+        return DoKey(ctx, (const byte*)alignKey, iv);
+    }
+#endif /* XSTREAM_ALIGN */
+
+    return DoKey(ctx, key, iv);
+}
+
+
+/* Encrypt/decrypt a message of any size */
+static INLINE int DoProcess(Rabbit* ctx, byte* output, const byte* input,
+                            word32 msglen)
+{
+    /* Encrypt/decrypt all full blocks */
+    while (msglen >= 16) {
+        /* Iterate the system */
+        RABBIT_next_state(&(ctx->workCtx));
+
+        /* Encrypt/decrypt 16 bytes of data */
+        *(word32*)(output+ 0) = *(word32*)(input+ 0) ^
+                   LITTLE32(ctx->workCtx.x[0] ^ (ctx->workCtx.x[5]>>16) ^
+                   U32V(ctx->workCtx.x[3]<<16));
+        *(word32*)(output+ 4) = *(word32*)(input+ 4) ^
+                   LITTLE32(ctx->workCtx.x[2] ^ (ctx->workCtx.x[7]>>16) ^
+                   U32V(ctx->workCtx.x[5]<<16));
+        *(word32*)(output+ 8) = *(word32*)(input+ 8) ^
+                   LITTLE32(ctx->workCtx.x[4] ^ (ctx->workCtx.x[1]>>16) ^
+                   U32V(ctx->workCtx.x[7]<<16));
+        *(word32*)(output+12) = *(word32*)(input+12) ^
+                   LITTLE32(ctx->workCtx.x[6] ^ (ctx->workCtx.x[3]>>16) ^
+                   U32V(ctx->workCtx.x[1]<<16));
+
+        /* Increment pointers and decrement length */
+        input  += 16;
+        output += 16;
+        msglen -= 16;
+    }
+
+    /* Encrypt/decrypt remaining data */
+    if (msglen) {
+
+        word32 i;
+        word32 tmp[4];
+        byte*  buffer = (byte*)tmp;
+
+        XMEMSET(tmp, 0, sizeof(tmp));   /* help static analysis */
+
+        /* Iterate the system */
+        RABBIT_next_state(&(ctx->workCtx));
+
+        /* Generate 16 bytes of pseudo-random data */
+        tmp[0] = LITTLE32(ctx->workCtx.x[0] ^
+                  (ctx->workCtx.x[5]>>16) ^ U32V(ctx->workCtx.x[3]<<16));
+        tmp[1] = LITTLE32(ctx->workCtx.x[2] ^ 
+                  (ctx->workCtx.x[7]>>16) ^ U32V(ctx->workCtx.x[5]<<16));
+        tmp[2] = LITTLE32(ctx->workCtx.x[4] ^ 
+                  (ctx->workCtx.x[1]>>16) ^ U32V(ctx->workCtx.x[7]<<16));
+        tmp[3] = LITTLE32(ctx->workCtx.x[6] ^ 
+                  (ctx->workCtx.x[3]>>16) ^ U32V(ctx->workCtx.x[1]<<16));
+
+        /* Encrypt/decrypt the data */
+        for (i=0; i<msglen; i++)
+            output[i] = input[i] ^ buffer[i];
+    }
+
+    return 0;
+}
+
+
+/* Encrypt/decrypt a message of any size */
+int 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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,746 @@
+/* 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
+
+#include <cyassl/ctaocrypt/settings.h>
+
+/* on HPUX 11 you may need to install /dev/random see
+   http://h20293.www2.hp.com/portal/swdepot/displayProductInfo.do?productNumber=KRNG11I
+
+*/
+
+#include <cyassl/ctaocrypt/random.h>
+#include <cyassl/ctaocrypt/error-crypt.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) \
+                                && !defined(CYASSL_IAR_ARM)
+            #include <fcntl.h>
+        #ifndef EBSNET
+            #include <unistd.h>
+        #endif
+    #else
+        /* include headers that may be needed to get good seed */
+    #endif
+#endif /* USE_WINDOWS_API */
+
+
+#ifdef 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++)
+    {
+        if (InitSha256(&rng->sha) != 0)
+            return DBRG_ERROR;
+        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 int Hash_gen(RNG* rng, byte* out, word32 outSz, byte* V)
+{
+    byte data[DBRG_SEED_LEN];
+    int i, ret;
+    int len = (outSz / SHA256_DIGEST_SIZE)
+        + ((outSz % SHA256_DIGEST_SIZE) ? 1 : 0);
+
+    XMEMCPY(data, V, sizeof(data));
+    for (i = 0; i < len; i++) {
+        ret = InitSha256(&rng->sha);
+        if (ret != 0) return ret;
+        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));
+
+    return 0;
+}
+
+
+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;
+
+        if (Hash_gen(rng, out, outSz, rng->V) != 0)
+            return DBRG_ERROR;
+        if (InitSha256(&rng->sha) != 0)
+            return DBRG_ERROR;
+        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)
+
+#ifdef MICROCHIP_MPLAB_HARMONY
+    #define PIC32_SEED_COUNT _CP0_GET_COUNT
+#else
+    #if !defined(CYASSL_MICROCHIP_PIC32MZ)
+        #include <peripheral/timer.h>
+    #endif
+    #define PIC32_SEED_COUNT ReadCoreTimer
+#endif
+    #ifdef CYASSL_MIC32MZ_RNG
+        #include "xc.h"
+        int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+        {
+            int i ;
+            byte rnd[8] ;
+            word32 *rnd32 = (word32 *)rnd ;
+            word32 size = sz ;
+            byte* op = output ;
+
+            /* This part has to be replaced with better random seed */
+            RNGNUMGEN1 = ReadCoreTimer();
+            RNGPOLY1 = ReadCoreTimer();
+            RNGPOLY2 = ReadCoreTimer();
+            RNGNUMGEN2 = ReadCoreTimer();
+#ifdef DEBUG_CYASSL
+            printf("GenerateSeed::Seed=%08x, %08x\n", RNGNUMGEN1, RNGNUMGEN2) ;
+#endif
+            RNGCONbits.PLEN = 0x40;
+            RNGCONbits.PRNGEN = 1;
+            for(i=0; i<5; i++) { /* wait for RNGNUMGEN ready */
+                volatile int x ;
+                x = RNGNUMGEN1 ;
+                x = RNGNUMGEN2 ;
+            }
+            do {
+                rnd32[0] = RNGNUMGEN1;
+                rnd32[1] = RNGNUMGEN2;
+
+                for(i=0; i<8; i++, op++) {
+                    *op = rnd[i] ;
+                    size -- ;
+                    if(size==0)break ;
+                }
+            } while(size) ;
+            return 0;
+        }
+    #else  /* CYASSL_MIC32MZ_RNG */
+        /* uses the core timer, in nanoseconds to seed srand */
+        int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+        {
+            int i;
+            srand(PIC32_SEED_COUNT() * 25);
+
+            for (i = 0; i < sz; i++ ) {
+                output[i] = rand() % 256;
+                if ( (i % 8) == 7)
+                    srand(PIC32_SEED_COUNT() * 25);
+            }
+            return 0;
+        }
+    #endif /* CYASSL_MIC32MZ_RNG */
+
+#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;
+        }
+
+    #elif defined(FREESCALE_K53_RNGB)
+        /*
+         * Generates a RNG seed using the Random Number Generator (RNGB)
+         * on the Kinetis K53. Documentation located in Chapter 33 of
+         * K53 Sub-Family Reference Manual (see note in the README for link).
+         */
+        int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+        {
+            int i;
+
+            /* turn on RNGB module */
+            SIM_SCGC3 |= SIM_SCGC3_RNGB_MASK;
+
+            /* reset RNGB */
+            RNG_CMD |= RNG_CMD_SR_MASK;
+
+            /* FIFO generate interrupt, return all zeros on underflow,
+             * set auto reseed */
+            RNG_CR |= (RNG_CR_FUFMOD_MASK | RNG_CR_AR_MASK);
+
+            /* gen seed, clear interrupts, clear errors */
+            RNG_CMD |= (RNG_CMD_GS_MASK | RNG_CMD_CI_MASK | RNG_CMD_CE_MASK);
+
+            /* wait for seeding to complete */
+            while ((RNG_SR & RNG_SR_SDN_MASK) == 0) {}
+
+            for (i = 0; i < sz; i++) {
+
+                /* wait for a word to be available from FIFO */
+                while((RNG_SR & RNG_SR_FIFO_LVL_MASK) == 0) {}
+
+                /* get value */
+                output[i] = RNG_OUT;
+            }
+
+            return 0;
+        }
+
+	#else
+        #warning "write a real random seed!!!!, just for testing now"
+
+        int 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(CYASSL_SAFERTOS) || defined(CYASSL_LEANPSK) \
+   || defined(CYASSL_IAR_ARM)
+
+#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(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(CUSTOM_RAND_GENERATE)
+
+   /* Implement your own random generation function
+    * word32 rand_gen(void);
+    * #define CUSTOM_RAND_GENERATE  rand_gen  */
+
+   int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
+   {
+     int i;
+
+     for (i = 0; i < sz; i++ )
+         output[i] = CUSTOM_RAND_GENERATE();
+
+     return 0;
+   }
+
+#elif defined(NO_DEV_RANDOM)
+
+#error "you need to write an os specific 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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,354 @@
+/* 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
+                ByteReverseWords(ripemd->buffer, ripemd->buffer,
+                                 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
+            ByteReverseWords(ripemd->buffer, ripemd->buffer, RIPEMD_BLOCK_SIZE);
+        #endif
+        Transform(ripemd);
+        ripemd->buffLen = 0;
+    }
+    XMEMSET(&local[ripemd->buffLen], 0, RIPEMD_PAD_SIZE - ripemd->buffLen);
+   
+    /* put lengths in bits */
+    ripemd->loLen = ripemd->loLen << 3;
+    ripemd->hiLen = (ripemd->loLen >> (8*sizeof(ripemd->loLen) - 3)) + 
+                 (ripemd->hiLen << 3);
+
+    /* store lengths */
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseWords(ripemd->buffer, ripemd->buffer, RIPEMD_BLOCK_SIZE);
+    #endif
+    /* ! length ordering dependent on digest endian type ! */
+    XMEMCPY(&local[RIPEMD_PAD_SIZE], &ripemd->loLen, sizeof(word32));
+    XMEMCPY(&local[RIPEMD_PAD_SIZE + sizeof(word32)], &ripemd->hiLen, 
+           sizeof(word32));
+
+    Transform(ripemd);
+    #ifdef BIG_ENDIAN_ORDER
+        ByteReverseWords(ripemd->digest, ripemd->digest, RIPEMD_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, ripemd->digest, RIPEMD_DIGEST_SIZE);
+
+    InitRipeMd(ripemd);  /* reset state */
+}
+
+
+#endif /* CYASSL_RIPEMD */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/rsa.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,820 @@
+/* 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
+
+#ifdef HAVE_FIPS
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+#endif
+
+#include <cyassl/ctaocrypt/rsa.h>
+#include <cyassl/ctaocrypt/random.h>
+#include <cyassl/ctaocrypt/error-crypt.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 int  InitCaviumRsaKey(RsaKey* key, void* heap);
+    static int  FreeCaviumRsaKey(RsaKey* key);
+    static int  CaviumRsaPublicEncrypt(const byte* in, word32 inLen, byte* out,
+                                       word32 outLen, RsaKey* key);
+    static int  CaviumRsaPrivateDecrypt(const byte* in, word32 inLen, byte* out,
+                                        word32 outLen, RsaKey* key);
+    static int  CaviumRsaSSL_Sign(const byte* in, word32 inLen, byte* out,
+                                  word32 outLen, RsaKey* key);
+    static int  CaviumRsaSSL_Verify(const byte* in, word32 inLen, byte* out,
+                                    word32 outLen, RsaKey* key);
+#endif
+
+enum {
+    RSA_PUBLIC_ENCRYPT  = 0,
+    RSA_PUBLIC_DECRYPT  = 1,
+    RSA_PRIVATE_ENCRYPT = 2,
+    RSA_PRIVATE_DECRYPT = 3,
+
+    RSA_BLOCK_TYPE_1 = 1,
+    RSA_BLOCK_TYPE_2 = 2,
+
+    RSA_MIN_SIZE = 512,
+    RSA_MAX_SIZE = 4096,
+
+    RSA_MIN_PAD_SZ   = 11      /* seperator + 0 + pad value + 8 pads */
+};
+
+
+int 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
+
+    return 0;
+}
+
+
+int 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
+
+    return 0;
+}
+
+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 int InitCaviumRsaKey(RsaKey* key, void* heap)
+{
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    key->heap = heap;
+    key->type = -1;   /* don't know yet */
+
+    key->c_n  = NULL;
+    key->c_e  = NULL;
+    key->c_d  = NULL;
+    key->c_p  = NULL;
+    key->c_q  = NULL;
+    key->c_dP = NULL;
+    key->c_dQ = NULL;
+    key->c_u  = NULL;
+
+    key->c_nSz   = 0;
+    key->c_eSz   = 0;
+    key->c_dSz   = 0;
+    key->c_pSz   = 0;
+    key->c_qSz   = 0;
+    key->c_dP_Sz = 0;
+    key->c_dQ_Sz = 0;
+    key->c_uSz   = 0;
+    
+    return 0;
+}
+
+
+/* Free cavium RSA key */
+static int FreeCaviumRsaKey(RsaKey* key)
+{
+    if (key == NULL)
+        return BAD_FUNC_ARG;
+
+    XFREE(key->c_n,  key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+    XFREE(key->c_e,  key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+    XFREE(key->c_d,  key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+    XFREE(key->c_p,  key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+    XFREE(key->c_q,  key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+    XFREE(key->c_dP, key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+    XFREE(key->c_dQ, key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+    XFREE(key->c_u,  key->heap, DYNAMIC_TYPE_CAVIUM_TMP);
+
+    return InitCaviumRsaKey(key, key->heap);  /* reset pointers */
+}
+
+
+static int CaviumRsaPublicEncrypt(const byte* in, word32 inLen, byte* out,
+                                   word32 outLen, RsaKey* key)
+{
+    word32 requestId;
+    word32 ret;
+
+    if (key == NULL || in == NULL || out == NULL || outLen < (word32)key->c_nSz)
+        return -1;
+
+    ret = CspPkcs1v15Enc(CAVIUM_BLOCKING, BT2, key->c_nSz, key->c_eSz,
+                         (word16)inLen, key->c_n, key->c_e, (byte*)in, out,
+                         &requestId, key->devId);
+    if (ret != 0) {
+        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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,395 @@
+/* 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>
+
+#if !defined(NO_SHA)
+
+#ifdef CYASSL_PIC32MZ_HASH
+#define InitSha   InitSha_sw
+#define ShaUpdate ShaUpdate_sw
+#define ShaFinal  ShaFinal_sw
+#endif
+
+#ifdef HAVE_FIPS
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+#endif
+
+#include <cyassl/ctaocrypt/sha.h>
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/src/misc.c>
+#endif
+
+#ifdef FREESCALE_MMCAU
+    #include "cau_api.h"
+    #define XTRANSFORM(S,B)  cau_sha1_hash_n((B), 1, ((S))->digest)
+#else
+    #define XTRANSFORM(S,B)  Transform((S))
+#endif
+
+
+#ifdef STM32F2_HASH
+    /*
+     * STM32F2 hardware SHA1 support through the STM32F2 standard peripheral
+     * library. Documentation located in STM32F2xx Standard Peripheral Library
+     * document (See note in README).
+     */
+    #include "stm32f2xx.h"
+    #include "stm32f2xx_hash.h"
+
+    int InitSha(Sha* sha)
+    {
+        /* STM32F2 struct notes:
+         * sha->buffer  = first 4 bytes used to hold partial block if needed 
+         * sha->buffLen = num bytes currently stored in sha->buffer
+         * sha->loLen   = num bytes that have been written to STM32 FIFO
+         */
+        XMEMSET(sha->buffer, 0, SHA_REG_SIZE);
+        sha->buffLen = 0;
+        sha->loLen = 0;
+
+        /* initialize HASH peripheral */
+        HASH_DeInit();
+
+        /* configure algo used, algo mode, datatype */
+        HASH->CR &= ~ (HASH_CR_ALGO | HASH_CR_DATATYPE | HASH_CR_MODE);
+        HASH->CR |= (HASH_AlgoSelection_SHA1 | HASH_AlgoMode_HASH 
+                 | HASH_DataType_8b);
+
+        /* reset HASH processor */
+        HASH->CR |= HASH_CR_INIT;
+
+        return 0;
+    }
+
+    int ShaUpdate(Sha* sha, const byte* data, word32 len)
+    {
+        word32 i = 0;
+        word32 fill = 0;
+        word32 diff = 0;
+
+        /* if saved partial block is available */
+        if (sha->buffLen) {
+            fill = 4 - sha->buffLen;
+
+            /* if enough data to fill, fill and push to FIFO */
+            if (fill <= len) {
+                XMEMCPY((byte*)sha->buffer + sha->buffLen, data, fill);
+                HASH_DataIn(*(uint32_t*)sha->buffer);
+
+                data += fill;
+                len -= fill;
+                sha->loLen += 4;
+                sha->buffLen = 0;
+            } else {
+                /* append partial to existing stored block */
+                XMEMCPY((byte*)sha->buffer + sha->buffLen, data, len);
+                sha->buffLen += len;
+                return;
+            }
+        }
+       
+        /* write input block in the IN FIFO */
+        for(i = 0; i < len; i += 4)
+        {
+            diff = len - i;
+            if ( diff < 4) {
+                /* store incomplete last block, not yet in FIFO */
+                XMEMSET(sha->buffer, 0, SHA_REG_SIZE);
+                XMEMCPY((byte*)sha->buffer, data, diff);
+                sha->buffLen = diff;
+            } else {
+                HASH_DataIn(*(uint32_t*)data);
+                data+=4;
+            }
+        }
+
+        /* keep track of total data length thus far */ 
+        sha->loLen += (len - sha->buffLen);
+
+        return 0;
+    }
+
+    int ShaFinal(Sha* sha, byte* hash)
+    {
+        __IO uint16_t nbvalidbitsdata = 0;
+        
+        /* finish reading any trailing bytes into FIFO */
+        if (sha->buffLen) {
+            HASH_DataIn(*(uint32_t*)sha->buffer);
+            sha->loLen += sha->buffLen;
+        }
+
+        /* calculate number of valid bits in last word of input data */
+        nbvalidbitsdata = 8 * (sha->loLen % SHA_REG_SIZE);
+
+        /* configure number of valid bits in last word of the data */
+        HASH_SetLastWordValidBitsNbr(nbvalidbitsdata);
+
+        /* start HASH processor */
+        HASH_StartDigest();
+
+        /* wait until Busy flag == RESET */
+        while (HASH_GetFlagStatus(HASH_FLAG_BUSY) != RESET) {}
+
+        /* read message digest */
+        sha->digest[0] = HASH->HR[0];
+        sha->digest[1] = HASH->HR[1];
+        sha->digest[2] = HASH->HR[2];
+        sha->digest[3] = HASH->HR[3];
+        sha->digest[4] = HASH->HR[4];
+        
+        ByteReverseWords(sha->digest, sha->digest, SHA_DIGEST_SIZE);
+
+        XMEMCPY(hash, sha->digest, SHA_DIGEST_SIZE);
+
+        return 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 */
+
+
+int InitSha(Sha* sha)
+{
+    #ifdef FREESCALE_MMCAU
+        cau_sha1_initialize_output(sha->digest);
+    #else
+        sha->digest[0] = 0x67452301L;
+        sha->digest[1] = 0xEFCDAB89L;
+        sha->digest[2] = 0x98BADCFEL;
+        sha->digest[3] = 0x10325476L;
+        sha->digest[4] = 0xC3D2E1F0L;
+    #endif
+
+    sha->buffLen = 0;
+    sha->loLen   = 0;
+    sha->hiLen   = 0;
+
+    return 0;
+}
+
+#ifndef FREESCALE_MMCAU
+
+#define blk0(i) (W[i] = sha->buffer[i])
+#define blk1(i) (W[i&15] = \
+                   rotlFixed(W[(i+13)&15]^W[(i+8)&15]^W[(i+2)&15]^W[i&15],1))
+
+#define f1(x,y,z) (z^(x &(y^z)))
+#define f2(x,y,z) (x^y^z)
+#define f3(x,y,z) ((x&y)|(z&(x|y)))
+#define f4(x,y,z) (x^y^z)
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+= f1(w,x,y) + blk0(i) + 0x5A827999+ \
+                        rotlFixed(v,5); w = rotlFixed(w,30);
+#define R1(v,w,x,y,z,i) z+= f1(w,x,y) + blk1(i) + 0x5A827999+ \
+                        rotlFixed(v,5); w = rotlFixed(w,30);
+#define R2(v,w,x,y,z,i) z+= f2(w,x,y) + blk1(i) + 0x6ED9EBA1+ \
+                        rotlFixed(v,5); w = rotlFixed(w,30);
+#define R3(v,w,x,y,z,i) z+= f3(w,x,y) + blk1(i) + 0x8F1BBCDC+ \
+                        rotlFixed(v,5); w = rotlFixed(w,30);
+#define R4(v,w,x,y,z,i) z+= f4(w,x,y) + blk1(i) + 0xCA62C1D6+ \
+                        rotlFixed(v,5); w = rotlFixed(w,30);
+
+
+static void Transform(Sha* sha)
+{
+    word32 W[SHA_BLOCK_SIZE / sizeof(word32)];
+
+    /* Copy context->state[] to working vars */ 
+    word32 a = sha->digest[0];
+    word32 b = sha->digest[1];
+    word32 c = sha->digest[2];
+    word32 d = sha->digest[3];
+    word32 e = sha->digest[4];
+
+#ifdef USE_SLOW_SHA
+    word32 t, i;
+
+    for (i = 0; i < 16; i++) {
+        R0(a, b, c, d, e, i);
+        t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 20; i++) {
+        R1(a, b, c, d, e, i);
+        t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 40; i++) {
+        R2(a, b, c, d, e, i);
+        t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 60; i++) {
+        R3(a, b, c, d, e, i);
+        t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 80; i++) {
+        R4(a, b, c, d, e, i);
+        t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+#else
+    /* nearly 1 K bigger in code size but 25% faster  */
+    /* 4 rounds of 20 operations each. Loop unrolled. */
+    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+
+    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+
+    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+
+    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+
+    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+#endif
+
+    /* Add the working vars back into digest state[] */
+    sha->digest[0] += a;
+    sha->digest[1] += b;
+    sha->digest[2] += c;
+    sha->digest[3] += d;
+    sha->digest[4] += e;
+}
+
+#endif /* FREESCALE_MMCAU */
+
+
+static INLINE void AddLength(Sha* sha, word32 len)
+{
+    word32 tmp = sha->loLen;
+    if ( (sha->loLen += len) < tmp)
+        sha->hiLen++;                       /* carry low to high */
+}
+
+
+int ShaUpdate(Sha* sha, const byte* data, word32 len)
+{
+    /* do block size increments */
+    byte* local = (byte*)sha->buffer;
+
+    while (len) {
+        word32 add = min(len, SHA_BLOCK_SIZE - sha->buffLen);
+        XMEMCPY(&local[sha->buffLen], data, add);
+
+        sha->buffLen += add;
+        data         += add;
+        len          -= add;
+
+        if (sha->buffLen == SHA_BLOCK_SIZE) {
+            #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+                ByteReverseWords(sha->buffer, sha->buffer, SHA_BLOCK_SIZE);
+            #endif
+            XTRANSFORM(sha, local);
+            AddLength(sha, SHA_BLOCK_SIZE);
+            sha->buffLen = 0;
+        }
+    }
+
+    return 0;
+}
+
+
+int ShaFinal(Sha* sha, byte* hash)
+{
+    byte* local = (byte*)sha->buffer;
+
+    AddLength(sha, sha->buffLen);  /* before adding pads */
+
+    local[sha->buffLen++] = 0x80;  /* add 1 */
+
+    /* pad with zeros */
+    if (sha->buffLen > SHA_PAD_SIZE) {
+        XMEMSET(&local[sha->buffLen], 0, SHA_BLOCK_SIZE - sha->buffLen);
+        sha->buffLen += SHA_BLOCK_SIZE - sha->buffLen;
+
+        #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+            ByteReverseWords(sha->buffer, sha->buffer, SHA_BLOCK_SIZE);
+        #endif
+        XTRANSFORM(sha, local);
+        sha->buffLen = 0;
+    }
+    XMEMSET(&local[sha->buffLen], 0, SHA_PAD_SIZE - sha->buffLen);
+   
+    /* put lengths in bits */
+    sha->hiLen = (sha->loLen >> (8*sizeof(sha->loLen) - 3)) + 
+                 (sha->hiLen << 3);
+    sha->loLen = sha->loLen << 3;
+
+    /* store lengths */
+    #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+        ByteReverseWords(sha->buffer, sha->buffer, SHA_BLOCK_SIZE);
+    #endif
+    /* ! length ordering dependent on digest endian type ! */
+    XMEMCPY(&local[SHA_PAD_SIZE], &sha->hiLen, sizeof(word32));
+    XMEMCPY(&local[SHA_PAD_SIZE + sizeof(word32)], &sha->loLen, sizeof(word32));
+
+    #ifdef FREESCALE_MMCAU
+        /* Kinetis requires only these bytes reversed */
+        ByteReverseWords(&sha->buffer[SHA_PAD_SIZE/sizeof(word32)],
+                         &sha->buffer[SHA_PAD_SIZE/sizeof(word32)],
+                         2 * sizeof(word32));
+    #endif
+
+    XTRANSFORM(sha, local);
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords(sha->digest, sha->digest, SHA_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, sha->digest, SHA_DIGEST_SIZE);
+
+    return 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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,249 @@
+/* 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>
+
+#if !defined(NO_SHA256)
+
+#ifdef CYASSL_PIC32MZ_HASH
+#define InitSha256   InitSha256_sw
+#define Sha256Update Sha256Update_sw
+#define Sha256Final  Sha256Final_sw
+#endif
+
+#ifdef HAVE_FIPS
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+#endif
+
+#include <cyassl/ctaocrypt/sha256.h>
+#ifdef NO_INLINE
+    #include <cyassl/ctaocrypt/misc.h>
+#else
+    #include <ctaocrypt/src/misc.c>
+#endif
+
+#ifdef FREESCALE_MMCAU
+    #include "cau_api.h"
+    #define XTRANSFORM(S,B)  cau_sha256_hash_n((B), 1, ((S))->digest)
+#else
+    #define XTRANSFORM(S,B)  Transform((S))
+#endif
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+int InitSha256(Sha256* sha256)
+{
+    #ifdef FREESCALE_MMCAU
+        cau_sha256_initialize_output(sha256->digest);
+    #else
+        sha256->digest[0] = 0x6A09E667L;
+        sha256->digest[1] = 0xBB67AE85L;
+        sha256->digest[2] = 0x3C6EF372L;
+        sha256->digest[3] = 0xA54FF53AL;
+        sha256->digest[4] = 0x510E527FL;
+        sha256->digest[5] = 0x9B05688CL;
+        sha256->digest[6] = 0x1F83D9ABL;
+        sha256->digest[7] = 0x5BE0CD19L;
+    #endif
+
+    sha256->buffLen = 0;
+    sha256->loLen   = 0;
+    sha256->hiLen   = 0;
+
+    return 0;
+}
+
+#ifndef FREESCALE_MMCAU
+
+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];
+    }
+}
+
+#endif /* FREESCALE_MMCAU */
+
+
+static INLINE void AddLength(Sha256* sha256, word32 len)
+{
+    word32 tmp = sha256->loLen;
+    if ( (sha256->loLen += len) < tmp)
+        sha256->hiLen++;                       /* carry low to high */
+}
+
+
+int 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) {
+            #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+                ByteReverseWords(sha256->buffer, sha256->buffer,
+                                 SHA256_BLOCK_SIZE);
+            #endif
+            XTRANSFORM(sha256, local);
+            AddLength(sha256, SHA256_BLOCK_SIZE);
+            sha256->buffLen = 0;
+        }
+    }
+
+    return 0;
+}
+
+
+int 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;
+
+        #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+            ByteReverseWords(sha256->buffer, sha256->buffer, SHA256_BLOCK_SIZE);
+        #endif
+        XTRANSFORM(sha256, local);
+        sha256->buffLen = 0;
+    }
+    XMEMSET(&local[sha256->buffLen], 0, SHA256_PAD_SIZE - sha256->buffLen);
+
+    /* put lengths in bits */
+    sha256->hiLen = (sha256->loLen >> (8*sizeof(sha256->loLen) - 3)) +
+                 (sha256->hiLen << 3);
+    sha256->loLen = sha256->loLen << 3;
+
+    /* store lengths */
+    #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)
+        ByteReverseWords(sha256->buffer, sha256->buffer, SHA256_BLOCK_SIZE);
+    #endif
+    /* ! length ordering dependent on digest endian type ! */
+    XMEMCPY(&local[SHA256_PAD_SIZE], &sha256->hiLen, sizeof(word32));
+    XMEMCPY(&local[SHA256_PAD_SIZE + sizeof(word32)], &sha256->loLen,
+            sizeof(word32));
+
+    #ifdef FREESCALE_MMCAU
+        /* Kinetis requires only these bytes reversed */
+        ByteReverseWords(&sha256->buffer[SHA256_PAD_SIZE/sizeof(word32)],
+                         &sha256->buffer[SHA256_PAD_SIZE/sizeof(word32)],
+                         2 * sizeof(word32));
+    #endif
+
+    XTRANSFORM(sha256, local);
+    #ifdef LITTLE_ENDIAN_ORDER
+        ByteReverseWords(sha256->digest, sha256->digest, SHA256_DIGEST_SIZE);
+    #endif
+    XMEMCPY(hash, sha256->digest, SHA256_DIGEST_SIZE);
+
+    return InitSha256(sha256);  /* reset state */
+}
+
+
+#endif /* NO_SHA256 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ctaocrypt/src/sha512.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,420 @@
+/* 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
+
+#ifdef HAVE_FIPS
+    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+    #define FIPS_NO_WRAPPERS
+#endif
+
+#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 */
+
+
+int 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;
+
+    return 0;
+}
+
+
+static const word64 K512[80] = {
+	W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd),
+	W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc),
+	W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019),
+	W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118),
+	W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe),
+	W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2),
+	W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1),
+	W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694),
+	W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3),
+	W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65),
+	W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483),
+	W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5),
+	W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210),
+	W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4),
+	W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725),
+	W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70),
+	W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926),
+	W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df),
+	W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8),
+	W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b),
+	W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001),
+	W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30),
+	W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910),
+	W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8),
+	W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53),
+	W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8),
+	W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb),
+	W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3),
+	W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60),
+	W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec),
+	W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9),
+	W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b),
+	W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207),
+	W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178),
+	W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6),
+	W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b),
+	W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493),
+	W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c),
+	W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a),
+	W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817)
+};
+
+
+#define blk0(i) (W[i] = sha512->buffer[i])
+#define blk2(i) (W[i&15]+=s1(W[(i-2)&15])+W[(i-7)&15]+s0(W[(i-15)&15]))
+
+#define Ch(x,y,z) (z^(x&(y^z)))
+#define Maj(x,y,z) ((x&y)|(z&(x|y)))
+
+#define a(i) T[(0-i)&7]
+#define b(i) T[(1-i)&7]
+#define c(i) T[(2-i)&7]
+#define d(i) T[(3-i)&7]
+#define e(i) T[(4-i)&7]
+#define f(i) T[(5-i)&7]
+#define g(i) T[(6-i)&7]
+#define h(i) T[(7-i)&7]
+
+#define S0(x) (rotrFixed64(x,28)^rotrFixed64(x,34)^rotrFixed64(x,39))
+#define S1(x) (rotrFixed64(x,14)^rotrFixed64(x,18)^rotrFixed64(x,41))
+#define s0(x) (rotrFixed64(x,1)^rotrFixed64(x,8)^(x>>7))
+#define s1(x) (rotrFixed64(x,19)^rotrFixed64(x,61)^(x>>6))
+
+#define R(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+K[i+j]+(j?blk2(i):blk0(i));\
+	d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i))
+
+#define blk384(i) (W[i] = sha384->buffer[i])
+
+#define R2(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+K[i+j]+(j?blk2(i):blk384(i));\
+	d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i))
+
+
+static 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));
+
+#ifdef USE_SLOW_SHA2
+    /* over twice as small, but 50% slower */
+    /* 80 operations, not unrolled */
+    for (j = 0; j < 80; j += 16) {
+        int m; 
+        for (m = 0; m < 16; m++) { /* braces needed here for macros {} */
+            R(m);
+        }
+    }
+#else
+    /* 80 operations, partially loop unrolled */
+    for (j = 0; j < 80; j += 16) {
+        R( 0); R( 1); R( 2); R( 3);
+        R( 4); R( 5); R( 6); R( 7);
+        R( 8); R( 9); R(10); R(11);
+        R(12); R(13); R(14); R(15);
+    }
+#endif /* USE_SLOW_SHA2 */
+
+    /* Add the working vars back into digest */
+
+    sha512->digest[0] += a(0);
+    sha512->digest[1] += b(0);
+    sha512->digest[2] += c(0);
+    sha512->digest[3] += d(0);
+    sha512->digest[4] += e(0);
+    sha512->digest[5] += f(0);
+    sha512->digest[6] += g(0);
+    sha512->digest[7] += h(0);
+
+    /* Wipe variables */
+    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 */
+}
+
+
+int 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;
+        }
+    }
+    return 0;
+}
+
+
+int 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);
+
+    return InitSha512(sha512);  /* reset state */
+}
+
+
+
+#ifdef CYASSL_SHA384
+
+int 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;
+
+    return 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));
+
+#ifdef USE_SLOW_SHA2
+    /* over twice as small, but 50% slower */
+    /* 80 operations, not unrolled */
+    for (j = 0; j < 80; j += 16) {
+        int m;
+        for (m = 0; m < 16; m++) {  /* braces needed for macros {} */
+            R2(m);
+        }
+    }
+#else
+    /* 80 operations, partially loop unrolled */
+    for (j = 0; j < 80; j += 16) {
+        R2( 0); R2( 1); R2( 2); R2( 3);
+        R2( 4); R2( 5); R2( 6); R2( 7);
+        R2( 8); R2( 9); R2(10); R2(11);
+        R2(12); R2(13); R2(14); R2(15);
+    }
+#endif /* USE_SLOW_SHA2 */
+
+    /* Add the working vars back into digest */
+
+    sha384->digest[0] += a(0);
+    sha384->digest[1] += b(0);
+    sha384->digest[2] += c(0);
+    sha384->digest[3] += d(0);
+    sha384->digest[4] += e(0);
+    sha384->digest[5] += f(0);
+    sha384->digest[6] += g(0);
+    sha384->digest[7] += h(0);
+
+    /* Wipe variables */
+    XMEMSET(W, 0, sizeof(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 */
+}
+
+
+int 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;
+        }
+    }
+    return 0;
+}
+
+
+int 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);
+
+    return 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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,2514 @@
+/* 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)
+{
+  int      D;
+  fp_int   t;
+
+  /* if the shift count is <= 0 then we do no work */
+  if (b <= 0) {
+    fp_copy (a, c);
+    if (d != NULL) {
+      fp_zero (d);
+    }
+    return;
+  }
+
+  fp_init(&t);
+
+  /* get the remainder */
+  if (d != NULL) {
+    fp_mod_2d (a, b, &t);
+  }
+
+  /* copy */
+  fp_copy(a, c);
+
+  /* shift by as many digits in the bit count */
+  if (b >= (int)DIGIT_BIT) {
+    fp_rshd (c, b / DIGIT_BIT);
+  }
+
+  /* shift any bit count < DIGIT_BIT */
+  D = (b % DIGIT_BIT);
+  if (D != 0) {
+    fp_rshb(c, D);
+  }
+  fp_clamp (c);
+  if (d != NULL) {
+    fp_copy (&t, d);
+  }
+}
+
+/* c = a mod b, 0 <= c < b  */
+int fp_mod(fp_int *a, fp_int *b, fp_int *c)
+{
+   fp_int t;
+   int    err;
+
+   fp_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;
+}
+
+int fp_leading_bit(fp_int *a)
+{
+    int bit = 0;
+
+    if (a->used != 0) {
+        fp_digit q = a->dp[a->used - 1];
+        int qSz = sizeof(fp_digit);
+
+        while (qSz > 0) {
+            if ((unsigned char)q != 0)
+                bit = (q & 0x80) != 0;
+            q >>= 8;
+            qSz--;
+        }
+    }
+
+    return bit;
+}
+
+void fp_lshd(fp_int *a, int x)
+{
+   int y;
+
+   /* move up and truncate as required */
+   y = MIN(a->used + x - 1, (int)(FP_SIZE-1));
+
+   /* store new size */
+   a->used = y + 1;
+
+   /* move digits */
+   for (; y >= x; y--) {
+       a->dp[y] = a->dp[y-x];
+   }
+ 
+   /* zero lower digits */
+   for (; y >= 0; y--) {
+       a->dp[y] = 0;
+   }
+
+   /* clamp digits */
+   fp_clamp(a);
+}
+
+
+/* right shift by bit count */
+void fp_rshb(fp_int *c, int x)
+{
+    register fp_digit *tmpc, mask, shift;
+    fp_digit r, rr;
+    fp_digit D = x;
+
+    /* mask */
+    mask = (((fp_digit)1) << D) - 1;
+
+    /* shift for lsb */
+    shift = DIGIT_BIT - D;
+
+    /* alias */
+    tmpc = c->dp + (c->used - 1);
+
+    /* carry */
+    r = 0;
+    for (x = c->used - 1; x >= 0; x--) {
+      /* get the lower  bits of this word in a temp */
+      rr = *tmpc & mask;
+
+      /* shift the current word and mix in the carry bits from previous word */
+      *tmpc = (*tmpc >> D) | (r << shift);
+      --tmpc;
+
+      /* set the carry to the carry bits of the current word found above */
+      r = rr;
+    }
+}
+
+
+void fp_rshd(fp_int *a, int x)
+{
+  int y;
+
+  /* too many digits just zero and return */
+  if (x >= a->used) {
+     fp_zero(a);
+     return;
+  }
+
+   /* shift */
+   for (y = 0; y < a->used - x; y++) {
+      a->dp[y] = a->dp[y+x];
+   }
+
+   /* zero rest */
+   for (; y < a->used; y++) {
+      a->dp[y] = 0;
+   }
+   
+   /* decrement count */
+   a->used -= x;
+   fp_clamp(a);
+}
+
+/* reverse an array, used for radix code */
+void fp_reverse (unsigned char *s, int len)
+{
+  int     ix, iy;
+  unsigned char t;
+
+  ix = 0;
+  iy = len - 1;
+  while (ix < iy) {
+    t     = s[ix];
+    s[ix] = s[iy];
+    s[iy] = t;
+    ++ix;
+    --iy;
+  }
+}
+
+
+/* c = a - b */
+void fp_sub_d(fp_int *a, fp_digit b, fp_int *c)
+{
+   fp_int tmp;
+   fp_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);
+}
+
+
+int mp_leading_bit (mp_int* a)
+{
+    return fp_leading_bit(a);
+}
+
+
+/* fast math conversion */
+void mp_rshb (mp_int* a, int x)
+{
+    fp_rshb(a, x);
+}
+
+
+/* fast math wrappers */
+int mp_set_int(fp_int *a, fp_digit b)
+{
+    fp_set(a, b);
+    return MP_OKAY;
+}
+
+
+#if defined(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 */
+static const char *fp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
+
+static int fp_read_radix(fp_int *a, const char *str, int radix)
+{
+  int     y, neg;
+  char    ch;
+
+  /* make sure the radix is ok */
+  if (radix < 2 || radix > 64) {
+    return FP_VAL;
+  }
+
+  /* if the leading digit is a
+   * minus set the sign to negative.
+   */
+  if (*str == '-') {
+    ++str;
+    neg = FP_NEG;
+  } else {
+    neg = FP_ZPOS;
+  }
+
+  /* set the integer to the default of zero */
+  fp_zero (a);
+
+  /* process each digit of the string */
+  while (*str) {
+    /* if the radix < 36 the conversion is case insensitive
+     * this allows numbers like 1AB and 1ab to represent the same  value
+     * [e.g. in hex]
+     */
+    ch = (char) ((radix < 36) ? XTOUPPER(*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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,80 @@
+/* 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 <sys/time.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+enum { /* CALLBACK CONTSTANTS */
+    MAX_PACKETNAME_SZ     =  24,
+    MAX_CIPHERNAME_SZ     =  24,
+    MAX_TIMEOUT_NAME_SZ   =  24,       
+    MAX_PACKETS_HANDSHAKE =  14,       /* 12 for client auth plus 2 alerts */
+    MAX_VALUE_SZ          = 128,       /* all handshake packets but Cert should
+                                          fit here  */
+};
+
+
+typedef struct handShakeInfo_st {
+    char   cipherName[MAX_CIPHERNAME_SZ + 1];    /* negotiated cipher */
+    char   packetNames[MAX_PACKETS_HANDSHAKE][MAX_PACKETNAME_SZ + 1];
+                                                 /* SSL packet names  */ 
+    int    numberPackets;                        /* actual # of packets */
+    int    negotiationError;                     /* cipher/parameter err */
+} HandShakeInfo;
+
+
+typedef struct timeval Timeval;
+
+
+typedef struct packetInfo_st {
+    char           packetName[MAX_PACKETNAME_SZ + 1]; /* SSL packet name */
+    Timeval        timestamp;                       /* when it occured    */
+    unsigned char  value[MAX_VALUE_SZ];             /* if fits, it's here */ 
+    unsigned char* bufferValue;                     /* otherwise here (non 0) */
+    int            valueSz;                         /* sz of value or buffer */
+} PacketInfo;
+
+
+typedef struct timeoutInfo_st {
+    char       timeoutName[MAX_TIMEOUT_NAME_SZ + 1]; /* timeout Name */
+    int        flags;                              /* for future use */
+    int        numberPackets;                      /* actual # of packets */
+    PacketInfo packets[MAX_PACKETS_HANDSHAKE];     /* list of all packets  */
+    Timeval    timeoutValue;                       /* timer that caused it */
+} TimeoutInfo;
+
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+
+#endif /* CYASSL_CALLBACKS_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/certs_test.h	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,180 @@
+/* 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
+#ifdef CYASSL_AES_COUNTER
+    word32  left;            /* unsued bytes left from last call */
+#endif
+#ifdef CYASSL_PIC32MZ_CRYPT
+    word32 key_ce[AES_BLOCK_SIZE*2/sizeof(word32)] ;
+    word32 iv_ce [AES_BLOCK_SIZE  /sizeof(word32)] ;
+    int    keylen ;
+#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);
+
+typedef struct Gmac {
+    Aes aes;
+} Gmac;
+CYASSL_API void GmacSetKey(Gmac* gmac, const byte* key, word32 len);
+CYASSL_API void GmacUpdate(Gmac* gmac, const byte* iv, word32 ivSz,
+                              const byte* authIn, word32 authInSz,
+                              byte* authTag, word32 authTagSz);
+#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 HAVE_FIPS
+    /* fips wrapper calls, user can call direct */
+    CYASSL_API int  AesSetKey_fips(Aes* aes, const byte* key, word32 len,
+                                   const byte* iv, int dir);
+    CYASSL_API int  AesSetIV_fips(Aes* aes, const byte* iv);
+    CYASSL_API int  AesCbcEncrypt_fips(Aes* aes, byte* out, const byte* in,
+                                       word32 sz);
+    CYASSL_API int  AesCbcDecrypt_fips(Aes* aes, byte* out, const byte* in,
+                                       word32 sz);
+    #ifndef FIPS_NO_WRAPPERS
+        /* if not impl or fips.c impl wrapper force fips calls if fips build */
+        #define AesSetKey     AesSetKey_fips
+        #define AesSetIV      AesSetIV_fips
+        #define AesCbcEncrypt AesCbcEncrypt_fips
+        #define AesCbcDecrypt AesCbcDecrypt_fips
+    #endif /* FIPS_NO_WRAPPERS */
+
+#endif /* HAVE_FIPS */
+
+
+#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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,668 @@
+/* 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_UTF8STRING        = 0x0c,
+    ASN_SEQUENCE          = 0x10,
+    ASN_SET               = 0x11,
+    ASN_UTC_TIME          = 0x17,
+    ASN_OTHER_TYPE        = 0x00,
+    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_SERIAL_NUMBER = 0x05,   /* serialNumber */
+    ASN_COUNTRY_NAME  = 0x06,   /* C  */
+    ASN_LOCALITY_NAME = 0x07,   /* L  */
+    ASN_STATE_NAME    = 0x08,   /* ST */
+    ASN_ORG_NAME      = 0x0a,   /* O  */
+    ASN_ORGUNIT_NAME  = 0x0b    /* OU */
+};
+
+enum PBES {
+    PBE_MD5_DES      = 0,
+    PBE_SHA1_DES     = 1,
+    PBE_SHA1_DES3    = 2,
+    PBE_SHA1_RC4_128 = 3,
+    PBES2            = 13       /* algo ID */
+};
+
+enum ENCRYPTION_TYPES {
+    DES_TYPE  = 0,
+    DES3_TYPE = 1,
+    RC4_TYPE  = 2
+};
+
+enum ECC_TYPES {
+    ECC_PREFIX_0 = 160,
+    ECC_PREFIX_1 = 161
+};
+
+enum Misc_ASN { 
+    ASN_NAME_MAX        = 256,
+    MAX_SALT_SIZE       =  64,     /* MAX PKCS Salt length */
+    MAX_IV_SIZE         =  64,     /* MAX PKCS Iv length */
+    MAX_KEY_SIZE        =  64,     /* MAX PKCS Key  length */
+    PKCS5               =   5,     /* PKCS oid tag */
+    PKCS5v2             =   6,     /* PKCS #5 v2.0 */
+    PKCS12              =  12,     /* PKCS #12 */
+    MAX_UNICODE_SZ      = 256,
+    ASN_BOOL_SIZE       =   2,     /* including type */
+    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_OCTET_STR_SZ    =   5,     /* enum(set | con) + length(4) */
+    MAX_EXP_SZ          =   5,     /* enum(contextspec|con|exp) + length(4) */
+    MAX_PRSTR_SZ        =   5,     /* enum(prstr) + length(4) */
+    MAX_VERSION_SZ      =   5,     /* enum + id + version(byte) + (header(2))*/
+    MAX_ENCODED_DIG_SZ  =  73,     /* sha512 + enum(bit or octet) + legnth(4) */
+    MAX_RSA_INT_SZ      = 517,     /* RSA raw sz 4096 for bits + tag + len(4) */
+    MAX_NTRU_KEY_SZ     = 610,     /* NTRU 112 bit public key */
+    MAX_NTRU_ENC_SZ     = 628,     /* NTRU 112 bit DER public encoding */
+    MAX_LENGTH_SZ       =   4,     /* Max length size for DER encoding */
+    MAX_RSA_E_SZ        =  16,     /* Max RSA public e size */
+    MAX_CA_SZ           =  32,     /* Max encoded CA basic constraint length */
+    MAX_SN_SZ           =  35,     /* Max encoded serial number (INT) length */
+#ifdef CYASSL_CERT_GEN
+    #ifdef CYASSL_CERT_REQ
+                          /* Max encoded cert req attributes length */
+        MAX_ATTRIB_SZ   = MAX_SEQ_SZ * 3 + (11 + MAX_SEQ_SZ) * 2 +
+                          MAX_PRSTR_SZ + CTC_NAME_SIZE, /* 11 is the OID size */
+    #endif
+    #ifdef 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,
+    curveType = 3,
+    blkType   = 4
+};
+
+
+enum Hash_Sum  {
+    MD2h    = 646,
+    MD5h    = 649,
+    SHAh    =  88,
+    SHA256h = 414,
+    SHA384h = 415,
+    SHA512h = 416
+};
+
+
+enum Block_Sum {
+    DESb  = 69,
+    DES3b = 652
+};
+
+
+enum Key_Sum {
+    DSAk   = 515,
+    RSAk   = 645,
+    NTRUk  = 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,
+    CERT_POLICY_OID = 146,
+    KEY_USAGE_OID   = 129,  /* 2.5.29.15 */
+    INHIBIT_ANY_OID = 168,  /* 2.5.29.54 */
+    EXT_KEY_USAGE_OID = 151, /* 2.5.29.37 */
+};
+
+enum CertificatePolicy_Sum {
+    CP_ANY_OID      = 146  /* id-ce 32 0 */
+};
+
+enum SepHardwareName_Sum {
+    HW_NAME_OID     = 79   /* 1.3.6.1.5.5.7.8.4 from RFC 4108*/
+};
+
+enum AuthInfo_Sum {
+    AIA_OCSP_OID      = 116, /* 1.3.6.1.5.5.7.48.1 */
+    AIA_CA_ISSUER_OID = 117  /* 1.3.6.1.5.5.7.48.2 */
+};
+
+enum ExtKeyUsage_Sum { /* From RFC 5280 */
+    EKU_ANY_OID         = 151, /* 2.5.29.37.0, anyExtendedKeyUsage         */
+    EKU_SERVER_AUTH_OID = 71,  /* 1.3.6.1.5.5.7.3.1, id-kp-serverAuth      */
+    EKU_CLIENT_AUTH_OID = 72,  /* 1.3.6.1.5.5.7.3.2, id-kp-clientAuth      */
+    EKU_OCSP_SIGN_OID   = 79,  /* 1.3.6.1.5.5.7.3.9, OCSPSigning           */
+};
+
+
+enum VerifyType {
+    NO_VERIFY = 0,
+    VERIFY    = 1
+};
+
+
+/* Key usage extension bits */
+#define KEYUSE_DIGITAL_SIG    0x0100
+#define KEYUSE_CONTENT_COMMIT 0x0080
+#define KEYUSE_KEY_ENCIPHER   0x0040
+#define KEYUSE_DATA_ENCIPHER  0x0020
+#define KEYUSE_KEY_AGREE      0x0010
+#define KEYUSE_KEY_CERT_SIGN  0x0008
+#define KEYUSE_CRL_SIGN       0x0004
+#define KEYUSE_ENCIPHER_ONLY  0x0002
+#define KEYUSE_DECIPHER_ONLY  0x0001
+
+#define EXTKEYUSE_ANY         0x08
+#define EXTKEYUSE_OCSP_SIGN   0x04
+#define EXTKEYUSE_CLIENT_AUTH 0x02
+#define EXTKEYUSE_SERVER_AUTH 0x01
+
+typedef struct DNS_entry   DNS_entry;
+
+struct DNS_entry {
+    DNS_entry* next;   /* next on DNS list */
+    char*      name;   /* actual DNS name */
+};
+
+
+struct DecodedName {
+    char*   fullName;
+    int     fullNameLen;
+    int     entryCount;
+    int     cnIdx;
+    int     cnLen;
+    int     snIdx;
+    int     snLen;
+    int     cIdx;
+    int     cLen;
+    int     lIdx;
+    int     lLen;
+    int     stIdx;
+    int     stLen;
+    int     oIdx;
+    int     oLen;
+    int     ouIdx;
+    int     ouLen;
+    int     emailIdx;
+    int     emailLen;
+    int     uidIdx;
+    int     uidLen;
+    int     serialIdx;
+    int     serialLen;
+};
+
+
+typedef struct DecodedCert DecodedCert;
+typedef struct DecodedName DecodedName;
+typedef struct Signer      Signer;
+
+
+struct DecodedCert {
+    byte*   publicKey;
+    word32  pubKeySize;
+    int     pubKeyStored;
+    word32  certBegin;               /* offset to start of cert          */
+    word32  sigIndex;                /* offset to start of signature     */
+    word32  sigLength;               /* length of signature              */
+    word32  signatureOID;            /* sum of algorithm object id       */
+    word32  keyOID;                  /* sum of key algo  object id       */
+    int     version;                 /* cert version, 1 or 3             */
+    DNS_entry* altNames;             /* alt names list of dns entries    */
+    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         */
+    byte    extKeyUsageSet;
+    word16  extKeyUsage;             /* Key usage bitfield               */
+    byte    extExtKeyUsageSet;       /* Extended Key Usage               */
+    byte    extExtKeyUsage;          /* Extended Key usage bitfield      */
+#ifdef OPENSSL_EXTRA
+    byte    extBasicConstSet;
+    byte    extBasicConstCrit;
+    byte    extBasicConstPlSet;
+    word32  pathLength;              /* CA basic constraint path length, opt */
+    byte    extSubjAltNameSet;
+    byte    extSubjAltNameCrit;
+    byte    extAuthKeyIdCrit;
+    byte    extSubjKeyIdCrit;
+    byte    extKeyUsageCrit;
+    byte    extExtKeyUsageCrit;
+    byte*   extExtKeyUsageSrc;
+    word32  extExtKeyUsageSz;
+    word32  extExtKeyUsageCount;
+    byte*   extAuthKeyIdSrc;
+    word32  extAuthKeyIdSz;
+    byte*   extSubjKeyIdSrc;
+    word32  extSubjKeyIdSz;
+#endif
+#ifdef HAVE_ECC
+    word32  pkCurveOID;           /* Public Key's curve OID */
+#endif /* HAVE_ECC */
+    byte*   beforeDate;
+    int     beforeDateLen;
+    byte*   afterDate;
+    int     afterDateLen;
+#ifdef HAVE_PKCS7
+    byte*   issuerRaw;               /* pointer to issuer inside source */
+    int     issuerRawLen;
+#endif
+#if defined(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;
+#endif /* CYASSL_CERT_GEN */
+#ifdef OPENSSL_EXTRA
+    DecodedName issuerName;
+    DecodedName subjectName;
+#endif /* OPENSSL_EXTRA */
+#ifdef CYASSL_SEP
+    int     deviceTypeSz;
+    byte*   deviceType;
+    int     hwTypeSz;
+    byte*   hwType;
+    int     hwSerialNumSz;
+    byte*   hwSerialNum;
+    #ifdef OPENSSL_EXTRA
+        byte    extCertPolicySet;
+        byte    extCertPolicyCrit;
+    #endif /* OPENSSL_EXTRA */
+#endif /* CYASSL_SEP */
+};
+
+
+#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);
+
+/* ASN.1 helper functions */
+CYASSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len,
+                           word32 maxIdx);
+CYASSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len,
+                             word32 maxIdx);
+CYASSL_LOCAL int GetSet(const byte* input, word32* inOutIdx, int* len,
+                        word32 maxIdx);
+CYASSL_LOCAL int GetMyVersion(const byte* input, word32* inOutIdx,
+                              int* version);
+CYASSL_LOCAL int GetInt(mp_int* mpi, const byte* input, word32* inOutIdx,
+                        word32 maxIdx);
+CYASSL_LOCAL int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid,
+                           word32 maxIdx);
+CYASSL_LOCAL word32 SetLength(word32 length, byte* output);
+CYASSL_LOCAL word32 SetSequence(word32 len, byte* output);
+CYASSL_LOCAL word32 SetOctetString(word32 len, byte* output);
+CYASSL_LOCAL word32 SetImplicit(byte tag, byte number, word32 len,byte* output);
+CYASSL_LOCAL word32 SetExplicit(byte number, word32 len, byte* output);
+CYASSL_LOCAL word32 SetSet(word32 len, byte* output);
+CYASSL_LOCAL word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz);
+CYASSL_LOCAL int SetMyVersion(word32 version, byte* output, int header);
+CYASSL_LOCAL int SetSerialNumber(const byte* sn, word32 snSz, byte* output);
+CYASSL_LOCAL int GetNameHash(const byte* source, word32* idx, byte* hash,
+                             int maxIdx);
+
+#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);
+#endif
+
+#ifdef CYASSL_CERT_GEN
+
+enum cert_enums {
+    NAME_ENTRIES    =  8,
+    JOINT_LEN       =  2,
+    EMAIL_JOINT_LEN =  9,
+    RSA_KEY         = 10,
+    NTRU_KEY        = 11,
+    ECC_KEY         = 12
+};
+
+
+#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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,177 @@
+/* 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>
+#include <cyassl/ctaocrypt/ecc.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,
+    CERTREQ_TYPE
+};
+
+
+/* Signature type, by OID sum */
+enum Ctc_SigType {
+    CTC_SHAwDSA      = 517,
+    CTC_MD2wRSA      = 646,
+    CTC_MD5wRSA      = 648,
+    CTC_SHAwRSA      = 649,
+    CTC_SHAwECDSA    = 520,
+    CTC_SHA256wRSA   = 655,
+    CTC_SHA256wECDSA = 524,
+    CTC_SHA384wRSA   = 656,
+    CTC_SHA384wECDSA = 525,
+    CTC_SHA512wRSA   = 657,
+    CTC_SHA512wECDSA = 526
+};
+
+
+#ifdef CYASSL_CERT_GEN
+
+#ifndef HAVE_ECC
+    typedef struct ecc_key ecc_key;
+#endif
+
+enum Ctc_Misc {
+    CTC_NAME_SIZE    =   64,
+    CTC_DATE_SIZE    =   32,
+    CTC_MAX_ALT_SIZE = 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
+#ifdef CYASSL_CERT_REQ
+    char     challengePw[CTC_NAME_SIZE];
+#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*,
+                         ecc_key*, RNG*);
+#ifdef CYASSL_CERT_REQ
+    CYASSL_API int  MakeCertReq(Cert*, byte* derBuffer, word32 derSz, RsaKey*,
+                                ecc_key*);
+#endif
+CYASSL_API int  SignCert(int requestSz, int sigType, byte* derBuffer,
+                         word32 derSz, RsaKey*, ecc_key*, 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 HAVE_ECC
+    /* private key helpers */
+    CYASSL_API int EccPrivateKeyDecode(const byte* input,word32* inOutIdx,
+                                         ecc_key*,word32);
+#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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,60 @@
+/* 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_256 = 32   /* 256 bit type, SSL default */
+};
+
+
+/* BLAKE2b digest */
+typedef struct Blake2b {
+    blake2b_state S[1];         /* our state */
+    word32        digestSz;     /* digest size used on init */
+} Blake2b;
+
+
+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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,58 @@
+/* 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_API
+    int Base64_EncodeEsc(const byte* in, word32 inLen, byte* out,
+                                  word32* outLen);
+#endif
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || defined(HAVE_FIPS)
+    CYASSL_API
+    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	Sun Apr 20 12:40:57 2014 +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/des3.h	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,137 @@
+/* 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
+};
+
+#define DES_IVLEN 8
+#define DES_KEYLEN 8
+#define DES3_IVLEN 8
+#define DES3_KEYLEN 24
+
+
+#ifdef STM32F2_CRYPTO
+enum {
+    DES_CBC = 0,
+    DES_ECB = 1
+};
+#endif
+
+
+/* DES encryption and decryption */
+typedef struct Des {
+    word32 reg[DES_BLOCK_SIZE / sizeof(word32)];      /* for CBC mode */
+    word32 tmp[DES_BLOCK_SIZE / sizeof(word32)];      /* same         */
+#ifdef HAVE_COLDFIRE_SEC
+    byte keylen ;        /* for Coldfire SEC   */
+    byte ivlen ;         /* for Coldfire SEC   */
+    byte iv[DES3_IVLEN]; /* for Coldfire SEC   */
+#endif
+    word32 key[DES_KS_SIZE];
+} Des;
+
+
+/* DES3 encryption and decryption */
+typedef struct Des3 {
+#ifdef HAVE_COLDFIRE_SEC
+    byte keylen ;        /* for Coldfire SEC   */
+    byte ivlen ;         /* for Coldfire SEC   */
+    byte iv[DES3_IVLEN]; /* for Coldfire SEC   */
+#endif
+    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 int  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 int  Des3_SetKey(Des3* des, const byte* key, const byte* iv,int dir);
+CYASSL_API int  Des3_SetIV(Des3* des, const byte* iv);
+CYASSL_API int  Des3_CbcEncrypt(Des3* des, byte* out, const byte* in,word32 sz);
+CYASSL_API int  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 HAVE_FIPS
+    /* fips wrapper calls, user can call direct */
+    CYASSL_API int  Des3_SetKey_fips(Des3* des, const byte* key, const byte* iv,
+                                     int dir);
+    CYASSL_API int  Des3_SetIV_fips(Des3* des, const byte* iv);
+    CYASSL_API int  Des3_CbcEncrypt_fips(Des3* des, byte* out, const byte* in,
+                                         word32 sz);
+    CYASSL_API int  Des3_CbcDecrypt_fips(Des3* des, byte* out, const byte* in,
+                                         word32 sz);
+    #ifndef FIPS_NO_WRAPPERS
+        /* if not impl or fips.c impl wrapper force fips calls if fips build */
+        #define Des3_SetKey     Des3_SetKey_fips
+        #define Des3_SetIV      Des3_SetIV_fips
+        #define Des3_CbcEncrypt Des3_CbcEncrypt_fips
+        #define Des3_CbcDecrypt Des3_CbcDecrypt_fips
+    #endif /* FIPS_NO_WRAPPERS */
+
+#endif /* HAVE_FIPS */
+
+
+#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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,182 @@
+/* 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* Bf;       /* fields B param (hex) */
+    const char* order;    /* order of the curve (hex) */
+    const char* Gx;       /* x coordinate of the base point on curve (hex) */
+    const char* Gy;       /* y coordinate of the base point on curve (hex) */
+} ecc_set_type;
+
+
+/* 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, const 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);
+CYASSL_API
+void ecc_fp_free(void);
+
+
+/* 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);
+CYASSL_API
+int ecc_export_private_only(ecc_key* key, byte* out, word32* outLen);
+
+/* size helper */
+CYASSL_API
+int ecc_size(ecc_key* key);
+CYASSL_API
+int ecc_sig_size(ecc_key* key);
+
+
+#ifdef HAVE_ECC_ENCRYPT
+/* ecc encrypt */
+
+enum ecEncAlgo {
+    ecAES_128_CBC = 1,  /* default */
+    ecAES_256_CBC = 2
+};
+
+enum ecKdfAlgo {
+    ecHKDF_SHA256 = 1,  /* default */
+    ecHKDF_SHA1   = 2
+};
+
+enum ecMacAlgo {
+    ecHMAC_SHA256 = 1,  /* default */
+    ecHMAC_SHA1   = 2
+};
+
+enum {
+    KEY_SIZE_128     = 16,   
+    KEY_SIZE_256     = 32,   
+    IV_SIZE_64       =  8,
+    EXCHANGE_SALT_SZ = 16,  
+    EXCHANGE_INFO_SZ = 23  
+};
+
+enum ecFlags {
+    REQ_RESP_CLIENT = 1,
+    REQ_RESP_SERVER = 2
+};
+
+
+typedef struct ecEncCtx ecEncCtx;
+
+CYASSL_API
+ecEncCtx* ecc_ctx_new(int flags, RNG* rng);
+CYASSL_API
+void ecc_ctx_free(ecEncCtx*);
+CYASSL_API
+int ecc_ctx_reset(ecEncCtx*, RNG*);   /* reset for use again w/o alloc/free */
+
+CYASSL_API
+const byte* ecc_ctx_get_own_salt(ecEncCtx*);
+CYASSL_API
+int ecc_ctx_set_peer_salt(ecEncCtx*, const byte* salt);
+
+CYASSL_API
+int ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
+                word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx);
+CYASSL_API
+int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
+                word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx);
+
+#endif /* HAVE_ECC_ENCRYPT */
+
+#ifdef __cplusplus
+    }    /* extern "C" */    
+#endif
+
+#endif /* CTAO_CRYPT_ECC_H */
+#endif /* HAVE_ECC */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/error-crypt.h	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,140 @@
+/* error-crypt.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_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 */
+    BAD_MUTEX_E        = -106,  /* Bad mutex operation */
+
+    MP_INIT_E          = -110,  /* mp_init error state */
+    MP_READ_E          = -111,  /* mp_read error state */
+    MP_EXPTMOD_E       = -112,  /* mp_exptmod error state */
+    MP_TO_E            = -113,  /* mp_to_xxx error state, can't convert */
+    MP_SUB_E           = -114,  /* mp_sub error state, can't subtract */
+    MP_ADD_E           = -115,  /* mp_add error state, can't add */
+    MP_MUL_E           = -116,  /* mp_mul error state, can't multiply */
+    MP_MULMOD_E        = -117,  /* mp_mulmod error state, can't multiply mod */
+    MP_MOD_E           = -118,  /* mp_mod error state, can't mod */
+    MP_INVMOD_E        = -119,  /* mp_invmod error state, can't inv mod */
+    MP_CMP_E           = -120,  /* mp_cmp error state */
+    MP_ZERO_E          = -121,  /* got a mp zero result, not expected */
+
+    MEMORY_E           = -125,  /* out of memory error */
+
+    RSA_WRONG_TYPE_E   = -130,  /* RSA wrong block type for RSA function */
+    RSA_BUFFER_E       = -131,  /* RSA buffer error, output too small or 
+                                   input too large */
+    BUFFER_E           = -132,  /* output buffer too small or input too large */
+    ALGO_ID_E          = -133,  /* setting algo id error */
+    PUBLIC_KEY_E       = -134,  /* setting public key error */
+    DATE_E             = -135,  /* setting date validity error */
+    SUBJECT_E          = -136,  /* setting subject name error */
+    ISSUER_E           = -137,  /* setting issuer  name error */
+    CA_TRUE_E          = -138,  /* setting CA basic constraint true error */
+    EXTENSIONS_E       = -139,  /* setting extensions error */
+
+    ASN_PARSE_E        = -140,  /* ASN parsing error, invalid input */
+    ASN_VERSION_E      = -141,  /* ASN version error, invalid number */
+    ASN_GETINT_E       = -142,  /* ASN get big int error, invalid data */
+    ASN_RSA_KEY_E      = -143,  /* ASN key init error, invalid input */
+    ASN_OBJECT_ID_E    = -144,  /* ASN object id error, invalid id */
+    ASN_TAG_NULL_E     = -145,  /* ASN tag error, not null */
+    ASN_EXPECT_0_E     = -146,  /* ASN expect error, not zero */
+    ASN_BITSTR_E       = -147,  /* ASN bit string error, wrong id */
+    ASN_UNKNOWN_OID_E  = -148,  /* ASN oid error, unknown sum id */
+    ASN_DATE_SZ_E      = -149,  /* ASN date error, bad size */
+    ASN_BEFORE_DATE_E  = -150,  /* ASN date error, current date before */
+    ASN_AFTER_DATE_E   = -151,  /* ASN date error, current date after */
+    ASN_SIG_OID_E      = -152,  /* ASN signature error, mismatched oid */
+    ASN_TIME_E         = -153,  /* ASN time error, unknown time type */
+    ASN_INPUT_E        = -154,  /* ASN input error, not enough data */
+    ASN_SIG_CONFIRM_E  = -155,  /* ASN sig error, confirm failure */
+    ASN_SIG_HASH_E     = -156,  /* ASN sig error, unsupported hash type */
+    ASN_SIG_KEY_E      = -157,  /* ASN sig error, unsupported key type */
+    ASN_DH_KEY_E       = -158,  /* ASN key init error, invalid input */
+    ASN_NTRU_KEY_E     = -159,  /* ASN ntru key decode error, invalid input */
+    ASN_CRIT_EXT_E     = -160,  /* ASN unsupported critical extension */
+
+    ECC_BAD_ARG_E      = -170,  /* ECC input argument of wrong type */
+    ASN_ECC_KEY_E      = -171,  /* ASN ECC bad input */
+    ECC_CURVE_OID_E    = -172,  /* Unsupported ECC OID curve type */
+    BAD_FUNC_ARG       = -173,  /* Bad function argument provided */
+    NOT_COMPILED_IN    = -174,  /* Feature not compiled in */
+    UNICODE_SIZE_E     = -175,  /* Unicode password too big */
+    NO_PASSWORD        = -176,  /* no password provided by user */
+    ALT_NAME_E         = -177,  /* alt name size problem, too big */
+
+    AES_GCM_AUTH_E     = -180,  /* AES-GCM Authentication check failure */
+    AES_CCM_AUTH_E     = -181,  /* AES-CCM Authentication check failure */
+
+    CAVIUM_INIT_E      = -182,  /* Cavium Init type error */
+
+    COMPRESS_INIT_E    = -183,  /* Compress init error */
+    COMPRESS_E         = -184,  /* Compress error */
+    DECOMPRESS_INIT_E  = -185,  /* DeCompress init error */
+    DECOMPRESS_E       = -186,  /* DeCompress error */
+
+    BAD_ALIGN_E         = -187,  /* Bad alignment for operation, no alloc */
+    ASN_NO_SIGNER_E     = -188,  /* ASN no signer to confirm failure */
+    ASN_CRL_CONFIRM_E   = -189,  /* ASN CRL signature confirm failure */
+    ASN_CRL_NO_SIGNER_E = -190,  /* ASN CRL no signer to confirm failure */
+    ASN_OCSP_CONFIRM_E  = -191,  /* ASN OCSP signature confirm failure */
+
+    BAD_ENC_STATE_E     = -192,  /* Bad ecc enc state operation */
+    BAD_PADDING_E       = -193,  /* Bad padding, msg not correct length  */
+
+    REQ_ATTRIBUTE_E     = -194,  /* setting cert request attributes error */
+
+    PKCS7_OID_E         = -195,  /* PKCS#7, mismatched OID error */
+    PKCS7_RECIP_E       = -196,  /* PKCS#7, recipient error */
+    FIPS_NOT_ALLOWED_E  = -197,  /* FIPS not allowed error */
+
+    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/fips_test.h	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,43 @@
+/* fips_test.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_FIPS_TEST_H
+#define CTAO_CRYPT_FIPS_TEST_H
+
+#include <cyassl/ctaocrypt/types.h>
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* Known Answer Test string inputs are hex */
+
+CYASSL_LOCAL int DoKnownAnswerTests(void);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_FIPS_TEST_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/hc128.h	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,199 @@
+/* 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_BLAKE2 
+    #include <cyassl/ctaocrypt/blake2.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
+#ifndef HAVE_BLAKE2 
+    BLAKE2B_ID = 7,
+#endif
+
+/* Select the largest available hash for the buffer size. */
+#if defined(CYASSL_SHA512)
+    MAX_DIGEST_SIZE = SHA512_DIGEST_SIZE,
+    HMAC_BLOCK_SIZE = SHA512_BLOCK_SIZE
+#elif defined(HAVE_BLAKE2)
+    MAX_DIGEST_SIZE = BLAKE2B_OUTBYTES,
+    HMAC_BLOCK_SIZE = BLAKE2B_BLOCKBYTES,
+#elif defined(CYASSL_SHA384)
+    MAX_DIGEST_SIZE = SHA384_DIGEST_SIZE,
+    HMAC_BLOCK_SIZE = SHA384_BLOCK_SIZE
+#elif !defined(NO_SHA256)
+    MAX_DIGEST_SIZE = SHA256_DIGEST_SIZE,
+    HMAC_BLOCK_SIZE = SHA256_BLOCK_SIZE
+#elif !defined(NO_SHA)
+    MAX_DIGEST_SIZE = SHA_DIGEST_SIZE,
+    HMAC_BLOCK_SIZE = SHA_BLOCK_SIZE
+#elif !defined(NO_MD5)
+    MAX_DIGEST_SIZE = MD5_DIGEST_SIZE,
+    HMAC_BLOCK_SIZE = MD5_BLOCK_SIZE
+#else
+    #error "You have to have some kind of hash if you want to use HMAC."
+#endif
+};
+
+
+/* hash union */
+typedef union {
+    #ifndef NO_MD5
+        Md5 md5;
+    #endif
+    #ifndef NO_SHA
+        Sha sha;
+    #endif
+    #ifndef NO_SHA256
+        Sha256 sha256;
+    #endif
+    #ifdef CYASSL_SHA384
+        Sha384 sha384;
+    #endif
+    #ifdef CYASSL_SHA512
+        Sha512 sha512;
+    #endif
+    #ifdef HAVE_BLAKE2 
+        Blake2b blake2b;
+    #endif
+} Hash;
+
+/* Hmac digest */
+typedef struct Hmac {
+    Hash    hash;
+    word32  ipad[HMAC_BLOCK_SIZE  / sizeof(word32)];  /* same block size all*/
+    word32  opad[HMAC_BLOCK_SIZE  / sizeof(word32)];
+    word32  innerHash[MAX_DIGEST_SIZE / sizeof(word32)];
+    byte    macType;                                     /* md5 sha or sha256 */
+    byte    innerHashKeyed;                              /* keyed flag */
+#ifdef HAVE_CAVIUM
+    word16   keyLen;          /* hmac key length */
+    word16   dataLen;
+    HashType type;            /* hmac key type */
+    int      devId;           /* nitrox device id */
+    word32   magic;           /* using cavium magic */
+    word64   contextHandle;   /* nitrox context memory handle */
+    byte*    data;            /* buffered input data for one call */
+#endif
+} Hmac;
+
+
+/* does init */
+CYASSL_API int HmacSetKey(Hmac*, int type, const byte* key, word32 keySz);
+CYASSL_API int HmacUpdate(Hmac*, const byte*, word32);
+CYASSL_API int HmacFinal(Hmac*, byte*);
+
+#ifdef HAVE_CAVIUM
+    CYASSL_API int  HmacInitCavium(Hmac*, int);
+    CYASSL_API void HmacFreeCavium(Hmac*);
+#endif
+
+CYASSL_API int CyaSSL_GetHmacMaxSize(void);
+
+
+#ifdef HAVE_HKDF
+
+CYASSL_API int HKDF(int type, const byte* inKey, word32 inKeySz,
+                    const byte* salt, word32 saltSz,
+                    const byte* info, word32 infoSz,
+                    byte* out, word32 outSz);
+
+#endif /* HAVE_HKDF */
+
+
+#ifdef HAVE_FIPS
+    /* fips wrapper calls, user can call direct */
+    CYASSL_API int HmacSetKey_fips(Hmac*, int type, const byte* key,
+                                   word32 keySz);
+    CYASSL_API int HmacUpdate_fips(Hmac*, const byte*, word32);
+    CYASSL_API int HmacFinal_fips(Hmac*, byte*);
+    #ifndef FIPS_NO_WRAPPERS
+        /* if not impl or fips.c impl wrapper force fips calls if fips build */
+        #define HmacSetKey HmacSetKey_fips
+        #define HmacUpdate HmacUpdate_fips
+        #define HmacFinal  HmacFinal_fips
+    #endif /* FIPS_NO_WRAPPERS */
+
+#endif /* HAVE_FIPS */
+
+
+#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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,317 @@
+/* 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_leading_bit (mp_int * a);
+int  mp_init_copy (mp_int * a, mp_int * b);
+int  mp_copy (mp_int * a, mp_int * b);
+int  mp_grow (mp_int * a, int size);
+int  mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d);
+void mp_zero (mp_int * a);
+void mp_clamp (mp_int * a);
+void mp_exch (mp_int * a, mp_int * b);
+void mp_rshd (mp_int * a, int b);
+void mp_rshb (mp_int * a, int b);
+int  mp_mod_2d (mp_int * a, int b, mp_int * c);
+int  mp_mul_2d (mp_int * a, int b, mp_int * c);
+int  mp_lshd (mp_int * a, int b);
+int  mp_abs (mp_int * a, mp_int * b);
+int  mp_invmod (mp_int * a, mp_int * b, mp_int * c);
+int  fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c);
+int  mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c);
+int  mp_cmp_mag (mp_int * a, mp_int * b);
+int  mp_cmp (mp_int * a, mp_int * b);
+int  mp_cmp_d(mp_int * a, mp_digit b);
+void mp_set (mp_int * a, mp_digit b);
+int  mp_mod (mp_int * a, mp_int * b, mp_int * c);
+int  mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d);
+int  mp_div_2(mp_int * a, mp_int * b);
+int  mp_add (mp_int * a, mp_int * b, mp_int * c);
+int  s_mp_add (mp_int * a, mp_int * b, mp_int * c);
+int  s_mp_sub (mp_int * a, mp_int * b, mp_int * c);
+int  mp_sub (mp_int * a, mp_int * b, mp_int * c);
+int  mp_reduce_is_2k_l(mp_int *a);
+int  mp_reduce_is_2k(mp_int *a);
+int  mp_dr_is_modulus(mp_int *a);
+int  mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int);
+int  mp_montgomery_setup (mp_int * n, mp_digit * rho);
+int  fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho);
+int  mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho);
+void mp_dr_setup(mp_int *a, mp_digit *d);
+int  mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k);
+int  mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d);
+int  fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+int  s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+int  mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
+int  mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
+int  mp_reduce (mp_int * x, mp_int * m, mp_int * mu);
+int  mp_reduce_setup (mp_int * a, mp_int * b);
+int  s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
+int  mp_montgomery_calc_normalization (mp_int * a, mp_int * b);
+int  s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+int  s_mp_sqr (mp_int * a, mp_int * b);
+int  fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+int  fast_s_mp_sqr (mp_int * a, mp_int * b);
+int  mp_init_size (mp_int * a, int size);
+int  mp_div_3 (mp_int * a, mp_int *c, mp_digit * d);
+int  mp_mul_2(mp_int * a, mp_int * b);
+int  mp_mul (mp_int * a, mp_int * b, mp_int * c);
+int  mp_sqr (mp_int * a, mp_int * b);
+int  mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d);
+int  mp_mul_d (mp_int * a, mp_digit b, mp_int * c);
+int  mp_2expt (mp_int * a, int b);
+int  mp_reduce_2k_setup(mp_int *a, mp_digit *d);
+int  mp_add_d (mp_int* a, mp_digit b, mp_int* c);
+int mp_set_int (mp_int * a, unsigned long b);
+int mp_sub_d (mp_int * a, mp_digit b, mp_int * c);
+/* end support added functions */
+
+/* added */
+int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e,
+                  mp_int* f);
+
+#if defined(HAVE_ECC) || defined(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
+
+#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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,72 @@
+/* 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
+};
+
+#ifdef CYASSL_PIC32MZ_HASH
+#include "port/pic32/pic32mz-crypt.h"
+#endif
+
+/* MD5 digest */
+typedef struct Md5 {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word32  buffer[MD5_BLOCK_SIZE  / sizeof(word32)];
+    #ifndef CYASSL_PIC32MZ_HASH
+    word32  digest[MD5_DIGEST_SIZE / sizeof(word32)];
+    #else
+    word32  digest[PIC32_HASH_SIZE / sizeof(word32)];
+    pic32mz_desc desc ; /* Crypt Engine descripter */
+    #endif
+} Md5;
+
+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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,72 @@
+/* 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 XorWords(word*, const word*, word32);
+CYASSL_LOCAL
+void xorbuf(void*, const void*, 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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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/pkcs7.h	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,123 @@
+/* pkcs7.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_PKCS7
+
+#ifndef CTAO_CRYPT_PKCS7_H
+#define CTAO_CRYPT_PKCS7_H
+
+#include <cyassl/ctaocrypt/types.h>
+#include <cyassl/ctaocrypt/asn.h>
+#include <cyassl/ctaocrypt/asn_public.h>
+#include <cyassl/ctaocrypt/random.h>
+#include <cyassl/ctaocrypt/des3.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* PKCS#7 content types, ref RFC 2315 (Section 14) */
+enum PKCS7_TYPES {
+    PKCS7_MSG                 = 650,   /* 1.2.840.113549.1.7   */
+    DATA                      = 651,   /* 1.2.840.113549.1.7.1 */
+    SIGNED_DATA               = 652,   /* 1.2.840.113549.1.7.2 */
+    ENVELOPED_DATA            = 653,   /* 1.2.840.113549.1.7.3 */
+    SIGNED_AND_ENVELOPED_DATA = 654,   /* 1.2.840.113549.1.7.4 */
+    DIGESTED_DATA             = 655,   /* 1.2.840.113549.1.7.5 */
+    ENCRYPTED_DATA            = 656    /* 1.2.840.113549.1.7.6 */
+};
+
+enum Pkcs7_Misc {
+    PKCS7_NONCE_SZ       = 16,
+    MAX_ENCRYPTED_KEY_SZ = 512,           /* max enc. key size, RSA <= 4096 */
+    MAX_CONTENT_KEY_LEN  = DES3_KEYLEN,   /* highest current cipher is 3DES */
+    MAX_RECIP_SZ         = MAX_VERSION_SZ +
+                           MAX_SEQ_SZ + ASN_NAME_MAX + MAX_SN_SZ +
+                           MAX_SEQ_SZ + MAX_ALGO_SZ + 1 + MAX_ENCRYPTED_KEY_SZ
+};
+
+
+typedef struct PKCS7Attrib {
+    byte* oid;
+    word32 oidSz;
+    byte* value;
+    word32 valueSz;
+} PKCS7Attrib;
+
+
+typedef struct PKCS7 {
+    byte* content;                /* inner content, not owner             */
+    word32 contentSz;             /* content size                         */
+    int contentOID;               /* PKCS#7 content type OID sum          */
+
+    RNG* rng;
+
+    int hashOID;
+    int encryptOID;               /* key encryption algorithm OID         */
+
+    byte*  singleCert;            /* recipient cert, DER, not owner       */
+    word32 singleCertSz;          /* size of recipient cert buffer, bytes */
+    byte issuerHash[SHA_SIZE];    /* hash of all alt Names                */
+    byte*  issuer;                /* issuer name of singleCert            */
+    word32 issuerSz;              /* length of issuer name                */
+    byte issuerSn[MAX_SN_SZ];     /* singleCert's serial number           */
+    word32 issuerSnSz;            /* length of serial number              */
+    byte publicKey[512];
+    word32 publicKeySz;
+    byte*  privateKey;            /* private key, DER, not owner          */
+    word32 privateKeySz;          /* size of private key buffer, bytes    */
+    
+    PKCS7Attrib* signedAttribs;
+    word32 signedAttribsSz;
+} PKCS7;
+
+
+CYASSL_LOCAL int SetContentType(int pkcs7TypeOID, byte* output);
+CYASSL_LOCAL int GetContentType(const byte* input, word32* inOutIdx,
+                                word32* oid, word32 maxIdx);
+CYASSL_LOCAL int CreateRecipientInfo(const byte* cert, word32 certSz,
+                                     int keyEncAlgo, int blockKeySz,
+                                     RNG* rng, byte* contentKeyPlain,
+                                     byte* contentKeyEnc,
+                                     int* keyEncSz, byte* out, word32 outSz);
+
+CYASSL_API int  PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz);
+CYASSL_API void PKCS7_Free(PKCS7* pkcs7);
+CYASSL_API int  PKCS7_EncodeData(PKCS7* pkcs7, byte* output, word32 outputSz);
+CYASSL_API int  PKCS7_EncodeSignedData(PKCS7* pkcs7,
+                                       byte* output, word32 outputSz);
+CYASSL_API int  PKCS7_VerifySignedData(PKCS7* pkcs7,
+                                       byte* pkiMsg, word32 pkiMsgSz);
+CYASSL_API int  PKCS7_EncodeEnvelopedData(PKCS7* pkcs7,
+                                          byte* output, word32 outputSz);
+CYASSL_API int  PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg,
+                                          word32 pkiMsgSz, byte* output,
+                                          word32 outputSz);
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_PKCS7_H */
+
+#endif /* HAVE_PKCS7 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/port.h	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,194 @@
+/* port.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_PORT_H
+#define CTAO_CRYPT_PORT_H
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#ifdef USE_WINDOWS_API 
+    #ifdef CYASSL_GAME_BUILD
+        #include "system/xtl.h"
+    #else
+        #ifndef WIN32_LEAN_AND_MEAN
+            #define WIN32_LEAN_AND_MEAN
+        #endif
+        #if defined(_WIN32_WCE) || defined(WIN32_LEAN_AND_MEAN)
+            /* On WinCE winsock2.h must be included before windows.h */
+            #include <winsock2.h>
+        #endif
+        #include <windows.h>
+    #endif
+#elif defined(THREADX)
+    #ifndef SINGLE_THREADED
+        #include "tx_api.h"
+    #endif
+#elif defined(MICRIUM)
+    /* do nothing, just don't pick Unix */
+#elif defined(FREERTOS) || defined(CYASSL_SAFERTOS)
+    /* do nothing */
+#elif defined(EBSNET)
+    /* do nothing */
+#elif defined(FREESCALE_MQX)
+    /* do nothing */
+#elif defined(CYASSL_MDK_ARM)
+    #if defined(CYASSL_MDK5)
+         #include "cmsis_os.h"
+    #else
+        #include <rtl.h>
+    #endif
+#elif defined(CYASSL_CMSIS_RTOS)
+    #include "cmsis_os.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 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)
+        #if defined(CYASSL_CMSIS_RTOS)
+            typedef osMutexId CyaSSL_Mutex;
+        #else
+            typedef OS_MUT CyaSSL_Mutex;
+        #endif
+    #elif defined(CYASSL_CMSIS_RTOS)
+        typedef osMutexId 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*);
+
+
+/* filesystem abstraction layer, used by ssl.c */
+#ifndef NO_FILESYSTEM
+
+#if defined(EBSNET)
+    #define XFILE                    int
+    #define XFOPEN(NAME, MODE)       vf_open((const char *)NAME, VO_RDONLY, 0);
+    #define XFSEEK                   vf_lseek
+    #define XFTELL                   vf_tell
+    #define XREWIND                  vf_rewind
+    #define XFREAD(BUF, SZ, AMT, FD) vf_read(FD, BUF, SZ*AMT)
+    #define XFWRITE(BUF, SZ, AMT, FD) vf_write(FD, BUF, SZ*AMT)
+    #define XFCLOSE                  vf_close
+    #define XSEEK_END                VSEEK_END
+    #define XBADFILE                 -1
+#elif defined(LSR_FS)
+    #include <fs.h>
+    #define XFILE                   struct fs_file*
+    #define XFOPEN(NAME, MODE)      fs_open((char*)NAME);
+    #define XFSEEK(F, O, W)         (void)F
+    #define XFTELL(F)               (F)->len
+    #define XREWIND(F)              (void)F
+    #define XFREAD(BUF, SZ, AMT, F) fs_read(F, (char*)BUF, SZ*AMT)
+    #define XFWRITE(BUF, SZ, AMT, F) fs_write(F, (char*)BUF, SZ*AMT)
+    #define XFCLOSE                 fs_close
+    #define XSEEK_END               0
+    #define XBADFILE                NULL
+#elif defined(FREESCALE_MQX)
+    #define XFILE                   MQX_FILE_PTR
+    #define XFOPEN                  fopen
+    #define XFSEEK                  fseek
+    #define XFTELL                  ftell
+    #define XREWIND(F)              fseek(F, 0, IO_SEEK_SET)
+    #define XFREAD                  fread
+    #define XFWRITE                 fwrite
+    #define XFCLOSE                 fclose
+    #define XSEEK_END               IO_SEEK_END
+    #define XBADFILE                NULL
+#elif defined(MICRIUM)
+    #include <fs.h>
+    #define XFILE      FS_FILE*
+    #define XFOPEN     fs_fopen
+    #define XFSEEK     fs_fseek
+    #define XFTELL     fs_ftell
+    #define XREWIND    fs_rewind
+    #define XFREAD     fs_fread
+    #define XFWRITE    fs_fwrite
+    #define XFCLOSE    fs_fclose
+    #define XSEEK_END  FS_SEEK_END
+    #define XBADFILE   NULL
+#else
+    /* stdio, default case */
+    #define XFILE      FILE*
+    #if defined(CYASSL_MDK_ARM)
+        extern FILE * CyaSSL_fopen(const char *name, const char *mode) ;
+        #define XFOPEN     CyaSSL_fopen
+    #else
+        #define XFOPEN     fopen
+    #endif
+    #define XFSEEK     fseek
+    #define XFTELL     ftell
+    #define XREWIND    rewind
+    #define XFREAD     fread
+    #define XFWRITE    fwrite
+    #define XFCLOSE    fclose
+    #define XSEEK_END  SEEK_END
+    #define XBADFILE   NULL
+#endif
+
+#endif /* NO_FILESYSTEM */
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_PORT_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/ctaocrypt/pwdbased.h	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,142 @@
+/* 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 int  InitRsaKey(RsaKey* key, void*);
+CYASSL_API int  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 HAVE_FIPS
+    /* fips wrapper calls, user can call direct */
+    CYASSL_API int  InitRsaKey_fips(RsaKey* key, void*);
+    CYASSL_API int  FreeRsaKey_fips(RsaKey* key);
+
+    CYASSL_API int  RsaPublicEncrypt_fips(const byte* in,word32 inLen,byte* out,
+                                 word32 outLen, RsaKey* key, RNG* rng);
+    CYASSL_API int  RsaPrivateDecryptInline_fips(byte* in, word32 inLen,
+                                                 byte** out, RsaKey* key);
+    CYASSL_API int  RsaPrivateDecrypt_fips(const byte* in, word32 inLen,
+                                           byte* out,word32 outLen,RsaKey* key);
+    CYASSL_API int  RsaSSL_Sign_fips(const byte* in, word32 inLen, byte* out,
+                            word32 outLen, RsaKey* key, RNG* rng);
+    CYASSL_API int  RsaSSL_VerifyInline_fips(byte* in, word32 inLen, byte** out,
+                                    RsaKey* key);
+    CYASSL_API int  RsaSSL_Verify_fips(const byte* in, word32 inLen, byte* out,
+                              word32 outLen, RsaKey* key);
+    CYASSL_API int  RsaEncryptSize_fips(RsaKey* key);
+
+    CYASSL_API int RsaPrivateKeyDecode_fips(const byte* input, word32* inOutIdx,
+                                            RsaKey*, word32);
+    CYASSL_API int RsaPublicKeyDecode_fips(const byte* input, word32* inOutIdx,
+                                           RsaKey*, word32);
+    #ifndef FIPS_NO_WRAPPERS
+        /* if not impl or fips.c impl wrapper force fips calls if fips build */
+        #define InitRsaKey              InitRsaKey_fips 
+        #define FreeRsaKey              FreeRsaKey_fips 
+        #define RsaPublicEncrypt        RsaPublicEncrypt_fips 
+        #define RsaPrivateDecryptInline RsaPrivateDecryptInline_fips 
+        #define RsaPrivateDecrypt       RsaPrivateDecrypt_fips 
+        #define RsaSSL_Sign             RsaSSL_Sign_fips
+        #define RsaSSL_VerifyInline     RsaSSL_VerifyInline_fips
+        #define RsaSSL_Verify           RsaSSL_Verify_fips
+        #define RsaEncryptSize          RsaEncryptSize_fips
+        /* no implicit KeyDecodes since in asn.c (not rsa.c) */
+    #endif /* FIPS_NO_WRAPPERS */
+
+#endif /* HAVE_FIPS */
+
+
+#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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,584 @@
+/* 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 */
+#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 */
+
+/* Uncomment next line if using Comverge settings */
+/* #define COMVERGE */
+
+
+#include <cyassl/ctaocrypt/visibility.h>
+
+#ifdef IPHONE
+    #define SIZEOF_LONG_LONG 8
+#endif
+
+
+#ifdef COMVERGE
+    #define THREADX
+    #define HAVE_NETX
+    #define CYASSL_USER_IO
+    #define NO_WRITEV
+    #define NO_DEV_RANDOM
+    #define NO_FILESYSTEM
+    #define NO_SHA512
+    #define NO_DH
+    #define NO_DSA
+    #define NO_HC128
+    #define NO_RSA
+    #define NO_SESSION_CACHE
+    #define HAVE_ECC 
+#endif
+
+
+#ifdef THREADX 
+    #define SIZEOF_LONG_LONG 8
+#endif
+
+#ifdef HAVE_NETX
+    #include "nx_api.h"
+#endif
+
+#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"
+    #ifdef MICROCHIP_MPLAB_HARMONY
+        #include "tcpip/tcpip.h"
+    #else
+        #include "tcpip/sntp.h"
+    #endif
+#endif
+
+#ifdef MBED
+    //#define SINGLE_THREADED
+    #define CYASSL_USER_IO
+    #define NO_FILESYSTEM
+    #define NO_CERT
+    #define USE_CERT_BUFFERS_1024
+    #define NO_WRITEV
+    #define NO_DEV_RANDOM
+    #define NO_SHA512
+    #define NO_DH
+    #define NO_DSA
+    #define NO_HC128
+    #define HAVE_ECC
+    #define NO_SESSION_CACHE
+    #define CYASSL_CMSIS_RTOS
+#endif
+
+#ifdef CYASSL_TYTO
+    #define FREERTOS
+    #define NO_FILESYSTEM
+    #define CYASSL_USER_IO
+    #define NO_DEV_RANDOM
+#endif
+
+#ifdef FREERTOS_WINSIM
+    #define FREERTOS
+    #define USE_WINDOWS_API
+#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
+
+
+#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
+    /* #define FREESCALE_K53_RNGB */
+    #include "mqx.h"
+    #ifndef NO_FILESYSTEM
+        #include "mfs.h"
+        #include "fio.h"
+    #endif
+    #ifndef SINGLE_THREADED
+        #include "mutex.h"
+    #endif
+
+    #define XMALLOC(s, h, 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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,91 @@
+/* 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
+};
+
+#ifdef CYASSL_PIC32MZ_HASH
+#include "port/pic32/pic32mz-crypt.h"
+#endif
+
+/* Sha digest */
+typedef struct Sha {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word32  buffer[SHA_BLOCK_SIZE  / sizeof(word32)];
+    #ifndef CYASSL_PIC32MZ_HASH
+        word32  digest[SHA_DIGEST_SIZE / sizeof(word32)];
+    #else
+        word32  digest[PIC32_HASH_SIZE / sizeof(word32)];
+        pic32mz_desc desc; /* Crypt Engine descripter */
+    #endif
+} Sha;
+
+
+CYASSL_API int InitSha(Sha*);
+CYASSL_API int ShaUpdate(Sha*, const byte*, word32);
+CYASSL_API int ShaFinal(Sha*, byte*);
+
+
+#ifdef HAVE_FIPS
+    /* fips wrapper calls, user can call direct */
+    CYASSL_API int InitSha_fips(Sha*);
+    CYASSL_API int ShaUpdate_fips(Sha*, const byte*, word32);
+    CYASSL_API int ShaFinal_fips(Sha*, byte*);
+    #ifndef FIPS_NO_WRAPPERS
+        /* if not impl or fips.c impl wrapper force fips calls if fips build */
+        #define InitSha   InitSha_fips
+        #define ShaUpdate ShaUpdate_fips
+        #define ShaFinal  ShaFinal_fips
+    #endif /* FIPS_NO_WRAPPERS */
+
+#endif /* HAVE_FIPS */
+
+ 
+#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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,90 @@
+/* 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
+
+#ifdef CYASSL_PIC32MZ_HASH
+#include "port/pic32/pic32mz-crypt.h"
+#endif
+
+
+/* in bytes */
+enum {
+    SHA256              =  2,   /* hash type unique */
+    SHA256_BLOCK_SIZE   = 64,
+    SHA256_DIGEST_SIZE  = 32,
+    SHA256_PAD_SIZE     = 56
+};
+
+
+/* Sha256 digest */
+typedef struct Sha256 {
+    word32  buffLen;   /* in bytes          */
+    word32  loLen;     /* length in bytes   */
+    word32  hiLen;     /* length in bytes   */
+    word32  digest[SHA256_DIGEST_SIZE / sizeof(word32)];
+    word32  buffer[SHA256_BLOCK_SIZE  / sizeof(word32)];
+    #ifdef CYASSL_PIC32MZ_HASH
+        pic32mz_desc desc ; /* Crypt Engine descripter */
+    #endif
+} Sha256;
+
+
+CYASSL_API int  InitSha256(Sha256*);
+CYASSL_API int  Sha256Update(Sha256*, const byte*, word32);
+CYASSL_API int  Sha256Final(Sha256*, byte*);
+
+
+#ifdef HAVE_FIPS
+    /* fips wrapper calls, user can call direct */
+    CYASSL_API int InitSha256_fips(Sha256*);
+    CYASSL_API int Sha256Update_fips(Sha256*, const byte*, word32);
+    CYASSL_API int Sha256Final_fips(Sha256*, byte*);
+    #ifndef FIPS_NO_WRAPPERS
+        /* if not impl or fips.c impl wrapper force fips calls if fips build */
+        #define InitSha256   InitSha256_fips
+        #define Sha256Update Sha256Update_fips
+        #define Sha256Final  Sha256Final_fips
+    #endif /* FIPS_NO_WRAPPERS */
+
+#endif /* HAVE_FIPS */
+
+ 
+#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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,118 @@
+/* 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 int InitSha512(Sha512*);
+CYASSL_API int Sha512Update(Sha512*, const byte*, word32);
+CYASSL_API int 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 int InitSha384(Sha384*);
+CYASSL_API int Sha384Update(Sha384*, const byte*, word32);
+CYASSL_API int Sha384Final(Sha384*, byte*);
+
+
+#ifdef HAVE_FIPS
+    /* fips wrapper calls, user can call direct */
+    CYASSL_API int InitSha512_fips(Sha512*);
+    CYASSL_API int Sha512Update_fips(Sha512*, const byte*, word32);
+    CYASSL_API int Sha512Final_fips(Sha512*, byte*);
+    #ifndef FIPS_NO_WRAPPERS
+        /* if not impl or fips.c impl wrapper force fips calls if fips build */
+        #define InitSha512   InitSha512_fips
+        #define Sha512Update Sha512Update_fips
+        #define Sha512Final  Sha512Final_fips
+    #endif /* FIPS_NO_WRAPPERS */
+
+    /* fips wrapper calls, user can call direct */
+    CYASSL_API int InitSha384_fips(Sha384*);
+    CYASSL_API int Sha384Update_fips(Sha384*, const byte*, word32);
+    CYASSL_API int Sha384Final_fips(Sha384*, byte*);
+    #ifndef FIPS_NO_WRAPPERS
+        /* if not impl or fips.c impl wrapper force fips calls if fips build */
+        #define InitSha384   InitSha384_fips
+        #define Sha384Update Sha384Update_fips
+        #define Sha384Final  Sha384Final_fips
+    #endif /* FIPS_NO_WRAPPERS */
+
+#endif /* HAVE_FIPS */
+
+
+#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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,694 @@
+/* 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_HUGE_SET
+#define TFM_MUL20
+#define TFM_MUL24
+#define TFM_MUL28
+#define TFM_MUL32
+#if (FP_MAX_BITS >= 6144) && defined(FP_64BIT)
+    #define TFM_MUL48
+#endif
+#if (FP_MAX_BITS >= 8192) && defined(FP_64BIT)
+    #define TFM_MUL64
+#endif
+#endif
+
+#if 0
+#define TFM_SQR3
+#define TFM_SQR4
+#define TFM_SQR6
+#define TFM_SQR7
+#define TFM_SQR8
+#define TFM_SQR9
+#define TFM_SQR12
+#define TFM_SQR17
+#endif
+#ifdef TFM_HUGE_SET
+#define TFM_SQR20
+#define TFM_SQR24
+#define TFM_SQR28
+#define TFM_SQR32
+#define TFM_SQR48
+#define TFM_SQR64
+#endif
+
+/* do we want some overflow checks
+   Not required if you make sure your numbers are within range (e.g. by default a modulus for fp_exptmod() can only be upto 2048 bits long)
+ */
+/* #define TFM_CHECK */
+
+/* Is the target a P4 Prescott
+ */
+/* #define TFM_PRESCOTT */
+
+/* Do we want timing resistant fp_exptmod() ?
+ * This makes it slower but also timing invariant with respect to the exponent 
+ */
+/* #define TFM_TIMING_RESISTANT */
+
+#endif /* TFM_ALREADY_SET */
+
+/* functions */
+
+/* returns a TFM ident string useful for debugging... */
+/*const char *fp_ident(void);*/
+
+/* initialize [or zero] an fp int */
+#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);
+
+/* right shift x bits */
+void fp_rshb(fp_int *a, int x);
+
+/* left shift x digits */
+void fp_lshd(fp_int *a, int x);
+
+/* signed comparison */
+int fp_cmp(fp_int *a, fp_int *b);
+
+/* unsigned comparison */
+int fp_cmp_mag(fp_int *a, fp_int *b);
+
+/* power of 2 operations */
+void fp_div_2d(fp_int *a, int b, fp_int *c, fp_int *d);
+void fp_mod_2d(fp_int *a, int b, fp_int *c);
+void fp_mul_2d(fp_int *a, int b, fp_int *c);
+void fp_2expt (fp_int *a, int b);
+void fp_mul_2(fp_int *a, fp_int *c);
+void fp_div_2(fp_int *a, fp_int *c);
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+/*int fp_cnt_lsb(fp_int *a);*/
+
+/* c = a + b */
+void fp_add(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = a - b */
+void fp_sub(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = a * b */
+void fp_mul(fp_int *a, fp_int *b, fp_int *c);
+
+/* b = a*a  */
+void fp_sqr(fp_int *a, fp_int *b);
+
+/* a/b => cb + d == a */
+int fp_div(fp_int *a, fp_int *b, fp_int *c, fp_int *d);
+
+/* c = a mod b, 0 <= c < b  */
+int fp_mod(fp_int *a, fp_int *b, fp_int *c);
+
+/* compare against a single digit */
+int fp_cmp_d(fp_int *a, fp_digit b);
+
+/* c = a + b */
+void fp_add_d(fp_int *a, fp_digit b, fp_int *c);
+
+/* c = a - b */
+void fp_sub_d(fp_int *a, fp_digit b, fp_int *c);
+
+/* c = a * b */
+void fp_mul_d(fp_int *a, fp_digit b, fp_int *c);
+
+/* a/b => cb + d == a */
+/*int fp_div_d(fp_int *a, fp_digit b, fp_int *c, fp_digit *d);*/
+
+/* c = a mod b, 0 <= c < b  */
+/*int fp_mod_d(fp_int *a, fp_digit b, fp_digit *c);*/
+
+/* ---> number theory <--- */
+/* d = a + b (mod c) */
+/*int fp_addmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);*/
+
+/* d = a - b (mod c) */
+/*int fp_submod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);*/
+
+/* d = a * b (mod c) */
+int fp_mulmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);
+
+/* c = a * a (mod b) */
+int fp_sqrmod(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = 1/a (mod b) */
+int fp_invmod(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = (a, b) */
+/*void fp_gcd(fp_int *a, fp_int *b, fp_int *c);*/
+
+/* c = [a, b] */
+/*void fp_lcm(fp_int *a, fp_int *b, fp_int *c);*/
+
+/* setups the montgomery reduction */
+int fp_montgomery_setup(fp_int *a, fp_digit *mp);
+
+/* computes a = B**n mod b without division or multiplication useful for
+ * normalizing numbers in a Montgomery system.
+ */
+void fp_montgomery_calc_normalization(fp_int *a, fp_int *b);
+
+/* computes x/R == x (mod N) via Montgomery Reduction */
+void fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp);
+
+/* d = a**b (mod c) */
+int fp_exptmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);
+
+/* primality stuff */
+
+/* perform a Miller-Rabin test of a to the base b and store result in "result" */
+/*void fp_prime_miller_rabin (fp_int * a, fp_int * b, int *result);*/
+
+/* 256 trial divisions + 8 Miller-Rabins, returns FP_YES if probable prime  */
+/*int fp_isprime(fp_int *a);*/
+
+/* Primality generation flags */
+/*#define TFM_PRIME_BBS      0x0001 */ /* BBS style prime */
+/*#define TFM_PRIME_SAFE     0x0002 */ /* Safe prime (p-1)/2 == prime */
+/*#define TFM_PRIME_2MSB_OFF 0x0004 */ /* force 2nd MSB to 0 */
+/*#define TFM_PRIME_2MSB_ON  0x0008 */ /* force 2nd MSB to 1 */
+
+/* callback for fp_prime_random, should fill dst with random bytes and return how many read [upto len] */
+/*typedef int tfm_prime_callback(unsigned char *dst, int len, void *dat);*/
+
+/*#define fp_prime_random(a, t, size, bbs, cb, dat) fp_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?TFM_PRIME_BBS:0, cb, dat)*/
+
+/*int fp_prime_random_ex(fp_int *a, int t, int size, int flags, tfm_prime_callback cb, void *dat);*/
+
+/* radix conersions */
+int fp_count_bits(fp_int *a);
+int fp_leading_bit(fp_int *a);
+
+int fp_unsigned_bin_size(fp_int *a);
+void fp_read_unsigned_bin(fp_int *a, unsigned char *b, int c);
+void fp_to_unsigned_bin(fp_int *a, unsigned char *b);
+
+/*int fp_signed_bin_size(fp_int *a);*/
+/*void fp_read_signed_bin(fp_int *a, unsigned char *b, int c);*/
+/*void fp_to_signed_bin(fp_int *a, unsigned char *b);*/
+
+/*int fp_read_radix(fp_int *a, char *str, int radix);*/
+/*int fp_toradix(fp_int *a, char *str, int radix);*/
+/*int fp_toradix_n(fp_int * a, char *str, int radix, int maxlen);*/
+
+
+/* VARIOUS LOW LEVEL STUFFS */
+void s_fp_add(fp_int *a, fp_int *b, fp_int *c);
+void s_fp_sub(fp_int *a, fp_int *b, fp_int *c);
+void fp_reverse(unsigned char *s, int len);
+
+void fp_mul_comba(fp_int *a, fp_int *b, fp_int *c);
+
+#ifdef TFM_SMALL_SET
+void fp_mul_comba_small(fp_int *a, fp_int *b, fp_int *c);
+#endif
+
+#ifdef TFM_MUL3
+void fp_mul_comba3(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL4
+void fp_mul_comba4(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL6
+void fp_mul_comba6(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL7
+void fp_mul_comba7(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL8
+void fp_mul_comba8(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL9
+void fp_mul_comba9(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL12
+void fp_mul_comba12(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL17
+void fp_mul_comba17(fp_int *a, fp_int *b, fp_int *c);
+#endif
+
+#ifdef TFM_MUL20
+void fp_mul_comba20(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL24
+void fp_mul_comba24(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL28
+void fp_mul_comba28(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL32
+void fp_mul_comba32(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL48
+void fp_mul_comba48(fp_int *a, fp_int *b, fp_int *c);
+#endif
+#ifdef TFM_MUL64
+void fp_mul_comba64(fp_int *a, fp_int *b, fp_int *c);
+#endif
+
+void fp_sqr_comba(fp_int *a, fp_int *b);
+
+#ifdef TFM_SMALL_SET
+void fp_sqr_comba_small(fp_int *a, fp_int *b);
+#endif
+
+#ifdef TFM_SQR3
+void fp_sqr_comba3(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR4
+void fp_sqr_comba4(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR6
+void fp_sqr_comba6(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR7
+void fp_sqr_comba7(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR8
+void fp_sqr_comba8(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR9
+void fp_sqr_comba9(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR12
+void fp_sqr_comba12(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR17
+void fp_sqr_comba17(fp_int *a, fp_int *b);
+#endif
+
+#ifdef TFM_SQR20
+void fp_sqr_comba20(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR24
+void fp_sqr_comba24(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR28
+void fp_sqr_comba28(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR32
+void fp_sqr_comba32(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR48
+void fp_sqr_comba48(fp_int *a, fp_int *b);
+#endif
+#ifdef TFM_SQR64
+void fp_sqr_comba64(fp_int *a, fp_int *b);
+#endif
+/*extern const char *fp_s_rmap;*/
+
+
+/**
+ * Used by 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_leading_bit(mp_int *a);
+int  mp_set_int(fp_int *a, fp_digit b);
+void mp_rshb(mp_int *a, int x);
+
+#ifdef HAVE_ECC
+    int mp_read_radix(mp_int* a, const char* str, int radix);
+    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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,328 @@
+/* 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>
+#include <cyassl/ctaocrypt/port.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#if defined(WORDS_BIGENDIAN)
+    #define BIG_ENDIAN_ORDER
+#endif
+
+#ifndef BIG_ENDIAN_ORDER
+    #define LITTLE_ENDIAN_ORDER
+#endif
+
+#ifndef 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
+
+
+/* set up thread local storage if available */
+#ifdef HAVE_THREAD_LS
+    #if defined(_MSC_VER)
+        #define THREAD_LS_T __declspec(thread)
+    #else
+        #define THREAD_LS_T __thread
+    #endif
+#else
+    #define THREAD_LS_T
+#endif
+
+
+/* Micrium will use Visual Studio for compilation but not the Win32 API */
+#if defined(_WIN32) && !defined(MICRIUM) && !defined(FREERTOS) \
+        && !defined(EBSNET)
+    #define USE_WINDOWS_API
+#endif
+
+
+/* idea to add global alloc override by Moisés Guimarães  */
+/* default to libc stuff */
+/* XREALLOC is used once in normal math lib, not in fast math lib */
+/* XFREE on some embeded systems doesn't like free(0) so test  */
+#if defined(XMALLOC_USER)
+    /* prototypes for user heap override functions */
+    #include <stddef.h>  /* for size_t */
+    extern void *XMALLOC(size_t n, void* heap, int type);
+    extern void *XREALLOC(void *p, size_t n, void* heap, int type);
+    extern void XFREE(void *p, void* heap, int type);
+#elif defined(NO_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))
+    #ifndef USE_WINDOWS_API
+        #define XSTRNCASECMP(s1,s2,n) strncasecmp((s1),(s2),(n))
+        #define XSNPRINTF snprintf
+    #else
+        #define XSTRNCASECMP(s1,s2,n) _strnicmp((s1),(s2),(n))
+        #define XSNPRINTF _snprintf
+    #endif
+#endif
+
+#ifndef CTYPE_USER
+    #include <ctype.h>
+    #if defined(HAVE_ECC) || defined(HAVE_OCSP)
+        #define XTOUPPER(c)     toupper((c))
+        #define XISALPHA(c)     isalpha((c))
+    #endif
+    /* needed by CyaSSL_check_domain_name() */
+    #ifdef __CYGWIN__
+        /* Cygwin uses a macro version of tolower() by default, use the
+         * function version. */
+        #undef tolower
+    #endif
+    #define XTOLOWER(c)      tolower((c))
+#endif
+
+
+/* memory allocation types for user hints */
+enum {
+    DYNAMIC_TYPE_CA           = 1,
+    DYNAMIC_TYPE_CERT         = 2,
+    DYNAMIC_TYPE_KEY          = 3,
+    DYNAMIC_TYPE_FILE         = 4,
+    DYNAMIC_TYPE_SUBJECT_CN   = 5,
+    DYNAMIC_TYPE_PUBLIC_KEY   = 6,
+    DYNAMIC_TYPE_SIGNER       = 7,
+    DYNAMIC_TYPE_NONE         = 8,
+    DYNAMIC_TYPE_BIGINT       = 9,
+    DYNAMIC_TYPE_RSA          = 10,
+    DYNAMIC_TYPE_METHOD       = 11,
+    DYNAMIC_TYPE_OUT_BUFFER   = 12,
+    DYNAMIC_TYPE_IN_BUFFER    = 13,
+    DYNAMIC_TYPE_INFO         = 14,
+    DYNAMIC_TYPE_DH           = 15,
+    DYNAMIC_TYPE_DOMAIN       = 16,
+    DYNAMIC_TYPE_SSL          = 17,
+    DYNAMIC_TYPE_CTX          = 18,
+    DYNAMIC_TYPE_WRITEV       = 19,
+    DYNAMIC_TYPE_OPENSSL      = 20,
+    DYNAMIC_TYPE_DSA          = 21,
+    DYNAMIC_TYPE_CRL          = 22,
+    DYNAMIC_TYPE_REVOKED      = 23,
+    DYNAMIC_TYPE_CRL_ENTRY    = 24,
+    DYNAMIC_TYPE_CERT_MANAGER = 25,
+    DYNAMIC_TYPE_CRL_MONITOR  = 26,
+    DYNAMIC_TYPE_OCSP_STATUS  = 27,
+    DYNAMIC_TYPE_OCSP_ENTRY   = 28,
+    DYNAMIC_TYPE_ALTNAME      = 29,
+    DYNAMIC_TYPE_SUITES       = 30,
+    DYNAMIC_TYPE_CIPHER       = 31,
+    DYNAMIC_TYPE_RNG          = 32,
+    DYNAMIC_TYPE_ARRAYS       = 33,
+    DYNAMIC_TYPE_DTLS_POOL    = 34,
+    DYNAMIC_TYPE_SOCKADDR     = 35,
+    DYNAMIC_TYPE_LIBZ         = 36,
+    DYNAMIC_TYPE_ECC          = 37,
+    DYNAMIC_TYPE_TMP_BUFFER   = 38,
+    DYNAMIC_TYPE_DTLS_MSG     = 39,
+    DYNAMIC_TYPE_CAVIUM_TMP   = 40,
+    DYNAMIC_TYPE_CAVIUM_RSA   = 41,
+    DYNAMIC_TYPE_X509         = 42,
+    DYNAMIC_TYPE_TLSX         = 43,
+    DYNAMIC_TYPE_OCSP         = 44,
+    DYNAMIC_TYPE_SIGNATURE    = 45
+};
+
+/* max error buffer string size */
+enum {
+    CYASSL_MAX_ERROR_SZ = 80
+};
+
+/* stack protection */
+enum {
+    MIN_STACK_BUFFER = 8
+};
+
+
+
+/* settings detection for compile vs runtime math incombatibilities */
+enum {
+#if !defined(USE_FAST_MATH) && !defined(SIZEOF_LONG) && !defined(SIZEOF_LONG_LONG)
+    CTC_SETTINGS = 0x0
+#elif !defined(USE_FAST_MATH) && defined(SIZEOF_LONG) && (SIZEOF_LONG == 8)
+    CTC_SETTINGS = 0x1
+#elif !defined(USE_FAST_MATH) && defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG == 8)
+    CTC_SETTINGS = 0x2
+#elif !defined(USE_FAST_MATH) && defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG == 4)
+    CTC_SETTINGS = 0x4
+#elif defined(USE_FAST_MATH) && !defined(SIZEOF_LONG) && !defined(SIZEOF_LONG_LONG)
+    CTC_SETTINGS = 0x8
+#elif defined(USE_FAST_MATH) && defined(SIZEOF_LONG) && (SIZEOF_LONG == 8)
+    CTC_SETTINGS = 0x10
+#elif defined(USE_FAST_MATH) && defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG == 8)
+    CTC_SETTINGS = 0x20
+#elif defined(USE_FAST_MATH) && defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG == 4)
+    CTC_SETTINGS = 0x40
+#else
+    #error "bad math long / long long settings"
+#endif
+};
+
+
+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	Sun Apr 20 12:40:57 2014 +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/error-ssl.h	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,146 @@
+/* error-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
+ */
+
+
+#ifndef CYASSL_ERROR_H
+#define CYASSL_ERROR_H
+
+#include <cyassl/ctaocrypt/error-crypt.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 */
+    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 */
+    UNKNOWN_MAX_FRAG_LEN_E  = -282,        /* Unrecognized max frag len 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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,2141 @@
+/* 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>
+#include <cyassl/ctaocrypt/hmac.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)
+    #if defined(CYASSL_MDK5)
+         #include "cmsis_os.h"
+    #else
+        #include <rtl.h>
+    #endif
+#elif defined(MBED)
+
+#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
+    #if defined(HAVE_BLAKE2)
+        #define BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
+        #define BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
+    #endif
+#endif
+
+#if defined(HAVE_CAMELLIA) && !defined(NO_TLS)
+    #ifndef NO_RSA
+      #if !defined(NO_SHA)
+        #define BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+        #define BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
+      #endif
+        #ifndef NO_SHA256
+            #define BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
+            #define BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
+        #endif
+        #if !defined(NO_DH) && 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_MD5
+  #if !defined(NO_SHA)
+    #define BUILD_TLS_RSA_WITH_HC_128_SHA
+  #endif
+  #if defined(HAVE_BLAKE2)
+    #define BUILD_TLS_RSA_WITH_HC_128_B2B256
+  #endif
+#endif
+
+#if !defined(NO_RABBIT) && !defined(NO_TLS) && !defined(NO_RSA)
+  #if !defined(NO_SHA)
+    #define BUILD_TLS_RSA_WITH_RABBIT_SHA
+  #endif
+#endif
+
+#if !defined(NO_DH) && !defined(NO_AES) && !defined(NO_TLS) && \
+    !defined(NO_RSA) && 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(CYASSL_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_SHA) || \
+    defined(BUILD_TLS_RSA_WITH_HC_128_MD5) || \
+    defined(BUILD_TLS_RSA_WITH_HC_128_B2B256)
+    #define BUILD_HC128
+#endif
+
+#if defined(BUILD_TLS_RSA_WITH_RABBIT_SHA)
+    #define BUILD_RABBIT
+#endif
+
+#ifdef NO_DES3
+    #define DES_BLOCK_SIZE 8
+#else
+    #undef  BUILD_DES3
+    #define BUILD_DES3
+#endif
+
+#ifdef NO_AES
+    #define AES_BLOCK_SIZE 16
+#else
+    #undef  BUILD_AES
+    #define BUILD_AES
+#endif
+
+#ifndef NO_RC4
+    #undef  BUILD_ARC4
+    #define BUILD_ARC4
+#endif
+
+
+
+#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_MD5       = 0xFB,
+    TLS_RSA_WITH_HC_128_SHA       = 0xFC,
+    TLS_RSA_WITH_RABBIT_SHA       = 0xFD,
+
+    /* CyaSSL extension - Blake2b 256 */
+    TLS_RSA_WITH_AES_128_CBC_B2B256   = 0xF8,
+    TLS_RSA_WITH_AES_256_CBC_B2B256   = 0xF9,
+    TLS_RSA_WITH_HC_128_B2B256        = 0xFA,   /* eSTREAM too */
+
+    /* 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,
+
+    /* Renegotiation Indication Extension Special Suite */
+    TLS_EMPTY_RENEGOTIATION_INFO_SCSV        = 0xff
+};
+
+
+enum Misc {
+    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     */
+    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           */
+    OPAQUE8_LEN  =  1,         /* 1 byte                  */
+    OPAQUE16_LEN =  2,         /* 2 bytes                 */
+    OPAQUE24_LEN =  3,         /* 3 bytes                 */
+    COMP_LEN     =  1,         /* compression length      */
+    CURVE_LEN    =  2,         /* ecc named curve length  */
+    SERVER_ID_LEN = 20,        /* server session id length  */
+    
+    HANDSHAKE_HEADER_SZ   = 4,  /* type + length(3)        */
+    RECORD_HEADER_SZ      = 5,  /* type + version + len(2) */
+    CERT_HEADER_SZ        = 3,  /* always 3 bytes          */
+    REQ_HEADER_SZ         = 2,  /* cert request header sz  */
+    HINT_LEN_SZ           = 2,  /* length of hint size field */
+    TRUNCATED_HMAC_SZ     = 10, /* length of hmac w/ truncated hmac extension */
+    HELLO_EXT_TYPE_SZ     = 2,  /* length of a hello extension type */
+    HELLO_EXT_SZ          = 8,  /* total length of the lazy hello extensions */
+    HELLO_EXT_LEN         = 6,  /* length of the lazy hello extensions */
+    HELLO_EXT_SIGALGO_SZ  = 2,  /* length of signature algo extension  */
+    HELLO_EXT_SIGALGO_MAX = 32, /* number of items in the signature algo list */
+
+    DTLS_HANDSHAKE_HEADER_SZ = 12, /* normal + seq(2) + offset(3) + length(3) */
+    DTLS_RECORD_HEADER_SZ    = 13, /* normal + epoch(2) + seq_num(6) */
+    DTLS_HANDSHAKE_EXTRA     = 8,  /* diff from normal */
+    DTLS_RECORD_EXTRA        = 8,  /* diff from normal */
+    DTLS_HANDSHAKE_SEQ_SZ    = 2,  /* handshake header sequence number */
+    DTLS_HANDSHAKE_FRAG_SZ   = 3,  /* fragment offset and length are 24 bit */
+    DTLS_POOL_SZ             = 5,  /* buffers to hold in the retry pool */
+
+    FINISHED_LABEL_SZ   = 15,  /* TLS finished label size */
+    TLS_FINISHED_SZ     = 12,  /* TLS has a shorter size  */
+    MASTER_LABEL_SZ     = 13,  /* TLS master secret label sz */
+    KEY_LABEL_SZ        = 13,  /* TLS key block expansion sz */
+    MAX_PRF_HALF        = 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 */
+};
+
+
+#ifdef SESSION_INDEX
+/* Shift values for making a session index */
+#define SESSIDX_ROW_SHIFT 4
+#define SESSIDX_IDX_MASK  0x0F
+#endif
+
+
+/* max cert chain peer depth */
+#ifndef MAX_CHAIN_DEPTH
+    #define MAX_CHAIN_DEPTH 9
+#endif
+
+
+/* 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,
+                            word32 size, word32 totalSz, 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
+    /* don't fragment memory from the record header */
+    #define STATIC_BUFFER_LEN RECORD_HEADER_SZ
+#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 */
+
+#ifdef HAVE_NETX
+    CYASSL_LOCAL int NetX_Receive(CYASSL *ssl, char *buf, int sz, void *ctx);
+    CYASSL_LOCAL int NetX_Send(CYASSL *ssl, char *buf, int sz, void *ctx);
+#endif /* HAVE_NETX */
+
+
+/* CyaSSL Cipher type just points back to SSL */
+struct CYASSL_CIPHER {
+    CYASSL* ssl;
+};
+
+
+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         */
+};
+
+
+#ifndef HAVE_OCSP
+    typedef struct CYASSL_OCSP CYASSL_OCSP;
+#endif
+
+/* CyaSSL OCSP controller */
+struct CYASSL_OCSP {
+    CYASSL_CERT_MANAGER* cm;            /* pointer back to cert manager */
+    OCSP_Entry*          ocspList;      /* OCSP response list */
+    CyaSSL_Mutex         ocspLock;      /* OCSP list lock */
+};
+
+#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_OCSP*    ocsp;               /* OCSP checker */
+    byte            ocspEnabled;        /* is OCSP on ? */
+    byte            ocspSendNonce;      /* send the OCSP nonce ? */
+    byte            ocspUseOverrideURL; /* ignore cert's responder, override */
+    char*           ocspOverrideURL;    /* use this responder */
+    void*           ocspIOCtx;          /* I/O callback CTX */
+    CbOCSPIO        ocspIOCb;           /* I/O callback for OCSP lookup */
+    CbOCSPRespFree  ocspRespFreeCb;     /* Frees OCSP Response from IO Cb */
+};
+
+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,
+    TRUNCATED_HMAC         =  4,
+    ELLIPTIC_CURVES        = 10
+} 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                       status;  /* Matching result   */
+#endif
+} SNI;
+
+CYASSL_LOCAL int TLSX_UseSNI(TLSX** extensions, byte type, const void* data,
+                                                                   word16 size);
+
+#ifndef NO_CYASSL_SERVER
+CYASSL_LOCAL void   TLSX_SNI_SetOptions(TLSX* extensions, byte type,
+                                                                  byte options);
+CYASSL_LOCAL byte   TLSX_SNI_Status(TLSX* extensions, byte type);
+CYASSL_LOCAL word16 TLSX_SNI_GetRequest(TLSX* extensions, byte type,
+                                                                   void** data);
+CYASSL_LOCAL int    TLSX_SNI_GetFromBuffer(const byte* buffer, word32 bufferSz,
+                                         byte type, byte* sni, word32* inOutSz);
+#endif
+
+#endif /* HAVE_SNI */
+
+/* Maximum Fragment Length */
+#ifdef HAVE_MAX_FRAGMENT
+
+CYASSL_LOCAL int TLSX_UseMaxFragment(TLSX** extensions, byte mfl);
+
+#endif /* HAVE_MAX_FRAGMENT */
+
+#ifdef HAVE_TRUNCATED_HMAC
+
+CYASSL_LOCAL int TLSX_UseTruncatedHMAC(TLSX** extensions);
+
+#endif /* HAVE_TRUNCATED_HMAC */
+
+#ifdef HAVE_SUPPORTED_CURVES
+
+typedef struct EllipticCurve {
+    word16                name; /* CurveNames    */
+    struct EllipticCurve* next; /* List Behavior */
+
+} EllipticCurve;
+
+CYASSL_LOCAL int TLSX_UseSupportedCurve(TLSX** extensions, word16 name);
+
+#ifndef NO_CYASSL_SERVER
+CYASSL_LOCAL int TLSX_ValidateEllipticCurves(CYASSL* ssl, byte first,
+                                                                   byte second);
+#endif
+
+#endif /* HAVE_SUPPORTED_CURVES */
+
+#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 */
+    word32          pkCurveOID;         /* curve Ecc_Sum */
+#endif
+#ifndef NO_PSK
+    byte        havePSK;                /* psk key set by user */
+    psk_client_callback client_psk_cb;  /* client callback */
+    psk_server_callback server_psk_cb;  /* server callback */
+    char        server_hint[MAX_PSK_ID_LEN];
+#endif /* NO_PSK */
+#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
+#ifdef ATOMIC_USER
+    CallbackMacEncrypt    MacEncryptCb;    /* Atomic User Mac/Encrypt Cb */
+    CallbackDecryptVerify DecryptVerifyCb; /* Atomic User Decrypt/Verify Cb */
+#endif
+#ifdef HAVE_PK_CALLBACKS
+    #ifdef HAVE_ECC
+        CallbackEccSign   EccSignCb;    /* User EccSign   Callback handler */
+        CallbackEccVerify EccVerifyCb;  /* User EccVerify Callback handler */
+    #endif /* HAVE_ECC */
+    #ifndef NO_RSA 
+        CallbackRsaSign   RsaSignCb;    /* User RsaSign   Callback handler */
+        CallbackRsaVerify RsaVerifyCb;  /* User RsaVerify Callback handler */
+        CallbackRsaEnc    RsaEncCb;     /* User Rsa Public Encrypt  handler */
+        CallbackRsaDec    RsaDecCb;     /* User Rsa Private Decrypt handler */
+    #endif /* NO_RSA */
+#endif /* HAVE_PK_CALLBACKS */
+};
+
+
+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 Message Authentication Codes from page 43 */
+enum MACAlgorithm { 
+    no_mac,
+    md5_mac,
+    sha_mac,
+    sha224_mac,
+    sha256_mac,
+    sha384_mac,
+    sha512_mac,
+    rmd_mac,
+    blake2b_mac
+};
+
+
+/* Supported Key Exchange Protocols */
+enum KeyExchangeAlgorithm { 
+    no_kea,
+    rsa_kea, 
+    diffie_hellman_kea, 
+    fortezza_kea,
+    psk_kea,
+    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 };
+
+
+#ifdef CYASSL_DTLS
+
+    #ifdef WORD64_AVAILABLE
+        typedef word64 DtlsSeq;
+    #else
+        typedef word32 DtlsSeq;
+    #endif
+    #define DTLS_SEQ_BITS (sizeof(DtlsSeq) * CHAR_BIT)
+
+    typedef struct DtlsState {
+        DtlsSeq window;     /* Sliding window for current epoch    */
+        word16 nextEpoch;   /* Expected epoch in next record       */
+        word32 nextSeq;     /* Expected sequence in next record    */
+
+        word16 curEpoch;    /* Received epoch in current record    */
+        word32 curSeq;      /* Received sequence in current record */
+
+        DtlsSeq prevWindow; /* Sliding window for old epoch        */
+        word32 prevSeq;     /* Next sequence in allowed old epoch  */
+    } DtlsState;
+
+#endif /* CYASSL_DTLS */
+
+
+/* keys and secrets */
+typedef struct Keys {
+    byte client_write_MAC_secret[MAX_DIGEST_SIZE];   /* max sizes */
+    byte server_write_MAC_secret[MAX_DIGEST_SIZE]; 
+    byte client_write_key[AES_256_KEY_SIZE];         /* max sizes */
+    byte server_write_key[AES_256_KEY_SIZE]; 
+    byte client_write_IV[AES_IV_SIZE];               /* max sizes */
+    byte server_write_IV[AES_IV_SIZE];
+#ifdef HAVE_AEAD
+    byte aead_exp_IV[AEAD_EXP_IV_SZ];
+    byte aead_enc_imp_IV[AEAD_IMP_IV_SZ];
+    byte aead_dec_imp_IV[AEAD_IMP_IV_SZ];
+#endif
+
+    word32 peer_sequence_number;
+    word32 sequence_number;
+    
+#ifdef CYASSL_DTLS
+    DtlsState dtls_state;                       /* Peer's state */
+    word16 dtls_peer_handshake_number;
+    word16 dtls_expected_peer_handshake_number;
+
+    word16 dtls_epoch;                          /* Current tx epoch    */
+    word32 dtls_sequence_number;                /* Current tx sequence */
+    word16 dtls_handshake_number;               /* Current tx handshake seq */
+#endif
+
+    word32 encryptSz;             /* last size of encrypted data   */
+    word32 padSz;                 /* how much to advance after decrypt part */
+    byte   encryptionOn;          /* true after change cipher spec */
+    byte   decryptedCur;          /* only decrypt current record once */
+} Keys;
+
+
+/* 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 int (*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
+#ifdef HAVE_PK_CALLBACKS
+    #ifdef HAVE_ECC
+        buffer peerEccDsaKey;              /* we own for Ecc Verify Callbacks */
+    #endif /* HAVE_ECC */
+    #ifndef NO_RSA
+        buffer peerRsaKey;                 /* we own for Rsa Verify Callbacks */
+    #endif /* NO_RSA */
+#endif /* HAVE_PK_CALLBACKS */
+} Buffers;
+
+typedef struct Options {
+    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
+
+#ifndef MAX_DATE_SZ
+#define MAX_DATE_SZ 32
+#endif
+
+struct CYASSL_X509_NAME {
+    char  *name;
+    char  staticName[ASN_NAME_MAX];
+    int   dynamicName;
+    int   sz;
+#ifdef OPENSSL_EXTRA
+    DecodedName fullName;
+#endif /* OPENSSL_EXTRA */
+};
+
+#ifndef EXTERNAL_SERIAL_SIZE
+    #define EXTERNAL_SERIAL_SIZE 32
+#endif
+
+#ifdef NO_ASN 
+    typedef struct DNS_entry DNS_entry;
+#endif
+
+struct CYASSL_X509 {
+    int              version;
+    CYASSL_X509_NAME issuer;
+    CYASSL_X509_NAME subject;
+    int              serialSz;
+    byte             serial[EXTERNAL_SERIAL_SIZE];
+    char             subjectCN[ASN_NAME_MAX];        /* common name short cut */
+#ifdef CYASSL_SEP
+    int              deviceTypeSz;
+    byte             deviceType[EXTERNAL_SERIAL_SIZE];
+    int              hwTypeSz;
+    byte             hwType[EXTERNAL_SERIAL_SIZE];
+    int              hwSerialNumSz;
+    byte             hwSerialNum[EXTERNAL_SERIAL_SIZE];
+    #ifdef OPENSSL_EXTRA
+        byte             certPolicySet;
+        byte             certPolicyCrit;
+    #endif /* OPENSSL_EXTRA */
+#endif
+    int              notBeforeSz;
+    byte             notBefore[MAX_DATE_SZ];
+    int              notAfterSz;
+    byte             notAfter[MAX_DATE_SZ];
+    int              sigOID;
+    buffer           sig;
+    int              pubKeyOID;
+    buffer           pubKey;
+    #ifdef HAVE_ECC
+        word32       pkCurveOID;
+    #endif /* HAVE_ECC */
+    buffer           derCert;                        /* may need  */
+    DNS_entry*       altNames;                       /* alt names list */
+    DNS_entry*       altNamesNext;                   /* hint for retrieval */
+    byte             dynamicMemory;                  /* dynamic memory flag */
+    byte             isCa;
+#ifdef OPENSSL_EXTRA
+    word32           pathLength;
+    word16           keyUsage;
+    byte             basicConstSet;
+    byte             basicConstCrit;
+    byte             basicConstPlSet;
+    byte             subjAltNameSet;
+    byte             subjAltNameCrit;
+    byte             authKeyIdSet;
+    byte             authKeyIdCrit;
+    byte*            authKeyId;
+    word32           authKeyIdSz;
+    byte             subjKeyIdSet;
+    byte             subjKeyIdCrit;
+    byte*            subjKeyId;
+    word32           subjKeyIdSz;
+    byte             keyUsageSet;
+    byte             keyUsageCrit;
+#endif /* OPENSSL_EXTRA */
+};
+
+
+/* record layer header for PlainText, Compressed, and CipherText */
+typedef struct RecordLayerHeader {
+    byte            type;
+    byte            pvMajor;
+    byte            pvMinor;
+    byte            length[2];
+} RecordLayerHeader;
+
+
+/* record layer header for DTLS PlainText, Compressed, and CipherText */
+typedef struct DtlsRecordLayerHeader {
+    byte            type;
+    byte            pvMajor;
+    byte            pvMinor;
+    byte            epoch[2];             /* increment on cipher state change */
+    byte            sequence_number[6];   /* per record */
+    byte            length[2];
+} DtlsRecordLayerHeader;
+
+
+typedef struct DtlsPool {
+    buffer          buf[DTLS_POOL_SZ];
+    int             used;
+} DtlsPool;
+
+typedef struct DtlsMsg {
+    struct DtlsMsg* next;
+    word32          seq;       /* Handshake sequence number    */
+    word32          sz;        /* Length of whole mesage       */
+    word32          fragSz;    /* Length of fragments received */
+    byte            type;
+    byte*           buf;
+    byte*           msg;
+} DtlsMsg;
+
+
+#ifdef HAVE_NETX
+
+    /* NETX I/O Callback default */
+    typedef struct NetX_Ctx {
+        NX_TCP_SOCKET* nxSocket;    /* send/recv socket handle */
+        NX_PACKET*     nxPacket;    /* incoming packet handle for short reads */
+        ULONG          nxOffset;    /* offset already read from nxPacket */
+        ULONG          nxWait;      /* wait option flag */
+    } NetX_Ctx;
+
+#endif
+
+
+/* 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 */
+    word32          pkCurveOID;              /* curve Ecc_Sum     */
+    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 */
+#ifdef HAVE_MAX_FRAGMENT
+    word16 max_fragment;
+#endif
+#ifdef HAVE_TRUNCATED_HMAC
+    byte truncated_hmac;
+#endif
+#endif
+#ifdef HAVE_NETX
+    NetX_Ctx        nxCtx;             /* NetX IO Context */
+#endif
+#ifdef SESSION_INDEX
+    int sessionIndex;                  /* Session's location in the cache. */
+#endif
+    CYASSL_ALERT_HISTORY alert_history;
+#ifdef ATOMIC_USER
+    void*    MacEncryptCtx;    /* Atomic User Mac/Encrypt Callback Context */
+    void*    DecryptVerifyCtx; /* Atomic User Decrypt/Verify Callback Context */
+#endif
+#ifdef HAVE_PK_CALLBACKS
+    #ifdef HAVE_ECC
+        void* EccSignCtx;     /* Ecc Sign   Callback Context */
+        void* EccVerifyCtx;   /* Ecc Verify Callback Context */
+    #endif /* HAVE_ECC */
+    #ifndef NO_RSA 
+        void* RsaSignCtx;     /* Rsa Sign   Callback Context */
+        void* RsaVerifyCtx;   /* Rsa Verify Callback Context */
+        void* RsaEncCtx;      /* Rsa Public  Encrypt   Callback Context */
+        void* RsaDecCtx;      /* Rsa Private Decrypt   Callback Context */
+    #endif /* NO_RSA */
+#endif /* HAVE_PK_CALLBACKS */
+};
+
+
+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
+};
+
+
+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 int  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 int  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 InitX509Name(CYASSL_X509_NAME*, int);
+CYASSL_LOCAL void FreeX509Name(CYASSL_X509_NAME* name);
+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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,52 @@
+/* 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  InitOCSP(CYASSL_OCSP*, CYASSL_CERT_MANAGER*);
+CYASSL_LOCAL void FreeOCSP(CYASSL_OCSP*, int dynamic);
+
+CYASSL_LOCAL int  CheckCertOCSP(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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,2 @@
+/* asn1.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/bio.h	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,2 @@
+/* conf.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/crypto.h	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,2 @@
+/* ec.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/ecdsa.h	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,2 @@
+/* ecdsa.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/engine.h	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,2 @@
+/* err.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/evp.h	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,2 @@
+/* lhash.h for openSSL */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/md4.h	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,1 @@
+/* md4.h for libcurl */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/md5.h	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,1 @@
+/* ocsp.h for libcurl */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/opensslconf.h	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,2 @@
+/* pkcs12.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/rand.h	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,2 @@
+/* stack.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/ui.h	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,2 @@
+/* ui.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/openssl/x509.h	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,2 @@
+/* x509v3.h for openssl */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/options.h	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,110 @@
+/* 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
+#define BAD_DECRYPT    70 
+
+/* !!!! 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	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,1304 @@
+/* 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 */
+    int pkey_sz;
+    union {
+        char* ptr;
+    } pkey;
+    #ifdef HAVE_ECC
+        int pkey_curve;
+    #endif
+} 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_CERT_MANAGER* cm;
+} 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_STORE* store;    /* Store full of a CA cert chain */
+    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;
+
+
+/* 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
+};
+
+
+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);
+
+#ifdef SESSION_INDEX
+CYASSL_API int CyaSSL_GetSessionIndex(CYASSL* ssl);
+CYASSL_API int CyaSSL_GetSessionAtIndex(int index, CYASSL_SESSION* session);
+#endif /* SESSION_INDEX */
+
+#if defined(SESSION_INDEX) && defined(SESSION_CERTS)
+CYASSL_API 
+    CYASSL_X509_CHAIN* CyaSSL_SESSION_get_peer_chain(CYASSL_SESSION* session);
+#endif /* SESSION_INDEX && SESSION_CERTS */
+
+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 int  CyaSSL_X509_ext_isSet_by_NID(CYASSL_X509*, int);
+CYASSL_API int  CyaSSL_X509_ext_get_critical_by_NID(CYASSL_X509*, int);
+CYASSL_API int  CyaSSL_X509_get_isCA(CYASSL_X509*);
+CYASSL_API int  CyaSSL_X509_get_isSet_pathLength(CYASSL_X509*);
+CYASSL_API unsigned int CyaSSL_X509_get_pathLength(CYASSL_X509*);
+CYASSL_API unsigned int CyaSSL_X509_get_keyUsage(CYASSL_X509*);
+CYASSL_API unsigned char* CyaSSL_X509_get_authorityKeyID(
+                                            CYASSL_X509*, unsigned char*, int*);
+CYASSL_API unsigned char* CyaSSL_X509_get_subjectKeyID(
+                                            CYASSL_X509*, unsigned char*, int*);
+CYASSL_API int CyaSSL_X509_NAME_entry_count(CYASSL_X509_NAME*);
+CYASSL_API int CyaSSL_X509_NAME_get_text_by_NID(
+                                            CYASSL_X509_NAME*, int, char*, int);
+CYASSL_API int         CyaSSL_X509_verify_cert(CYASSL_X509_STORE_CTX*);
+CYASSL_API const char* CyaSSL_X509_verify_cert_error_string(long);
+CYASSL_API int CyaSSL_X509_get_signature_type(CYASSL_X509*);
+CYASSL_API int CyaSSL_X509_get_signature(CYASSL_X509*, unsigned char*, int*);
+
+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 void         CyaSSL_X509_STORE_free(CYASSL_X509_STORE*);
+CYASSL_API int          CyaSSL_X509_STORE_add_cert(
+                                              CYASSL_X509_STORE*, CYASSL_X509*);
+CYASSL_API int          CyaSSL_X509_STORE_set_default_paths(CYASSL_X509_STORE*);
+CYASSL_API int          CyaSSL_X509_STORE_get_by_subject(CYASSL_X509_STORE_CTX*,
+                                   int, CYASSL_X509_NAME*, CYASSL_X509_OBJECT*);
+CYASSL_API CYASSL_X509_STORE_CTX* CyaSSL_X509_STORE_CTX_new(void);
+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_free(CYASSL_X509_STORE_CTX*);
+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_OCSP_URL_OVERRIDE = 1,
+    CYASSL_OCSP_NO_NONCE     = 2,
+
+    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 */
+
+#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_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 const unsigned char* CyaSSL_X509_notBefore(CYASSL_X509*);
+CYASSL_API const unsigned char* CyaSSL_X509_notAfter(CYASSL_X509*);
+CYASSL_API int CyaSSL_X509_version(CYASSL_X509*);
+CYASSL_API 
+
+CYASSL_API int CyaSSL_cmp_peer_cert_to_file(CYASSL*, const char*);
+
+CYASSL_API char* CyaSSL_X509_get_next_altname(CYASSL_X509*);
+
+CYASSL_API CYASSL_X509*
+    CyaSSL_X509_d2i(CYASSL_X509** x509, const unsigned char* in, int len);
+#ifndef NO_FILESYSTEM
+    #ifndef NO_STDIO_FILESYSTEM
+    CYASSL_API CYASSL_X509*
+        CyaSSL_X509_d2i_fp(CYASSL_X509** x509, FILE* file);
+    #endif
+CYASSL_API CYASSL_X509*
+    CyaSSL_X509_load_certificate_file(const char* fname, int format);
+#endif
+
+#ifdef CYASSL_SEP
+    CYASSL_API unsigned char*
+           CyaSSL_X509_get_device_type(CYASSL_X509*, unsigned char*, int*);
+    CYASSL_API unsigned char*
+           CyaSSL_X509_get_hw_type(CYASSL_X509*, unsigned char*, int*);
+    CYASSL_API unsigned char*
+           CyaSSL_X509_get_hw_serial_number(CYASSL_X509*, unsigned char*, int*);
+#endif
+
+/* 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);
+    CYASSL_API int CyaSSL_UnloadCertsKeys(CYASSL*);
+#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_GetIOReadCtx( CYASSL* ssl);
+CYASSL_API void* CyaSSL_GetIOWriteCtx(CYASSL* ssl);
+
+CYASSL_API void CyaSSL_SetIOReadFlags( CYASSL* ssl, int flags);
+CYASSL_API void CyaSSL_SetIOWriteFlags(CYASSL* ssl, int flags);
+
+#ifdef HAVE_NETX
+    CYASSL_API void CyaSSL_SetIO_NetX(CYASSL* ssl, NX_TCP_SOCKET* nxsocket,
+                                      ULONG waitoption);
+#endif
+
+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);
+CYASSL_API void* CyaSSL_GetCookieCtx(CYASSL* ssl);
+
+
+/* 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*);
+CYASSL_API int CyaSSL_CertPemToDer(const unsigned char*, int sz, unsigned char*,
+                                   int, int);
+
+typedef void (*CallbackCACache)(unsigned char* der, int sz, int type);
+typedef void (*CbMissingCRL)(const char* url);
+typedef int  (*CbOCSPIO)(void*, const char*, int,
+                                         unsigned char*, int, unsigned char**);
+typedef void (*CbOCSPRespFree)(void*,unsigned char*);
+
+/* User Atomic Record Layer CallBacks */
+typedef int (*CallbackMacEncrypt)(CYASSL* ssl, unsigned char* macOut, 
+       const unsigned char* macIn, unsigned int macInSz, int macContent, 
+       int macVerify, unsigned char* encOut, const unsigned char* encIn,
+       unsigned int encSz, void* ctx);
+CYASSL_API void  CyaSSL_CTX_SetMacEncryptCb(CYASSL_CTX*, CallbackMacEncrypt);
+CYASSL_API void  CyaSSL_SetMacEncryptCtx(CYASSL* ssl, void *ctx);
+CYASSL_API void* CyaSSL_GetMacEncryptCtx(CYASSL* ssl);
+
+typedef int (*CallbackDecryptVerify)(CYASSL* ssl, 
+       unsigned char* decOut, const unsigned char* decIn,
+       unsigned int decSz, int content, int verify, unsigned int* padSz,
+       void* ctx);
+CYASSL_API void  CyaSSL_CTX_SetDecryptVerifyCb(CYASSL_CTX*,
+                                               CallbackDecryptVerify);
+CYASSL_API void  CyaSSL_SetDecryptVerifyCtx(CYASSL* ssl, void *ctx);
+CYASSL_API void* CyaSSL_GetDecryptVerifyCtx(CYASSL* ssl);
+
+CYASSL_API const unsigned char* CyaSSL_GetMacSecret(CYASSL*, int);
+CYASSL_API const unsigned char* CyaSSL_GetClientWriteKey(CYASSL*);
+CYASSL_API const unsigned char* CyaSSL_GetClientWriteIV(CYASSL*);
+CYASSL_API const unsigned char* CyaSSL_GetServerWriteKey(CYASSL*);
+CYASSL_API const unsigned char* CyaSSL_GetServerWriteIV(CYASSL*);
+CYASSL_API int                  CyaSSL_GetKeySize(CYASSL*);
+CYASSL_API int                  CyaSSL_GetIVSize(CYASSL*);
+CYASSL_API int                  CyaSSL_GetSide(CYASSL*);
+CYASSL_API int                  CyaSSL_IsTLSv1_1(CYASSL*);
+CYASSL_API int                  CyaSSL_GetBulkCipher(CYASSL*);
+CYASSL_API int                  CyaSSL_GetCipherBlockSize(CYASSL*);
+CYASSL_API int                  CyaSSL_GetAeadMacSize(CYASSL*);
+CYASSL_API int                  CyaSSL_GetHmacSize(CYASSL*);
+CYASSL_API int                  CyaSSL_GetHmacType(CYASSL*);
+CYASSL_API int                  CyaSSL_GetCipherType(CYASSL*);
+CYASSL_API int                  CyaSSL_SetTlsHmacInner(CYASSL*, unsigned char*,
+                                                       unsigned int, int, int);
+
+/* Atomic User Needs */
+enum {
+    CYASSL_SERVER_END = 0,
+    CYASSL_CLIENT_END = 1,
+    CYASSL_BLOCK_TYPE = 2,
+    CYASSL_STREAM_TYPE = 3,
+    CYASSL_AEAD_TYPE = 4,
+    CYASSL_TLS_HMAC_INNER_SZ = 13      /* SEQ_SZ + ENUM + VERSION_SZ + LEN_SZ */
+};
+
+/* for GetBulkCipher and internal use */
+enum BulkCipherAlgorithm { 
+    cyassl_cipher_null,
+    cyassl_rc4,
+    cyassl_rc2,
+    cyassl_des,
+    cyassl_triple_des,             /* leading 3 (3des) not valid identifier */
+    cyassl_des40,
+    cyassl_idea,
+    cyassl_aes,
+    cyassl_aes_gcm,
+    cyassl_aes_ccm,
+    cyassl_camellia,
+    cyassl_hc128,                  /* CyaSSL extensions */
+    cyassl_rabbit
+};
+
+
+/* Public Key Callback support */
+typedef int (*CallbackEccSign)(CYASSL* ssl, 
+       const unsigned char* in, unsigned int inSz,
+       unsigned char* out, unsigned int* outSz,
+       const unsigned char* keyDer, unsigned int keySz,
+       void* ctx);
+CYASSL_API void  CyaSSL_CTX_SetEccSignCb(CYASSL_CTX*, CallbackEccSign);
+CYASSL_API void  CyaSSL_SetEccSignCtx(CYASSL* ssl, void *ctx);
+CYASSL_API void* CyaSSL_GetEccSignCtx(CYASSL* ssl);
+
+typedef int (*CallbackEccVerify)(CYASSL* ssl, 
+       const unsigned char* sig, unsigned int sigSz,
+       const unsigned char* hash, unsigned int hashSz,
+       const unsigned char* keyDer, unsigned int keySz,
+       int* result, void* ctx);
+CYASSL_API void  CyaSSL_CTX_SetEccVerifyCb(CYASSL_CTX*, CallbackEccVerify);
+CYASSL_API void  CyaSSL_SetEccVerifyCtx(CYASSL* ssl, void *ctx);
+CYASSL_API void* CyaSSL_GetEccVerifyCtx(CYASSL* ssl);
+
+typedef int (*CallbackRsaSign)(CYASSL* ssl, 
+       const unsigned char* in, unsigned int inSz,
+       unsigned char* out, unsigned int* outSz,
+       const unsigned char* keyDer, unsigned int keySz,
+       void* ctx);
+CYASSL_API void  CyaSSL_CTX_SetRsaSignCb(CYASSL_CTX*, CallbackRsaSign);
+CYASSL_API void  CyaSSL_SetRsaSignCtx(CYASSL* ssl, void *ctx);
+CYASSL_API void* CyaSSL_GetRsaSignCtx(CYASSL* ssl);
+
+typedef int (*CallbackRsaVerify)(CYASSL* ssl, 
+       unsigned char* sig, unsigned int sigSz,
+       unsigned char** out,
+       const unsigned char* keyDer, unsigned int keySz,
+       void* ctx);
+CYASSL_API void  CyaSSL_CTX_SetRsaVerifyCb(CYASSL_CTX*, CallbackRsaVerify);
+CYASSL_API void  CyaSSL_SetRsaVerifyCtx(CYASSL* ssl, void *ctx);
+CYASSL_API void* CyaSSL_GetRsaVerifyCtx(CYASSL* ssl);
+
+/* RSA Public Encrypt cb */
+typedef int (*CallbackRsaEnc)(CYASSL* ssl, 
+       const unsigned char* in, unsigned int inSz,
+       unsigned char* out, unsigned int* outSz,
+       const unsigned char* keyDer, unsigned int keySz,
+       void* ctx);
+CYASSL_API void  CyaSSL_CTX_SetRsaEncCb(CYASSL_CTX*, CallbackRsaEnc);
+CYASSL_API void  CyaSSL_SetRsaEncCtx(CYASSL* ssl, void *ctx);
+CYASSL_API void* CyaSSL_GetRsaEncCtx(CYASSL* ssl);
+
+/* RSA Private Decrypt cb */
+typedef int (*CallbackRsaDec)(CYASSL* ssl, 
+       unsigned char* in, unsigned int inSz,
+       unsigned char** out,
+       const unsigned char* keyDer, unsigned int keySz,
+       void* ctx);
+CYASSL_API void  CyaSSL_CTX_SetRsaDecCb(CYASSL_CTX*, CallbackRsaDec);
+CYASSL_API void  CyaSSL_SetRsaDecCtx(CYASSL* ssl, void *ctx);
+CYASSL_API void* CyaSSL_GetRsaDecCtx(CYASSL* ssl);
+
+
+#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_CertManagerCheckOCSP(CYASSL_CERT_MANAGER*,
+                                                        unsigned char*, int sz);
+    CYASSL_API int CyaSSL_CertManagerEnableOCSP(CYASSL_CERT_MANAGER*,
+                                                                   int options);
+    CYASSL_API int CyaSSL_CertManagerDisableOCSP(CYASSL_CERT_MANAGER*);
+    CYASSL_API int CyaSSL_CertManagerSetOCSPOverrideURL(CYASSL_CERT_MANAGER*,
+                                                                   const char*);
+    CYASSL_API int CyaSSL_CertManagerSetOCSP_Cb(CYASSL_CERT_MANAGER*,
+                                               CbOCSPIO, CbOCSPRespFree, void*);
+
+    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_EnableOCSP(CYASSL*, int options);
+    CYASSL_API int CyaSSL_DisableOCSP(CYASSL*);
+    CYASSL_API int CyaSSL_SetOCSP_OverrideURL(CYASSL*, const char*);
+    CYASSL_API int CyaSSL_SetOCSP_Cb(CYASSL*, CbOCSPIO, CbOCSPRespFree, void*);
+
+    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);
+    CYASSL_API int CyaSSL_CTX_EnableOCSP(CYASSL_CTX*, int options);
+    CYASSL_API int CyaSSL_CTX_DisableOCSP(CYASSL_CTX*);
+    CYASSL_API int CyaSSL_CTX_SetOCSP_OverrideURL(CYASSL_CTX*, const char*);
+    CYASSL_API int CyaSSL_CTX_SetOCSP_Cb(CYASSL_CTX*,
+                                               CbOCSPIO, CbOCSPRespFree, void*);
+#endif /* !NO_CERTS */
+
+/* end of handshake frees temporary arrays, if user needs for get_keys or
+   psk hints, call KeepArrays before handshake and then FreeArrays when done
+   if don't want to wait for object free */
+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 */
+
+/* Server Name Indication */
+#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 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);
+
+/* SNI status */
+enum {
+    CYASSL_SNI_NO_MATCH   = 0,
+    CYASSL_SNI_FAKE_MATCH = 1, /* if CYASSL_SNI_ANSWER_ON_MISMATCH is enabled */
+    CYASSL_SNI_REAL_MATCH = 2
+};
+
+CYASSL_API unsigned char CyaSSL_SNI_Status(CYASSL* ssl, unsigned char type);
+
+CYASSL_API unsigned short CyaSSL_SNI_GetRequest(CYASSL *ssl, unsigned char type,
+                                                                   void** data);
+
+CYASSL_API int CyaSSL_SNI_GetFromBuffer(
+                 const unsigned char* clientHello, unsigned int helloSz,
+                 unsigned char type, unsigned char* sni, unsigned int* inOutSz);
+
+#endif /* NO_CYASSL_SERVER */
+#endif /* HAVE_SNI */
+
+/* Maximum Fragment Length */
+#ifdef HAVE_MAX_FRAGMENT
+/* Fragment lengths */
+enum {
+    CYASSL_MFL_2_9  = 1, /*  512 bytes */
+    CYASSL_MFL_2_10 = 2, /* 1024 bytes */
+    CYASSL_MFL_2_11 = 3, /* 2048 bytes */
+    CYASSL_MFL_2_12 = 4, /* 4096 bytes */
+    CYASSL_MFL_2_13 = 5  /* 8192 bytes *//* CyaSSL ONLY!!! */
+};
+
+#ifndef NO_CYASSL_CLIENT
+
+CYASSL_API int CyaSSL_UseMaxFragment(CYASSL* ssl, unsigned char mfl);
+CYASSL_API int CyaSSL_CTX_UseMaxFragment(CYASSL_CTX* ctx, unsigned char mfl);
+
+#endif /* NO_CYASSL_CLIENT */
+#endif /* HAVE_MAX_FRAGMENT */
+
+/* Truncated HMAC */
+#ifdef HAVE_TRUNCATED_HMAC
+#ifndef NO_CYASSL_CLIENT
+
+CYASSL_API int CyaSSL_UseTruncatedHMAC(CYASSL* ssl);
+CYASSL_API int CyaSSL_CTX_UseTruncatedHMAC(CYASSL_CTX* ctx);
+
+#endif /* NO_CYASSL_CLIENT */
+#endif /* HAVE_TRUNCATED_HMAC */
+
+/* Elliptic Curves */
+#ifdef HAVE_SUPPORTED_CURVES
+
+enum {
+    CYASSL_ECC_SECP160R1 = 0x10,
+    CYASSL_ECC_SECP192R1 = 0x13,
+    CYASSL_ECC_SECP224R1 = 0x15,
+    CYASSL_ECC_SECP256R1 = 0x17,
+    CYASSL_ECC_SECP384R1 = 0x18,
+    CYASSL_ECC_SECP521R1 = 0x19
+};
+
+#ifndef NO_CYASSL_CLIENT
+
+CYASSL_API int CyaSSL_UseSupportedCurve(CYASSL* ssl, unsigned short name);
+CYASSL_API int CyaSSL_CTX_UseSupportedCurve(CYASSL_CTX* ctx,
+                                                          unsigned short name);
+
+#endif /* NO_CYASSL_CLIENT */
+#endif /* HAVE_SUPPORTED_CURVES */
+
+
+#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 */
+
+
+#ifdef CYASSL_HAVE_WOLFSCEP
+    CYASSL_API void CyaSSL_wolfSCEP(void);
+#endif /* CYASSL_HAVE_WOLFSCEP */
+
+#ifdef CYASSL_HAVE_CERT_SERVICE
+    CYASSL_API void CyaSSL_cert_service(void);
+#endif
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+
+#endif /* CYASSL_SSL_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyassl/test.h	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,1709 @@
+/* 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 ATOMIC_USER
+    #include <cyassl/ctaocrypt/aes.h>
+    #include <cyassl/ctaocrypt/arc4.h>
+    #include <cyassl/ctaocrypt/hmac.h>
+#endif
+#ifdef HAVE_PK_CALLBACKS
+    #include <cyassl/ctaocrypt/random.h>
+    #include <cyassl/ctaocrypt/asn.h>
+    #ifdef HAVE_ECC
+        #include <cyassl/ctaocrypt/ecc.h>
+    #endif /* HAVE_ECC */
+#endif /*HAVE_PK_CALLBACKS */
+
+#ifdef USE_WINDOWS_API 
+    #include <winsock2.h>
+    #include <process.h>
+    #ifdef TEST_IPV6            /* don't require newer SDK for IPV4 */
+        #include <ws2tcpip.h>
+        #include <wspiapi.h>
+    #endif
+    #define SOCKET_T SOCKET
+    #define SNPRINTF _snprintf
+#elif defined(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) && !defined(CYASSL_IAR_ARM)
+    typedef socklen_t* ACCEPT_THIRD_T;
+#else
+    #if defined _XOPEN_SOURCE_EXTENDED
+        typedef socklen_t* ACCEPT_THIRD_T;
+    #else
+        typedef int*       ACCEPT_THIRD_T;
+    #endif
+#endif
+
+
+#ifdef USE_WINDOWS_API 
+    #define CloseSocket(s) closesocket(s)
+    #define StartTCP() { WSADATA wsd; WSAStartup(0x0002, &wsd); }
+#elif defined(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 {
+    word16 ready;              /* predicate */
+    word16 port;
+#if defined(_POSIX_THREADS) && !defined(__MINGW32__)
+    pthread_mutex_t mutex;
+    pthread_cond_t  cond;
+#endif
+} tcp_ready;    
+
+
+void InitTcpReady(tcp_ready*);
+void FreeTcpReady(tcp_ready*);
+
+typedef CYASSL_METHOD* (*method_provider)(void);
+typedef void (*ctx_callback)(CYASSL_CTX* ctx);
+typedef void (*ssl_callback)(CYASSL* ssl);
+
+typedef struct callback_functions {
+    method_provider method;
+    ctx_callback ctx_ready;
+    ssl_callback ssl_ready;
+    ssl_callback on_result;
+} callback_functions;
+
+typedef struct func_args {
+    int    argc;
+    char** argv;
+    int    return_code;
+    tcp_ready* signal;
+    callback_functions *callbacks;
+} func_args;
+
+void wait_tcp_ready(func_args*);
+
+typedef THREAD_RETURN 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);
+    if (msg)
+        exit(EXIT_FAILURE);
+}
+
+
+#define MY_EX_USAGE 2
+
+extern int   myoptind;
+extern char* myoptarg;
+
+static INLINE int mygetopt(int argc, char** argv, const char* optstring)
+{
+    static char* next = NULL;
+
+    char  c;
+    char* cp;
+
+    if (myoptind == 0)
+        next = NULL;   /* we're starting new/over */
+
+    if (next == NULL || *next == '\0') {
+        if (myoptind == 0)
+            myoptind++;
+
+        if (myoptind >= argc || argv[myoptind][0] != '-' ||
+                                argv[myoptind][1] == '\0') {
+            myoptarg = NULL;
+            if (myoptind < argc)
+                myoptarg = argv[myoptind];
+
+            return -1;
+        }
+
+        if (strcmp(argv[myoptind], "--") == 0) {
+            myoptind++;
+            myoptarg = NULL;
+
+            if (myoptind < argc)
+                myoptarg = argv[myoptind];
+
+            return -1;
+        }
+
+        next = argv[myoptind];
+        next++;                  /* skip - */
+        myoptind++;
+    }
+
+    c  = *next++;
+    /* The C++ strchr can return a different value */
+    cp = (char*)strchr(optstring, c);
+
+    if (cp == NULL || c == ':') 
+        return '?';
+
+    cp++;
+
+    if (*cp == ':') {
+        if (*next != '\0') {
+            myoptarg = next;
+            next     = NULL;
+        }
+        else if (myoptind < argc) {
+            myoptarg = argv[myoptind];
+            myoptind++;
+        }
+        else 
+            return '?';
+    }
+
+    return c;
+}
+
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+
+static INLINE int PasswordCallBack(char* passwd, int sz, int rw, void* userdata)
+{
+    (void)rw;
+    (void)userdata;
+    strncpy(passwd, "yassl123", sz);
+    return 8;
+}
+
+#endif
+
+
+#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
+
+static INLINE void ShowX509(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, word16* port, int useAnyAddr,
+                              int udp)
+{
+    SOCKADDR_IN_T addr;
+
+    /* don't use INADDR_ANY by default, firewall may block, make user switch
+       on */
+    build_addr(&addr, (useAnyAddr ? INADDR_ANY : 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, word16 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, word16 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)
+{
+    (void)preverify;
+    char buffer[CYASSL_MAX_ERROR_SZ];
+
+#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*)ptr;
+        --mt;   /* same as minus sizeof(memoryTrack), removes header */
+
+#ifdef DO_MEM_STATS 
+        ourMemStats.currentBytes -= mt->u.hint.thisSize; 
+#endif
+
+        free(mt);
+    }
+
+
+    static INLINE void* TrackRealloc(void* ptr, size_t sz)
+    {
+        void* ret = TrackMalloc(sz);
+
+        if (ptr) {
+            /* if realloc is bigger, don't overread old ptr */
+            memoryTrack* mt = (memoryTrack*)ptr;
+            --mt;  /* same as minus sizeof(memoryTrack), removes header */
+
+            if (mt->u.hint.thisSize < sz)
+                sz = mt->u.hint.thisSize;
+        }
+
+        if (ret && ptr)
+            memcpy(ret, ptr, sz);
+
+        if (ret)
+            TrackFree(ptr);
+
+        return ret;
+    }
+
+    static INLINE void InitMemoryTracker(void) 
+    {
+        if (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, 0x01, stackSize);
+
+    ret = pthread_attr_init(&myAttr);
+    if (ret != 0)
+        err_sys("attr_init failed");
+
+    ret = pthread_attr_setstack(&myAttr, myStack, stackSize);
+    if (ret != 0)
+        err_sys("attr_setstackaddr failed");
+
+    ret = pthread_create(&threadId, &myAttr, tf, args);
+    if (ret != 0) {
+        perror("pthread_create failed");
+        exit(EXIT_FAILURE);
+    }
+
+    ret = pthread_join(threadId, NULL);
+    if (ret != 0)
+        err_sys("pthread_join failed");
+
+    for (i = 0; i < stackSize; i++) {
+        if (myStack[i] != 0x01) {
+            break;
+        }
+    }
+
+    used = stackSize - i;
+    printf("stack used = %d\n", used);
+}
+
+
+#endif /* HAVE_STACK_SIZE */
+
+
+#ifdef STACK_TRAP
+
+/* good settings
+   --enable-debug --disable-shared C_EXTRA_FLAGS="-DUSER_TIME -DTFM_TIMING_RESISTANT -DPOSITIVE_EXP_ONLY -DSTACK_TRAP"
+
+*/
+
+#ifdef HAVE_STACK_SIZE
+    /* client only for now, setrlimit will fail if pthread_create() called */
+    /* STACK_SIZE does pthread_create() on client */
+    #error "can't use STACK_TRAP with STACK_SIZE, setrlimit will fail"
+#endif /* HAVE_STACK_SIZE */
+
+static INLINE void StackTrap(void)
+{
+    struct rlimit  rl;
+    if (getrlimit(RLIMIT_STACK, &rl) != 0)
+        err_sys("getrlimit failed");
+    printf("rlim_cur = %llu\n", rl.rlim_cur);
+    rl.rlim_cur = 1024*21;  /* adjust trap size here */
+    if (setrlimit(RLIMIT_STACK, &rl) != 0) {
+        perror("setrlimit");
+        err_sys("setrlimit failed");
+    }
+}
+
+#else /* STACK_TRAP */
+
+static INLINE void StackTrap(void)
+{
+}
+
+#endif /* STACK_TRAP */
+
+
+#ifdef ATOMIC_USER
+
+/* Atomic Encrypt Context example */
+typedef struct AtomicEncCtx {
+    int  keySetup;           /* have we done key setup yet */
+    Aes  aes;                /* for aes example */
+} AtomicEncCtx;
+
+
+/* Atomic Decrypt Context example */
+typedef struct AtomicDecCtx {
+    int  keySetup;           /* have we done key setup yet */
+    Aes  aes;                /* for aes example */
+} AtomicDecCtx;
+
+
+static INLINE int myMacEncryptCb(CYASSL* ssl, unsigned char* macOut, 
+       const unsigned char* macIn, unsigned int macInSz, int macContent, 
+       int macVerify, unsigned char* encOut, const unsigned char* encIn,
+       unsigned int encSz, void* ctx)
+{
+    int  ret;
+    Hmac hmac;
+    byte myInner[CYASSL_TLS_HMAC_INNER_SZ];
+    AtomicEncCtx* encCtx = (AtomicEncCtx*)ctx;
+    const char* tlsStr = "TLS";
+
+    /* example supports (d)tls aes */
+    if (CyaSSL_GetBulkCipher(ssl) != cyassl_aes) {
+        printf("myMacEncryptCb not using AES\n");
+        return -1;
+    }
+
+    if (strstr(CyaSSL_get_version(ssl), tlsStr) == NULL) {
+        printf("myMacEncryptCb not using (D)TLS\n");
+        return -1;
+    }
+
+    /* hmac, not needed if aead mode */
+    CyaSSL_SetTlsHmacInner(ssl, myInner, macInSz, macContent, macVerify);
+
+    ret = HmacSetKey(&hmac, CyaSSL_GetHmacType(ssl),
+               CyaSSL_GetMacSecret(ssl, macVerify), CyaSSL_GetHmacSize(ssl));
+    if (ret != 0)
+        return ret;
+    HmacUpdate(&hmac, myInner, sizeof(myInner));
+    HmacUpdate(&hmac, macIn, macInSz);
+    HmacFinal(&hmac, macOut);
+
+
+    /* encrypt setup on first time */
+    if (encCtx->keySetup == 0) {
+        int   keyLen = CyaSSL_GetKeySize(ssl);
+        const byte* key;
+        const byte* iv;
+
+        if (CyaSSL_GetSide(ssl) == CYASSL_CLIENT_END) {
+            key = CyaSSL_GetClientWriteKey(ssl);
+            iv  = CyaSSL_GetClientWriteIV(ssl);
+        }
+        else {
+            key = CyaSSL_GetServerWriteKey(ssl);
+            iv  = CyaSSL_GetServerWriteIV(ssl);
+        }
+
+        ret = AesSetKey(&encCtx->aes, key, keyLen, iv, AES_ENCRYPTION);
+        if (ret != 0) {
+            printf("AesSetKey failed in myMacEncryptCb\n");
+            return ret;
+        }
+        encCtx->keySetup = 1;
+    }
+
+    /* encrypt */
+    return AesCbcEncrypt(&encCtx->aes, encOut, encIn, encSz);
+}
+
+
+static INLINE int myDecryptVerifyCb(CYASSL* ssl, 
+       unsigned char* decOut, const unsigned char* decIn,
+       unsigned int decSz, int macContent, int macVerify,
+       unsigned int* padSz, void* ctx)
+{
+    AtomicDecCtx* decCtx = (AtomicDecCtx*)ctx;
+    int ret      = 0;
+    int macInSz  = 0;
+    int ivExtra  = 0;
+    int digestSz = CyaSSL_GetHmacSize(ssl);
+    unsigned int pad     = 0;
+    unsigned int padByte = 0;
+    Hmac hmac;
+    byte myInner[CYASSL_TLS_HMAC_INNER_SZ];
+    byte verify[MAX_DIGEST_SIZE];
+    const char* tlsStr = "TLS";
+
+    /* example supports (d)tls aes */
+    if (CyaSSL_GetBulkCipher(ssl) != cyassl_aes) {
+        printf("myMacEncryptCb not using AES\n");
+        return -1;
+    }
+
+    if (strstr(CyaSSL_get_version(ssl), tlsStr) == NULL) {
+        printf("myMacEncryptCb not using (D)TLS\n");
+        return -1;
+    }
+
+    /*decrypt */
+    if (decCtx->keySetup == 0) {
+        int   keyLen = CyaSSL_GetKeySize(ssl);
+        const byte* key;
+        const byte* iv;
+
+        /* decrypt is from other side (peer) */
+        if (CyaSSL_GetSide(ssl) == CYASSL_SERVER_END) {
+            key = CyaSSL_GetClientWriteKey(ssl);
+            iv  = CyaSSL_GetClientWriteIV(ssl);
+        }
+        else {
+            key = CyaSSL_GetServerWriteKey(ssl);
+            iv  = CyaSSL_GetServerWriteIV(ssl);
+        }
+
+        ret = AesSetKey(&decCtx->aes, key, keyLen, iv, AES_DECRYPTION);
+        if (ret != 0) {
+            printf("AesSetKey failed in myDecryptVerifyCb\n");
+            return ret;
+        }
+        decCtx->keySetup = 1;
+    }
+
+    /* decrypt */
+    ret = AesCbcDecrypt(&decCtx->aes, decOut, decIn, decSz);
+
+    if (CyaSSL_GetCipherType(ssl) == CYASSL_AEAD_TYPE) {
+        *padSz = CyaSSL_GetAeadMacSize(ssl);
+        return 0; /* hmac, not needed if aead mode */
+    }
+
+    if (CyaSSL_GetCipherType(ssl) == CYASSL_BLOCK_TYPE) {
+        pad     = *(decOut + decSz - 1);
+        padByte = 1;
+        if (CyaSSL_IsTLSv1_1(ssl))
+            ivExtra = CyaSSL_GetCipherBlockSize(ssl);
+    }
+
+    *padSz  = CyaSSL_GetHmacSize(ssl) + pad + padByte;
+    macInSz = decSz - ivExtra - digestSz - pad - padByte;
+
+    CyaSSL_SetTlsHmacInner(ssl, myInner, macInSz, macContent, macVerify);
+
+    ret = HmacSetKey(&hmac, CyaSSL_GetHmacType(ssl),
+               CyaSSL_GetMacSecret(ssl, macVerify), digestSz);
+    if (ret != 0)
+        return ret;
+    HmacUpdate(&hmac, myInner, sizeof(myInner));
+    HmacUpdate(&hmac, decOut + ivExtra, macInSz);
+    HmacFinal(&hmac, verify);
+
+    if (memcmp(verify, decOut + decSz - digestSz - pad - padByte,
+               digestSz) != 0) {
+        printf("myDecryptVerify verify failed\n");
+        return -1;
+    }
+
+    return ret;
+}
+
+
+static INLINE void SetupAtomicUser(CYASSL_CTX* ctx, CYASSL* ssl)
+{
+    AtomicEncCtx* encCtx;
+    AtomicDecCtx* decCtx;
+
+    encCtx = (AtomicEncCtx*)malloc(sizeof(AtomicEncCtx));
+    if (encCtx == NULL)
+        err_sys("AtomicEncCtx malloc failed");
+    memset(encCtx, 0, sizeof(AtomicEncCtx));
+
+    decCtx = (AtomicDecCtx*)malloc(sizeof(AtomicDecCtx));
+    if (decCtx == NULL) {
+        free(encCtx);
+        err_sys("AtomicDecCtx malloc failed");
+    }
+    memset(decCtx, 0, sizeof(AtomicDecCtx));
+
+    CyaSSL_CTX_SetMacEncryptCb(ctx, myMacEncryptCb);
+    CyaSSL_SetMacEncryptCtx(ssl, encCtx);
+
+    CyaSSL_CTX_SetDecryptVerifyCb(ctx, myDecryptVerifyCb);
+    CyaSSL_SetDecryptVerifyCtx(ssl, decCtx);
+}
+
+
+static INLINE void FreeAtomicUser(CYASSL* ssl)
+{
+    AtomicEncCtx* encCtx = CyaSSL_GetMacEncryptCtx(ssl);
+    AtomicDecCtx* decCtx = CyaSSL_GetDecryptVerifyCtx(ssl);
+
+    free(decCtx);
+    free(encCtx);
+}
+
+#endif /* ATOMIC_USER */
+
+
+#ifdef HAVE_PK_CALLBACKS
+
+#ifdef HAVE_ECC
+
+static INLINE int myEccSign(CYASSL* ssl, const byte* in, word32 inSz,
+        byte* out, word32* outSz, const byte* key, word32 keySz, void* ctx)
+{
+    RNG     rng;
+    int     ret;
+    word32  idx = 0;
+    ecc_key myKey;
+
+    (void)ssl;
+    (void)ctx;
+
+    InitRng(&rng);
+    ecc_init(&myKey);
+    
+    ret = EccPrivateKeyDecode(key, &idx, &myKey, keySz);    
+    if (ret == 0)
+        ret = ecc_sign_hash(in, inSz, out, outSz, &rng, &myKey);
+    ecc_free(&myKey);
+
+    return ret;
+}
+
+
+static INLINE int myEccVerify(CYASSL* ssl, const byte* sig, word32 sigSz,
+        const byte* hash, word32 hashSz, const byte* key, word32 keySz,
+        int* result, void* ctx)
+{
+    int     ret;
+    ecc_key myKey;
+
+    (void)ssl;
+    (void)ctx;
+
+    ecc_init(&myKey);
+    
+    ret = ecc_import_x963(key, keySz, &myKey);
+    if (ret == 0)
+        ret = ecc_verify_hash(sig, sigSz, hash, hashSz, result, &myKey);
+    ecc_free(&myKey);
+
+    return ret;
+}
+
+#endif /* HAVE_ECC */
+
+#ifndef NO_RSA
+
+static INLINE int myRsaSign(CYASSL* ssl, const byte* in, word32 inSz,
+        byte* out, word32* outSz, const byte* key, word32 keySz, void* ctx)
+{
+    RNG     rng;
+    int     ret;
+    word32  idx = 0;
+    RsaKey  myKey;
+
+    (void)ssl;
+    (void)ctx;
+
+    InitRng(&rng);
+    InitRsaKey(&myKey, NULL);
+    
+    ret = RsaPrivateKeyDecode(key, &idx, &myKey, keySz);    
+    if (ret == 0)
+        ret = RsaSSL_Sign(in, inSz, out, *outSz, &myKey, &rng);
+    if (ret > 0) {  /* save and convert to 0 success */
+        *outSz = ret;
+        ret = 0;
+    }
+    FreeRsaKey(&myKey);
+
+    return ret;
+}
+
+
+static INLINE int myRsaVerify(CYASSL* ssl, byte* sig, word32 sigSz,
+        byte** out,
+        const byte* key, word32 keySz,
+        void* ctx)
+{
+    int     ret;
+    word32  idx = 0;
+    RsaKey  myKey;
+
+    (void)ssl;
+    (void)ctx;
+
+    InitRsaKey(&myKey, NULL);
+    
+    ret = RsaPublicKeyDecode(key, &idx, &myKey, keySz);
+    if (ret == 0)
+        ret = RsaSSL_VerifyInline(sig, sigSz, out, &myKey);
+    FreeRsaKey(&myKey);
+
+    return ret;
+}
+
+
+static INLINE int myRsaEnc(CYASSL* ssl, const byte* in, word32 inSz,
+                           byte* out, word32* outSz, const byte* key,
+                           word32 keySz, void* ctx)
+{
+    int     ret;
+    word32  idx = 0;
+    RsaKey  myKey;
+    RNG     rng;
+
+    (void)ssl;
+    (void)ctx;
+
+    InitRng(&rng);
+    InitRsaKey(&myKey, NULL);
+    
+    ret = RsaPublicKeyDecode(key, &idx, &myKey, keySz);
+    if (ret == 0) {
+        ret = RsaPublicEncrypt(in, inSz, out, *outSz, &myKey, &rng);
+        if (ret > 0) {
+            *outSz = ret;
+            ret = 0;  /* reset to success */
+        }
+    }
+    FreeRsaKey(&myKey);
+
+    return ret;
+}
+
+static INLINE int myRsaDec(CYASSL* ssl, byte* in, word32 inSz,
+                           byte** out,
+                           const byte* key, word32 keySz, void* ctx)
+{
+    int     ret;
+    word32  idx = 0;
+    RsaKey  myKey;
+
+    (void)ssl;
+    (void)ctx;
+
+    InitRsaKey(&myKey, NULL);
+    
+    ret = RsaPrivateKeyDecode(key, &idx, &myKey, keySz);
+    if (ret == 0) {
+        ret = RsaPrivateDecryptInline(in, inSz, out, &myKey);
+    }
+    FreeRsaKey(&myKey);
+
+    return ret;
+}
+
+#endif /* NO_RSA */
+
+static INLINE void SetupPkCallbacks(CYASSL_CTX* ctx, CYASSL* ssl)
+{
+    (void)ctx;
+    (void)ssl;
+
+    #ifdef HAVE_ECC
+        CyaSSL_CTX_SetEccSignCb(ctx, myEccSign);
+        CyaSSL_CTX_SetEccVerifyCb(ctx, myEccVerify);
+    #endif /* HAVE_ECC */
+    #ifndef NO_RSA 
+        CyaSSL_CTX_SetRsaSignCb(ctx, myRsaSign);
+        CyaSSL_CTX_SetRsaVerifyCb(ctx, myRsaVerify);
+        CyaSSL_CTX_SetRsaEncCb(ctx, myRsaEnc);
+        CyaSSL_CTX_SetRsaDecCb(ctx, myRsaDec);
+    #endif /* NO_RSA */
+}
+
+#endif /* HAVE_PK_CALLBACKS */
+
+
+
+
+
+#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	Sun Apr 20 12:40:57 2014 +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.9.4"
+#define LIBCYASSL_VERSION_HEX 0x02009004
+
+#ifdef __cplusplus
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/crl.c	Sun Apr 20 12:40:57 2014 +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/error-ssl.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_E; 
+
+    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_E;
+    }
+
+    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_E;
+    }
+    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/src/internal.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,11096 @@
+/* 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/error-ssl.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*,
+                                                                        word32);
+    static int DoServerHello(CYASSL* ssl, const byte* input, word32*, word32);
+    static int DoServerKeyExchange(CYASSL* ssl, const byte* input, word32*,
+                                                                        word32);
+    #ifndef NO_CERTS
+        static int DoCertificateRequest(CYASSL* ssl, const byte* input, word32*,
+                                                                        word32);
+    #endif
+#endif
+
+
+#ifndef NO_CYASSL_SERVER
+    static int DoClientHello(CYASSL* ssl, const byte* input, 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
+
+
+#ifdef CYASSL_DTLS
+    static INLINE int DtlsCheckWindow(DtlsState* state);
+    static INLINE int DtlsUpdateWindow(DtlsState* state);
+#endif
+
+
+typedef enum {
+    doProcessInit = 0,
+#ifndef NO_CYASSL_SERVER
+    runProcessOldClientHello,
+#endif
+    getRecordLayerHeader,
+    getData,
+    runProcessingOneMessage
+} processReply;
+
+#ifndef NO_OLD_TLS
+static int SSL_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 = (word16) ((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       = CYASSL_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
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+    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 /* CYASSL_USER_IO */
+#ifdef HAVE_NETX
+    ctx->CBIORecv = NetX_Receive;
+    ctx->CBIOSend = NetX_Send;
+#endif
+    ctx->partialWrite   = 0;
+    ctx->verifyCallback = 0;
+
+#ifndef NO_CERTS
+    ctx->cm = CyaSSL_CertManagerNew();
+#endif
+#ifdef HAVE_NTRU
+    if (method->side == CYASSL_CLIENT_END)
+        ctx->haveNTRU = 1;           /* always on cliet side */
+                                     /* server can turn on by loading key */
+#endif
+#ifdef HAVE_ECC
+    if (method->side == CYASSL_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_CAVIUM
+    ctx->devId = NO_CAVIUM_DEVICE; 
+#endif
+#ifdef HAVE_TLS_EXTENSIONS
+    ctx->extensions = NULL;
+#endif
+#ifdef ATOMIC_USER
+    ctx->MacEncryptCb    = NULL;
+    ctx->DecryptVerifyCb = NULL;
+#endif
+#ifdef HAVE_PK_CALLBACKS
+    #ifdef HAVE_ECC
+        ctx->EccSignCb   = NULL;
+        ctx->EccVerifyCb = NULL;
+    #endif /* HAVE_ECC */
+    #ifndef NO_RSA 
+        ctx->RsaSignCb   = NULL;
+        ctx->RsaVerifyCb = NULL;
+        ctx->RsaEncCb    = NULL;
+        ctx->RsaDecCb    = NULL;
+    #endif /* NO_RSA */
+#endif /* HAVE_PK_CALLBACKS */
+
+    if (InitMutex(&ctx->countMutex) < 0) {
+        CYASSL_MSG("Mutex error on CTX init");
+        return BAD_MUTEX_E;
+    } 
+#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_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 HAVE_CAMELLIA
+    XFREE(ssl->encrypt.cam, ssl->heap, DYNAMIC_TYPE_CIPHER);
+    XFREE(ssl->decrypt.cam, ssl->heap, DYNAMIC_TYPE_CIPHER);
+#endif
+#ifdef HAVE_HC128
+    XFREE(ssl->encrypt.hc128, ssl->heap, DYNAMIC_TYPE_CIPHER);
+    XFREE(ssl->decrypt.hc128, ssl->heap, DYNAMIC_TYPE_CIPHER);
+#endif
+#ifdef BUILD_RABBIT
+    XFREE(ssl->encrypt.rabbit, ssl->heap, DYNAMIC_TYPE_CIPHER);
+    XFREE(ssl->decrypt.rabbit, ssl->heap, DYNAMIC_TYPE_CIPHER);
+#endif
+}
+
+
+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 == CYASSL_SERVER_END && haveStaticECC) {
+        haveRSA = 0;   /* can't do RSA with ECDSA key */
+        (void)haveRSA; /* some builds won't read */
+    }
+
+    if (side == CYASSL_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 HAVE_RENEGOTIATION_INDICATION
+    if (side == CYASSL_CLIENT_END) {
+        suites->suites[idx++] = 0;
+        suites->suites[idx++] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV;
+    }
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    if (tls && haveNTRU && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+    if (tls && haveNTRU && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+    if (tls && haveNTRU && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_RC4_128_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    if (tls && haveNTRU && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_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_MD5
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_HC_128_MD5;
+    }
+#endif
+    
+#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_HC_128_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_HC_128_B2B256;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_B2B256;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_B2B256;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_RABBIT_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+    if (tls && haveDH && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_WITH_RSA_CAMELLIA_256_CBC_SHA
+    if (tls && haveDH && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+    if (tls && haveDH && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
+    if (tls && haveDH && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256;
+    }
+#endif
+
+    suites->suiteSz = idx;
+
+    {
+        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
+
+
+void InitX509Name(CYASSL_X509_NAME* name, int dynamicFlag)
+{
+    (void)dynamicFlag;
+
+    if (name != NULL) {
+        name->name        = name->staticName;
+        name->dynamicName = 0;
+#ifdef OPENSSL_EXTRA
+        XMEMSET(&name->fullName, 0, sizeof(DecodedName));
+#endif /* OPENSSL_EXTRA */
+    }
+}
+
+
+void FreeX509Name(CYASSL_X509_NAME* name)
+{
+    if (name != NULL) {
+        if (name->dynamicName)
+            XFREE(name->name, NULL, DYNAMIC_TYPE_SUBJECT_CN);
+#ifdef OPENSSL_EXTRA
+        if (name->fullName.fullName != NULL)
+            XFREE(name->fullName.fullName, NULL, DYNAMIC_TYPE_X509);
+#endif /* OPENSSL_EXTRA */
+    }
+}
+
+
+/* Initialize CyaSSL X509 type */
+void InitX509(CYASSL_X509* x509, int dynamicFlag)
+{
+    InitX509Name(&x509->issuer, 0);
+    InitX509Name(&x509->subject, 0);
+    x509->version        = 0;
+    x509->pubKey.buffer  = NULL;
+    x509->sig.buffer     = NULL;
+    x509->derCert.buffer = NULL;
+    x509->altNames       = NULL;
+    x509->altNamesNext   = NULL;
+    x509->dynamicMemory  = (byte)dynamicFlag;
+    x509->isCa           = 0;
+#ifdef HAVE_ECC
+    x509->pkCurveOID = 0;
+#endif /* HAVE_ECC */
+#ifdef OPENSSL_EXTRA
+    x509->pathLength     = 0;
+    x509->basicConstSet  = 0;
+    x509->basicConstCrit = 0;
+    x509->basicConstPlSet = 0;
+    x509->subjAltNameSet = 0;
+    x509->subjAltNameCrit = 0;
+    x509->authKeyIdSet   = 0;
+    x509->authKeyIdCrit  = 0;
+    x509->authKeyId      = NULL;
+    x509->authKeyIdSz    = 0;
+    x509->subjKeyIdSet   = 0;
+    x509->subjKeyIdCrit  = 0;
+    x509->subjKeyId      = NULL;
+    x509->subjKeyIdSz    = 0;
+    x509->keyUsageSet    = 0;
+    x509->keyUsageCrit   = 0;
+    x509->keyUsage       = 0;
+    #ifdef CYASSL_SEP
+        x509->certPolicySet  = 0;
+        x509->certPolicyCrit = 0;
+    #endif /* CYASSL_SEP */
+#endif /* OPENSSL_EXTRA */
+}
+
+
+/* Free CyaSSL X509 type */
+void FreeX509(CYASSL_X509* x509)
+{
+    if (x509 == NULL)
+        return;
+
+    FreeX509Name(&x509->issuer);
+    FreeX509Name(&x509->subject);
+    if (x509->pubKey.buffer)
+        XFREE(x509->pubKey.buffer, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
+    XFREE(x509->derCert.buffer, NULL, DYNAMIC_TYPE_SUBJECT_CN);
+    XFREE(x509->sig.buffer, NULL, DYNAMIC_TYPE_SIGNATURE);
+    #ifdef OPENSSL_EXTRA
+        XFREE(x509->authKeyId, NULL, 0);
+        XFREE(x509->subjKeyId, NULL, 0);
+    #endif /* OPENSSL_EXTRA */
+    if (x509->altNames)
+        FreeAltNames(x509->altNames, NULL);
+    if (x509->dynamicMemory)
+        XFREE(x509, NULL, DYNAMIC_TYPE_X509);
+}
+
+#endif /* NO_CERTS */
+
+
+/* init everything to 0, NULL, default values before calling anything that may
+   fail so that desctructor has a "good" state to cleanup */
+int InitSSL(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 HAVE_PK_CALLBACKS
+    #ifdef HAVE_ECC
+        ssl->buffers.peerEccDsaKey.buffer = 0;
+        ssl->buffers.peerEccDsaKey.length = 0;
+    #endif /* HAVE_ECC */
+    #ifndef NO_RSA 
+        ssl->buffers.peerRsaKey.buffer = 0;
+        ssl->buffers.peerRsaKey.length = 0;
+    #endif /* NO_RSA */
+#endif /* HAVE_PK_CALLBACKS */
+
+#ifdef KEEP_PEER_CERT
+    InitX509(&ssl->peerCert, 0);
+#endif
+
+#ifdef HAVE_ECC
+    ssl->eccTempKeySz = ctx->eccTempKeySz;
+    ssl->pkCurveOID = ctx->pkCurveOID;
+    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 HAVE_NETX
+    ssl->nxCtx.nxSocket = NULL;
+    ssl->nxCtx.nxPacket = NULL;
+    ssl->nxCtx.nxOffset = 0;
+    ssl->nxCtx.nxWait   = 0;
+    ssl->IOCB_ReadCtx  = &ssl->nxCtx;  /* default NetX IO ctx, same for read */
+    ssl->IOCB_WriteCtx = &ssl->nxCtx;  /* and write */
+#endif
+#ifdef CYASSL_DTLS
+    ssl->IOCB_CookieCtx = NULL;      /* we don't use for default cb */
+    ssl->dtls_expected_rx = MAX_MTU;
+    ssl->keys.dtls_state.window = 0;
+    ssl->keys.dtls_state.nextEpoch = 0;
+    ssl->keys.dtls_state.nextSeq = 0;
+#endif
+
+#ifndef NO_OLD_TLS
+#ifndef NO_MD5
+    InitMd5(&ssl->hashMd5);
+#endif
+#ifndef NO_SHA
+    ret = InitSha(&ssl->hashSha);
+    if (ret != 0) {
+        return ret;
+    }
+#endif
+#endif
+#ifndef NO_SHA256
+    ret = InitSha256(&ssl->hashSha256);
+    if (ret != 0) {
+        return ret;
+    }
+#endif
+#ifdef CYASSL_SHA384
+    ret = InitSha384(&ssl->hashSha384);
+    if (ret != 0) {
+        return ret;
+    }
+#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 == CYASSL_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_state.curSeq         = 0;
+    ssl->keys.dtls_state.nextSeq        = 0;
+    ssl->keys.dtls_handshake_number     = 0;
+    ssl->keys.dtls_expected_peer_handshake_number = 0;
+    ssl->keys.dtls_epoch                = 0;
+    ssl->keys.dtls_state.curEpoch       = 0;
+    ssl->keys.dtls_state.nextEpoch      = 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.padSz        = 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 = SSL_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 == CYASSL_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;
+#ifdef HAVE_MAX_FRAGMENT
+    ssl->max_fragment = MAX_RECORD_SIZE;
+#endif
+#ifdef HAVE_TRUNCATED_HMAC
+    ssl->truncated_hmac = 0;
+#endif
+#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);
+#ifdef ATOMIC_USER
+    ssl->MacEncryptCtx    = NULL;
+    ssl->DecryptVerifyCtx = NULL;
+#endif
+#ifdef HAVE_PK_CALLBACKS
+    #ifdef HAVE_ECC
+        ssl->EccSignCtx   = NULL;
+        ssl->EccVerifyCtx = NULL;
+    #endif /* HAVE_ECC */
+    #ifndef NO_RSA 
+        ssl->RsaSignCtx   = NULL;
+        ssl->RsaVerifyCtx = NULL;
+        ssl->RsaEncCtx    = NULL;
+        ssl->RsaDecCtx    = NULL;
+    #endif /* NO_RSA */
+#endif /* HAVE_PK_CALLBACKS */
+
+    /* 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_E;
+    }
+    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;
+    }
+    XMEMSET(ssl->arrays, 0, sizeof(Arrays));
+
+#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;
+    }
+    ret = InitRsaKey(ssl->peerRsaKey, ctx->heap);
+    if (ret != 0) return ret;
+#endif
+#ifndef NO_CERTS
+    /* make sure server has cert and key unless using PSK */
+    if (ssl->options.side == CYASSL_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 == CYASSL_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 == CYASSL_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_PK_CALLBACKS
+    #ifdef HAVE_ECC
+        XFREE(ssl->buffers.peerEccDsaKey.buffer, ssl->heap, DYNAMIC_TYPE_ECC);
+    #endif /* HAVE_ECC */
+    #ifndef NO_RSA 
+        XFREE(ssl->buffers.peerRsaKey.buffer, ssl->heap, DYNAMIC_TYPE_RSA);
+    #endif /* NO_RSA */
+#endif /* HAVE_PK_CALLBACKS */
+#ifdef HAVE_TLS_EXTENSIONS
+    TLSX_FreeAll(ssl->extensions);
+#endif
+#ifdef HAVE_NETX
+    if (ssl->nxCtx.nxPacket)
+        nx_packet_release(ssl->nxCtx.nxPacket);
+#endif
+}
+
+
+/* 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
+#ifdef HAVE_PK_CALLBACKS
+    #ifdef HAVE_ECC
+        XFREE(ssl->buffers.peerEccDsaKey.buffer, ssl->heap, DYNAMIC_TYPE_ECC);
+        ssl->buffers.peerEccDsaKey.buffer = NULL;
+    #endif /* HAVE_ECC */
+    #ifndef NO_RSA 
+        XFREE(ssl->buffers.peerRsaKey.buffer, ssl->heap, DYNAMIC_TYPE_RSA);
+        ssl->buffers.peerRsaKey.buffer = NULL;
+    #endif /* NO_RSA */
+#endif /* HAVE_PK_CALLBACKS */
+}
+
+
+void FreeSSL(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);
+            if (cur != NULL) {
+                DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz);
+                head = DtlsMsgInsert(head, cur);
+            }
+        }
+        else {
+            DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz);
+        }
+    }
+    else {
+        head = DtlsMsgNew(dataSz, heap);
+        DtlsMsgSet(head, seq, data, type, fragOffset, fragSz);
+    }
+
+    return head;
+}
+
+
+/* DtlsMsgInsert() is an in-order insert. */
+DtlsMsg* DtlsMsgInsert(DtlsMsg* head, DtlsMsg* item)
+{
+    if (head == NULL || item->seq < head->seq) {
+        item->next = head;
+        head = item;
+    }
+    else if (head->next == NULL) {
+        head->next = item;
+    }
+    else {
+        DtlsMsg* cur = head->next;
+        DtlsMsg* prev = head;
+        while (cur) {
+            if (item->seq < cur->seq) {
+                item->next = cur;
+                prev->next = item;
+                break;
+            }
+            prev = cur;
+            cur = cur->next;
+        }
+        if (cur == NULL) {
+            prev->next = item;
+        }
+    }
+
+    return head;
+}
+
+#endif /* 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)
+
+    #if defined(MICROCHIP_MPLAB_HARMONY)
+
+        #include <system/tmr/sys_tmr.h>
+
+        word32 LowResTimer(void)
+        {
+            return (word32) SYS_TMR_TickCountGet();
+        }
+
+    #else
+
+        word32 LowResTimer(void)
+        {
+            return (word32) SYS_TICK_Get();
+        }
+
+    #endif
+
+#elif defined(FREESCALE_MQX)
+
+    word32 LowResTimer(void)
+    {
+        TIME_STRUCT mqxTime;
+
+        _time_get_elapsed(&mqxTime);
+
+        return (word32) mqxTime.SECONDS;
+    }
+
+
+#elif defined(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_state.curEpoch);
+        *inOutIdx += 4; /* advance past epoch, skip first 2 seq bytes for now */
+        ato32(input + *inOutIdx, &ssl->keys.dtls_state.curSeq);
+        *inOutIdx += 4;  /* advance past rest of seq */
+        ato16(input + *inOutIdx, size);
+        *inOutIdx += LENGTH_SZ;
+#endif
+    }
+
+    /* catch version mismatch */
+    if (rh->pvMajor != ssl->version.major || rh->pvMinor != ssl->version.minor){
+        if (ssl->options.side == CYASSL_SERVER_END &&
+            ssl->options.acceptState == ACCEPT_BEGIN)
+            CYASSL_MSG("Client attempting to connect with different version"); 
+        else if (ssl->options.side == CYASSL_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 */
+        }
+    }
+
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        if (DtlsCheckWindow(&ssl->keys.dtls_state) != 1)
+            return SEQUENCE_ERROR;
+    }
+#endif
+
+    /* record layer length check */
+#ifdef HAVE_MAX_FRAGMENT
+    if (*size > (ssl->max_fragment + MAX_COMP_EXTRA + MAX_MSG_EXTRA))
+        return LENGTH_ERROR;
+#else
+    if (*size > (MAX_RECORD_SIZE + MAX_COMP_EXTRA + MAX_MSG_EXTRA))
+        return LENGTH_ERROR;
+#endif
+
+    /* verify record type here as well */
+    switch (rh->type) {
+        case handshake:
+        case change_cipher_spec:
+        case application_data:
+        case alert:
+            break;
+        case no_type:
+        default:
+            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 int 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
+
+    int ret = 0;
+
+#ifndef NO_TLS
+    if (ssl->options.tls) {
+        ret = BuildTlsFinished(ssl, hashes, sender);
+    }
+#endif
+#ifndef NO_OLD_TLS
+    if (!ssl->options.tls) {
+        BuildMD5(ssl, hashes, sender);
+        BuildSHA(ssl, hashes, sender);
+    }
+#endif
+    
+    /* restore */
+#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
+    }
+
+    return ret;
+}
+
+
+#ifndef NO_CERTS
+
+
+/* Match names with wildcards, each wildcard can represent a single name
+   component or fragment but not mulitple names, i.e.,
+   *.z.com matches y.z.com but not x.y.z.com 
+
+   return 1 on success */
+static int MatchDomainName(const char* pattern, int len, const char* str)
+{
+    char p, s;
+
+    if (pattern == NULL || str == NULL || len <= 0)
+        return 0;
+
+    while (len > 0) {
+
+        p = (char)XTOLOWER(*pattern++);
+        if (p == 0)
+            break;
+
+        if (p == '*') {
+            while (--len > 0 && (p = (char)XTOLOWER(*pattern++)) == '*')
+                ;
+
+            if (len == 0)
+                p = '\0';
+
+            while ( (s = (char)XTOLOWER(*str)) != '\0') {
+                if (s == p)
+                    break;
+                if (s == '.')
+                    return 0;
+                str++;
+            }
+        }
+        else {
+            if (p != (char)XTOLOWER(*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;
+
+    x509->version = dCert->version + 1;
+
+    XSTRNCPY(x509->issuer.name, dCert->issuer, ASN_NAME_MAX);
+    x509->issuer.name[ASN_NAME_MAX - 1] = '\0';
+    x509->issuer.sz = (int)XSTRLEN(x509->issuer.name) + 1;
+#ifdef OPENSSL_EXTRA
+    if (dCert->issuerName.fullName != NULL) {
+        XMEMCPY(&x509->issuer.fullName,
+                                       &dCert->issuerName, sizeof(DecodedName));
+        x509->issuer.fullName.fullName = (char*)XMALLOC(
+                        dCert->issuerName.fullNameLen, NULL, DYNAMIC_TYPE_X509);
+        if (x509->issuer.fullName.fullName != NULL)
+            XMEMCPY(x509->issuer.fullName.fullName,
+                     dCert->issuerName.fullName, dCert->issuerName.fullNameLen);
+    }
+#endif /* OPENSSL_EXTRA */
+
+    XSTRNCPY(x509->subject.name, dCert->subject, ASN_NAME_MAX);
+    x509->subject.name[ASN_NAME_MAX - 1] = '\0';
+    x509->subject.sz = (int)XSTRLEN(x509->subject.name) + 1;
+#ifdef OPENSSL_EXTRA
+    if (dCert->subjectName.fullName != NULL) {
+        XMEMCPY(&x509->subject.fullName,
+                                      &dCert->subjectName, sizeof(DecodedName));
+        x509->subject.fullName.fullName = (char*)XMALLOC(
+                       dCert->subjectName.fullNameLen, NULL, DYNAMIC_TYPE_X509);
+        if (x509->subject.fullName.fullName != NULL)
+            XMEMCPY(x509->subject.fullName.fullName,
+                   dCert->subjectName.fullName, dCert->subjectName.fullNameLen);
+    }
+#endif /* OPENSSL_EXTRA */
+
+    XMEMCPY(x509->serial, dCert->serial, EXTERNAL_SERIAL_SIZE);
+    x509->serialSz = dCert->serialSz;
+    if (dCert->subjectCNLen < ASN_NAME_MAX) {
+        XMEMCPY(x509->subjectCN, dCert->subjectCN, dCert->subjectCNLen);
+        x509->subjectCN[dCert->subjectCNLen] = '\0';
+    }
+    else
+        x509->subjectCN[0] = '\0';
+
+#ifdef CYASSL_SEP
+    {
+        int minSz = min(dCert->deviceTypeSz, EXTERNAL_SERIAL_SIZE);
+        if (minSz > 0) {
+            x509->deviceTypeSz = minSz;
+            XMEMCPY(x509->deviceType, dCert->deviceType, minSz);
+        }
+        else
+            x509->deviceTypeSz = 0;
+        minSz = min(dCert->hwTypeSz, EXTERNAL_SERIAL_SIZE);
+        if (minSz != 0) {
+            x509->hwTypeSz = minSz;
+            XMEMCPY(x509->hwType, dCert->hwType, minSz);
+        }
+        else
+            x509->hwTypeSz = 0;
+        minSz = min(dCert->hwSerialNumSz, EXTERNAL_SERIAL_SIZE);
+        if (minSz != 0) {
+            x509->hwSerialNumSz = minSz;
+            XMEMCPY(x509->hwSerialNum, dCert->hwSerialNum, minSz);
+        }
+        else
+            x509->hwSerialNumSz = 0;
+    }
+#endif /* CYASSL_SEP */
+    {
+        int minSz = min(dCert->beforeDateLen, MAX_DATE_SZ);
+        if (minSz != 0) {
+            x509->notBeforeSz = minSz;
+            XMEMCPY(x509->notBefore, dCert->beforeDate, minSz);
+        }
+        else
+            x509->notBeforeSz = 0;
+        minSz = min(dCert->afterDateLen, MAX_DATE_SZ);
+        if (minSz != 0) {
+            x509->notAfterSz = minSz;
+            XMEMCPY(x509->notAfter, dCert->afterDate, minSz);
+        }
+        else
+            x509->notAfterSz = 0;
+    }
+
+    if (dCert->publicKey != NULL && dCert->pubKeySize != 0) {
+        x509->pubKey.buffer = (byte*)XMALLOC(
+                              dCert->pubKeySize, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
+        if (x509->pubKey.buffer != NULL) {
+            x509->pubKeyOID = dCert->keyOID;
+            x509->pubKey.length = dCert->pubKeySize;
+            XMEMCPY(x509->pubKey.buffer, dCert->publicKey, dCert->pubKeySize);
+        }
+        else
+            ret = MEMORY_E;
+    }
+
+    if (dCert->signature != NULL && dCert->sigLength != 0) {
+        x509->sig.buffer = (byte*)XMALLOC(
+                                dCert->sigLength, NULL, DYNAMIC_TYPE_SIGNATURE);
+        if (x509->sig.buffer == NULL) {
+            ret = MEMORY_E;
+        }
+        else {
+            XMEMCPY(x509->sig.buffer, dCert->signature, dCert->sigLength);
+            x509->sig.length = dCert->sigLength;
+            x509->sigOID = dCert->signatureOID;
+        }
+    }
+
+    /* store cert for potential retrieval */
+    x509->derCert.buffer = (byte*)XMALLOC(dCert->maxIdx, NULL,
+                                          DYNAMIC_TYPE_CERT);
+    if (x509->derCert.buffer == NULL) {
+        ret = MEMORY_E;
+    }
+    else {
+        XMEMCPY(x509->derCert.buffer, dCert->source, dCert->maxIdx);
+        x509->derCert.length = dCert->maxIdx;
+    }
+
+    x509->altNames     = dCert->altNames;
+    dCert->altNames    = NULL;     /* takes ownership */
+    x509->altNamesNext = x509->altNames;  /* index hint */
+
+    x509->isCa = dCert->isCA;
+#ifdef OPENSSL_EXTRA
+    x509->pathLength = dCert->pathLength;
+    x509->keyUsage = dCert->extKeyUsage;
+
+    x509->basicConstSet = dCert->extBasicConstSet;
+    x509->basicConstCrit = dCert->extBasicConstCrit;
+    x509->basicConstPlSet = dCert->extBasicConstPlSet;
+    x509->subjAltNameSet = dCert->extSubjAltNameSet;
+    x509->subjAltNameCrit = dCert->extSubjAltNameCrit;
+    x509->authKeyIdSet = dCert->extAuthKeyIdSet;
+    x509->authKeyIdCrit = dCert->extAuthKeyIdCrit;
+    if (dCert->extAuthKeyIdSrc != NULL && dCert->extAuthKeyIdSz != 0) {
+        x509->authKeyId = (byte*)XMALLOC(dCert->extAuthKeyIdSz, NULL, 0);
+        if (x509->authKeyId != NULL) {
+            XMEMCPY(x509->authKeyId,
+                                 dCert->extAuthKeyIdSrc, dCert->extAuthKeyIdSz);
+            x509->authKeyIdSz = dCert->extAuthKeyIdSz;
+        }
+        else
+            ret = MEMORY_E;
+    }
+    x509->subjKeyIdSet = dCert->extSubjKeyIdSet;
+    x509->subjKeyIdCrit = dCert->extSubjKeyIdCrit;
+    if (dCert->extSubjKeyIdSrc != NULL && dCert->extSubjKeyIdSz != 0) {
+        x509->subjKeyId = (byte*)XMALLOC(dCert->extSubjKeyIdSz, NULL, 0);
+        if (x509->subjKeyId != NULL) {
+            XMEMCPY(x509->subjKeyId,
+                                 dCert->extSubjKeyIdSrc, dCert->extSubjKeyIdSz);
+            x509->subjKeyIdSz = dCert->extSubjKeyIdSz;
+        }
+        else
+            ret = MEMORY_E;
+    }
+    x509->keyUsageSet = dCert->extKeyUsageSet;
+    x509->keyUsageCrit = dCert->extKeyUsageCrit;
+    #ifdef CYASSL_SEP
+        x509->certPolicySet = dCert->extCertPolicySet;
+        x509->certPolicyCrit = dCert->extCertPolicyCrit;
+    #endif /* CYASSL_SEP */
+#endif /* OPENSSL_EXTRA */
+#ifdef HAVE_ECC
+    x509->pkCurveOID = dCert->pkCurveOID;
+#endif /* HAVE_ECC */
+
+    return ret;
+}
+
+#endif /* KEEP_PEER_CERT || SESSION_CERTS */
+
+
+static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
+                                                                    word32 size)
+{
+    word32 listSz, begin = *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
+
+    if ((*inOutIdx - begin) + OPAQUE24_LEN > size)
+        return BUFFER_ERROR;
+
+    c24to32(input + *inOutIdx, &listSz);
+    *inOutIdx += OPAQUE24_LEN;
+
+#ifdef HAVE_MAX_FRAGMENT
+    if (listSz > ssl->max_fragment)
+        return BUFFER_E;
+#else
+    if (listSz > MAX_RECORD_SIZE)
+        return BUFFER_E;
+#endif
+
+    if ((*inOutIdx - begin) + listSz != size)
+        return BUFFER_ERROR;
+
+    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) {
+        word32 certSz;
+
+        if (totalCerts >= MAX_CHAIN_DEPTH)
+            return MAX_CHAIN_ERROR;
+
+        if ((*inOutIdx - begin) + OPAQUE24_LEN > size)
+            return BUFFER_ERROR;
+
+        c24to32(input + *inOutIdx, &certSz);
+        *inOutIdx += OPAQUE24_LEN;
+
+        if ((*inOutIdx - begin) + certSz > size)
+            return BUFFER_ERROR;
+
+        certs[totalCerts].length = certSz;
+        certs[totalCerts].buffer = input + *inOutIdx;
+
+#ifdef SESSION_CERTS
+        if (ssl->session.chain.count < MAX_CHAIN_DEPTH &&
+                                       certSz < MAX_X509_SIZE) {
+            ssl->session.chain.certs[ssl->session.chain.count].length = certSz;
+            XMEMCPY(ssl->session.chain.certs[ssl->session.chain.count].buffer,
+                    input + *inOutIdx, certSz);
+            ssl->session.chain.count++;
+        } else {
+            CYASSL_MSG("Couldn't store chain cert for session");
+        }
+#endif
+
+        *inOutIdx += 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 && ssl->ctx->cm->ocspEnabled) {
+            ret = CheckCertOCSP(ssl->ctx->cm->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->cm->ocspEnabled) {
+                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;
+                        #ifdef HAVE_PK_CALLBACKS
+                            #ifndef NO_RSA
+                                ssl->buffers.peerRsaKey.buffer =
+                                       XMALLOC(dCert.pubKeySize,
+                                               ssl->heap, DYNAMIC_TYPE_RSA);
+                                if (ssl->buffers.peerRsaKey.buffer == NULL)
+                                    ret = MEMORY_ERROR;
+                                else {
+                                    XMEMCPY(ssl->buffers.peerRsaKey.buffer,
+                                            dCert.publicKey, dCert.pubKeySize);
+                                    ssl->buffers.peerRsaKey.length = 
+                                            dCert.pubKeySize;
+                                }
+                            #endif /* NO_RSA */
+                        #endif /*HAVE_PK_CALLBACKS */
+                    }
+                }
+                break;
+        #endif /* NO_RSA */
+        #ifdef HAVE_NTRU
+            case NTRUk:
+                {
+                    if (dCert.pubKeySize > sizeof(ssl->peerNtruKey)) {
+                        ret = PEER_KEY_ERROR;
+                    }
+                    else {
+                        XMEMCPY(ssl->peerNtruKey, dCert.publicKey, dCert.pubKeySize);
+                        ssl->peerNtruKeyLen = (word16)dCert.pubKeySize;
+                        ssl->peerNtruKeyPresent = 1;
+                    }
+                }
+                break;
+        #endif /* HAVE_NTRU */
+        #ifdef HAVE_ECC
+            case ECDSAk:
+                {
+                    if (ecc_import_x963(dCert.publicKey, dCert.pubKeySize,
+                                        ssl->peerEccDsaKey) != 0) {
+                        ret = PEER_KEY_ERROR;
+                    }
+                    else {
+                        ssl->peerEccDsaKeyPresent = 1;
+                        #ifdef HAVE_PK_CALLBACKS
+                            #ifdef HAVE_ECC
+                                ssl->buffers.peerEccDsaKey.buffer =
+                                       XMALLOC(dCert.pubKeySize,
+                                               ssl->heap, DYNAMIC_TYPE_ECC);
+                                if (ssl->buffers.peerEccDsaKey.buffer == NULL)
+                                    ret = MEMORY_ERROR;
+                                else {
+                                    XMEMCPY(ssl->buffers.peerEccDsaKey.buffer,
+                                            dCert.publicKey, dCert.pubKeySize);
+                                    ssl->buffers.peerEccDsaKey.length = 
+                                            dCert.pubKeySize;
+                                }
+                            #endif /* HAVE_ECC */
+                        #endif /*HAVE_PK_CALLBACKS */
+                    }
+                }
+                break;
+        #endif /* HAVE_ECC */
+            default:
+                break;
+        }
+
+        FreeDecodedCert(&dCert);
+    }
+    
+    if (anyError != 0 && ret == 0)
+        ret = anyError;
+
+    if (ret == 0 && ssl->options.side == CYASSL_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 CYASSL_ALWAYS_VERIFY_CB
+    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;
+#ifdef KEEP_PEER_CERT
+            store.current_cert = &ssl->peerCert;
+#endif
+            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
+
+    return ret;
+}
+
+#endif /* !NO_CERTS */
+
+
+static int DoHelloRequest(CYASSL* ssl, const byte* input, word32* inOutIdx,
+                                                    word32 size, word32 totalSz)
+{
+    int ret = 0;
+
+    if (size) /* must be 0 */
+        return BUFFER_ERROR;
+
+    if (ssl->keys.encryptionOn) {
+        byte verify[MAX_DIGEST_SIZE];
+        int  padSz = ssl->keys.encryptSz - HANDSHAKE_HEADER_SZ -
+                     ssl->specs.hash_size;
+
+        ret = ssl->hmac(ssl, verify, input + *inOutIdx - HANDSHAKE_HEADER_SZ,
+                        HANDSHAKE_HEADER_SZ, handshake, 1);
+        if (ret != 0)
+            return ret;
+
+        if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
+            padSz -= ssl->specs.block_size;
+
+        /* access beyond input + size should be checked against totalSz */
+        if ((word32) (*inOutIdx + ssl->specs.hash_size + padSz) > totalSz)
+            return INCOMPLETE_DATA;
+
+        /* verify */
+        if (XMEMCMP(input + *inOutIdx, verify, ssl->specs.hash_size) != 0) {
+            CYASSL_MSG("    hello_request verify mac error");
+            return VERIFY_MAC_ERROR;
+        }
+
+        *inOutIdx += ssl->specs.hash_size + padSz;
+    }
+
+    if (ssl->options.side == CYASSL_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, word32 size,
+                                                      word32 totalSz, int sniff)
+{
+    word32 finishedSz = (ssl->options.tls ? TLS_FINISHED_SZ : FINISHED_SZ);
+
+    if (finishedSz != size)
+        return BUFFER_ERROR;
+
+    #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 + *inOutIdx, &ssl->verifyHashes, size) != 0) {
+            CYASSL_MSG("Verify finished error on hashes");
+            return VERIFY_FINISHED_ERROR;
+        }
+    }
+
+    /* increment beyond input + size should be checked against totalSz */
+    if (*inOutIdx + size + ssl->keys.padSz > totalSz)
+        return INCOMPLETE_DATA;
+
+    /* force input exhaustion at ProcessReply consuming padSz */
+    *inOutIdx += size + ssl->keys.padSz;
+
+    if (ssl->options.side == CYASSL_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
+        }
+    }
+
+    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");
+
+    /* make sure can read the message */
+    if (*inOutIdx + size > totalSz)
+        return INCOMPLETE_DATA;
+
+    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 == CYASSL_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 == CYASSL_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 == CYASSL_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, size, totalSz);
+        break;
+
+#ifndef NO_CYASSL_CLIENT
+    case hello_verify_request:
+        CYASSL_MSG("processing hello verify request");
+        ret = DoHelloVerifyRequest(ssl, input,inOutIdx, size);
+        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, size);
+        break;
+#endif
+
+    case server_key_exchange:
+        CYASSL_MSG("processing server key exchange");
+        ret = DoServerKeyExchange(ssl, input, inOutIdx, size);
+        break;
+#endif
+
+#ifndef NO_CERTS
+    case certificate:
+        CYASSL_MSG("processing certificate");
+        ret =  DoCertificate(ssl, input, inOutIdx, size);
+        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, size, totalSz, NO_SNIFF);
+        break;
+
+#ifndef NO_CYASSL_SERVER
+    case client_hello:
+        CYASSL_MSG("processing client hello");
+        ret = DoClientHello(ssl, input, inOutIdx, size);
+        break;
+
+    case client_key_exchange:
+        CYASSL_MSG("processing client key exchange");
+        ret = DoClientKeyExchange(ssl, input, inOutIdx, size);
+        break;
+
+#if !defined(NO_RSA) || defined(HAVE_ECC)
+    case certificate_verify:
+        CYASSL_MSG("processing certificate verify");
+        ret = DoCertificateVerify(ssl, input, inOutIdx, size);
+        break;
+#endif /* !NO_RSA || HAVE_ECC */
+
+#endif /* !NO_CYASSL_SERVER */
+
+    default:
+        CYASSL_MSG("Unknown handshake message type");
+        ret = UNKNOWN_HANDSHAKE_TYPE;
+        break;
+    }
+
+    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;
+
+    ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz);
+
+    CYASSL_LEAVE("DoHandShakeMsg()", ret);
+    return ret;
+}
+
+
+#ifdef CYASSL_DTLS
+
+static INLINE int DtlsCheckWindow(DtlsState* state)
+{
+    word32 cur;
+    word32 next;
+    DtlsSeq window;
+
+    if (state->curEpoch == state->nextEpoch) {
+        next = state->nextSeq;
+        window = state->window;
+    }
+    else if (state->curEpoch < state->nextEpoch) {
+        next = state->prevSeq;
+        window = state->prevWindow;
+    }
+    else {
+        return 0;
+    }
+
+    cur = state->curSeq;
+
+    if ((next > DTLS_SEQ_BITS) && (cur < next - DTLS_SEQ_BITS)) {
+        return 0;
+    }
+    else if ((cur < next) && (window & (1 << (next - cur - 1)))) {
+        return 0;
+    }
+
+    return 1;
+}
+
+
+static INLINE int DtlsUpdateWindow(DtlsState* state)
+{
+    word32 cur;
+    word32* next;
+    DtlsSeq* window;
+
+    if (state->curEpoch == state->nextEpoch) {
+        next = &state->nextSeq;
+        window = &state->window;
+    }
+    else {
+        next = &state->prevSeq;
+        window = &state->prevWindow;
+    }
+
+    cur = state->curSeq;
+
+    if (cur < *next) {
+        *window |= (1 << (*next - cur - 1));
+    }
+    else {
+        *window <<= (1 + cur - *next);
+        *window |= 1;
+        *next = cur + 1;
+    }
+
+    return 1;
+}
+
+
+static int DtlsMsgDrain(CYASSL* ssl)
+{
+    DtlsMsg* item = ssl->dtls_msg_list;
+    int ret = 0;
+
+    /* While there is an item in the store list, and it is the expected
+     * message, and it is complete, and there hasn't been an error in the
+     * last messge... */
+    while (item != NULL &&
+            ssl->keys.dtls_expected_peer_handshake_number == item->seq &&
+            item->fragSz == item->sz &&
+            ret == 0) {
+        word32 idx = 0;
+        ssl->keys.dtls_expected_peer_handshake_number++;
+        ret = DoHandShakeMsgType(ssl, item->msg,
+                                 &idx, item->type, item->sz, item->sz);
+        ssl->dtls_msg_list = item->next;
+        DtlsMsgDelete(item, ssl->heap);
+        item = ssl->dtls_msg_list;
+    }
+
+    return ret;
+}
+
+
+static int DoDtlsHandShakeMsg(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 != NULL &&
+            ssl->dtls_msg_list->fragSz >= ssl->dtls_msg_list->sz)
+            ret = DtlsMsgDrain(ssl);
+    }
+    else {
+        /* This branch is in order next, and a complete message. */
+        ssl->keys.dtls_expected_peer_handshake_number++;
+        ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz);
+        if (ret == 0 && ssl->dtls_msg_list != NULL)
+            ret = DtlsMsgDrain(ssl);
+    }
+
+    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, word16 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 cyassl_rc4:
+                Arc4Process(ssl->encrypt.arc4, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_DES3
+            case cyassl_triple_des:
+                return Des3_CbcEncrypt(ssl->encrypt.des3, out, input, sz);
+        #endif
+
+        #ifdef BUILD_AES
+            case cyassl_aes:
+                return AesCbcEncrypt(ssl->encrypt.aes, out, input, sz);
+        #endif
+
+        #ifdef BUILD_AESGCM
+            case cyassl_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 cyassl_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) {
+                            c16toa(ssl->keys.dtls_epoch, additional);
+                            additionalSrc -= DTLS_HANDSHAKE_EXTRA;
+                        }
+                    #endif
+                    XMEMCPY(additional + AEAD_TYPE_OFFSET, additionalSrc, 3);
+
+                    /* Store the length of the plain text minus the explicit
+                     * IV length minus the authentication tag size. */
+                    c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
+                                                additional + AEAD_LEN_OFFSET);
+                    XMEMCPY(nonce,
+                                 ssl->keys.aead_enc_imp_IV, AEAD_IMP_IV_SZ);
+                    XMEMCPY(nonce + AEAD_IMP_IV_SZ,
+                                     ssl->keys.aead_exp_IV, AEAD_EXP_IV_SZ);
+                    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 cyassl_camellia:
+                CamelliaCbcEncrypt(ssl->encrypt.cam, out, input, sz);
+                break;
+        #endif
+
+        #ifdef HAVE_HC128
+            case cyassl_hc128:
+                return Hc128_Process(ssl->encrypt.hc128, out, input, sz);
+        #endif
+
+        #ifdef BUILD_RABBIT
+            case cyassl_rabbit:
+                return RabbitProcess(ssl->encrypt.rabbit, out, input, sz);
+        #endif
+
+        #ifdef HAVE_NULL_CIPHER
+            case cyassl_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,
+                           word16 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 cyassl_rc4:
+                Arc4Process(ssl->decrypt.arc4, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_DES3
+            case cyassl_triple_des:
+                return Des3_CbcDecrypt(ssl->decrypt.des3, plain, input, sz);
+        #endif
+
+        #ifdef BUILD_AES
+            case cyassl_aes:
+                return AesCbcDecrypt(ssl->decrypt.aes, plain, input, sz);
+        #endif
+
+        #ifdef BUILD_AESGCM
+            case cyassl_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 cyassl_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);
+
+                #ifdef CYASSL_DTLS
+                    if (ssl->options.dtls)
+                        c16toa(ssl->keys.dtls_state.curEpoch, additional);
+                #endif
+
+                additional[AEAD_TYPE_OFFSET] = ssl->curRL.type;
+                additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor;
+                additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor;
+
+                c16toa(sz - AEAD_EXP_IV_SZ - ssl->specs.aead_mac_size,
+                                        additional + AEAD_LEN_OFFSET);
+                XMEMCPY(nonce, ssl->keys.aead_dec_imp_IV, AEAD_IMP_IV_SZ);
+                XMEMCPY(nonce + AEAD_IMP_IV_SZ, input, AEAD_EXP_IV_SZ);
+                if (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 cyassl_camellia:
+                CamelliaCbcDecrypt(ssl->decrypt.cam, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef HAVE_HC128
+            case cyassl_hc128:
+                return Hc128_Process(ssl->decrypt.hc128, plain, input, sz);
+        #endif
+
+        #ifdef BUILD_RABBIT
+            case cyassl_rabbit:
+                return RabbitProcess(ssl->decrypt.rabbit, plain, input, sz);
+        #endif
+
+        #ifdef HAVE_NULL_CIPHER
+            case cyassl_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)
+{
+#ifdef HAVE_TRUNCATED_HMAC
+    word32 minLength = ssl->truncated_hmac ? TRUNCATED_HMAC_SZ
+                                           : ssl->specs.hash_size;
+#else
+    word32 minLength = ssl->specs.hash_size; /* covers stream */
+#endif
+
+    if (ssl->specs.cipher_type == block) {
+        if (encryptSz % ssl->specs.block_size) {
+            CYASSL_MSG("Block ciphertext not block size");
+            return SANITY_CIPHER_E;
+        }
+
+        minLength++;  /* pad byte */
+
+        if (ssl->specs.block_size > minLength)
+            minLength = ssl->specs.block_size;
+
+        if (ssl->options.tls1_1)
+            minLength += ssl->specs.block_size;  /* explicit IV */
+    }
+    else if (ssl->specs.cipher_type == aead) {
+        minLength = ssl->specs.aead_mac_size + AEAD_EXP_IV_SZ;
+                                               /* explicit IV + authTag size */
+    }
+
+    if (encryptSz < minLength) {
+        CYASSL_MSG("Ciphertext not minimum size");
+        return SANITY_CIPHER_E;
+    }
+
+    return 0;
+}
+
+
+#ifndef NO_OLD_TLS
+
+static INLINE void Md5Rounds(int rounds, const byte* data, int sz)
+{
+    Md5 md5;
+    int i;
+
+    InitMd5(&md5);
+
+    for (i = 0; i < rounds; i++)
+        Md5Update(&md5, data, sz);
+}
+
+
+
+/* do a dummy sha round */
+static INLINE void ShaRounds(int rounds, const byte* data, int sz)
+{
+    Sha sha;
+    int i;
+
+    InitSha(&sha);  /* no error check on purpose, dummy round */
+
+    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);  /* no error check on purpose, dummy round */
+
+    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);  /* no error check on purpose, dummy round */
+
+    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);  /* no error check on purpose, dummy round */
+
+    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
+
+
+/* Do dummy rounds */
+static INLINE void DoRounds(int type, int rounds, const byte* data, int sz)
+{
+    switch (type) {
+    
+        case no_mac :
+            break;
+
+#ifndef NO_OLD_TLS
+#ifndef NO_MD5
+        case md5_mac :
+            Md5Rounds(rounds, data, sz);
+            break;
+#endif
+
+#ifndef NO_SHA
+        case sha_mac :
+            ShaRounds(rounds, data, sz);
+            break;
+#endif
+#endif
+
+#ifndef NO_SHA256
+        case sha256_mac :
+            Sha256Rounds(rounds, data, sz);
+            break;
+#endif
+
+#ifdef 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, int content)
+{
+    byte verify[MAX_DIGEST_SIZE];
+    byte dummy[MAX_PAD_SIZE];
+    int  ret = 0;
+
+    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, content, 1); /* still compare */
+        ConstantCompare(verify, input + pLen - t, t);
+
+        return VERIFY_MAC_ERROR;
+    }
+
+    if (PadCheck(input + pLen - (padLen + 1), (byte)padLen, padLen + 1) != 0) {
+        CYASSL_MSG("PadCheck failed");
+        PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1);
+        ssl->hmac(ssl, verify, input, pLen - t, content, 1); /* still compare */
+        ConstantCompare(verify, input + pLen - t, t);
+
+        return VERIFY_MAC_ERROR;
+    }
+
+    PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1);
+    ret = ssl->hmac(ssl, verify, input, pLen - padLen - 1 - t, content, 1);
+
+    CompressRounds(ssl, GetRounds(pLen, padLen, t), dummy);
+
+    if (ConstantCompare(verify, input + (pLen - padLen - 1 - t), t) != 0) {
+        CYASSL_MSG("Verify MAC compare failed");
+        return VERIFY_MAC_ERROR;
+    }
+
+    if (ret != 0)
+        return VERIFY_MAC_ERROR;
+    return 0;
+}
+
+
+int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx)
+{
+    word32 msgSz   = ssl->keys.encryptSz;
+    word32 idx     = *inOutIdx;
+    int    dataSz;
+    int    ivExtra = 0;
+    byte*  rawData = input + idx;  /* keep current  for hmac */
+#ifdef HAVE_LIBZ
+    byte   decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
+#endif
+
+    if (ssl->options.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;
+    }
+    else if (ssl->specs.cipher_type == aead) {
+        ivExtra = AEAD_EXP_IV_SZ;
+    }
+
+    dataSz = msgSz - ivExtra - ssl->keys.padSz;
+    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 += ssl->keys.padSz;
+
+#ifdef HAVE_LIBZ
+    /* decompress could be bigger, overwrite after verify */
+    if (ssl->options.usingCompression)
+        XMEMMOVE(rawData, decomp, dataSz);
+#endif
+
+    *inOutIdx = idx;
+    return 0;
+}
+
+
+/* process alert, return level */
+static int DoAlert(CYASSL* ssl, byte* input, word32* inOutIdx, int* type,
+                   word32 totalSz)
+{
+    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
+
+    /* make sure can read the message */
+    if (*inOutIdx + ALERT_SIZE > totalSz)
+        return BUFFER_E;
+
+    level = input[(*inOutIdx)++];
+    code  = input[(*inOutIdx)++];
+    ssl->alert_history.last_rx.code = code;
+    ssl->alert_history.last_rx.level = level;
+    *type = code;
+    if (level == alert_fatal) {
+        ssl->options.isClosed = 1;  /* Don't send close_notify */
+    }
+
+    CYASSL_MSG("Got alert");
+    if (*type == close_notify) {
+        CYASSL_MSG("    close notify");
+        ssl->options.closeNotify = 1;
+    }
+    CYASSL_ERROR(*type);
+
+    if (ssl->keys.encryptionOn) {
+        if (*inOutIdx + ssl->keys.padSz > totalSz)
+            return BUFFER_E;
+        *inOutIdx += ssl->keys.padSz;
+    }
+
+    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;
+}
+
+
+static INLINE int VerifyMac(CYASSL* ssl, const byte* input, word32 msgSz,
+                            int content, word32* padSz)
+{
+    int    ivExtra = 0;
+    int    ret;
+    word32 pad     = 0;
+    word32 padByte = 0;
+#ifdef HAVE_TRUNCATED_HMAC
+    word32 digestSz = ssl->truncated_hmac ? TRUNCATED_HMAC_SZ
+                                          : ssl->specs.hash_size;
+#else
+    word32 digestSz = ssl->specs.hash_size;
+#endif
+    byte   verify[MAX_DIGEST_SIZE];
+
+    if (ssl->specs.cipher_type == block) {
+        if (ssl->options.tls1_1)
+            ivExtra = ssl->specs.block_size;
+        pad = *(input + msgSz - ivExtra - 1);
+        padByte = 1;
+
+        if (ssl->options.tls) {
+            ret = TimingPadVerify(ssl, input, pad, digestSz, msgSz - ivExtra,
+                                  content);
+            if (ret != 0)
+                return ret;
+        }
+        else {  /* sslv3, some implementations have bad padding, but don't
+                 * allow bad read */ 
+            int  badPadLen = 0;
+            byte dummy[MAX_PAD_SIZE];
+
+            XMEMSET(dummy, 1, sizeof(dummy));
+
+            if (pad > (msgSz - digestSz - 1)) {
+                CYASSL_MSG("Plain Len not long enough for pad/mac");
+                pad       = 0;  /* no bad read */
+                badPadLen = 1;
+            }
+            PadCheck(dummy, (byte)pad, MAX_PAD_SIZE);  /* timing only */
+            ret = ssl->hmac(ssl, verify, input, msgSz - digestSz - pad - 1,
+                            content, 1);
+            if (ConstantCompare(verify, input + msgSz - digestSz - pad - 1,
+                                digestSz) != 0)
+                return VERIFY_MAC_ERROR;
+            if (ret != 0 || badPadLen)
+                return VERIFY_MAC_ERROR;
+        }
+    }
+    else if (ssl->specs.cipher_type == stream) {
+        ret = ssl->hmac(ssl, verify, input, msgSz - digestSz, content, 1);
+        if (ConstantCompare(verify, input + msgSz - digestSz, digestSz) != 0){
+            return VERIFY_MAC_ERROR;
+        }
+        if (ret != 0)
+            return VERIFY_MAC_ERROR;
+    }
+
+    if (ssl->specs.cipher_type == aead) {
+        *padSz = ssl->specs.aead_mac_size;
+    }
+    else {
+        *padSz = digestSz + pad + padByte;
+    }
+
+    return 0;
+}
+
+
+/* process input requests, return 0 is done, 1 is call again to complete, and
+   negative number is error */
+int ProcessReply(CYASSL* ssl)
+{
+    int    ret = 0, type, readSz;
+    int    atomicUser = 0;
+    word32 startIdx = 0;
+#ifndef NO_CYASSL_SERVER
+    byte   b0, b1;
+#endif
+#ifdef CYASSL_DTLS
+    int    used;
+#endif
+
+#ifdef ATOMIC_USER
+    if (ssl->ctx->DecryptVerifyCb)
+        atomicUser = 1;
+#endif
+
+    if (ssl->error != 0 && ssl->error != WANT_READ && ssl->error != WANT_WRITE){
+        CYASSL_MSG("ProcessReply retry in error state, not allowed");
+        return ssl->error;
+    }
+
+    for (;;) {
+        switch (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 == CYASSL_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 = (word16)(((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) {
+                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:
+
+            #ifdef CYASSL_DTLS
+            if (ssl->options.dtls &&
+                ssl->keys.dtls_state.curEpoch < ssl->keys.dtls_state.nextEpoch)
+                ssl->keys.decryptedCur = 1;
+            #endif
+
+            if (ssl->keys.encryptionOn && ssl->keys.decryptedCur == 0)
+            {
+                ret = SanityCheckCipherText(ssl, ssl->curSize);
+                if (ret < 0)
+                    return ret;
+
+                if (atomicUser) {
+                #ifdef ATOMIC_USER
+                    ret = ssl->ctx->DecryptVerifyCb(ssl,
+                                  ssl->buffers.inputBuffer.buffer + 
+                                  ssl->buffers.inputBuffer.idx,
+                                  ssl->buffers.inputBuffer.buffer +
+                                  ssl->buffers.inputBuffer.idx,
+                                  ssl->curSize, ssl->curRL.type, 1,
+                                  &ssl->keys.padSz, ssl->DecryptVerifyCtx);
+                    if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
+                        ssl->buffers.inputBuffer.idx += ssl->specs.block_size;
+                        /* go past TLSv1.1 IV */
+                    if (ssl->specs.cipher_type == aead)
+                        ssl->buffers.inputBuffer.idx += AEAD_EXP_IV_SZ;
+                #endif /* ATOMIC_USER */
+                }
+                else {
+                    ret = Decrypt(ssl, ssl->buffers.inputBuffer.buffer + 
+                                  ssl->buffers.inputBuffer.idx,
+                                  ssl->buffers.inputBuffer.buffer +
+                                  ssl->buffers.inputBuffer.idx,
+                                  ssl->curSize);
+                    if (ret < 0) {
+                        CYASSL_ERROR(ret);
+                        return DECRYPT_ERROR;
+                    }
+                    if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
+                        ssl->buffers.inputBuffer.idx += ssl->specs.block_size;
+                        /* go past TLSv1.1 IV */
+                    if (ssl->specs.cipher_type == aead)
+                        ssl->buffers.inputBuffer.idx += AEAD_EXP_IV_SZ;
+
+                    ret = VerifyMac(ssl, ssl->buffers.inputBuffer.buffer +
+                                    ssl->buffers.inputBuffer.idx,
+                                    ssl->curSize, ssl->curRL.type,
+                                    &ssl->keys.padSz);
+                }
+                if (ret < 0) {
+                    CYASSL_ERROR(ret);
+                    return DECRYPT_ERROR;
+                }
+                ssl->keys.encryptSz    = ssl->curSize;
+                ssl->keys.decryptedCur = 1;
+            }
+
+            if (ssl->options.dtls) {
+            #ifdef CYASSL_DTLS
+                DtlsUpdateWindow(&ssl->keys.dtls_state);
+            #endif /* CYASSL_DTLS */
+            }
+
+            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 == CYASSL_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_state.nextEpoch++;
+                            ssl->keys.dtls_state.nextSeq = 0;
+                        }
+                    #endif
+
+                    #ifdef HAVE_LIBZ
+                        if (ssl->options.usingCompression)
+                            if ( (ret = InitStreams(ssl)) != 0)
+                                return ret;
+                    #endif
+                    if (ssl->options.resuming && ssl->options.side ==
+                                                              CYASSL_CLIENT_END)
+                        ret = BuildFinished(ssl, &ssl->verifyHashes, server);
+                    else if (!ssl->options.resuming && ssl->options.side ==
+                                                              CYASSL_SERVER_END)
+                        ret = BuildFinished(ssl, &ssl->verifyHashes, client);
+                    if (ret != 0)
+                        return ret;
+                    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!");
+                    ret = DoAlert(ssl, ssl->buffers.inputBuffer.buffer,
+                                  &ssl->buffers.inputBuffer.idx, &type,
+                                   ssl->buffers.inputBuffer.length);
+                    if (ret == alert_fatal)
+                        return FATAL_ERROR;
+                    else if (ret < 0)
+                        return ret;
+
+                    /* catch warnings that are handled as errors */
+                    if (type == close_notify)
+                        return ssl->error = ZERO_RETURN;
+                           
+                    if (type == decrypt_error)
+                        return FATAL_ERROR;
+                    break;
+            
+                default:
+                    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);
+}
+
+
+#ifndef NO_OLD_TLS
+static int SSL_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;
+    int    ret      = 0;
+
+    Md5 md5;
+    Sha sha;
+
+    /* data */
+    byte seq[SEQ_SZ];
+    byte conLen[ENUM_LEN + LENGTH_SZ];     /* content & length */
+    const byte* macSecret = CyaSSL_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 {
+        ret = InitSha(&sha);
+        if (ret != 0)
+            return ret;
+        /* 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);        
+    }
+    return 0;
+}
+
+#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)
+{
+#ifdef HAVE_TRUNCATED_HMAC
+    word32 digestSz = min(ssl->specs.hash_size,
+                ssl->truncated_hmac ? TRUNCATED_HMAC_SZ : ssl->specs.hash_size);
+#else
+    word32 digestSz = ssl->specs.hash_size;
+#endif
+    word32 sz = RECORD_HEADER_SZ + inSz + digestSz;                
+    word32 pad  = 0, i;
+    word32 idx  = RECORD_HEADER_SZ;
+    word32 ivSz = 0;      /* TLSv1.1  IV */
+    word32 headerSz = RECORD_HEADER_SZ;
+    word16 size;
+    byte               iv[AES_BLOCK_SIZE];                  /* max size */
+    int ret        = 0;
+    int atomicUser = 0;
+
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        sz       += DTLS_RECORD_EXTRA;
+        idx      += DTLS_RECORD_EXTRA; 
+        headerSz += DTLS_RECORD_EXTRA;
+    }
+#endif
+
+#ifdef ATOMIC_USER
+    if (ssl->ctx->MacEncryptCb)
+        atomicUser = 1;
+#endif
+
+    if (ssl->specs.cipher_type == block) {
+        word32 blockSz = ssl->specs.block_size;
+        if (ssl->options.tls1_1) {
+            ivSz = blockSz;
+            sz  += ivSz;
+            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 == block) {
+        word32 tmpIdx = idx + digestSz;
+
+        for (i = 0; i <= pad; i++)
+            output[tmpIdx++] = (byte)pad; /* pad byte gets pad value too */
+    }
+
+    if (atomicUser) {   /* User Record Layer Callback handling */
+#ifdef ATOMIC_USER
+        if ( (ret = ssl->ctx->MacEncryptCb(ssl, output + idx,
+                        output + headerSz + ivSz, inSz, type, 0,
+                        output + headerSz, output + headerSz, size,
+                        ssl->MacEncryptCtx)) != 0)
+            return ret;
+#endif
+    }
+    else {  
+        if (ssl->specs.cipher_type != aead) {
+#ifdef HAVE_TRUNCATED_HMAC
+            if (ssl->truncated_hmac && ssl->specs.hash_size > digestSz) {
+                byte hmac[MAX_DIGEST_SIZE];
+
+                ret = ssl->hmac(ssl, hmac, output + headerSz + ivSz, inSz,
+                                type, 0);
+                XMEMCPY(output + idx, hmac, digestSz);
+            } else
+#endif
+                ret = ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz,
+                                                                       type, 0);
+        }
+        if (ret != 0)
+            return ret;
+
+        if ( (ret = Encrypt(ssl, output + headerSz, output+headerSz,size)) != 0)
+            return ret;
+    }
+
+    return sz;
+}
+
+
+int SendFinished(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];
+    ret = BuildFinished(ssl, hashes,
+                      ssl->options.side == CYASSL_CLIENT_END ? client : server);
+    if (ret != 0) return ret;
+
+    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 == CYASSL_CLIENT_END) {
+            ret = BuildFinished(ssl, &ssl->verifyHashes, server);
+            if (ret != 0) return ret;
+        }
+        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 == CYASSL_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 {
+            ret = BuildFinished(ssl, &ssl->verifyHashes, client);
+            if (ret != 0) return ret;
+        }
+    }
+    #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 == CYASSL_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 (;;) {
+#ifdef HAVE_MAX_FRAGMENT
+        int   len = min(sz - sent, min(ssl->max_fragment, OUTPUT_RECORD_SIZE));
+#else
+        int   len = min(sz - sent, OUTPUT_RECORD_SIZE);
+#endif
+        byte* out;
+        byte* sendBuffer = (byte*)data + sent;  /* may switch on comp */
+        int   buffSz = len;                       /* may switch on comp */
+#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->error != 0 && ssl->error != WANT_WRITE) {
+        CYASSL_MSG("User calling CyaSSL_read in error state, not allowed");
+        return ssl->error;
+    }
+
+    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 = CYASSL_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 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 !!!! */
+static const char* const cipher_names[] = 
+{
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
+    "RC4-SHA",
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
+    "RC4-MD5",
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+    "DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+    "AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
+    "AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_NULL_SHA
+    "NULL-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256
+    "NULL-SHA256",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+    "DHE-RSA-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+    "DHE-RSA-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_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_MD5
+    "HC128-MD5",
+#endif
+    
+#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA
+    "HC128-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256
+    "HC128-B2B256",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
+    "AES128-B2B256",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
+    "AES256-B2B256",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA
+    "RABBIT-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+    "NTRU-RC4-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    "NTRU-DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+    "NTRU-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    "NTRU-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8
+    "AES128-CCM-8",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8
+    "AES256-CCM-8",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+    "ECDHE-ECDSA-AES128-CCM-8",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
+    "ECDHE-ECDSA-AES256-CCM-8",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+    "ECDHE-RSA-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+    "ECDHE-RSA-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+    "ECDHE-ECDSA-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+    "ECDHE-ECDSA-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
+    "ECDHE-RSA-RC4-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+    "ECDHE-RSA-DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+    "ECDHE-ECDSA-RC4-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+    "ECDHE-ECDSA-DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256
+    "AES128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256
+    "AES256-SHA256",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
+    "DHE-RSA-AES128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
+    "DHE-RSA-AES256-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
+    "ECDH-RSA-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
+    "ECDH-RSA-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
+    "ECDH-ECDSA-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
+    "ECDH-ECDSA-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA
+    "ECDH-RSA-RC4-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+    "ECDH-RSA-DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
+    "ECDH-ECDSA-RC4-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
+    "ECDH-ECDSA-DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256
+    "AES128-GCM-SHA256",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384
+    "AES256-GCM-SHA384",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+    "DHE-RSA-AES128-GCM-SHA256",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+    "DHE-RSA-AES256-GCM-SHA384",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+    "ECDHE-RSA-AES128-GCM-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+    "ECDHE-RSA-AES256-GCM-SHA384",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+    "ECDHE-ECDSA-AES128-GCM-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+    "ECDHE-ECDSA-AES256-GCM-SHA384",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+    "ECDH-RSA-AES128-GCM-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+    "ECDH-RSA-AES256-GCM-SHA384",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+    "ECDH-ECDSA-AES128-GCM-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+    "ECDH-ECDSA-AES256-GCM-SHA384",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+    "CAMELLIA128-SHA",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+    "DHE-RSA-CAMELLIA128-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
+    "CAMELLIA256-SHA",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+    "DHE-RSA-CAMELLIA256-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
+    "CAMELLIA128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+    "DHE-RSA-CAMELLIA128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
+    "CAMELLIA256-SHA256",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
+    "DHE-RSA-CAMELLIA256-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+    "ECDHE-RSA-AES128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+    "ECDHE-ECDSA-AES128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
+    "ECDH-RSA-AES128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
+    "ECDH-ECDSA-AES128-SHA256",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+    "ECDHE-RSA-AES256-SHA384",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+    "ECDHE-ECDSA-AES256-SHA384",
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
+    "ECDH-RSA-AES256-SHA384",
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
+    "ECDH-ECDSA-AES256-SHA384",
+#endif
+
+};
+
+
+
+/* cipher suite number that matches above name table */
+static int cipher_name_idx[] =
+{
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
+    SSL_RSA_WITH_RC4_128_SHA,
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
+    SSL_RSA_WITH_RC4_128_MD5,
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+    SSL_RSA_WITH_3DES_EDE_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+    TLS_RSA_WITH_AES_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
+    TLS_RSA_WITH_AES_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_NULL_SHA
+    TLS_RSA_WITH_NULL_SHA,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_NULL_SHA256
+    TLS_RSA_WITH_NULL_SHA256,
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_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_MD5
+    TLS_RSA_WITH_HC_128_MD5,    
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA
+    TLS_RSA_WITH_HC_128_SHA,    
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256
+    TLS_RSA_WITH_HC_128_B2B256,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
+    TLS_RSA_WITH_AES_128_CBC_B2B256,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
+    TLS_RSA_WITH_AES_256_CBC_B2B256,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA
+    TLS_RSA_WITH_RABBIT_SHA,    
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+    TLS_NTRU_RSA_WITH_RC4_128_SHA,
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+    TLS_NTRU_RSA_WITH_AES_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    TLS_NTRU_RSA_WITH_AES_256_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CCM_8
+    TLS_RSA_WITH_AES_128_CCM_8,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CCM_8
+    TLS_RSA_WITH_AES_256_CCM_8,
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+    TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
+    TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
+    TLS_ECDHE_RSA_WITH_RC4_128_SHA,    
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+    TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+    TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,    
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+    TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256
+    TLS_RSA_WITH_AES_128_CBC_SHA256,    
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256
+    TLS_RSA_WITH_AES_256_CBC_SHA256,
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,    
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
+    TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
+    TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
+    TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
+    TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA
+    TLS_ECDH_RSA_WITH_RC4_128_SHA,
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+    TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
+    TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
+    TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256
+    TLS_RSA_WITH_AES_128_GCM_SHA256,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384
+    TLS_RSA_WITH_AES_256_GCM_SHA384,
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+    TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+    TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+    TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+    TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+    TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+    TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+    TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+    TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+    TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
+    TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+    TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
+    TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+    TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
+    TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
+    TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
+    TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
+    TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+#endif
+
+#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
+    TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+#endif
+
+#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
+    TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
+#endif
+};
+
+
+/* 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, word32 size)
+    {
+        ProtocolVersion pv;
+        byte            cookieSz;
+        word32          begin = *inOutIdx;
+        
+#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
+        
+        if ((*inOutIdx - begin) + OPAQUE16_LEN + OPAQUE8_LEN > size)
+            return BUFFER_ERROR;
+
+        XMEMCPY(&pv, input + *inOutIdx, OPAQUE16_LEN);
+        *inOutIdx += OPAQUE16_LEN;
+
+        cookieSz = input[(*inOutIdx)++];
+        
+        if (cookieSz) {
+            if ((*inOutIdx - begin) + cookieSz > size)
+                return BUFFER_ERROR;
+
+#ifdef 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;
+        ProtocolVersion pv;
+        byte            compression;
+        word32          i = *inOutIdx;
+        word32          begin = i;
+
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo);
+#endif
+
+        /* protocol version, random and session id length check */
+        if ((i - begin) + OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz)
+            return BUFFER_ERROR;
+
+        /* protocol version */
+        XMEMCPY(&pv, input + i, OPAQUE16_LEN);
+        i += OPAQUE16_LEN;
+
+        if (pv.minor > ssl->version.minor) {
+            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;
+            }
+
+            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;
+            }
+        }
+
+        /* random */
+        XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN);
+        i += RAN_LEN;
+
+        /* session id */
+        b = input[i++];
+
+        if (b == ID_LEN) {
+            if ((i - begin) + ID_LEN > helloSz)
+                return BUFFER_ERROR;
+
+            XMEMCPY(ssl->arrays->sessionID, input + i, min(b, ID_LEN));
+            i += ID_LEN;
+            ssl->options.haveSessionId = 1;
+        }
+        else if (b) {
+            CYASSL_MSG("Invalid session ID size");
+            return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */
+        }
+
+        /* suite and compression */
+        if ((i - begin) + OPAQUE16_LEN + OPAQUE8_LEN > helloSz)
+            return BUFFER_ERROR;
+
+        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;
+
+        /* tls extensions */
+        if ( (i - begin) < helloSz) {
+#ifdef HAVE_TLS_EXTENSIONS
+            if (IsTLS(ssl)) {
+                int    ret = 0;
+                word16 totalExtSz;
+                Suites clSuites; /* just for compatibility right now */
+
+                if ((i - begin) + OPAQUE16_LEN > helloSz)
+                    return BUFFER_ERROR;
+
+                ato16(&input[i], &totalExtSz);
+                i += OPAQUE16_LEN;
+
+                if ((i - begin) + totalExtSz > helloSz)
+                    return BUFFER_ERROR;
+
+                if ((ret = TLSX_Parse(ssl, (byte *) input + i,
+                                                     totalExtSz, 0, &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, word32 size)
+    {
+        word16 len;
+        word32 begin = *inOutIdx;
+       
+        #ifdef CYASSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("CertificateRequest", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("CertificateRequest", &ssl->timeoutInfo);
+        #endif
+
+        if ((*inOutIdx - begin) + OPAQUE8_LEN > size)
+            return BUFFER_ERROR;
+
+        len = input[(*inOutIdx)++];
+
+        if ((*inOutIdx - begin) + len > size)
+            return BUFFER_ERROR;
+
+        /* types, read in here */
+        *inOutIdx += len;
+
+        /* signature and hash signature algorithm */
+        if (IsAtLeastTLSv1_2(ssl)) {
+            if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                return BUFFER_ERROR;
+
+            ato16(input + *inOutIdx, &len);
+            *inOutIdx += OPAQUE16_LEN;
+
+            if ((*inOutIdx - begin) + len > size)
+                return BUFFER_ERROR;
+
+            PickHashSigAlgo(ssl, input + *inOutIdx, len);
+            *inOutIdx += len;
+        }
+
+        /* authorities */
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &len);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + len > size)
+            return BUFFER_ERROR;
+
+        while (len) {
+            word16 dnSz;
+
+            if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                return BUFFER_ERROR;
+
+            ato16(input + *inOutIdx, &dnSz);
+            *inOutIdx += OPAQUE16_LEN;
+
+            if ((*inOutIdx - begin) + dnSz > size)
+                return BUFFER_ERROR;
+
+            *inOutIdx += dnSz;
+            len -= OPAQUE16_LEN + dnSz;
+        }
+
+        /* don't send client cert or cert verify if user hasn't provided
+           cert and private key */
+        if (ssl->buffers.certificate.buffer && ssl->buffers.key.buffer)
+            ssl->options.sendVerify = SEND_CERT;
+        else if (IsTLS(ssl))
+            ssl->options.sendVerify = SEND_BLANK_CERT;
+
+        return 0;
+    }
+#endif /* !NO_CERTS */
+
+
+    static int DoServerKeyExchange(CYASSL* ssl, const byte* input,
+                                   word32* inOutIdx, word32 size)
+    {
+        word16 length = 0;
+        word32 begin  = *inOutIdx;
+        int    ret    = 0;
+
+        (void)length; /* shut up compiler warnings */
+        (void)begin;
+        (void)ssl;
+        (void)input;
+        (void)size;
+        (void)ret;
+
+    #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) {
+
+            if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                return BUFFER_ERROR;
+
+            ato16(input + *inOutIdx, &length);
+            *inOutIdx += OPAQUE16_LEN;
+
+            if ((*inOutIdx - begin) + length > size)
+                return BUFFER_ERROR;
+
+            XMEMCPY(ssl->arrays->server_hint, input + *inOutIdx,
+                   min(length, MAX_PSK_ID_LEN));
+
+            ssl->arrays->server_hint[min(length, MAX_PSK_ID_LEN - 1)] = 0;
+            *inOutIdx += length;
+
+            return 0;
+        }
+    #endif
+    #ifdef OPENSSL_EXTRA
+        if (ssl->specs.kea == diffie_hellman_kea)
+        {
+        /* p */
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &length);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + length > size)
+            return BUFFER_ERROR;
+
+        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 */
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &length);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + length > size)
+            return BUFFER_ERROR;
+
+        ssl->buffers.serverDH_G.buffer = (byte*) XMALLOC(length, ssl->heap,
+                                                         DYNAMIC_TYPE_DH);
+
+        if (ssl->buffers.serverDH_G.buffer)
+            ssl->buffers.serverDH_G.length = length;
+        else
+            return MEMORY_ERROR;
+
+        XMEMCPY(ssl->buffers.serverDH_G.buffer, input + *inOutIdx, length);
+        *inOutIdx += length;
+
+        /* pub */
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &length);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + length > size)
+            return BUFFER_ERROR;
+
+        ssl->buffers.serverDH_Pub.buffer = (byte*) XMALLOC(length, ssl->heap,
+                                                           DYNAMIC_TYPE_DH);
+
+        if (ssl->buffers.serverDH_Pub.buffer)
+            ssl->buffers.serverDH_Pub.length = length;
+        else
+            return MEMORY_ERROR;
+
+        XMEMCPY(ssl->buffers.serverDH_Pub.buffer, input + *inOutIdx, length);
+        *inOutIdx += length;
+        }  /* dh_kea */
+    #endif /* OPENSSL_EXTRA */
+
+    #ifdef HAVE_ECC
+        if (ssl->specs.kea == ecc_diffie_hellman_kea)
+        {
+        byte b;
+
+        if ((*inOutIdx - begin) + ENUM_LEN + OPAQUE16_LEN + OPAQUE8_LEN > size)
+            return BUFFER_ERROR;
+
+        b = input[(*inOutIdx)++];
+
+        if (b != named_curve)
+            return ECC_CURVETYPE_ERROR;
+
+        *inOutIdx += 1;   /* curve type, eat leading 0 */
+        b = input[(*inOutIdx)++];
+
+        if (b != secp256r1 && b != secp384r1 && b != secp521r1 && b !=
+                 secp160r1 && b != secp192r1 && b != secp224r1)
+            return ECC_CURVE_ERROR;
+
+        length = input[(*inOutIdx)++];
+
+        if ((*inOutIdx - begin) + length > size)
+            return BUFFER_ERROR;
+
+        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
+#ifndef NO_SHA256
+        Sha256 sha256;
+        byte hash256[SHA256_DIGEST_SIZE];
+#endif
+#ifdef CYASSL_SHA384
+        Sha384 sha384;
+        byte hash384[SHA384_DIGEST_SIZE];
+#endif
+        byte   hash[FINISHED_SZ];
+        byte   messageVerify[MAX_DH_SZ];
+        byte   hashAlgo = sha_mac;
+        byte   sigAlgo  = ssl->specs.sig_algo;
+        word16 verifySz = (word16) (*inOutIdx - begin);
+
+        /* save message for hash verify */
+        if (verifySz > sizeof(messageVerify))
+            return BUFFER_ERROR;
+
+        XMEMCPY(messageVerify, input + begin, verifySz);
+
+        if (IsAtLeastTLSv1_2(ssl)) {
+            if ((*inOutIdx - begin) + ENUM_LEN + ENUM_LEN > size)
+                return BUFFER_ERROR;
+
+            hashAlgo = input[(*inOutIdx)++];
+            sigAlgo  = input[(*inOutIdx)++];
+        }
+
+        /* signature */
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &length);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + length > size)
+            return BUFFER_ERROR;
+
+        /* inOutIdx updated at the end of the function */
+
+        /* 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 */
+        ret = InitSha(&sha);
+        if (ret != 0)
+            return ret;
+        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
+        ret = InitSha256(&sha256);
+        if (ret != 0)
+            return ret;
+        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
+        ret = InitSha384(&sha384);
+        if (ret != 0)
+            return ret;
+        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)
+        {
+            byte* out       = NULL;
+            byte  doUserRsa = 0;
+
+            #ifdef HAVE_PK_CALLBACKS
+                if (ssl->ctx->RsaVerifyCb)
+                    doUserRsa = 1;
+            #endif /*HAVE_PK_CALLBACKS */
+
+            if (!ssl->peerRsaKeyPresent)
+                return NO_PEER_KEY;
+
+            if (doUserRsa) {
+            #ifdef HAVE_PK_CALLBACKS
+                ret = ssl->ctx->RsaVerifyCb(ssl, input + *inOutIdx, length,
+                                            &out, 
+                                            ssl->buffers.peerRsaKey.buffer,
+                                            ssl->buffers.peerRsaKey.length,
+                                            ssl->RsaVerifyCtx);
+            #endif /*HAVE_PK_CALLBACKS */
+            }
+            else {
+                ret = RsaSSL_VerifyInline((byte *) input + *inOutIdx, length,
+                                          &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 || !out || XMEMCMP(out, encodedSig,
+                                        min(encSigSz, MAX_ENCODED_SIG_SZ)) != 0)
+                    return VERIFY_SIGN_ERROR;
+            }
+            else { 
+                if (ret != sizeof(hash) || !out || 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;
+#ifndef NO_OLD_TLS
+            byte* digest = &hash[MD5_DIGEST_SIZE];
+            word32 digestSz = SHA_DIGEST_SIZE;
+#else
+            byte* digest = hash256;
+            word32 digestSz = SHA256_DIGEST_SIZE;
+#endif
+            byte doUserEcc = 0;
+
+            #ifdef HAVE_PK_CALLBACKS
+                if (ssl->ctx->EccVerifyCb)
+                    doUserEcc = 1;
+            #endif
+
+            if (!ssl->peerEccDsaKeyPresent)
+                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
+                }
+            }
+            if (doUserEcc) {
+            #ifdef HAVE_PK_CALLBACKS
+                ret = ssl->ctx->EccVerifyCb(ssl, input + *inOutIdx, length,
+                                            digest, digestSz,
+                                            ssl->buffers.peerEccDsaKey.buffer,
+                                            ssl->buffers.peerEccDsaKey.length,
+                                            &verify, ssl->EccVerifyCtx);
+            #endif
+            }
+            else {
+                ret = ecc_verify_hash(input + *inOutIdx, length,
+                                 digest, digestSz, &verify, ssl->peerEccDsaKey);
+            }
+            if (ret != 0 || verify == 0)
+                return VERIFY_SIGN_ERROR;
+        }
+        else
+#endif /* HAVE_ECC */
+            return ALGO_ID_E;
+
+        /* signature length */
+        *inOutIdx += length;
+
+        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;
+        byte   doUserRsa = 0;
+
+        (void)doUserRsa;
+
+        #ifdef HAVE_PK_CALLBACKS
+            #ifndef NO_RSA
+                if (ssl->ctx->RsaEncCb)
+                    doUserRsa = 1;
+            #endif /* NO_RSA */
+        #endif /*HAVE_PK_CALLBACKS */
+
+        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;
+
+                if (doUserRsa) {
+                #ifdef HAVE_PK_CALLBACKS
+                    #ifndef NO_RSA
+                        encSz = sizeof(encSecret);
+                        ret = ssl->ctx->RsaEncCb(ssl,
+                                            ssl->arrays->preMasterSecret,
+                                            SECRET_LEN,
+                                            encSecret, &encSz,
+                                            ssl->buffers.peerRsaKey.buffer,
+                                            ssl->buffers.peerRsaKey.length,
+                                            ssl->RsaEncCtx);
+                    #endif /* NO_RSA */
+                #endif /*HAVE_PK_CALLBACKS */
+                }
+                else {
+                    ret = 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 = NULL;
+                    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;
+                    }
+
+                    if (peerKey == NULL)
+                        return NO_PEER_KEY;
+
+                    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;
+        int                initRsaKey = 0;
+#endif
+        int                usingEcc = 0;
+#ifdef HAVE_ECC
+        ecc_key            eccKey;
+#endif
+
+        (void)idx;
+
+        if (ssl->options.sendVerify == SEND_BLANK_CERT)
+            return 0;  /* sent blank cert, can't verify */
+
+        /* 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
+        ret = InitRsaKey(&key, ssl->heap);
+        if (ret == 0) initRsaKey = 1;
+        if (ret == 0)
+            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;
+                byte   doUserEcc = 0;
+#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
+
+                #ifdef HAVE_PK_CALLBACKS
+                    #ifdef HAVE_ECC
+                        if (ssl->ctx->EccSignCb)
+                            doUserEcc = 1;
+                    #endif /* HAVE_ECC */
+                #endif /*HAVE_PK_CALLBACKS */
+
+                if (IsAtLeastTLSv1_2(ssl)) {
+                    if (ssl->suites->hashAlgo == sha_mac) {
+                        #ifndef NO_SHA
+                            digest = ssl->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
+                    }
+                }
+
+                if (doUserEcc) {
+                #ifdef HAVE_PK_CALLBACKS
+                    #ifdef HAVE_ECC
+                        ret = ssl->ctx->EccSignCb(ssl, digest, digestSz,
+                                        encodedSig, &localSz,
+                                        ssl->buffers.key.buffer,
+                                        ssl->buffers.key.length,
+                                        ssl->EccSignCtx);
+                    #endif /* HAVE_ECC */
+                #endif /*HAVE_PK_CALLBACKS */
+                }
+                else {
+                    ret = ecc_sign_hash(digest, digestSz, encodedSig,
+                                        &localSz, ssl->rng, &eccKey);
+                }
+                if (ret == 0) {
+                    length = localSz;
+                    c16toa((word16)length, verify + extraSz); /* prepend hdr */
+                    XMEMCPY(verify + extraSz + VERIFY_HEADER,encodedSig,length);
+                }
+#endif
+            }
+#ifndef NO_RSA
+            else {
+                byte doUserRsa = 0;
+
+                #ifdef HAVE_PK_CALLBACKS
+                    if (ssl->ctx->RsaSignCb)
+                        doUserRsa = 1;
+                #endif /*HAVE_PK_CALLBACKS */
+
+                if (IsAtLeastTLSv1_2(ssl)) {
+#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 */
+                if (doUserRsa) {
+                #ifdef HAVE_PK_CALLBACKS
+                    #ifndef NO_RSA
+                        word32 ioLen = ENCRYPT_LEN;
+                        ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz,
+                                            verify + extraSz + VERIFY_HEADER,
+                                            &ioLen,
+                                            ssl->buffers.key.buffer,
+                                            ssl->buffers.key.length,
+                                            ssl->RsaSignCtx);
+                    #endif /* NO_RSA */
+                #endif /*HAVE_PK_CALLBACKS */
+                }
+                else {
+                    ret = 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
+        if (initRsaKey)
+            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;
+            case 24:
+                return secp192r1;
+            case 28:
+                return secp224r1;
+            case 32:
+                return secp256r1;
+            case 48:
+                return secp384r1;
+            case 66:
+                return secp521r1;
+            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
+            ret = InitRsaKey(&rsaKey, ssl->heap);
+            if (ret != 0) return ret;
+#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);  /* 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 */
+                ret = InitSha(&sha);
+                if (ret != 0)
+                    return ret;
+                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
+                    ret = InitSha256(&sha256);
+                    if (ret != 0)
+                        return ret;
+                    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
+                    ret = InitSha384(&sha384);
+                    if (ret != 0)
+                        return ret;
+                    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];
+                    byte   doUserRsa = 0;
+
+                    #ifdef HAVE_PK_CALLBACKS
+                        if (ssl->ctx->RsaSignCb)
+                            doUserRsa = 1;
+                    #endif /*HAVE_PK_CALLBACKS */
+
+                    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;
+
+                    if (doUserRsa) {
+                        #ifdef HAVE_PK_CALLBACKS
+                            word32 ioLen = sigSz;
+                            ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz,
+                                                output + idx,
+                                                &ioLen,
+                                                ssl->buffers.key.buffer,
+                                                ssl->buffers.key.length,
+                                                ssl->RsaSignCtx);
+                        #endif /*HAVE_PK_CALLBACKS */
+                    }
+                    else {
+                        ret = RsaSSL_Sign(signBuffer, signSz, output + idx,
+                                          sigSz, &rsaKey, ssl->rng);
+                        if (ret > 0)
+                            ret = 0; /* reset on success */
+                    }
+                    FreeRsaKey(&rsaKey);
+                    ecc_free(&dsaKey);
+                    if (ret < 0)
+                        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;
+                    byte   doUserEcc = 0;
+
+                    #ifdef HAVE_PK_CALLBACKS
+                        #ifdef HAVE_ECC
+                            if (ssl->ctx->EccSignCb)
+                                doUserEcc = 1;
+                        #endif /* HAVE_ECC */
+                    #endif /*HAVE_PK_CALLBACKS */
+
+                    if (IsAtLeastTLSv1_2(ssl)) {
+                        if (ssl->suites->hashAlgo == sha_mac) {
+                            #ifndef NO_SHA
+                                digest   = &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
+                        }
+                    }
+
+                    if (doUserEcc) {
+                    #ifdef HAVE_PK_CALLBACKS
+                        #ifdef HAVE_ECC
+                            ret = ssl->ctx->EccSignCb(ssl, digest, digestSz,
+                                            output + LENGTH_SZ + idx, &sz,
+                                            ssl->buffers.key.buffer,
+                                            ssl->buffers.key.length,
+                                            ssl->EccSignCtx);
+                        #endif /* HAVE_ECC */
+                    #endif /*HAVE_PK_CALLBACKS */
+                    }
+                    else {
+                        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);
+
+            if (ret == 0) {
+                ret = InitRsaKey(&rsaKey, ssl->heap);
+                if (ret != 0) return ret;
+            }
+            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 */
+                ret = InitSha(&sha);
+                if (ret != 0)
+                    return ret;
+                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
+                    ret = InitSha256(&sha256);
+                    if (ret != 0)
+                        return ret;
+                    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
+                    ret = InitSha384(&sha384);
+                    if (ret != 0)
+                        return ret;
+                    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];
+                    byte   doUserRsa = 0;
+
+                    #ifdef HAVE_PK_CALLBACKS
+                        if (ssl->ctx->RsaSignCb)
+                            doUserRsa = 1;
+                    #endif /*HAVE_PK_CALLBACKS */
+
+                    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;
+                    }
+                    if (doUserRsa) {
+                        #ifdef HAVE_PK_CALLBACKS
+                            word32 ioLen = sigSz;
+                            ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz,
+                                                output + idx,
+                                                &ioLen,
+                                                ssl->buffers.key.buffer,
+                                                ssl->buffers.key.length,
+                                                ssl->RsaSignCtx);
+                        #endif /*HAVE_PK_CALLBACKS */
+                    }
+                    else {
+                        ret = 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_DES3
+        case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            break;
+#endif
+
+#ifndef NO_RC4
+        case TLS_ECDHE_RSA_WITH_RC4_128_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_RSA_WITH_RC4_128_SHA :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            break;
+#endif
+#endif /* NO_RSA */
+
+#ifndef NO_DES3
+        case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+#endif
+#ifndef NO_RC4
+        case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_ECDSA_WITH_RC4_128_SHA :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+#endif
+#ifndef NO_RSA
+        case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            break;
+#endif
+
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+
+        case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+
+        case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+
+#ifndef NO_RSA
+        case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            break;
+
+        case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 :
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_AES_128_CCM_8 :
+        case TLS_RSA_WITH_AES_256_CCM_8 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            break;
+
+        case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 :
+        case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            break;
+
+        case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 :
+        case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 :
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+#endif
+
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 :
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 :
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            break;
+
+        case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 :
+        case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 :
+            if (requirement == REQUIRES_ECC_DSA)
+                return 1;
+            if (requirement == REQUIRES_ECC_STATIC)
+                return 1;
+            break;
+
+        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_MD5 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+                
+        case TLS_RSA_WITH_HC_128_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_HC_128_B2B256:
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_AES_128_CBC_B2B256:
+        case TLS_RSA_WITH_AES_256_CBC_B2B256:
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_RABBIT_SHA :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_AES_128_GCM_SHA256 :
+        case TLS_RSA_WITH_AES_256_GCM_SHA384 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 :
+        case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            if (requirement == REQUIRES_DHE)
+                return 1;
+            break;
+
+        case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA :
+        case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA :
+        case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 :
+        case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            break;
+
+        case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA :
+        case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA :
+        case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 :
+        case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 :
+            if (requirement == REQUIRES_RSA)
+                return 1;
+            if (requirement == REQUIRES_RSA_SIG)
+                return 1;
+            if (requirement == REQUIRES_DHE)
+                return 1;
+            break;
+#endif
+
+        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 == CYASSL_SERVER_END &&
+                                           ssl->options.haveECDSAsig == 1) {
+                CYASSL_MSG("Don't have RSA Signature");
+                return 0;
+            }
+        }
+
+#ifdef HAVE_SUPPORTED_CURVES
+        if (!TLSX_ValidateEllipticCurves(ssl, first, second)) {
+            CYASSL_MSG("Don't have matching curves");
+                return 0;
+        }
+#endif
+
+        /* 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;
+        clSuites.hashSigAlgoSz = 0;
+
+        /* session size */
+        ato16(&input[idx], &sessionSz);
+        idx += 2;
+
+        if (sessionSz > ID_LEN)
+            return BUFFER_ERROR;
+    
+        /* random size */
+        ato16(&input[idx], &randomSz);
+        idx += 2;
+
+        if (randomSz > RAN_LEN)
+            return BUFFER_ERROR;
+
+        /* suites */
+        for (i = 0, j = 0; i < clSuites.suiteSz; i += 3) {    
+            byte first = input[idx++];
+            if (!first) { /* implicit: skip sslv2 type */
+                XMEMCPY(&clSuites.suites[j], &input[idx], 2);
+                j += 2;
+            }
+            idx += 2;
+        }
+        clSuites.suiteSz = j;
+
+        /* session id */
+        if (sessionSz) {
+            XMEMCPY(ssl->arrays->sessionID, input + idx, sessionSz);
+            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 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
+
+        /* protocol version, random and session id length check */
+        if ((i - begin) + OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz)
+            return BUFFER_ERROR;
+
+        /* protocol version */
+        XMEMCPY(&pv, input + i, OPAQUE16_LEN);
+        ssl->chVersion = pv;   /* store */
+        i += OPAQUE16_LEN;
+
+        if (ssl->version.minor > pv.minor) {
+            byte haveRSA = 0;
+            byte havePSK = 0;
+
+            if (!ssl->options.downgrade) {
+                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 == ID_LEN) {
+            if ((i - begin) + ID_LEN > helloSz)
+                return BUFFER_ERROR;
+
+            XMEMCPY(ssl->arrays->sessionID, input + i, ID_LEN);
+            i += ID_LEN;
+            ssl->options.resuming = 1; /* client wants to resume */
+            CYASSL_MSG("Client wants to resume session");
+        }
+        else if (b) {
+            CYASSL_MSG("Invalid session ID size");
+            return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */
+        }
+        
+        #ifdef CYASSL_DTLS
+            /* cookie */
+            if (ssl->options.dtls) {
+
+                if ((i - begin) + OPAQUE8_LEN > helloSz)
+                    return BUFFER_ERROR;
+
+                b = input[i++];
+
+                if (b) {
+                    byte cookie[MAX_COOKIE_LEN];
+
+                    if (b > MAX_COOKIE_LEN)
+                        return BUFFER_ERROR;
+
+                    if ((i - begin) + b > helloSz)
+                        return BUFFER_ERROR;
+
+                    if (ssl->ctx->CBIOCookie == NULL) {
+                        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
+
+        /* suites */
+        if ((i - begin) + OPAQUE16_LEN > helloSz)
+            return BUFFER_ERROR;
+
+        ato16(&input[i], &clSuites.suiteSz);
+        i += OPAQUE16_LEN;
+
+        /* suites and compression length check */
+        if ((i - begin) + clSuites.suiteSz + OPAQUE8_LEN > helloSz)
+            return BUFFER_ERROR;
+
+        if (clSuites.suiteSz > MAX_SUITE_SZ)
+            return BUFFER_ERROR;
+
+        XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz);
+        i += clSuites.suiteSz;
+        clSuites.hashSigAlgoSz = 0;
+
+        /* compression length */
+        b = input[i++];
+
+        if ((i - begin) + b > helloSz)
+            return BUFFER_ERROR;
+
+        if (ssl->options.usingCompression) {
+            int match = 0;
+
+            while (b--) {
+                byte comp = input[i++];
+
+                if (comp == ZLIB_COMPRESSION)
+                    match = 1;
+            }
+
+            if (!match) {
+                CYASSL_MSG("Not matching compression, turning off"); 
+                ssl->options.usingCompression = 0;  /* turn off */
+            }
+        }
+        else
+            i += b; /* ignore, since we're not on */
+
+        *inOutIdx = i;
+
+        /* tls extensions */
+        if ((i - begin) < helloSz) {
+#ifdef HAVE_TLS_EXTENSIONS
+            if (IsTLS(ssl)) {
+                int ret = 0;
+#else
+            if (IsAtLeastTLSv1_2(ssl)) {
+#endif
+                /* Process the hello extension. Skip unsupported. */
+                word16 totalExtSz;
+
+                if ((i - begin) + OPAQUE16_LEN > helloSz)
+                    return BUFFER_ERROR;
+
+                ato16(&input[i], &totalExtSz);
+                i += OPAQUE16_LEN;
+
+                if ((i - begin) + totalExtSz > helloSz)
+                    return BUFFER_ERROR;
+
+#ifdef HAVE_TLS_EXTENSIONS
+                if ((ret = TLSX_Parse(ssl, (byte *) input + i,
+                                                     totalExtSz, 1, &clSuites)))
+                    return ret;
+
+                i += totalExtSz;
+#else
+                while (totalExtSz) {
+                    word16 extId, extSz;
+
+                    if (OPAQUE16_LEN + OPAQUE16_LEN > totalExtSz)
+                        return BUFFER_ERROR;
+                   
+                    ato16(&input[i], &extId);
+                    i += OPAQUE16_LEN;
+                    ato16(&input[i], &extSz);
+                    i += OPAQUE16_LEN;
+
+                    if (OPAQUE16_LEN + OPAQUE16_LEN + extSz > totalExtSz)
+                        return BUFFER_ERROR;
+
+                    if (extId == HELLO_EXT_SIG_ALGO) {
+                        ato16(&input[i], &clSuites.hashSigAlgoSz);
+                        i += OPAQUE16_LEN;
+
+                        if (OPAQUE16_LEN + clSuites.hashSigAlgoSz > extSz)
+                            return BUFFER_ERROR;
+
+                        XMEMCPY(clSuites.hashSigAlgo, &input[i],
+                            min(clSuites.hashSigAlgoSz, HELLO_EXT_SIGALGO_MAX));
+                        i += clSuites.hashSigAlgoSz;
+                    }
+                    else
+                        i += extSz;
+
+                    totalExtSz -= OPAQUE16_LEN + OPAQUE16_LEN + extSz;
+                }
+#endif
+                *inOutIdx = i;
+            }
+            else
+                *inOutIdx = begin + helloSz; /* skip extensions */
+        }
+
+        ssl->options.clientState   = CLIENT_HELLO_COMPLETE;
+        ssl->options.haveSessionId = 1;
+        
+        /* ProcessOld uses same resume code */
+        if (ssl->options.resuming && (!ssl->options.dtls ||
+               ssl->options.acceptState == HELLO_VERIFY_SENT)) { /* let's try */
+            int ret = -1;            
+            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* inOutIdx,
+                                   word32 size)
+    {
+        word16      sz = 0;
+        int         ret = VERIFY_CERT_ERROR;   /* start in error state */
+        byte        hashAlgo = sha_mac;
+        byte        sigAlgo = anonymous_sa_algo;
+        word32      begin = *inOutIdx;
+
+        #ifdef CYASSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("CertificateVerify", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("CertificateVerify", &ssl->timeoutInfo);
+        #endif
+
+
+        if (IsAtLeastTLSv1_2(ssl)) {
+            if ((*inOutIdx - begin) + ENUM_LEN + ENUM_LEN > size)
+                return BUFFER_ERROR;
+
+            hashAlgo = input[(*inOutIdx)++];
+            sigAlgo  = input[(*inOutIdx)++];
+        }
+
+        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+            return BUFFER_ERROR;
+
+        ato16(input + *inOutIdx, &sz);
+        *inOutIdx += OPAQUE16_LEN;
+
+        if ((*inOutIdx - begin) + sz > size || sz > ENCRYPT_LEN)
+            return BUFFER_ERROR;
+
+        /* RSA */
+#ifndef NO_RSA
+        if (ssl->peerRsaKeyPresent != 0) {
+            byte* out       = NULL;
+            int   outLen    = 0;
+            byte  doUserRsa = 0;
+
+            #ifdef HAVE_PK_CALLBACKS
+                if (ssl->ctx->RsaVerifyCb)
+                    doUserRsa = 1;
+            #endif /*HAVE_PK_CALLBACKS */
+
+            CYASSL_MSG("Doing RSA peer cert verify");
+
+            if (doUserRsa) {
+            #ifdef HAVE_PK_CALLBACKS
+                outLen = ssl->ctx->RsaVerifyCb(ssl, input + *inOutIdx, sz,
+                                            &out, 
+                                            ssl->buffers.peerRsaKey.buffer,
+                                            ssl->buffers.peerRsaKey.length,
+                                            ssl->RsaVerifyCtx);
+            #endif /*HAVE_PK_CALLBACKS */
+            }
+            else {
+                outLen = RsaSSL_VerifyInline(input + *inOutIdx, 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 && out && XMEMCMP(out, encodedSig,
+                                           min(sigSz, MAX_ENCODED_SIG_SZ)) == 0)
+                    ret = 0; /* verified */
+            }
+            else {
+                if (outLen == FINISHED_SZ && out && 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;
+            byte doUserEcc = 0;
+
+            #ifdef HAVE_PK_CALLBACKS
+                if (ssl->ctx->EccVerifyCb)
+                    doUserEcc = 1;
+            #endif
+
+            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
+                }
+            }
+
+            if (doUserEcc) {
+            #ifdef HAVE_PK_CALLBACKS
+                ret = ssl->ctx->EccVerifyCb(ssl, input + *inOutIdx, sz, digest,
+                                            digestSz,
+                                            ssl->buffers.peerEccDsaKey.buffer,
+                                            ssl->buffers.peerEccDsaKey.length,
+                                            &verify, ssl->EccVerifyCtx);
+            #endif
+            }
+            else {
+                err = ecc_verify_hash(input + *inOutIdx, sz, digest, digestSz,
+                                                   &verify, ssl->peerEccDsaKey);
+            }
+
+            if (err == 0 && verify == 1)
+               ret = 0; /* verified */
+        }
+#endif
+        *inOutIdx += sz;
+
+        if (ret == 0)
+            ssl->options.havePeerVerify = 1;
+          
+        return ret;
+    }
+#endif /* !NO_RSA || HAVE_ECC */
+
+    int SendServerHelloDone(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 size)
+    {
+        int    ret = 0;
+        word32 length = 0;
+        byte*  out = NULL;
+        word32 begin = *inOutIdx;
+
+        (void)length; /* shut up compiler warnings */
+        (void)out;
+        (void)input;
+        (void)size;
+
+        if (ssl->options.side != CYASSL_SERVER_END) {
+            CYASSL_MSG("Client received client keyexchange, attack?");
+            CYASSL_ERROR(ssl->error = SIDE_ERROR);
+            return SSL_FATAL_ERROR;
+        }
+
+        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   doUserRsa = 0;
+
+                #ifdef HAVE_PK_CALLBACKS
+                    if (ssl->ctx->RsaDecCb)
+                        doUserRsa = 1;
+                #endif
+
+                ret = InitRsaKey(&key, ssl->heap);
+                if (ret != 0) return ret;
+
+                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;
+
+                        if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                            return BUFFER_ERROR;
+
+                        ato16(input + *inOutIdx, &check);
+                        *inOutIdx += OPAQUE16_LEN;
+
+                        if ((word32) check != length) {
+                            CYASSL_MSG("RSA explicit size doesn't match");
+                            FreeRsaKey(&key);
+                            return RSA_PRIVATE_ERROR;
+                        }
+                    }
+
+                    if ((*inOutIdx - begin) + length > size) {
+                        CYASSL_MSG("RSA message too big");
+                        FreeRsaKey(&key);
+                        return BUFFER_ERROR;
+                    }
+
+                    if (doUserRsa) {
+                        #ifdef HAVE_PK_CALLBACKS
+                            ret = ssl->ctx->RsaDecCb(ssl,
+                                        input + *inOutIdx, length, &out,
+                                        ssl->buffers.key.buffer,
+                                        ssl->buffers.key.length,
+                                        ssl->RsaDecCtx);
+                        #endif
+                    }
+                    else {
+                        ret = RsaPrivateDecryptInline(input + *inOutIdx, length,
+                                                                    &out, &key);
+                    }
+
+                    *inOutIdx += length;
+
+                    if (ret == SECRET_LEN) {
+                        XMEMCPY(ssl->arrays->preMasterSecret, out, SECRET_LEN);
+                        if (ssl->arrays->preMasterSecret[0] !=
+                                                           ssl->chVersion.major
+                            || ssl->arrays->preMasterSecret[1] != 
+                                                           ssl->chVersion.minor)
+                            ret = PMS_VERSION_ERROR;
+                        else
+                            ret = MakeMasterSecret(ssl);
+                    }
+                    else {
+                        ret = RSA_PRIVATE_ERROR;
+                    }
+                }
+
+                FreeRsaKey(&key);
+            }
+            break;
+        #endif
+        #ifndef NO_PSK
+            case psk_kea:
+            {
+                byte* pms = ssl->arrays->preMasterSecret;
+                word16 ci_sz;
+
+                if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                    return BUFFER_ERROR;
+
+                ato16(input + *inOutIdx, &ci_sz);
+                *inOutIdx += OPAQUE16_LEN;
+
+                if (ci_sz > MAX_PSK_ID_LEN)
+                    return CLIENT_ID_ERROR;
+
+                if ((*inOutIdx - begin) + ci_sz > size)
+                    return BUFFER_ERROR;
+
+                XMEMCPY(ssl->arrays->client_identity, input + *inOutIdx, ci_sz);
+                *inOutIdx += ci_sz;
+
+                ssl->arrays->client_identity[min(ci_sz, MAX_PSK_ID_LEN-1)] = 0;
+                ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl,
+                    ssl->arrays->client_identity, ssl->arrays->psk_key,
+                    MAX_PSK_KEY_LEN);
+
+                if (ssl->arrays->psk_keySz == 0 || 
+                                       ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN)
+                    return PSK_KEY_ERROR;
+                
+                /* make psk pre master secret */
+                /* length of key + length 0s + length of key + key */
+                c16toa((word16) ssl->arrays->psk_keySz, pms);
+                pms += OPAQUE16_LEN;
+
+                XMEMSET(pms, 0, ssl->arrays->psk_keySz);
+                pms += ssl->arrays->psk_keySz;
+
+                c16toa((word16) ssl->arrays->psk_keySz, pms);
+                pms += OPAQUE16_LEN;
+
+                XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz);
+                ssl->arrays->preMasterSz = ssl->arrays->psk_keySz * 2 + 4;
+
+                ret = MakeMasterSecret(ssl);
+
+                /* No further need for PSK */
+                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:
+            {
+                word16 cipherLen;
+                word16 plainLen = sizeof(ssl->arrays->preMasterSecret);
+
+                if (!ssl->buffers.key.buffer)
+                    return NO_PRIVATE_KEY;
+
+                if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                    return BUFFER_ERROR;
+
+                ato16(input + *inOutIdx, &cipherLen);
+                *inOutIdx += OPAQUE16_LEN;
+
+                if (cipherLen > MAX_NTRU_ENCRYPT_SZ)
+                    return NTRU_KEY_ERROR;
+
+                if ((*inOutIdx - begin) + cipherLen > size)
+                    return BUFFER_ERROR;
+
+                if (NTRU_OK != crypto_ntru_decrypt(
+                            (word16) ssl->buffers.key.length,
+                            ssl->buffers.key.buffer, cipherLen,
+                            input + *inOutIdx, &plainLen,
+                            ssl->arrays->preMasterSecret))
+                    return NTRU_DECRYPT_ERROR;
+
+                if (plainLen != SECRET_LEN)
+                    return NTRU_DECRYPT_ERROR;
+
+                *inOutIdx += cipherLen;
+
+                ssl->arrays->preMasterSz = plainLen;
+                ret = MakeMasterSecret(ssl);
+            }
+            break;
+        #endif /* HAVE_NTRU */
+        #ifdef HAVE_ECC
+            case ecc_diffie_hellman_kea:
+            {
+                if ((*inOutIdx - begin) + OPAQUE8_LEN > size)
+                    return BUFFER_ERROR;
+
+                length = input[(*inOutIdx)++];
+
+                if ((*inOutIdx - begin) + length > size)
+                    return BUFFER_ERROR;
+
+                if (ecc_import_x963(input + *inOutIdx, length, ssl->peerEccKey))
+                    return ECC_PEERKEY_ERROR;
+
+                *inOutIdx += length;
+                ssl->peerEccKeyPresent = 1;
+
+                length = sizeof(ssl->arrays->preMasterSecret);
+
+                if (ssl->specs.static_ecdh) {
+                    ecc_key staticKey;
+                    word32 i = 0;
+
+                    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, &length);
+
+                    ecc_free(&staticKey);
+                }
+                else
+                    ret = ecc_shared_secret(ssl->eccTempKey, ssl->peerEccKey,
+                                         ssl->arrays->preMasterSecret, &length);
+
+                if (ret != 0)
+                    return ECC_SHARED_ERROR;
+
+                ssl->arrays->preMasterSz = length;
+                ret = MakeMasterSecret(ssl);
+            }
+            break;
+        #endif /* HAVE_ECC */
+        #ifdef OPENSSL_EXTRA 
+            case diffie_hellman_kea:
+            {
+                word16 clientPubSz;
+                DhKey  dhKey;
+
+                if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
+                    return BUFFER_ERROR;
+
+                ato16(input + *inOutIdx, &clientPubSz);
+                *inOutIdx += OPAQUE16_LEN;
+
+                if ((*inOutIdx - begin) + clientPubSz > size)
+                    return BUFFER_ERROR;
+
+                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,
+                                          input + *inOutIdx, clientPubSz);
+                FreeDhKey(&dhKey);
+
+                *inOutIdx += clientPubSz;
+
+                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 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/io.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,1050 @@
+/* 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 <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/error-ssl.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)
+        #if defined(CYASSL_MDK5)
+            #include "cmsis_os.h"
+            #include "rl_fs.h" 
+            #include "rl_net.h" 
+        #else
+            #include <rtl.h>
+        #endif
+        #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
+    #define close(s) closesocket(s)
+#elif defined(__PPU)
+    #define SOCKET_EWOULDBLOCK SYS_NET_EWOULDBLOCK
+    #define SOCKET_EAGAIN      SYS_NET_EAGAIN
+    #define SOCKET_ECONNRESET  SYS_NET_ECONNRESET
+    #define SOCKET_EINTR       SYS_NET_EINTR
+    #define SOCKET_EPIPE       SYS_NET_EPIPE
+    #define SOCKET_ECONNREFUSED SYS_NET_ECONNREFUSED
+    #define SOCKET_ECONNABORTED SYS_NET_ECONNABORTED
+#elif defined(FREESCALE_MQX)
+    /* RTCS doesn't have an EWOULDBLOCK error */
+    #define SOCKET_EWOULDBLOCK EAGAIN
+    #define SOCKET_EAGAIN      EAGAIN
+    #define SOCKET_ECONNRESET  RTCSERR_TCP_CONN_RESET
+    #define SOCKET_EINTR       EINTR
+    #define SOCKET_EPIPE       EPIPE
+    #define SOCKET_ECONNREFUSED RTCSERR_TCP_CONN_REFUSED
+    #define SOCKET_ECONNABORTED RTCSERR_TCP_CONN_ABORTED
+#elif defined(CYASSL_MDK_ARM)
+    #if defined(CYASSL_MDK5)
+        #define SOCKET_EWOULDBLOCK BSD_ERROR_WOULDBLOCK
+        #define SOCKET_EAGAIN      BSD_ERROR_LOCKED
+        #define SOCKET_ECONNRESET  BSD_ERROR_CLOSED
+        #define SOCKET_EINTR       BSD_ERROR
+        #define SOCKET_EPIPE       BSD_ERROR
+        #define SOCKET_ECONNREFUSED BSD_ERROR
+        #define SOCKET_ECONNABORTED BSD_ERROR
+    #else
+        #define SOCKET_EWOULDBLOCK SCK_EWOULDBLOCK
+        #define SOCKET_EAGAIN      SCK_ELOCKED
+        #define SOCKET_ECONNRESET  SCK_ECLOSED
+        #define SOCKET_EINTR       SCK_ERROR
+        #define SOCKET_EPIPE       SCK_ERROR
+        #define SOCKET_ECONNREFUSED SCK_ERROR
+        #define SOCKET_ECONNABORTED SCK_ERROR
+    #endif
+#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_storage 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);
+
+    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_storage peer;
+    XSOCKLENT peerSz = sizeof(peer);
+    Sha sha;
+    byte digest[SHA_DIGEST_SIZE];
+    int  ret = 0;
+
+    (void)ctx;
+
+    XMEMSET(&peer, 0, sizeof(peer));
+    if (getpeername(sd, (struct sockaddr*)&peer, &peerSz) != 0) {
+        CYASSL_MSG("getpeername failed in EmbedGenerateCookie");
+        return GEN_COOKIE_E;
+    }
+    
+    ret = InitSha(&sha);
+    if (ret != 0)
+        return ret;
+    ShaUpdate(&sha, (byte*)&peer, peerSz);
+    ShaFinal(&sha, digest);
+
+    if (sz > SHA_DIGEST_SIZE)
+        sz = SHA_DIGEST_SIZE;
+    XMEMCPY(buf, digest, sz);
+
+    return sz;
+}
+
+#endif /* CYASSL_DTLS */
+
+#ifdef HAVE_OCSP
+
+
+static int tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port)
+{
+    struct sockaddr_storage addr;
+    int sockaddr_len = sizeof(struct sockaddr_in);
+    XMEMSET(&addr, 0, sizeof(addr));
+
+    #ifdef HAVE_GETADDRINFO
+    {
+        struct addrinfo hints;
+        struct addrinfo* answer = NULL;
+        char strPort[8];
+
+        XMEMSET(&hints, 0, sizeof(hints));
+        hints.ai_family = AF_UNSPEC;
+        hints.ai_socktype = SOCK_STREAM;
+        hints.ai_protocol = IPPROTO_TCP;
+
+        XSNPRINTF(strPort, sizeof(strPort), "%d", port);
+        strPort[7] = '\0';
+
+        if (getaddrinfo(ip, strPort, &hints, &answer) < 0 || answer == NULL) {
+            CYASSL_MSG("no addr info for OCSP responder");
+            return -1;
+        }
+
+        sockaddr_len = answer->ai_addrlen;
+        XMEMCPY(&addr, answer->ai_addr, sockaddr_len);
+        freeaddrinfo(answer);
+
+    }
+    #else /* HAVE_GETADDRINFO */
+    {
+        struct hostent* entry = gethostbyname(ip);
+        struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
+
+        if (entry) {
+            sin->sin_family = AF_INET;
+            sin->sin_port = htons(port);
+            XMEMCPY(&sin->sin_addr.s_addr, entry->h_addr_list[0],
+                                                               entry->h_length);
+        }
+        else {
+            CYASSL_MSG("no addr info for OCSP responder");
+            return -1;
+        }
+    }
+    #endif /* HAVE_GETADDRINFO */
+
+    *sockfd = socket(addr.ss_family, SOCK_STREAM, 0);
+    if (*sockfd < 0) {
+        CYASSL_MSG("bad socket fd, out of fds?");
+        return -1;
+    }
+
+    if (connect(*sockfd, (struct sockaddr *)&addr, sockaddr_len) != 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 XSNPRINTF((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_url(const char* url, int urlSz,
+    char* outName, char* outPath, word16* outPort)
+{
+    int result = -1;
+
+    if (outName != NULL && outPath != NULL && outPort != NULL)
+    {
+        if (url == NULL || urlSz == 0)
+        {
+            *outName = 0;
+            *outPath = 0;
+            *outPort = 0;
+        }
+        else
+        {
+            int i, cur;
+    
+            /* need to break the url down into scheme, address, and port */
+            /*     "http://example.com:8080/" */
+            /*     "http://[::1]:443/"        */
+            if (XSTRNCMP(url, "http://", 7) == 0) {
+                cur = 7;
+            } else cur = 0;
+    
+            i = 0;
+            if (url[cur] == '[') {
+                cur++;
+                /* copy until ']' */
+                while (url[cur] != 0 && url[cur] != ']' && cur < urlSz) {
+                    outName[i++] = url[cur++];
+                }
+                cur++; /* skip ']' */
+            }
+            else {
+                while (url[cur] != 0 && url[cur] != ':' &&
+                                               url[cur] != '/' && cur < urlSz) {
+                    outName[i++] = url[cur++];
+                }
+            }
+            outName[i] = 0;
+            /* Need to pick out the path after the domain name */
+    
+            if (cur < urlSz && url[cur] == ':') {
+                char port[6];
+                int j;
+                word32 bigPort = 0;
+                i = 0;
+                cur++;
+                while (cur < urlSz && url[cur] != 0 && url[cur] != '/' &&
+                        i < 6) {
+                    port[i++] = url[cur++];
+                }
+    
+                for (j = 0; j < i; j++) {
+                    if (port[j] < '0' || port[j] > '9') return -1;
+                    bigPort = (bigPort * 10) + (port[j] - '0');
+                }
+                *outPort = (word16)bigPort;
+            }
+            else
+                *outPort = 80;
+    
+            if (cur < urlSz && url[cur] == '/') {
+                i = 0;
+                while (cur < urlSz && url[cur] != 0 && i < 80) {
+                    outPath[i++] = url[cur++];
+                }
+                outPath[i] = 0;
+            }
+            else {
+                outPath[0] = '/';
+                outPath[1] = 0;
+            }
+            result = 0;
+        }
+    }
+
+    return result;
+}
+
+
+/* return: >0 OCSP Response Size
+ *         -1 error */
+static int process_http_response(int sfd, byte** respBuf,
+                                                  byte* httpBuf, int httpBufSz)
+{
+    int result;
+    int len = 0;
+    char *start, *end;
+    byte *recvBuf = NULL;
+    int recvBufSz = 0;
+    enum phr_state { phr_init, phr_http_start, phr_have_length,
+                     phr_have_type, phr_wait_end, phr_http_end
+    } state = phr_init;
+
+    start = end = NULL;
+    do {
+        if (end == NULL) {
+            result = (int)recv(sfd, (char*)httpBuf+len, httpBufSz-len-1, 0);
+            if (result > 0) {
+                len += result;
+                start = (char*)httpBuf;
+                start[len] = 0;
+            }
+            else {
+                CYASSL_MSG("process_http_response recv http from peer failed");
+                return -1;
+            }
+        }
+        end = XSTRSTR(start, "\r\n");
+
+        if (end == NULL) {
+            if (len != 0)
+                XMEMMOVE(httpBuf, start, len);
+            start = end = NULL;
+        }
+        else if (end == start) {
+            if (state == phr_wait_end) {
+                state = phr_http_end;
+                len -= 2;
+                start += 2;
+             }
+             else {
+                CYASSL_MSG("process_http_response header ended early");
+                return -1;
+             }
+        }
+        else {
+            *end = 0;
+            len -= (int)(end - start) + 2;
+                /* adjust len to remove the first line including the /r/n */
+
+            if (XSTRNCASECMP(start, "HTTP/1", 6) == 0) {
+                start += 9;
+                if (XSTRNCASECMP(start, "200 OK", 6) != 0 ||
+                                                           state != phr_init) {
+                    CYASSL_MSG("process_http_response not OK");
+                    return -1;
+                }
+                state = phr_http_start;
+            }
+            else if (XSTRNCASECMP(start, "Content-Type:", 13) == 0) {
+                start += 13;
+                while (*start == ' ' && *start != '\0') start++;
+                if (XSTRNCASECMP(start, "application/ocsp-response", 25) != 0) {
+                    CYASSL_MSG("process_http_response not ocsp-response");
+                    return -1;
+                }
+                
+                if (state == phr_http_start) state = phr_have_type;
+                else if (state == phr_have_length) state = phr_wait_end;
+                else {
+                    CYASSL_MSG("process_http_response type invalid state");
+                    return -1;
+                }
+            }
+            else if (XSTRNCASECMP(start, "Content-Length:", 15) == 0) {
+                start += 15;
+                while (*start == ' ' && *start != '\0') start++;
+                recvBufSz = atoi(start);
+
+                if (state == phr_http_start) state = phr_have_length;
+                else if (state == phr_have_type) state = phr_wait_end;
+                else {
+                    CYASSL_MSG("process_http_response length invalid state");
+                    return -1;
+                }
+            }
+            
+            start = end + 2;
+        }
+    } while (state != phr_http_end);
+
+    recvBuf = XMALLOC(recvBufSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
+    if (recvBuf == NULL) {
+        CYASSL_MSG("process_http_response couldn't create response buffer");
+        return -1;
+    }
+
+    /* copy the remainder of the httpBuf into the respBuf */
+    if (len != 0)
+        XMEMCPY(recvBuf, start, len);
+
+    /* receive the OCSP response data */
+    do {
+        result = (int)recv(sfd, (char*)recvBuf+len, recvBufSz-len, 0);
+        if (result > 0)
+            len += result;
+        else {
+            CYASSL_MSG("process_http_response recv ocsp from peer failed");
+            return -1;
+        }
+    } while (len != recvBufSz);
+
+    *respBuf = recvBuf;
+    return recvBufSz;
+}
+
+
+#define SCRATCH_BUFFER_SIZE 512
+
+int EmbedOcspLookup(void* ctx, const char* url, int urlSz,
+                        byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf)
+{
+    char domainName[80], path[80];
+    int httpBufSz;
+    SOCKET_T sfd = 0;
+    word16 port;
+    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;
+    }
+    
+    /* Note, the library uses the EmbedOcspRespFree() callback to
+     * free this buffer. */
+    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;
+    }
+
+    httpBufSz = build_http_request(domainName, path, ocspReqSz,
+                                                        httpBuf, httpBufSz);
+
+    if ((tcp_connect(&sfd, domainName, port) == 0) && (sfd > 0)) {
+        int written;
+        written = (int)send(sfd, (char*)httpBuf, httpBufSz, 0);
+        if (written == httpBufSz) {
+            written = (int)send(sfd, (char*)ocspReqBuf, ocspReqSz, 0);
+            if (written == ocspReqSz) {
+                ocspRespSz = process_http_response(sfd, ocspRespBuf,
+                                                 httpBuf, SCRATCH_BUFFER_SIZE);
+            }
+        }
+        close(sfd);
+        if (ocspRespSz == 0) {
+            CYASSL_MSG("OCSP response was not OK, no OCSP response");
+            XFREE(httpBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
+            return -1;
+        }
+    } else {
+        CYASSL_MSG("OCSP Responder connection failed");
+        close(sfd);
+        XFREE(httpBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
+        return -1;
+    }
+
+    XFREE(httpBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
+    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_GetIOReadCtx(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->IOCB_ReadCtx;
+
+    return NULL;
+}
+
+
+CYASSL_API void* CyaSSL_GetIOWriteCtx(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->IOCB_WriteCtx;
+
+    return NULL;
+}
+
+
+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;
+}
+
+
+CYASSL_API void* CyaSSL_GetCookieCtx(CYASSL* ssl)
+{
+    if (ssl)
+	    return ssl->IOCB_CookieCtx;
+
+    return NULL;
+}
+
+#endif /* CYASSL_DTLS */
+
+
+#ifdef HAVE_NETX
+
+/* The NetX receive callback
+ *  return :  bytes read, or error
+ */
+int NetX_Receive(CYASSL *ssl, char *buf, int sz, void *ctx)
+{
+    NetX_Ctx* nxCtx = (NetX_Ctx*)ctx;
+    ULONG left;
+    ULONG total;
+    ULONG copied = 0;
+    UINT  status;
+
+    if (nxCtx == NULL || nxCtx->nxSocket == NULL) {
+        CYASSL_MSG("NetX Recv NULL parameters");
+        return CYASSL_CBIO_ERR_GENERAL;
+    }
+
+    if (nxCtx->nxPacket == NULL) {
+        status = nx_tcp_socket_receive(nxCtx->nxSocket, &nxCtx->nxPacket,
+                                       nxCtx->nxWait);
+        if (status != NX_SUCCESS) {
+            CYASSL_MSG("NetX Recv receive error");
+            return CYASSL_CBIO_ERR_GENERAL;
+        }
+    }
+
+    if (nxCtx->nxPacket) {
+        status = nx_packet_length_get(nxCtx->nxPacket, &total);
+        if (status != NX_SUCCESS) {
+            CYASSL_MSG("NetX Recv length get error");
+            return CYASSL_CBIO_ERR_GENERAL;
+        }
+
+        left = total - nxCtx->nxOffset;
+        status = nx_packet_data_extract_offset(nxCtx->nxPacket, nxCtx->nxOffset,
+                                               buf, sz, &copied);
+        if (status != NX_SUCCESS) {
+            CYASSL_MSG("NetX Recv data extract offset error");
+            return CYASSL_CBIO_ERR_GENERAL;
+        }
+
+        nxCtx->nxOffset += copied;
+
+        if (copied == left) {
+            CYASSL_MSG("NetX Recv Drained packet");
+            nx_packet_release(nxCtx->nxPacket);
+            nxCtx->nxPacket = NULL;
+            nxCtx->nxOffset = 0;
+        }
+    }
+
+    return copied;
+}
+
+
+/* The NetX send callback
+ *  return : bytes sent, or error
+ */
+int NetX_Send(CYASSL* ssl, char *buf, int sz, void *ctx)
+{
+    NetX_Ctx*       nxCtx = (NetX_Ctx*)ctx;
+    NX_PACKET*      packet;
+    NX_PACKET_POOL* pool;   /* shorthand */
+    UINT            status;
+
+    if (nxCtx == NULL || nxCtx->nxSocket == NULL) {
+        CYASSL_MSG("NetX Send NULL parameters");
+        return CYASSL_CBIO_ERR_GENERAL;
+    }
+
+    pool = nxCtx->nxSocket->nx_tcp_socket_ip_ptr->nx_ip_default_packet_pool;
+    status = nx_packet_allocate(pool, &packet, NX_TCP_PACKET,
+                                nxCtx->nxWait);
+    if (status != NX_SUCCESS) {
+        CYASSL_MSG("NetX Send packet alloc error");
+        return CYASSL_CBIO_ERR_GENERAL;
+    }
+
+    status = nx_packet_data_append(packet, buf, sz, pool, nxCtx->nxWait);
+    if (status != NX_SUCCESS) {
+        nx_packet_release(packet);
+        CYASSL_MSG("NetX Send data append error");
+        return CYASSL_CBIO_ERR_GENERAL;
+    }
+
+    status = nx_tcp_socket_send(nxCtx->nxSocket, packet, nxCtx->nxWait);
+    if (status != NX_SUCCESS) {
+        nx_packet_release(packet);
+        CYASSL_MSG("NetX Send socket send error");
+        return CYASSL_CBIO_ERR_GENERAL;
+    }
+
+    return sz;
+}
+
+
+/* like set_fd, but for default NetX context */
+void CyaSSL_SetIO_NetX(CYASSL* ssl, NX_TCP_SOCKET* nxSocket, ULONG waitOption)
+{
+    if (ssl) {
+        ssl->nxCtx.nxSocket = nxSocket;
+        ssl->nxCtx.nxWait   = waitOption;
+    }
+}
+
+#endif /* HAVE_NETX */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/keys.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,1984 @@
+/* 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/error-ssl.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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_MD5
+    case TLS_RSA_WITH_HC_128_MD5 :
+        ssl->specs.bulk_cipher_algorithm = cyassl_hc128;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = md5_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = MD5_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_MD5;
+        ssl->specs.static_ecdh           = 0;
+        ssl->specs.key_size              = HC_128_KEY_SIZE;
+        ssl->specs.block_size            = 0;
+        ssl->specs.iv_size               = HC_128_IV_SIZE;
+
+        break;
+#endif
+            
+#ifdef BUILD_TLS_RSA_WITH_HC_128_SHA
+        case TLS_RSA_WITH_HC_128_SHA :
+            ssl->specs.bulk_cipher_algorithm = cyassl_hc128;
+            ssl->specs.cipher_type           = stream;
+            ssl->specs.mac_algorithm         = sha_mac;
+            ssl->specs.kea                   = rsa_kea;
+            ssl->specs.sig_algo              = rsa_sa_algo;
+            ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+            ssl->specs.pad_size              = PAD_SHA;
+            ssl->specs.static_ecdh           = 0;
+            ssl->specs.key_size              = HC_128_KEY_SIZE;
+            ssl->specs.block_size            = 0;
+            ssl->specs.iv_size               = HC_128_IV_SIZE;
+            
+            break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_B2B256
+        case TLS_RSA_WITH_HC_128_B2B256:
+            ssl->specs.bulk_cipher_algorithm = cyassl_hc128;
+            ssl->specs.cipher_type           = stream;
+            ssl->specs.mac_algorithm         = blake2b_mac;
+            ssl->specs.kea                   = rsa_kea;
+            ssl->specs.sig_algo              = rsa_sa_algo;
+            ssl->specs.hash_size             = BLAKE2B_256;
+            ssl->specs.pad_size              = PAD_SHA;
+            ssl->specs.static_ecdh           = 0;
+            ssl->specs.key_size              = HC_128_KEY_SIZE;
+            ssl->specs.block_size            = 0;
+            ssl->specs.iv_size               = HC_128_IV_SIZE;
+            
+            break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_B2B256
+        case TLS_RSA_WITH_AES_128_CBC_B2B256:
+            ssl->specs.bulk_cipher_algorithm = cyassl_aes;
+            ssl->specs.cipher_type           = block;
+            ssl->specs.mac_algorithm         = blake2b_mac;
+            ssl->specs.kea                   = rsa_kea;
+            ssl->specs.sig_algo              = rsa_sa_algo;
+            ssl->specs.hash_size             = BLAKE2B_256;
+            ssl->specs.pad_size              = PAD_SHA;
+            ssl->specs.static_ecdh           = 0;
+            ssl->specs.key_size              = AES_128_KEY_SIZE;
+            ssl->specs.iv_size               = AES_IV_SIZE;
+            ssl->specs.block_size            = AES_BLOCK_SIZE;
+            
+            break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_B2B256
+        case TLS_RSA_WITH_AES_256_CBC_B2B256:
+            ssl->specs.bulk_cipher_algorithm = cyassl_aes;
+            ssl->specs.cipher_type           = block;
+            ssl->specs.mac_algorithm         = blake2b_mac;
+            ssl->specs.kea                   = rsa_kea;
+            ssl->specs.sig_algo              = rsa_sa_algo;
+            ssl->specs.hash_size             = BLAKE2B_256;
+            ssl->specs.pad_size              = PAD_SHA;
+            ssl->specs.static_ecdh           = 0;
+            ssl->specs.key_size              = AES_256_KEY_SIZE;
+            ssl->specs.iv_size               = AES_IV_SIZE;
+            ssl->specs.block_size            = AES_BLOCK_SIZE;
+            
+            break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_SHA
+    case TLS_RSA_WITH_RABBIT_SHA :
+        ssl->specs.bulk_cipher_algorithm = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 = cyassl_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 == cyassl_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 == CYASSL_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 == cyassl_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 == CYASSL_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 == cyassl_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 == CYASSL_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 == cyassl_triple_des) {
+        int desRet = 0;
+
+        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 == CYASSL_CLIENT_END) {
+            desRet = Des3_SetKey(enc->des3, keys->client_write_key,
+                        keys->client_write_IV, DES_ENCRYPTION);
+            if (desRet != 0)
+                return desRet;
+            desRet = Des3_SetKey(dec->des3, keys->server_write_key,
+                        keys->server_write_IV, DES_DECRYPTION);
+            if (desRet != 0)
+                return desRet;
+        }
+        else {
+            desRet = Des3_SetKey(enc->des3, keys->server_write_key,
+                        keys->server_write_IV, DES_ENCRYPTION);
+            if (desRet != 0)
+                return desRet;
+            desRet = Des3_SetKey(dec->des3, keys->client_write_key,
+                keys->client_write_IV, DES_DECRYPTION);
+            if (desRet != 0)
+                return desRet;
+        }
+        enc->setup = 1;
+        dec->setup = 1;
+    }
+#endif
+
+#ifdef BUILD_AES
+    if (specs->bulk_cipher_algorithm == cyassl_aes) {
+        int aesRet = 0;
+
+        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 == CYASSL_CLIENT_END) {
+            aesRet = AesSetKey(enc->aes, keys->client_write_key,
+                               specs->key_size, keys->client_write_IV,
+                               AES_ENCRYPTION);
+            if (aesRet != 0)
+                return aesRet;
+            aesRet = AesSetKey(dec->aes, keys->server_write_key,
+                               specs->key_size, keys->server_write_IV,
+                               AES_DECRYPTION);
+            if (aesRet != 0)
+                return aesRet;
+        }
+        else {
+            aesRet = AesSetKey(enc->aes, keys->server_write_key,
+                               specs->key_size, keys->server_write_IV,
+                               AES_ENCRYPTION);
+            if (aesRet != 0)
+                return aesRet;
+            aesRet = AesSetKey(dec->aes, keys->client_write_key,
+                               specs->key_size, keys->client_write_IV,
+                               AES_DECRYPTION);
+            if (aesRet != 0)
+                return aesRet;
+        }
+        enc->setup = 1;
+        dec->setup = 1;
+    }
+#endif
+
+#ifdef BUILD_AESGCM
+    if (specs->bulk_cipher_algorithm == cyassl_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 == CYASSL_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 == cyassl_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 == CYASSL_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 == cyassl_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 == CYASSL_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 == cyassl_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/CCM explicit IV to a zero. */
+        XMEMSET(ssl->keys.aead_exp_IV, 0, 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;
+    int ret = 0;
+
+    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);
+    ret = InitSha(&sha);
+    if (ret != 0) 
+        return ret;
+
+    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);
+    ret = InitSha(&sha);
+    if (ret != 0) 
+        return ret;
+
+    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/src/ocsp.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,269 @@
+/* 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
+
+#include <cyassl/error-ssl.h>
+#include <cyassl/ocsp.h>
+#include <cyassl/internal.h>
+
+
+int InitOCSP(CYASSL_OCSP* ocsp, CYASSL_CERT_MANAGER* cm)
+{
+    CYASSL_ENTER("InitOCSP");
+    XMEMSET(ocsp, 0, sizeof(*ocsp));
+    ocsp->cm = cm;
+    if (InitMutex(&ocsp->ocspLock) != 0)
+        return BAD_MUTEX_E;
+
+    return 0;
+}
+
+
+static int InitOCSP_Entry(OCSP_Entry* ocspe, DecodedCert* cert)
+{
+    CYASSL_ENTER("InitOCSP_Entry");
+
+    XMEMSET(ocspe, 0, sizeof(*ocspe));
+    XMEMCPY(ocspe->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE);
+    XMEMCPY(ocspe->issuerKeyHash, cert->issuerKeyHash, SHA_DIGEST_SIZE);
+
+    return 0;
+}
+
+
+static void FreeOCSP_Entry(OCSP_Entry* ocspe)
+{
+    CertStatus* tmp = ocspe->status;
+
+    CYASSL_ENTER("FreeOCSP_Entry");
+
+    while (tmp) {
+        CertStatus* next = tmp->next;
+        XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_STATUS);
+        tmp = next;
+    }
+}
+
+
+void FreeOCSP(CYASSL_OCSP* ocsp, int dynamic)
+{
+    OCSP_Entry* tmp = ocsp->ocspList;
+
+    CYASSL_ENTER("FreeOCSP");
+
+    while (tmp) {
+        OCSP_Entry* next = tmp->next;
+        FreeOCSP_Entry(tmp);
+        XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_ENTRY);
+        tmp = next;
+    }
+
+    FreeMutex(&ocsp->ocspLock);
+    if (dynamic)
+        XFREE(ocsp, NULL, DYNAMIC_TYPE_OCSP);
+}
+
+
+static int xstat2err(int stat)
+{
+    switch (stat) {
+        case CERT_GOOD:
+            return 0;
+        case CERT_REVOKED:
+            return OCSP_CERT_REVOKED;
+        default:
+            return OCSP_CERT_UNKNOWN;
+    }
+}
+
+
+int CheckCertOCSP(CYASSL_OCSP* ocsp, DecodedCert* cert)
+{
+    byte* ocspReqBuf = NULL;
+    int ocspReqSz = 2048;
+    byte* ocspRespBuf = NULL;
+    OcspRequest ocspRequest;
+    OcspResponse ocspResponse;
+    int result = -1;
+    OCSP_Entry* ocspe;
+    CertStatus* certStatus = NULL;
+    CertStatus newStatus;
+    const char *url;
+    int urlSz;
+
+    CYASSL_ENTER("CheckCertOCSP");
+
+    if (LockMutex(&ocsp->ocspLock) != 0) {
+        CYASSL_LEAVE("CheckCertOCSP", BAD_MUTEX_E);
+        return BAD_MUTEX_E;
+    }
+
+    ocspe = ocsp->ocspList;
+    while (ocspe) {
+        if (XMEMCMP(ocspe->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE) == 0
+            && XMEMCMP(ocspe->issuerKeyHash, cert->issuerKeyHash,
+                                                        SHA_DIGEST_SIZE) == 0)
+            break;
+        else
+            ocspe = ocspe->next;
+    }
+
+    if (ocspe == NULL) {
+        ocspe = (OCSP_Entry*)XMALLOC(sizeof(OCSP_Entry),
+                                                NULL, DYNAMIC_TYPE_OCSP_ENTRY);
+        if (ocspe != NULL) {
+            InitOCSP_Entry(ocspe, cert);
+            ocspe->next = ocsp->ocspList;
+            ocsp->ocspList = ocspe;
+        }
+        else {
+            UnLockMutex(&ocsp->ocspLock);
+            CYASSL_LEAVE("CheckCertOCSP", MEMORY_ERROR);
+            return MEMORY_ERROR;
+        }
+    }
+    else {
+        certStatus = ocspe->status;
+        while (certStatus) {
+            if (certStatus->serialSz == cert->serialSz &&
+                 XMEMCMP(certStatus->serial, cert->serial, cert->serialSz) == 0)
+                break;
+            else
+                certStatus = certStatus->next;
+        }
+    }
+
+    if (certStatus != NULL) {
+        if (!ValidateDate(certStatus->thisDate,
+                                        certStatus->thisDateFormat, BEFORE) ||
+            (certStatus->nextDate[0] == 0) ||
+            !ValidateDate(certStatus->nextDate,
+                                        certStatus->nextDateFormat, AFTER)) {
+            CYASSL_MSG("\tinvalid status date, looking up cert");
+        }
+        else {
+            result = xstat2err(certStatus->status);
+            UnLockMutex(&ocsp->ocspLock);
+            CYASSL_LEAVE("CheckCertOCSP", result);
+            return result;
+        }
+    }
+
+    UnLockMutex(&ocsp->ocspLock);
+
+    if (ocsp->cm->ocspUseOverrideURL) {
+        url = ocsp->cm->ocspOverrideURL;
+        if (url != NULL && url[0] != '\0')
+            urlSz = (int)XSTRLEN(url);
+        else
+            return OCSP_NEED_URL;
+    }
+    else if (cert->extAuthInfoSz != 0 && cert->extAuthInfo != NULL) {
+        url = (const char *)cert->extAuthInfo;
+        urlSz = cert->extAuthInfoSz;
+    }
+    else {
+        /* cert doesn't have extAuthInfo, assuming CERT_GOOD */
+        return 0;
+    }
+
+    ocspReqBuf = (byte*)XMALLOC(ocspReqSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
+    if (ocspReqBuf == NULL) {
+        CYASSL_LEAVE("CheckCertOCSP", MEMORY_ERROR);
+        return MEMORY_ERROR;
+    }
+    InitOcspRequest(&ocspRequest, cert, ocsp->cm->ocspSendNonce,
+                                                         ocspReqBuf, ocspReqSz);
+    ocspReqSz = EncodeOcspRequest(&ocspRequest);
+    
+    if (ocsp->cm->ocspIOCb)
+        result = ocsp->cm->ocspIOCb(ocsp->cm->ocspIOCtx, url, urlSz,
+                                           ocspReqBuf, ocspReqSz, &ocspRespBuf);
+
+    if (result >= 0 && ocspRespBuf) {
+        XMEMSET(&newStatus, 0, sizeof(CertStatus));
+
+        InitOcspResponse(&ocspResponse, &newStatus, ocspRespBuf, result);
+        OcspResponseDecode(&ocspResponse);
+    
+        if (ocspResponse.responseStatus != OCSP_SUCCESSFUL)
+            result = OCSP_LOOKUP_FAIL;
+        else {
+            if (CompareOcspReqResp(&ocspRequest, &ocspResponse) == 0) {
+                result = xstat2err(ocspResponse.status->status);
+
+                if (LockMutex(&ocsp->ocspLock) != 0)
+                    result = BAD_MUTEX_E;
+                else {
+                    if (certStatus != NULL)
+                        /* Replace existing certificate entry with updated */
+                        XMEMCPY(certStatus, &newStatus, sizeof(CertStatus));
+                    else {
+                        /* Save new certificate entry */
+                        certStatus = (CertStatus*)XMALLOC(sizeof(CertStatus),
+                                          NULL, DYNAMIC_TYPE_OCSP_STATUS);
+                        if (certStatus != NULL) {
+                            XMEMCPY(certStatus, &newStatus, sizeof(CertStatus));
+                            certStatus->next = ocspe->status;
+                            ocspe->status = certStatus;
+                            ocspe->totalStatus++;
+                        }
+                    }
+
+                    UnLockMutex(&ocsp->ocspLock);
+                }
+            }
+            else
+                result = OCSP_LOOKUP_FAIL;
+        }
+    }
+    else
+        result = OCSP_LOOKUP_FAIL;
+
+    if (ocspReqBuf != NULL)
+        XFREE(ocspReqBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
+
+    if (ocspRespBuf != NULL && ocsp->cm->ocspRespFreeCb)
+        ocsp->cm->ocspRespFreeCb(ocsp->cm->ocspIOCtx, ocspRespBuf);
+
+    CYASSL_LEAVE("CheckCertOCSP", result);
+    return result;
+}
+
+
+#else /* HAVE_OCSP */
+
+
+#ifdef _MSC_VER
+    /* 4206 warning for blank file */
+    #pragma warning(disable: 4206)
+#endif
+
+
+#endif /* HAVE_OCSP */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sniffer.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,2567 @@
+/* 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/error-ssl.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",
+    "Bad Decrypt Operation"
+};
+
+
+/* *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);
+
+    if (TraceFile) {
+        TraceOn = 0;
+        fclose(TraceFile);
+        TraceFile = NULL;
+    }
+
+    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 = CYASSL_SERVER_END;
+        else
+            session->flags.side = CYASSL_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, int length, char* error)
+{
+    int    version = IP_V(iphdr);
+
+    TraceIP(iphdr);
+    Trace(IP_CHECK_STR);
+
+    if (version != IPV4) {
+        SetError(BAD_IPVER_STR, error, NULL, 0); 
+        return -1;
+    }
+
+    if (iphdr->protocol != TCP_PROTOCOL) { 
+        SetError(BAD_PROTO_STR, error, NULL, 0);
+        return -1;
+    }
+
+    if (!IsServerRegistered(iphdr->src) && !IsServerRegistered(iphdr->dst)) {
+        SetError(SERVER_NOT_REG_STR, error, NULL, 0);
+        return -1;
+    }
+
+    info->length  = IP_HL(iphdr);
+    info->total   = ntohs(iphdr->length);
+    info->src     = iphdr->src;
+    info->dst     = iphdr->dst;
+
+    if (info->total == 0)
+        info->total = length;  /* reassembled may be off */
+
+    return 0;
+}
+
+
+/* Check TCP Header for a registered port */
+/* returns 0 on success, -1 on error */
+static int CheckTcpHdr(TcpHdr* tcphdr, TcpInfo* info, char* error)
+{
+    TraceTcp(tcphdr);
+    Trace(TCP_CHECK_STR);
+    info->srcPort   = ntohs(tcphdr->srcPort);
+    info->dstPort   = ntohs(tcphdr->dstPort);
+    info->length    = TCP_LEN(tcphdr);
+    info->sequence  = ntohl(tcphdr->sequence);
+    info->fin       = tcphdr->flags & TCP_FIN;
+    info->rst       = tcphdr->flags & TCP_RST;
+    info->syn       = tcphdr->flags & TCP_SYN;
+    info->ack       = tcphdr->flags & TCP_ACK;
+    if (info->ack)
+        info->ackNumber = ntohl(tcphdr->ack); 
+
+    if (!IsPortRegistered(info->srcPort) && !IsPortRegistered(info->dstPort)) {
+        SetError(SERVER_PORT_NOT_REG_STR, error, NULL, 0);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/* Decode Record Layer Header */
+static int GetRecordHeader(const byte* input, RecordLayerHeader* rh, int* size)
+{
+    XMEMCPY(rh, input, RECORD_HEADER_SZ);
+    *size = (rh->length[0] << 8) | rh->length[1];
+
+    if (*size > (MAX_RECORD_SIZE + COMP_EXTRA + MAX_MSG_EXTRA))
+        return LENGTH_ERROR;
+
+    return 0;
+}
+
+
+/* Process Client Key Exchange, RSA only */
+static int ProcessClientKeyExchange(const byte* input, int* sslBytes,
+                                    SnifferSession* session, char* error)
+{
+    word32 idx = 0;
+    RsaKey key;
+    int    ret;
+
+    ret = InitRsaKey(&key, 0);
+    if (ret == 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 = (word16)((input[0] << 8) | input[1]);
+    input     += LENGTH_SZ;
+    *sslBytes -= LENGTH_SZ;
+
+    /* make sure can read through ticket */
+    if (len > *sslBytes || len < ID_LEN) {
+        SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    /* store session with macID as sessionID */
+    session->sslServer->options.haveSessionId = 1;
+    XMEMCPY(session->sslServer->arrays->sessionID, input + len - ID_LEN,ID_LEN);
+    
+    return 0;
+}
+
+
+/* Process Server Hello */
+static int ProcessServerHello(const byte* input, int* sslBytes,
+                              SnifferSession* session, char* error)
+{
+    ProtocolVersion pv;
+    byte            b;
+    int             toRead = VERSION_SZ + RAN_LEN + ENUM_LEN;
+    int             doResume     = 0;
+    
+    /* make sure we didn't miss ClientHello */
+    if (session->flags.clientHello == 0) {
+        SetError(MISSED_CLIENT_HELLO_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    /* make sure can read through session len */
+    if (toRead > *sslBytes) {
+        SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    
+    XMEMCPY(&pv, input, VERSION_SZ);
+    input     += VERSION_SZ;
+    *sslBytes -= VERSION_SZ;
+           
+    session->sslServer->version = pv;
+    session->sslClient->version = pv;
+           
+    XMEMCPY(session->sslServer->arrays->serverRandom, input, RAN_LEN);
+    XMEMCPY(session->sslClient->arrays->serverRandom, input, RAN_LEN);
+    input    += RAN_LEN;
+    *sslBytes -= RAN_LEN;
+    
+    b = *input++;
+    *sslBytes -= 1;
+    
+    /* make sure can read through compression */
+    if ( (b + SUITE_LEN + ENUM_LEN) > *sslBytes) {
+        SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    if (b) {
+        XMEMCPY(session->sslServer->arrays->sessionID, input, ID_LEN);
+        session->sslServer->options.haveSessionId = 1;
+    }
+    input     += b;
+    *sslBytes -= b;
+   
+    /* cipher suite */ 
+    b = *input++;  /* first byte, ECC or not */
+    session->sslServer->options.cipherSuite0 = b;
+    session->sslClient->options.cipherSuite0 = b;
+    b = *input++;
+    session->sslServer->options.cipherSuite = b;
+    session->sslClient->options.cipherSuite = b;
+    *sslBytes -= SUITE_LEN;
+
+    /* compression */
+    b = *input++;
+    *sslBytes -= ENUM_LEN;
+
+    if (b) {
+        SetError(BAD_COMPRESSION_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+   
+    if (session->sslServer->options.haveSessionId &&
+            XMEMCMP(session->sslServer->arrays->sessionID,
+                    session->sslClient->arrays->sessionID, ID_LEN) == 0)
+        doResume = 1;
+    else if (session->sslClient->options.haveSessionId == 0 &&
+             session->sslServer->options.haveSessionId == 0 &&
+             session->ticketID)
+        doResume = 1;
+
+    if (session->ticketID && doResume) {
+        /* use ticketID to retrieve from session, prefer over sessionID */
+        XMEMCPY(session->sslServer->arrays->sessionID,session->ticketID,ID_LEN);
+        session->sslServer->options.haveSessionId = 1;  /* may not have
+                                                           actual sessionID */
+    }
+
+    if (doResume ) {
+        int ret = 0;
+        SSL_SESSION* resume = GetSession(session->sslServer,
+                                      session->sslServer->arrays->masterSecret);
+        if (resume == NULL) {
+            SetError(BAD_SESSION_RESUME_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        /* make sure client has master secret too */
+        XMEMCPY(session->sslClient->arrays->masterSecret,
+               session->sslServer->arrays->masterSecret, SECRET_LEN);
+        session->flags.resuming = 1;
+        
+        Trace(SERVER_DID_RESUMPTION_STR);
+        if (SetCipherSpecs(session->sslServer) != 0) {
+            SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        
+        if (SetCipherSpecs(session->sslClient) != 0) {
+            SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        
+        if (session->sslServer->options.tls) {
+            ret =  DeriveTlsKeys(session->sslServer);
+            ret += DeriveTlsKeys(session->sslClient);
+        }
+        else {
+            ret =  DeriveKeys(session->sslServer);
+            ret += DeriveKeys(session->sslClient);
+        }
+        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 = (word16)((input[0] << 8) | input[1]);
+    input     += SUITE_LEN;
+    *sslBytes -= SUITE_LEN;
+    /* make sure can read suites + comp len */
+    if (len + ENUM_LEN > *sslBytes) {
+        SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    input     += len;
+    *sslBytes -= len;
+
+    /* skip compression */
+    bLen       = *input++;
+    *sslBytes -= ENUM_LEN;
+    /* make sure can read len */
+    if (bLen > *sslBytes) {
+        SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    input     += bLen;
+    *sslBytes -= bLen;
+  
+    if (*sslBytes == 0) {
+        /* no extensions */
+        return 0;
+    }
+    
+    /* skip extensions until session ticket */
+    /* make sure can read len */
+    if (SUITE_LEN > *sslBytes) {
+        SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    len = (word16)((input[0] << 8) | input[1]);
+    input     += SUITE_LEN;
+    *sslBytes -= SUITE_LEN;
+    /* make sure can read through all extensions */
+    if (len > *sslBytes) {
+        SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    while (len > EXT_TYPE_SZ + LENGTH_SZ) {
+        byte   extType[EXT_TYPE_SZ];
+        word16 extLen;
+
+        extType[0] = input[0];
+        extType[1] = input[1];
+        input     += EXT_TYPE_SZ;
+        *sslBytes -= EXT_TYPE_SZ;
+
+        extLen = (word16)((input[0] << 8) | input[1]);
+        input     += LENGTH_SZ;
+        *sslBytes -= LENGTH_SZ;
+
+        /* make sure can read through individual extension */
+        if (extLen > *sslBytes) {
+            SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+
+        if (extType[0] == 0x00 && extType[1] == TICKET_EXT_ID) {
+
+            /* make sure can read through ticket if there is a non blank one */
+            if (extLen && extLen < ID_LEN) {
+                SetError(CLIENT_HELLO_INPUT_STR, error, session,
+                         FATAL_ERROR_STATE);
+                return -1;
+            }
+
+            if (extLen) {
+                if (session->ticketID == 0) {
+                    session->ticketID = (byte*)malloc(ID_LEN);
+                    if (session->ticketID == 0) {
+                        SetError(MEMORY_STR, error, session,
+                                 FATAL_ERROR_STATE);
+                        return -1;
+                    }
+                }
+                XMEMCPY(session->ticketID, input + extLen - ID_LEN, ID_LEN);
+            }
+        }
+
+        input     += extLen;
+        *sslBytes -= extLen;
+        len       -= extLen + EXT_TYPE_SZ + LENGTH_SZ;
+    }
+
+    return 0;
+}
+
+
+/* Process Finished */
+static int ProcessFinished(const byte* input, int size, int* sslBytes,
+                           SnifferSession* session, char* error)
+{
+    SSL*   ssl;
+    word32 inOutIdx = 0;
+    int    ret;
+                
+    if (session->flags.side == CYASSL_SERVER_END)
+        ssl = session->sslServer;
+    else
+        ssl = session->sslClient;
+
+    ret = DoFinished(ssl, input, &inOutIdx, (word32) size, (word32) *sslBytes,
+                                                                         SNIFF);
+    *sslBytes -= (int)inOutIdx;
+
+    if (ret < 0) {
+        SetError(BAD_FINISHED_MSG, error, session, FATAL_ERROR_STATE);
+        return ret;
+    }
+                
+    if (ret == 0 && session->flags.cached == 0) {
+        if (session->sslServer->options.haveSessionId) {
+            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, size, sslBytes, session, error);
+            break;
+        case client_hello:
+            Trace(GOT_CLIENT_HELLO_STR);
+            ret = ProcessClientHello(input, sslBytes, session, error);
+            break;
+        case client_key_exchange:
+            Trace(GOT_CLIENT_KEY_EX_STR);
+            ret = ProcessClientKeyExchange(input, sslBytes, session, error);
+            break;
+        case certificate_verify:
+            Trace(GOT_CERT_VER_STR);
+            break;
+        default:
+            SetError(GOT_UNKNOWN_HANDSHAKE_STR, error, session, 0);
+            return -1;
+    }   
+
+    return ret;
+}
+
+
+/* Decrypt input into plain output, 0 on success */
+static int Decrypt(SSL* ssl, byte* output, const byte* input, word32 sz)
+{
+    int ret = 0;
+
+    switch (ssl->specs.bulk_cipher_algorithm) {
+        #ifdef BUILD_ARC4
+        case cyassl_rc4:
+            Arc4Process(ssl->decrypt.arc4, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef BUILD_DES3
+        case cyassl_triple_des:
+            ret = Des3_CbcDecrypt(ssl->decrypt.des3, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef BUILD_AES
+        case cyassl_aes:
+            ret = AesCbcDecrypt(ssl->decrypt.aes, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef HAVE_HC128
+        case cyassl_hc128:
+            Hc128_Process(ssl->decrypt.hc128, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef BUILD_RABBIT
+        case cyassl_rabbit:
+            RabbitProcess(ssl->decrypt.rabbit, output, input, sz);
+            break;
+        #endif
+
+        #ifdef HAVE_CAMELLIA 
+        case cyassl_camellia:
+            CamelliaCbcDecrypt(ssl->decrypt.cam, output, input, sz);
+            break;
+        #endif
+
+        default:
+            Trace(BAD_DECRYPT_TYPE);
+            ret = -1;
+            break;
+    }
+
+    return ret;
+}
+
+
+/* Decrypt input message into output, adjust output steam if needed */
+static const byte* DecryptMessage(SSL* ssl, const byte* input, word32 sz,
+                                  byte* output, int* error)
+{
+    int ivExtra = 0;
+
+    int ret = Decrypt(ssl, output, input, sz);
+    if (ret != 0) {
+        *error = ret;
+        return NULL;
+    }
+    ssl->keys.encryptSz = sz;
+    if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) {
+        output += ssl->specs.block_size;     /* go past TLSv1.1 IV */
+        ivExtra = ssl->specs.block_size;
+    }
+
+    ssl->keys.padSz = ssl->specs.hash_size;
+
+    if (ssl->specs.cipher_type == block)
+        ssl->keys.padSz += *(output + sz - ivExtra - 1) + 1;
+    
+    return output;
+}
+
+
+/* remove session from table, use rowHint if no info (means we have a lock) */
+static void RemoveSession(SnifferSession* session, IpInfo* ipInfo,
+                        TcpInfo* tcpInfo, word32 rowHint)
+{
+    SnifferSession* previous = 0;
+    SnifferSession* current;
+    word32          row = rowHint;
+    int             haveLock = 0;
+   
+    if (ipInfo && tcpInfo)
+        row = SessionHash(ipInfo, tcpInfo);
+    else
+        haveLock = 1;
+    
+    assert(row <= HASH_SIZE);
+    Trace(REMOVE_SESSION_STR);
+    
+    if (!haveLock)
+        LockMutex(&SessionMutex);
+    
+    current = SessionTable[row];
+    
+    while (current) {
+        if (current == session) {
+            if (previous)
+                previous->next = current->next;
+            else
+                SessionTable[row] = current->next;
+            FreeSnifferSession(session);
+            TraceRemovedSession();
+            break;
+        }
+        previous = current;
+        current  = current->next;
+    }
+    
+    if (!haveLock)
+        UnLockMutex(&SessionMutex);
+}
+
+
+/* Remove stale sessions from the Session Table, have a lock */
+static void RemoveStaleSessions(void)
+{
+    word32 i;
+    SnifferSession* session;
+    
+    for (i = 0; i < HASH_SIZE; i++) {
+        session = SessionTable[i];
+        while (session) {
+            SnifferSession* next = session->next; 
+            if (time(NULL) >= session->lastUsed + SNIFFER_TIMEOUT) {
+                TraceStaleSession();
+                RemoveSession(session, NULL, NULL, i);
+            }
+            session = next;
+        }
+    }
+}
+
+
+/* Create a new Sniffer Session */
+static SnifferSession* CreateSession(IpInfo* ipInfo, TcpInfo* tcpInfo,
+                                     char* error)
+{
+    SnifferSession* session = 0;
+    int row;
+        
+    Trace(NEW_SESSION_STR);
+    /* create a new one */
+    session = (SnifferSession*)malloc(sizeof(SnifferSession));
+    if (session == NULL) {
+        SetError(MEMORY_STR, error, NULL, 0);
+        return 0;
+    }
+    InitSession(session);
+    session->server  = ipInfo->dst;
+    session->client  = ipInfo->src;
+    session->srvPort = (word16)tcpInfo->dstPort;
+    session->cliPort = (word16)tcpInfo->srcPort;
+    session->cliSeqStart = tcpInfo->sequence;
+    session->cliExpected = 1;  /* relative */
+    session->lastUsed= time(NULL);
+                
+    session->context = GetSnifferServer(ipInfo, tcpInfo);
+    if (session->context == NULL) {
+        SetError(SERVER_NOT_REG_STR, error, NULL, 0);
+        free(session);
+        return 0;
+    }
+        
+    session->sslServer = SSL_new(session->context->ctx);
+    if (session->sslServer == NULL) {
+        SetError(BAD_NEW_SSL_STR, error, session, FATAL_ERROR_STATE);
+        free(session);
+        return 0;
+    }
+    session->sslClient = SSL_new(session->context->ctx);
+    if (session->sslClient == NULL) {
+        SSL_free(session->sslServer);
+        session->sslServer = 0;
+
+        SetError(BAD_NEW_SSL_STR, error, session, FATAL_ERROR_STATE);
+        free(session);
+        return 0;
+    }
+    /* put server back into server mode */
+    session->sslServer->options.side = CYASSL_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 = CYASSL_SERVER_END;
+    else
+        session->flags.side = CYASSL_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,
+                                (word16)*rhSize);    
+    if (ret < 0 && ret != MATCH_SUITE_ERROR) {
+        SetError(BAD_OLD_CLIENT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    
+    Trace(OLD_CLIENT_OK_STR);
+    XMEMCPY(session->sslClient->arrays->clientRandom,
+           session->sslServer->arrays->clientRandom, RAN_LEN);
+    
+    *sslBytes -= *rhSize;
+    return 0;
+}
+
+
+#if 0
+/* Calculate the TCP checksum, see RFC 1071 */
+/* return 0 for success, -1 on error */
+/* can be called from decode() with
+   TcpChecksum(&ipInfo, &tcpInfo, sslBytes, packet + ipInfo.length);
+   could also add a 64bit version if type available and using this
+*/
+int TcpChecksum(IpInfo* ipInfo, TcpInfo* tcpInfo, int dataLen,
+                const byte* packet)
+{
+    TcpPseudoHdr  pseudo;
+    int           count = PSEUDO_HDR_SZ;
+    const word16* data = (word16*)&pseudo;
+    word32        sum = 0;
+    word16        checksum;
+    
+    pseudo.src = ipInfo->src;
+    pseudo.dst = ipInfo->dst;
+    pseudo.rsv = 0;
+    pseudo.protocol = TCP_PROTO;
+    pseudo.legnth = htons(tcpInfo->length + dataLen);
+    
+    /* pseudo header sum */
+    while (count >= 2) {
+        sum   += *data++;
+        count -= 2;
+    }
+    
+    count = tcpInfo->length + dataLen;
+    data = (word16*)packet;
+    
+    /* main sum */
+    while (count > 1) {
+        sum   += *data++;
+        count -=2;
+    }
+    
+    /* get left-over, if any */
+    packet = (byte*)data;
+    if (count > 0) {
+        sum += *packet;
+    }
+    
+    /* fold 32bit sum into 16 bits */
+    while (sum >> 16)
+        sum = (sum & 0xffff) + (sum >> 16);
+    
+    checksum = (word16)~sum;
+    /* checksum should now equal 0, since included already calcd checksum */
+    /* field, but tcp checksum offloading could negate calculation */
+    if (checksum == 0)
+        return 0;
+    return -1;
+}
+#endif
+
+
+/* Check IP and TCP headers, set payload */
+/* returns 0 on success, -1 on error */
+static int CheckHeaders(IpInfo* ipInfo, TcpInfo* tcpInfo, const byte* packet,
+                  int length, const byte** sslFrame, int* sslBytes, char* error)
+{
+    TraceHeader();
+    TracePacket();
+
+    /* ip header */
+    if (length < IP_HDR_SZ) {
+        SetError(PACKET_HDR_SHORT_STR, error, NULL, 0);
+        return -1;
+    }
+    if (CheckIpHdr((IpHdr*)packet, ipInfo, length, error) != 0)
+        return -1;
+   
+    /* tcp header */ 
+    if (length < (ipInfo->length + TCP_HDR_SZ)) {
+        SetError(PACKET_HDR_SHORT_STR, error, NULL, 0);
+        return -1;
+    }
+    if (CheckTcpHdr((TcpHdr*)(packet + ipInfo->length), tcpInfo, error) != 0)
+        return -1;
+   
+    /* setup */ 
+    *sslFrame = packet + ipInfo->length + tcpInfo->length;
+    if (*sslFrame > packet + length) {
+        SetError(PACKET_HDR_SHORT_STR, error, NULL, 0);
+        return -1;
+    }
+    *sslBytes = (int)(packet + length - *sslFrame);
+    
+    return 0;
+}
+
+
+/* Create or Find existing session */
+/* returns 0 on success (continue), -1 on error, 1 on success (end) */
+static int CheckSession(IpInfo* ipInfo, TcpInfo* tcpInfo, int sslBytes,
+                        SnifferSession** session, char* error)
+{
+    /* create a new SnifferSession on client SYN */
+    if (tcpInfo->syn && !tcpInfo->ack) {
+        TraceClientSyn(tcpInfo->sequence);
+        *session = CreateSession(ipInfo, tcpInfo, error);
+        if (*session == NULL) {
+            *session = GetSnifferSession(ipInfo, tcpInfo);
+            /* already had exisiting, so OK */
+            if (*session)
+                return 1;
+            
+            SetError(MEMORY_STR, error, NULL, 0);
+            return -1;
+        }
+        return 1;
+    }
+    /* get existing sniffer session */
+    else {
+        *session = GetSnifferSession(ipInfo, tcpInfo);
+        if (*session == NULL) {
+            /* don't worry about extraneous RST or duplicate FINs */
+            if (tcpInfo->fin || tcpInfo->rst)
+                return 1;
+            /* don't worry about duplicate ACKs either */
+            if (sslBytes == 0 && tcpInfo->ack)
+                return 1;
+            
+            SetError(BAD_SESSION_STR, error, NULL, 0);
+            return -1;
+        }        
+    }
+    return 0;
+}
+
+
+/* Create a Packet Buffer from *begin - end, adjust new *begin and bytesLeft */
+static PacketBuffer* CreateBuffer(word32* begin, word32 end, const byte* data,
+                                  int* bytesLeft)
+{
+    PacketBuffer* pb;
+    
+    int added = end - *begin + 1;
+    assert(*begin <= end);
+    
+    pb = (PacketBuffer*)malloc(sizeof(PacketBuffer));
+    if (pb == NULL) return NULL;
+    
+    pb->next  = 0;
+    pb->begin = *begin;
+    pb->end   = end;
+    pb->data = (byte*)malloc(added);
+    
+    if (pb->data == NULL) {
+        free(pb);
+        return NULL;
+    }
+    XMEMCPY(pb->data, data, added);
+    
+    *bytesLeft -= added;
+    *begin      = pb->end + 1;
+    
+    return pb;
+}
+
+
+/* Add sslFrame to Reassembly List */
+/* returns 1 (end) on success, -1, on error */
+static int AddToReassembly(byte from, word32 seq, const byte* sslFrame,
+                           int sslBytes, SnifferSession* session, char* error)
+{
+    PacketBuffer*  add;
+    PacketBuffer** front = (from == CYASSL_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 == CYASSL_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 == CYASSL_SERVER_END) ? 
+                                     session->cliSeqStart :session->srvSeqStart;
+    word32  real     = tcpInfo->sequence - seqStart;
+    word32* expected = (session->flags.side == CYASSL_SERVER_END) ?
+                                  &session->cliExpected : &session->srvExpected;
+    PacketBuffer* reassemblyList = (session->flags.side == CYASSL_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 == CYASSL_SERVER_END) ? 
+                                     session->srvSeqStart :session->cliSeqStart;
+        word32  real     = tcpInfo->ackNumber - seqStart;
+        word32  expected = (session->flags.side == CYASSL_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 == CYASSL_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 == CYASSL_SERVER_END) ?
+                      &session->cliReassemblyList : &session->srvReassemblyList;
+    word32*        expected = (session->flags.side == CYASSL_SERVER_END) ?
+                                  &session->cliExpected : &session->srvExpected;
+    /* buffer is on receiving end */
+    word32*        length = (session->flags.side == CYASSL_SERVER_END) ?
+                               &session->sslServer->buffers.inputBuffer.length :
+                               &session->sslClient->buffers.inputBuffer.length;
+    byte*          myBuffer = (session->flags.side == CYASSL_SERVER_END) ?
+                                session->sslServer->buffers.inputBuffer.buffer :
+                                session->sslClient->buffers.inputBuffer.buffer;
+    word32       bufferSize = (session->flags.side == CYASSL_SERVER_END) ?
+                            session->sslServer->buffers.inputBuffer.bufferSize :
+                            session->sslClient->buffers.inputBuffer.bufferSize;
+    SSL*               ssl  = (session->flags.side == CYASSL_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               errCode = 0;
+    int               decoded = 0;      /* bytes stored for user in data */
+    int               notEnough;        /* notEnough bytes yet flag */
+    SSL*              ssl = (session->flags.side == CYASSL_SERVER_END) ?
+                                        session->sslServer : session->sslClient;
+doMessage:
+    notEnough = 0;
+    if (sslBytes < 0) {
+        SetError(PACKET_HDR_SHORT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    if (sslBytes >= RECORD_HEADER_SZ) {
+        if (GetRecordHeader(sslFrame, &rh, &rhSize) != 0) {
+            SetError(BAD_RECORD_HDR_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+    }
+    else
+        notEnough = 1;
+
+    if (notEnough || rhSize > (sslBytes - RECORD_HEADER_SZ)) {
+        /* don't have enough input yet to process full SSL record */
+        Trace(PARTIAL_INPUT_STR);
+        
+        /* store partial if not there already or we advanced */
+        if (ssl->buffers.inputBuffer.length == 0 || sslBegin != sslFrame) {
+            if (sslBytes > (int)ssl->buffers.inputBuffer.bufferSize) {
+                if (GrowInputBuffer(ssl, sslBytes, 0) < 0) { 
+                    SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
+                    return -1;
+                }
+            }
+            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 == CYASSL_SERVER_END &&
+                                               session->flags.serverCipherOn)
+     || (session->flags.side == CYASSL_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, &errCode);
+        if (errCode != 0) {
+            SetError(BAD_DECRYPT, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+    }
+            
+    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 == CYASSL_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/src/ssl.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,11503 @@
+/* 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/error-ssl.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
+#ifdef CYASSL_DTLS
+    static INLINE word32 max(word32 a, word32 b)
+    {
+        return a > b ? a : b;
+    }
+#endif
+#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;
+}
+
+
+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;
+}
+
+
+#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_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 == CYASSL_SERVER_END)
+        err = CyaSSL_accept(ssl);
+#endif
+
+#ifndef NO_CYASSL_CLIENT
+    if (ssl->options.side == CYASSL_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 != CYASSL_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()");
+
+    if (ssl == NULL || data == NULL || sz < 0)
+        return BAD_FUNC_ARG;
+
+#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()");
+
+    if (ssl == NULL || data == NULL || sz < 0)
+        return BAD_FUNC_ARG;
+
+#ifdef HAVE_ERRNO_H
+        errno = 0;
+#endif
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls)
+        ssl->dtls_expected_rx = max(sz + 100, MAX_MTU);
+#endif
+
+#ifdef HAVE_MAX_FRAGMENT
+    ret = ReceiveData(ssl, (byte*)data,
+                     min(sz, min(ssl->max_fragment, OUTPUT_RECORD_SIZE)), peek);
+#else
+    ret = ReceiveData(ssl, (byte*)data, min(sz, OUTPUT_RECORD_SIZE), peek);
+#endif
+
+    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
+
+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);
+}
+
+byte CyaSSL_SNI_Status(CYASSL* ssl, byte type)
+{
+    return TLSX_SNI_Status(ssl ? ssl->extensions : NULL, type);
+}
+
+word16 CyaSSL_SNI_GetRequest(CYASSL* ssl, byte type, void** data)
+{
+    if (data)
+        *data = NULL;
+
+    if (ssl && ssl->extensions)
+        return TLSX_SNI_GetRequest(ssl->extensions, type, data);
+
+    return 0;
+}
+
+int CyaSSL_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, byte type,
+                                                     byte* sni, word32* inOutSz)
+{
+    if (clientHello && helloSz > 0 && sni && inOutSz && *inOutSz > 0)
+        return TLSX_SNI_GetFromBuffer(clientHello, helloSz, type, sni, inOutSz);
+
+    return BAD_FUNC_ARG;
+}
+
+#endif /* NO_CYASSL_SERVER */
+
+#endif /* HAVE_SNI */
+
+
+#ifdef HAVE_MAX_FRAGMENT
+#ifndef NO_CYASSL_CLIENT
+int CyaSSL_UseMaxFragment(CYASSL* ssl, byte mfl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    return TLSX_UseMaxFragment(&ssl->extensions, mfl);
+}
+
+int CyaSSL_CTX_UseMaxFragment(CYASSL_CTX* ctx, byte mfl)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    return TLSX_UseMaxFragment(&ctx->extensions, mfl);
+}
+#endif /* NO_CYASSL_CLIENT */
+#endif /* HAVE_MAX_FRAGMENT */
+
+#ifdef HAVE_TRUNCATED_HMAC
+#ifndef NO_CYASSL_CLIENT
+int CyaSSL_UseTruncatedHMAC(CYASSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    return TLSX_UseTruncatedHMAC(&ssl->extensions);
+}
+
+int CyaSSL_CTX_UseTruncatedHMAC(CYASSL_CTX* ctx)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    return TLSX_UseTruncatedHMAC(&ctx->extensions);
+}
+#endif /* NO_CYASSL_CLIENT */
+#endif /* HAVE_TRUNCATED_HMAC */
+
+/* Elliptic Curves */
+#ifdef HAVE_SUPPORTED_CURVES
+#ifndef NO_CYASSL_CLIENT
+
+int CyaSSL_UseSupportedCurve(CYASSL* ssl, word16 name)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    switch (name) {
+        case CYASSL_ECC_SECP160R1:
+        case CYASSL_ECC_SECP192R1:
+        case CYASSL_ECC_SECP224R1:
+        case CYASSL_ECC_SECP256R1:
+        case CYASSL_ECC_SECP384R1:
+        case CYASSL_ECC_SECP521R1:
+            break;
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    return TLSX_UseSupportedCurve(&ssl->extensions, name);
+}
+
+int CyaSSL_CTX_UseSupportedCurve(CYASSL_CTX* ctx, word16 name)
+{
+    if (ctx == NULL)
+        return BAD_FUNC_ARG;
+
+    switch (name) {
+        case CYASSL_ECC_SECP160R1:
+        case CYASSL_ECC_SECP192R1:
+        case CYASSL_ECC_SECP224R1:
+        case CYASSL_ECC_SECP256R1:
+        case CYASSL_ECC_SECP384R1:
+        case CYASSL_ECC_SECP521R1:
+            break;
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+
+    return TLSX_UseSupportedCurve(&ctx->extensions, name);
+}
+
+#endif /* NO_CYASSL_CLIENT */
+#endif /* HAVE_SUPPORTED_CURVES */
+
+
+#ifndef CYASSL_LEANPSK
+int CyaSSL_send(CYASSL* ssl, const void* data, int sz, int flags)
+{
+    int ret;
+    int oldFlags;
+
+    CYASSL_ENTER("CyaSSL_send()");
+
+    if (ssl == NULL || data == NULL || sz < 0)
+        return BAD_FUNC_ARG;
+
+    oldFlags = ssl->wflags;
+
+    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;
+
+    CYASSL_ENTER("CyaSSL_recv()");
+
+    if (ssl == NULL || data == NULL || sz < 0)
+        return BAD_FUNC_ARG;
+
+    oldFlags = ssl->rflags;
+
+    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");
+
+    if (ret > 0)
+        return SSL_ERROR_NONE;
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    CYASSL_LEAVE("SSL_get_error", ssl->error);
+
+    /* make sure converted types are handled in SetErrorString() too */
+    if (ssl->error == WANT_READ)
+        return SSL_ERROR_WANT_READ;         /* convert to OpenSSL type */
+    else if (ssl->error == WANT_WRITE)
+        return SSL_ERROR_WANT_WRITE;        /* convert to OpenSSL type */
+    else if (ssl->error == ZERO_RETURN)
+        return SSL_ERROR_ZERO_RETURN;       /* convert to OpenSSL type */
+    return ssl->error;
+}
+
+
+/* retrive alert history, SSL_SUCCESS on ok */
+int 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 >= CYASSL_MAX_ERROR_SZ)
+        CyaSSL_ERR_error_string(e, buf);
+    else {
+        char tmp[CYASSL_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);
+    }
+}
+
+
+const byte* CyaSSL_GetMacSecret(CYASSL* ssl, int verify)
+{
+    if (ssl == NULL)
+        return NULL;
+
+    if ( (ssl->options.side == CYASSL_CLIENT_END && !verify) ||
+         (ssl->options.side == CYASSL_SERVER_END &&  verify) )
+        return ssl->keys.client_write_MAC_secret;
+    else
+        return ssl->keys.server_write_MAC_secret;
+}
+
+
+#ifdef ATOMIC_USER
+
+void  CyaSSL_CTX_SetMacEncryptCb(CYASSL_CTX* ctx, CallbackMacEncrypt cb)
+{
+    if (ctx)
+        ctx->MacEncryptCb = cb;
+}
+
+
+void  CyaSSL_SetMacEncryptCtx(CYASSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->MacEncryptCtx = ctx;
+}
+
+
+void* CyaSSL_GetMacEncryptCtx(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->MacEncryptCtx;
+
+    return NULL;
+}
+
+
+void  CyaSSL_CTX_SetDecryptVerifyCb(CYASSL_CTX* ctx, CallbackDecryptVerify cb)
+{
+    if (ctx)
+        ctx->DecryptVerifyCb = cb;
+}
+
+
+void  CyaSSL_SetDecryptVerifyCtx(CYASSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->DecryptVerifyCtx = ctx;
+}
+
+
+void* CyaSSL_GetDecryptVerifyCtx(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->DecryptVerifyCtx;
+
+    return NULL;
+}
+
+
+const byte* CyaSSL_GetClientWriteKey(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->keys.client_write_key;
+
+    return NULL;
+}
+
+
+const byte* CyaSSL_GetClientWriteIV(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->keys.client_write_IV;
+
+    return NULL;
+}
+
+
+const byte* CyaSSL_GetServerWriteKey(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->keys.server_write_key;
+
+    return NULL;
+}
+
+
+const byte* CyaSSL_GetServerWriteIV(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->keys.server_write_IV;
+
+    return NULL;
+}
+
+
+int CyaSSL_GetKeySize(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->specs.key_size;
+
+    return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_GetIVSize(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->specs.iv_size;
+
+    return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_GetBulkCipher(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->specs.bulk_cipher_algorithm;
+
+    return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_GetCipherType(CYASSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    if (ssl->specs.cipher_type == block)
+        return CYASSL_BLOCK_TYPE;
+    if (ssl->specs.cipher_type == stream)
+        return CYASSL_STREAM_TYPE;
+    if (ssl->specs.cipher_type == aead)
+        return CYASSL_AEAD_TYPE;
+
+    return -1;
+}
+
+
+int CyaSSL_GetCipherBlockSize(CYASSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    return ssl->specs.block_size;
+}
+
+
+int CyaSSL_GetAeadMacSize(CYASSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    return ssl->specs.aead_mac_size;
+}
+
+
+int CyaSSL_IsTLSv1_1(CYASSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    if (ssl->options.tls1_1)
+        return 1;
+
+    return 0;
+}
+
+
+int CyaSSL_GetSide(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->options.side;
+
+    return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_GetHmacSize(CYASSL* ssl)
+{
+    /* AEAD ciphers don't have HMAC keys */
+    if (ssl)
+        return (ssl->specs.cipher_type != aead) ? ssl->specs.hash_size : 0;
+
+    return BAD_FUNC_ARG;
+}
+
+#endif /* ATOMIC_USER */
+
+#ifndef NO_CERTS
+
+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) {
+        XMEMSET(cm, 0, sizeof(CYASSL_CERT_MANAGER));
+
+        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
+        #ifdef HAVE_OCSP
+            if (cm->ocsp)
+                FreeOCSP(cm->ocsp, 1);
+        #endif
+        FreeSignerTable(cm->caTable, CA_TABLE_SIZE, NULL);
+        FreeMutex(&cm->caLock);
+        XFREE(cm, NULL, DYNAMIC_TYPE_CERT_MANAGER);
+    }
+
+}
+
+
+/* Unload the CA signer list */
+int 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_E;
+
+    FreeSignerTable(cm->caTable, CA_TABLE_SIZE, NULL);
+
+    UnLockMutex(&cm->caLock);
+
+
+    return SSL_SUCCESS;
+}
+
+
+/* Return bytes written to buff or < 0 for error */
+int CyaSSL_CertPemToDer(const unsigned char* pem, int pemSz,
+                        unsigned char* buff, int buffSz,
+                        int type)
+{
+    EncryptedInfo info;
+    int           eccKey = 0;
+    int           ret;
+    buffer        der;
+
+    CYASSL_ENTER("CyaSSL_CertPemToDer");
+
+    if (pem == NULL || buff == NULL || buffSz <= 0) {
+        CYASSL_MSG("Bad pem der args");
+        return BAD_FUNC_ARG;
+    }
+
+    if (type != CERT_TYPE && type != CA_TYPE && type != CERTREQ_TYPE) {
+        CYASSL_MSG("Bad cert type");
+        return BAD_FUNC_ARG;
+    }
+
+    info.set       = 0;
+    info.ctx      = NULL;
+    info.consumed = 0;
+    der.buffer    = NULL;
+
+    ret = PemToDer(pem, pemSz, 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, DYNAMIC_TYPE_KEY);
+
+    return ret;
+}
+
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+
+/* our KeyPemToDer password callback, password in userData */
+static INLINE int OurPasswordCb(char* passwd, int sz, int rw, void* userdata)
+{
+    (void)rw;
+
+    if (userdata == NULL)
+        return 0;
+
+    XSTRNCPY(passwd, (char*)userdata, sz);
+    return min((word32)sz, (word32)XSTRLEN((char*)userdata));
+}
+
+#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */
+
+
+/* Return bytes written to buff or < 0 for error */
+int 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;
+
+#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+    if (pass) {
+        info.ctx = CyaSSL_CTX_new(CyaSSLv23_client_method());
+        if (info.ctx == NULL)
+            return MEMORY_E;
+        CyaSSL_CTX_set_default_passwd_cb(info.ctx, OurPasswordCb);
+        CyaSSL_CTX_set_default_passwd_cb_userdata(info.ctx, (void*)pass);
+    }
+#endif
+
+    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, DYNAMIC_TYPE_KEY);
+
+    if (info.ctx)
+        CyaSSL_CTX_free(info.ctx);
+
+    return ret;
+}
+
+
+#endif /* !NO_CERTS */
+
+
+
+#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)
+
+void CyaSSL_ERR_print_errors_fp(FILE* fp, int err)
+{
+    char data[CYASSL_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_E;
+                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 */
+
+#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_E;
+#endif
+        if (InitMutex(&count_mutex) != 0)
+            ret = BAD_MUTEX_E;
+    }
+    if (ret == SSL_SUCCESS) {
+        if (LockMutex(&count_mutex) != 0) {
+            CYASSL_MSG("Bad Lock Mutex count");
+            return BAD_MUTEX_E;
+        }
+        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   ret      = 0;
+        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 == CERTREQ_TYPE) {
+            XSTRNCPY(header, "-----BEGIN CERTIFICATE REQUEST-----",
+                     sizeof(header));
+            XSTRNCPY(footer, "-----END CERTIFICATE REQUEST-----",
+                     sizeof(footer));
+            dynamicType = DYNAMIC_TYPE_KEY;
+        } 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) {
+            /* convert and adjust length */
+            if ( (ret = ToTraditional(der->buffer, der->length)) < 0 ) {
+                return ret;
+            } else {
+                der->length = ret;
+                return 0;
+            }
+        }
+
+#if (defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)) && !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);
+            /* convert and adjust length */
+            if ( (ret = ToTraditionalEnc(der->buffer, der->length, password,
+                                         passwordSz)) < 0 ) {
+                return ret;
+            } else {
+                der->length = ret;
+                return 0;
+            }
+         }
+#endif
+
+        return 0;
+    }
+
+
+    /* process the buffer buff, legnth sz, into ctx of format and type
+       used tracks bytes consumed, userChain specifies a user cert chain
+       to pass during the handshake */
+    static int ProcessBuffer(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;
+        (void)rsaKey;
+
+        if (used)
+            *used = sz;     /* used bytes default to sz, PEM chain may shorten*/
+
+        if (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM
+                                        && format != SSL_FILETYPE_RAW)
+            return SSL_BAD_FILETYPE;
+
+        if (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;
+            }
+            ret = 0; /* back to good status */
+
+            if (XSTRNCMP(info.name, "DES-CBC", 7) == 0) {
+                Des enc;
+
+                ret = Des_SetKey(&enc, key, info.iv, DES_DECRYPTION);
+                if (ret != 0)
+                    return ret;
+
+                Des_CbcDecrypt(&enc, der.buffer, der.buffer, der.length);
+            }
+            else if (XSTRNCMP(info.name, "DES-EDE3-CBC", 13) == 0) {
+                Des3 enc;
+
+                ret = Des3_SetKey(&enc, key, info.iv, DES_DECRYPTION);
+                if (ret != 0)
+                    return ret;
+
+                ret = Des3_CbcDecrypt(&enc, der.buffer, der.buffer, der.length);
+                if (ret != 0)
+                    return ret;
+            }
+            else if (XSTRNCMP(info.name, "AES-128-CBC", 13) == 0) {
+                Aes enc;
+                ret = AesSetKey(&enc, key, AES_128_KEY_SIZE, info.iv,
+                                AES_DECRYPTION);
+                if (ret == 0)
+                    ret = AesCbcDecrypt(&enc, der.buffer,der.buffer,der.length);
+            }
+            else if (XSTRNCMP(info.name, "AES-192-CBC", 13) == 0) {
+                Aes enc;
+                ret = AesSetKey(&enc, key, AES_192_KEY_SIZE, info.iv,
+                                AES_DECRYPTION);
+                if (ret == 0)
+                    ret = AesCbcDecrypt(&enc, der.buffer,der.buffer,der.length);
+            }
+            else if (XSTRNCMP(info.name, "AES-256-CBC", 13) == 0) {
+                Aes enc;
+                ret = AesSetKey(&enc, key, AES_256_KEY_SIZE, info.iv,
+                                AES_DECRYPTION);
+                if (ret == 0)
+                    ret = AesCbcDecrypt(&enc, der.buffer,der.buffer,der.length);
+            }
+            else {
+                XFREE(der.buffer, heap, dynamicType);
+                return SSL_BAD_FILE;
+            }
+
+            if (ret != 0) {
+                XFREE(der.buffer, heap, dynamicType);
+                return ret;
+            }
+        }
+#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;
+
+                ret = InitRsaKey(&key, 0);
+                if (ret != 0) return ret;
+                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;
+                if (ctx)
+                    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;
+            }
+
+#ifdef HAVE_ECC
+            if (ctx)
+                ctx->pkCurveOID = cert.pkCurveOID;
+            if (ssl)
+                ssl->pkCurveOID = cert.pkCurveOID;
+#endif
+
+            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(CYASSL_MDK_ARM)
+        extern FILE * CyaSSL_fopen(const char *name, const char *mode) ;
+        #define XFOPEN     CyaSSL_fopen
+    #else
+        #define XFOPEN     fopen
+    #endif
+
+/* process a file with name fname into ctx of format and type
+   userChain specifies a user certificate chain to pass during handshake */
+int ProcessFile(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;
+}
+
+
+/* turn on OCSP if off and compiled in, set options */
+int CyaSSL_CertManagerEnableOCSP(CYASSL_CERT_MANAGER* cm, int options)
+{
+    int ret = SSL_SUCCESS;
+
+    (void)options;
+
+    CYASSL_ENTER("CyaSSL_CertManagerEnableOCSP");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    #ifdef HAVE_OCSP
+        if (cm->ocsp == NULL) {
+            cm->ocsp = (CYASSL_OCSP*)XMALLOC(sizeof(CYASSL_OCSP), cm->heap,
+                                                             DYNAMIC_TYPE_OCSP);
+            if (cm->ocsp == NULL)
+                return MEMORY_E;
+
+            if (InitOCSP(cm->ocsp, cm) != 0) {
+                CYASSL_MSG("Init OCSP failed");
+                FreeOCSP(cm->ocsp, 1);
+                cm->ocsp = NULL;
+                return SSL_FAILURE;
+            }
+        }
+        cm->ocspEnabled = 1;
+        if (options & CYASSL_OCSP_URL_OVERRIDE)
+            cm->ocspUseOverrideURL = 1;
+        if (options & CYASSL_OCSP_NO_NONCE)
+            cm->ocspSendNonce = 0;
+        else
+            cm->ocspSendNonce = 1;
+        #ifndef CYASSL_USER_IO
+            cm->ocspIOCb = EmbedOcspLookup;
+            cm->ocspRespFreeCb = EmbedOcspRespFree;
+        #endif /* CYASSL_USER_IO */
+    #else
+        ret = NOT_COMPILED_IN;
+    #endif
+
+    return ret;
+}
+
+
+int CyaSSL_CertManagerDisableOCSP(CYASSL_CERT_MANAGER* cm)
+{
+    CYASSL_ENTER("CyaSSL_CertManagerDisableOCSP");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    cm->ocspEnabled = 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 HAVE_OCSP
+
+
+/* check CRL if enabled, SSL_SUCCESS  */
+int CyaSSL_CertManagerCheckOCSP(CYASSL_CERT_MANAGER* cm, byte* der, int sz)
+{
+    int         ret;
+    DecodedCert cert;
+
+    CYASSL_ENTER("CyaSSL_CertManagerCheckOCSP");
+
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    if (cm->ocspEnabled == 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 = CheckCertOCSP(cm->ocsp, &cert);
+        if (ret != 0) {
+            CYASSL_MSG("CheckCertOCSP failed");
+        }
+    }
+
+    FreeDecodedCert(&cert);
+
+    if (ret == 0)
+        return SSL_SUCCESS;  /* convert */
+
+    return ret;
+}
+
+
+int CyaSSL_CertManagerSetOCSPOverrideURL(CYASSL_CERT_MANAGER* cm,
+                                                                const char* url)
+{
+    CYASSL_ENTER("CyaSSL_CertManagerSetOCSPOverrideURL");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    XFREE(cm->ocspOverrideURL, cm->heap, 0);
+    if (url != NULL) {
+        int urlSz = (int)XSTRLEN(url) + 1;
+        cm->ocspOverrideURL = (char*)XMALLOC(urlSz, cm->heap, 0);
+        if (cm->ocspOverrideURL != NULL) {
+            XMEMCPY(cm->ocspOverrideURL, url, urlSz);
+        }
+        else
+            return MEMORY_E;
+    }
+    else
+        cm->ocspOverrideURL = NULL;
+
+    return SSL_SUCCESS;
+}
+
+
+int CyaSSL_CertManagerSetOCSP_Cb(CYASSL_CERT_MANAGER* cm,
+                        CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx)
+{
+    CYASSL_ENTER("CyaSSL_CertManagerSetOCSP_Cb");
+    if (cm == NULL)
+        return BAD_FUNC_ARG;
+
+    cm->ocspIOCb = ioCb;
+    cm->ocspRespFreeCb = respFreeCb;
+    cm->ocspIOCtx = ioCbCtx;
+
+    return SSL_SUCCESS;
+}
+
+
+int CyaSSL_EnableOCSP(CYASSL* ssl, int options)
+{
+    CYASSL_ENTER("CyaSSL_EnableOCSP");
+    if (ssl)
+        return CyaSSL_CertManagerEnableOCSP(ssl->ctx->cm, options);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_DisableOCSP(CYASSL* ssl)
+{
+    CYASSL_ENTER("CyaSSL_DisableOCSP");
+    if (ssl)
+        return CyaSSL_CertManagerDisableOCSP(ssl->ctx->cm);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_SetOCSP_OverrideURL(CYASSL* ssl, const char* url)
+{
+    CYASSL_ENTER("CyaSSL_SetOCSP_OverrideURL");
+    if (ssl)
+        return CyaSSL_CertManagerSetOCSPOverrideURL(ssl->ctx->cm, url);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_SetOCSP_Cb(CYASSL* ssl,
+                        CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx)
+{
+    CYASSL_ENTER("CyaSSL_SetOCSP_Cb");
+    if (ssl)
+        return CyaSSL_CertManagerSetOCSP_Cb(ssl->ctx->cm,
+                                                     ioCb, respFreeCb, ioCbCtx);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_CTX_EnableOCSP(CYASSL_CTX* ctx, int options)
+{
+    CYASSL_ENTER("CyaSSL_CTX_EnableOCSP");
+    if (ctx)
+        return CyaSSL_CertManagerEnableOCSP(ctx->cm, options);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_CTX_DisableOCSP(CYASSL_CTX* ctx)
+{
+    CYASSL_ENTER("CyaSSL_CTX_DisableOCSP");
+    if (ctx)
+        return CyaSSL_CertManagerDisableOCSP(ctx->cm);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_CTX_SetOCSP_OverrideURL(CYASSL_CTX* ctx, const char* url)
+{
+    CYASSL_ENTER("CyaSSL_SetOCSP_OverrideURL");
+    if (ctx)
+        return CyaSSL_CertManagerSetOCSPOverrideURL(ctx->cm, url);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+int CyaSSL_CTX_SetOCSP_Cb(CYASSL_CTX* ctx,
+                        CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx)
+{
+    CYASSL_ENTER("CyaSSL_CTX_SetOCSP_Cb");
+    if (ctx)
+        return CyaSSL_CertManagerSetOCSP_Cb(ctx->cm, ioCb, respFreeCb, ioCbCtx);
+    else
+        return BAD_FUNC_ARG;
+}
+
+
+#endif /* HAVE_OCSP */
+
+
+#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)
+
+/* 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
+
+/* 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_E;
+    }
+
+    for (i = 0; i < cache_header.rows; ++i)
+        XMEMCPY(row++, SessionCache + i, sizeof(SessionRow));
+
+#ifndef NO_CLIENT_CACHE
+    clRow = (ClientRow*)row;
+    for (i = 0; i < cache_header.rows; ++i)
+        XMEMCPY(clRow++, ClientCache + i, sizeof(ClientRow));
+#endif
+
+    UnLockMutex(&session_mutex);
+
+    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_E;
+    }
+
+    for (i = 0; i < cache_header.rows; ++i)
+        XMEMCPY(SessionCache + i, row++, sizeof(SessionRow));
+
+#ifndef NO_CLIENT_CACHE
+    clRow = (ClientRow*)row;
+    for (i = 0; i < cache_header.rows; ++i)
+        XMEMCPY(ClientCache + i, clRow++, sizeof(ClientRow));
+#endif
+
+    UnLockMutex(&session_mutex);
+
+    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_E;
+    }
+
+    /* 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_E;
+    }
+
+    /* 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 += (int)sizeof(signer->subjectKeyIdHash);
+#endif
+
+    /* add dynamic bytes needed */
+    sz += signer->pubKeySize;
+    sz += signer->nameLen;
+
+    return sz;
+}
+
+
+/* Return memory needed to persist this row, have lock */
+static INLINE int GetCertCacheRowMemory(Signer* row)
+{
+    int sz = 0;
+
+    while (row) {
+        sz += GetSignerMemory(row);
+        row = row->next;
+    }
+
+    return sz;
+}
+
+
+/* get the size of persist cert cache, have lock */
+static INLINE int GetCertCacheMemSize(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 += (int)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 += (int)sizeof(signer->pubKeySize);
+
+        /* keyOID */
+        XMEMCPY(&signer->keyOID, current + idx, sizeof(signer->keyOID));
+        idx += (int)sizeof(signer->keyOID);
+
+        /* pulicKey */
+        if (start + minSz + signer->pubKeySize > end) {
+            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 += (int)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 += (int)sizeof(list->pubKeySize);
+
+        XMEMCPY(current + added, &list->keyOID,     sizeof(list->keyOID));
+        added += (int)sizeof(list->keyOID);
+
+        XMEMCPY(current + added, list->publicKey, list->pubKeySize);
+        added += list->pubKeySize;
+
+        XMEMCPY(current + added, &list->nameLen, sizeof(list->nameLen));
+        added += (int)sizeof(list->nameLen);
+
+        XMEMCPY(current + added, list->name, list->nameLen);
+        added += list->nameLen;
+
+        XMEMCPY(current + added, list->subjectNameHash, SIGNER_DIGEST_SIZE);
+        added += SIGNER_DIGEST_SIZE;
+
+        #ifndef NO_SKID
+            XMEMCPY(current + added, list->subjectKeyIdHash,SIGNER_DIGEST_SIZE);
+            added += SIGNER_DIGEST_SIZE;
+        #endif
+
+        list = list->next;
+    }
+
+    return added;
+}
+
+
+/* Persist cert cache to memory, have lock */
+static INLINE int DoMemSaveCertCache(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_E;
+    }
+
+    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_E;
+    }
+
+    ret = DoMemSaveCertCache(cm, mem, sz);
+    if (ret == SSL_SUCCESS)
+        *used  = GetCertCacheMemSize(cm);
+
+    UnLockMutex(&cm->caLock);
+
+    return ret;
+}
+
+
+/* Restore cert cache from memory */
+int CM_MemRestoreCertCache(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_E;
+    }
+
+    FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap);
+
+    for (i = 0; i < CA_TABLE_SIZE; ++i) {
+        int added = RestoreCertRow(cm, current, i, hdr->columns[i], end);
+        if (added < 0) {
+            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_E;
+    }
+
+    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;
+
+    if (timeout > ssl->dtls_timeout_max) {
+        CYASSL_MSG("Can't set dtls timeout init greater than dtls timeout max");
+        return BAD_FUNC_ARG;
+    }
+
+    ssl->dtls_timeout_init = timeout;
+    ssl->dtls_timeout = timeout;
+
+    return SSL_SUCCESS;
+}
+
+
+/* user may need to alter max dtls recv timeout, SSL_SUCCESS on ok */
+int CyaSSL_dtls_set_timeout_max(CYASSL* ssl, int timeout)
+{
+    if (ssl == NULL || timeout < 0)
+        return BAD_FUNC_ARG;
+
+    if (timeout < 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 != CYASSL_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);
+                    if ( (ssl->error = InitSha(&ssl->hashSha)) != 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+#endif
+                    if (IsAtLeastTLSv1_2(ssl)) {
+                        #ifndef NO_SHA256
+                            if ( (ssl->error =
+                                           InitSha256(&ssl->hashSha256)) != 0) {
+                                CYASSL_ERROR(ssl->error);
+                                return SSL_FATAL_ERROR;
+                            }
+                        #endif
+                        #ifdef CYASSL_SHA384
+                            if ( (ssl->error =
+                                           InitSha384(&ssl->hashSha384)) != 0) {
+                                CYASSL_ERROR(ssl->error);
+                                return SSL_FATAL_ERROR;
+                            }
+                        #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 = CYASSL_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 = CYASSL_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 = CYASSL_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 != CYASSL_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);
+                    if ( (ssl->error = InitSha(&ssl->hashSha)) != 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+#endif
+                    if (IsAtLeastTLSv1_2(ssl)) {
+                        #ifndef NO_SHA256
+                            if ( (ssl->error =
+                                           InitSha256(&ssl->hashSha256)) != 0) {
+                               CYASSL_ERROR(ssl->error);
+                               return SSL_FATAL_ERROR;
+                            }
+                        #endif
+                        #ifdef CYASSL_SHA384
+                            if ( (ssl->error =
+                                           InitSha384(&ssl->hashSha384)) != 0) {
+                               CYASSL_ERROR(ssl->error);
+                               return SSL_FATAL_ERROR;
+                            }
+                        #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_E;
+    }
+
+    release = initRefCount-- == 1;
+    if (initRefCount < 0)
+        initRefCount = 0;
+
+    UnLockMutex(&count_mutex);
+
+    if (!release)
+        return ret;
+
+#ifndef NO_SESSION_CACHE
+    if (FreeMutex(&session_mutex) != 0)
+        ret = BAD_MUTEX_E;
+#endif
+    if (FreeMutex(&count_mutex) != 0)
+        ret = BAD_MUTEX_E;
+
+#if defined(HAVE_ECC) && defined(FP_ECC)
+    ecc_fp_free();
+#endif
+
+    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, int* error)
+{
+    byte digest[MD5_DIGEST_SIZE];
+    Md5  md5;
+
+    (void)error;
+
+    InitMd5(&md5);
+    Md5Update(&md5, sessionID, len);
+    Md5Final(&md5, digest);
+
+    return MakeWordFromHash(digest);
+}
+
+#elif !defined(NO_SHA)
+
+/* 0 on failure */
+static INLINE word32 HashSession(const byte* sessionID, word32 len, int* error)
+{
+    byte digest[SHA_DIGEST_SIZE];
+    Sha  sha;
+    int  ret = 0;
+
+    ret = InitSha(&sha);
+    if (ret != 0) {
+        *error = ret;
+        return 0;
+    }
+    ShaUpdate(&sha, sessionID, len);
+    ShaFinal(&sha, digest);
+
+    return MakeWordFromHash(digest);
+}
+
+#elif !defined(NO_SHA256)
+
+static INLINE word32 HashSession(const byte* sessionID, word32 len, int* error)
+{
+    byte    digest[SHA256_DIGEST_SIZE];
+    Sha256  sha256;
+    int     ret;
+
+    ret = InitSha256(&sha256);
+    if (ret != 0) {
+        *error = ret;
+        return 0;
+    }
+    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;
+    int             error = 0;
+
+    CYASSL_ENTER("GetSessionClient");
+
+    if (ssl->options.side == CYASSL_SERVER_END)
+        return NULL;
+
+    len = min(SERVER_ID_LEN, (word32)len);
+    row = HashSession(id, len, &error) % SESSION_ROWS;
+    if (error != 0) {
+        CYASSL_MSG("Hash session failed");
+        return NULL;
+    }
+
+    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;
+    int          error = 0;
+
+    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, &error) % SESSION_ROWS;
+    if (error != 0) {
+        CYASSL_MSG("Hash session failed");
+        return NULL;
+    }
+
+    if (LockMutex(&session_mutex) != 0)
+        return 0;
+
+    /* start from most recently used */
+    count = min((word32)SessionCache[row].totalCount, SESSIONS_PER_ROW);
+    idx = SessionCache[row].nextIdx - 1;
+    if (idx < 0)
+        idx = SESSIONS_PER_ROW - 1; /* if back to front, the previous was end */
+
+    for (; count > 0; --count, idx = idx ? idx - 1 : SESSIONS_PER_ROW - 1) {
+        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;
+    int    error = 0;
+
+    if (ssl->options.sessionCacheOff)
+        return 0;
+
+    if (ssl->options.haveSessionId == 0)
+        return 0;
+
+    row = HashSession(ssl->arrays->sessionID, ID_LEN, &error) % SESSION_ROWS;
+    if (error != 0) {
+        CYASSL_MSG("Hash session failed");
+        return error;
+    }
+
+    if (LockMutex(&session_mutex) != 0)
+        return BAD_MUTEX_E;
+
+    idx = SessionCache[row].nextIdx++;
+#ifdef SESSION_INDEX
+    ssl->sessionIndex = (row << SESSIDX_ROW_SHIFT) | idx;
+#endif
+
+    XMEMCPY(SessionCache[row].Sessions[idx].masterSecret,
+           ssl->arrays->masterSecret, SECRET_LEN);
+    XMEMCPY(SessionCache[row].Sessions[idx].sessionID, ssl->arrays->sessionID,
+           ID_LEN);
+
+    SessionCache[row].Sessions[idx].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 == CYASSL_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,
+                                &error) % SESSION_ROWS;
+        if (error != 0) {
+            CYASSL_MSG("Hash session failed");
+            return error;
+        }
+        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_E;
+
+    return 0;
+}
+
+
+#ifdef SESSION_INDEX
+
+int CyaSSL_GetSessionIndex(CYASSL* ssl)
+{
+    CYASSL_ENTER("CyaSSL_GetSessionIndex");
+    CYASSL_LEAVE("CyaSSL_GetSessionIndex", ssl->sessionIndex);
+    return ssl->sessionIndex;
+}
+
+
+int CyaSSL_GetSessionAtIndex(int idx, CYASSL_SESSION* session)
+{
+    int row, col, result = SSL_FAILURE;
+
+    CYASSL_ENTER("CyaSSL_GetSessionAtIndex");
+
+    row = idx >> SESSIDX_ROW_SHIFT;
+    col = idx & SESSIDX_IDX_MASK;
+
+    if (LockMutex(&session_mutex) != 0) {
+        return BAD_MUTEX_E;
+    }
+
+    if (row < SESSION_ROWS &&
+        col < (int)min(SessionCache[row].totalCount, SESSIONS_PER_ROW)) {
+        XMEMCPY(session,
+                 &SessionCache[row].Sessions[col], sizeof(CYASSL_SESSION));
+        result = SSL_SUCCESS;
+    }
+
+    if (UnLockMutex(&session_mutex) != 0)
+        result = BAD_MUTEX_E;
+
+    CYASSL_LEAVE("CyaSSL_GetSessionAtIndex", result);
+    return result;
+}
+
+#endif /* SESSION_INDEX */
+
+#if defined(SESSION_INDEX) && defined(SESSION_CERTS)
+
+CYASSL_X509_CHAIN* CyaSSL_SESSION_get_peer_chain(CYASSL_SESSION* session)
+{
+    CYASSL_X509_CHAIN* chain = NULL;
+
+    CYASSL_ENTER("CyaSSL_SESSION_get_peer_chain");
+    if (session)
+        chain = &session->chain;
+
+    CYASSL_LEAVE("CyaSSL_SESSION_get_peer_chain", chain ? 1 : 0);
+    return chain;
+}
+
+#endif /* SESSION_INDEX && SESSION_CERTS */
+
+
+    #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 == CYASSL_CLIENT_END)
+            ret = CyaSSL_connect(ssl);
+#endif
+#ifndef NO_CYASSL_SERVER
+        if (ssl->options.side == CYASSL_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);
+    }
+
+
+    /* unload any certs or keys that SSL owns, leave CTX as is
+       SSL_SUCCESS on ok */
+    int CyaSSL_UnloadCertsKeys(CYASSL* ssl)
+    {
+        if (ssl == NULL) {
+            CYASSL_MSG("Null function arg");
+            return BAD_FUNC_ARG;
+        }
+
+        if (ssl->buffers.weOwnCert) {
+            CYASSL_MSG("Unloading cert");
+            XFREE(ssl->buffers.certificate.buffer, ssl->heap,DYNAMIC_TYPE_CERT);
+            ssl->buffers.weOwnCert = 0;
+            ssl->buffers.certificate.length = 0;
+            ssl->buffers.certificate.buffer = NULL;
+        }
+
+        if (ssl->buffers.weOwnKey) {
+            CYASSL_MSG("Unloading key");
+            XFREE(ssl->buffers.key.buffer, ssl->heap, DYNAMIC_TYPE_KEY);
+            ssl->buffers.weOwnKey = 0;
+            ssl->buffers.key.length = 0;
+            ssl->buffers.key.buffer = NULL;
+        }
+
+        return SSL_SUCCESS;
+    }
+
+
+    int 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 = CYASSL_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)
+    {
+        if (ctx != NULL)
+            return ctx->error;
+        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)
+    extern int closesocket(int) ;
+#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);  /* OpenSSL compat, no ret */
+    }
+
+
+    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);  /* OpenSSL compat, no error */
+    }
+
+
+    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);   /* OpenSSL compat, no error */
+    }
+
+
+    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);  /* OpenSSL compat, no error */
+    }
+
+
+    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)
+    {
+        int ret = 0;
+
+        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) {
+                ret = AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                                ctx->enc ? AES_ENCRYPTION : AES_DECRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+            if (iv && key == NULL) {
+                ret = AesSetIV(&ctx->cipher.aes, iv);
+                if (ret != 0)
+                    return ret;
+            }
+        }
+        else if (ctx->cipherType == AES_192_CBC_TYPE || (type &&
+                                       XSTRNCMP(type, "AES192-CBC", 10) == 0)) {
+            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) {
+                ret = AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                                ctx->enc ? AES_ENCRYPTION : AES_DECRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+            if (iv && key == NULL) {
+                ret = AesSetIV(&ctx->cipher.aes, iv);
+                if (ret != 0)
+                    return ret;
+            }
+        }
+        else if (ctx->cipherType == AES_256_CBC_TYPE || (type &&
+                                       XSTRNCMP(type, "AES256-CBC", 10) == 0)) {
+            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) {
+                ret = AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                                ctx->enc ? AES_ENCRYPTION : AES_DECRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+            if (iv && key == NULL) {
+                ret = AesSetIV(&ctx->cipher.aes, iv);
+                if (ret != 0)
+                    return ret;
+            }
+        }
+#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) {
+                ret = AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                                AES_ENCRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+            if (iv && key == NULL) {
+                ret = AesSetIV(&ctx->cipher.aes, iv);
+                if (ret != 0)
+                    return ret;
+            }
+        }
+        else if (ctx->cipherType == AES_192_CTR_TYPE || (type &&
+                                       XSTRNCMP(type, "AES192-CTR", 10) == 0)) {
+            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) {
+                ret = AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                                AES_ENCRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+            if (iv && key == NULL) {
+                ret = AesSetIV(&ctx->cipher.aes, iv);
+                if (ret != 0)
+                    return ret;
+            }
+        }
+        else if (ctx->cipherType == AES_256_CTR_TYPE || (type &&
+                                       XSTRNCMP(type, "AES256-CTR", 10) == 0)) {
+            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) {
+                ret = AesSetKey(&ctx->cipher.aes, key, ctx->keyLen, iv,
+                                AES_ENCRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+            if (iv && key == NULL) {
+                ret = AesSetIV(&ctx->cipher.aes, iv);
+                if (ret != 0)
+                    return ret;
+            }
+        }
+#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) {
+                ret = Des_SetKey(&ctx->cipher.des, key, iv,
+                          ctx->enc ? DES_ENCRYPTION : DES_DECRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+
+            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) {
+                ret = Des3_SetKey(&ctx->cipher.des3, key, iv,
+                          ctx->enc ? DES_ENCRYPTION : DES_DECRYPTION);
+                if (ret != 0)
+                    return ret;
+            }
+
+            if (iv && key == NULL) {
+                ret = Des3_SetIV(&ctx->cipher.des3, iv);
+                if (ret != 0)
+                    return ret;
+            }
+        }
+        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)
+                    ret = Des3_CbcEncrypt(&ctx->cipher.des3, dst, src, len);
+                else
+                    ret = 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;
+        int  ret;
+
+        CYASSL_ENTER("HMAC");
+        if (!md) return NULL;  /* no static buffer support */
+
+        if (XSTRNCMP(evp_md, "MD5", 3) == 0) {
+            ret = HmacSetKey(&hmac, MD5, (const byte*)key, key_len);
+            if (md_len) *md_len = MD5_DIGEST_SIZE;
+        }
+        else if (XSTRNCMP(evp_md, "SHA", 3) == 0) {
+            ret = HmacSetKey(&hmac, SHA, (const byte*)key, key_len);
+            if (md_len) *md_len = SHA_DIGEST_SIZE;
+        }
+        else
+            return NULL;
+
+        if (ret != 0)
+            return NULL;
+
+        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");
+
+        /* OpenSSL compat, no ret */
+        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");
+
+        /* OpenSSL compat, no ret */
+        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;
+    }
+
+
+    int CyaSSL_X509_get_isCA(CYASSL_X509* x509)
+    {
+        int isCA = 0;
+
+        CYASSL_ENTER("CyaSSL_X509_get_isCA");
+
+        if (x509 != NULL)
+            isCA = x509->isCa;
+
+        CYASSL_LEAVE("CyaSSL_X509_get_isCA", isCA);
+
+        return isCA;
+    }
+
+
+#ifdef OPENSSL_EXTRA
+    int CyaSSL_X509_ext_isSet_by_NID(CYASSL_X509* x509, int nid)
+    {
+        int isSet = 0;
+
+        CYASSL_ENTER("CyaSSL_X509_ext_isSet_by_NID");
+
+        if (x509 != NULL) {
+            switch (nid) {
+                case BASIC_CA_OID: isSet = x509->basicConstSet; break;
+                case ALT_NAMES_OID: isSet = x509->subjAltNameSet; break;
+                case AUTH_KEY_OID: isSet = x509->authKeyIdSet; break;
+                case SUBJ_KEY_OID: isSet = x509->subjKeyIdSet; break;
+                case KEY_USAGE_OID: isSet = x509->keyUsageSet; break;
+                #ifdef CYASSL_SEP
+                    case CERT_POLICY_OID: isSet = x509->certPolicySet; break;
+                #endif /* CYASSL_SEP */
+            }
+        }
+
+        CYASSL_LEAVE("CyaSSL_X509_ext_isSet_by_NID", isSet);
+
+        return isSet;
+    }
+
+
+    int CyaSSL_X509_ext_get_critical_by_NID(CYASSL_X509* x509, int nid)
+    {
+        int crit = 0;
+
+        CYASSL_ENTER("CyaSSL_X509_ext_get_critical_by_NID");
+
+        if (x509 != NULL) {
+            switch (nid) {
+                case BASIC_CA_OID: crit = x509->basicConstCrit; break;
+                case ALT_NAMES_OID: crit = x509->subjAltNameCrit; break;
+                case AUTH_KEY_OID: crit = x509->authKeyIdCrit; break;
+                case SUBJ_KEY_OID: crit = x509->subjKeyIdCrit; break;
+                case KEY_USAGE_OID: crit = x509->keyUsageCrit; break;
+                #ifdef CYASSL_SEP
+                    case CERT_POLICY_OID: crit = x509->certPolicyCrit; break;
+                #endif /* CYASSL_SEP */
+            }
+        }
+
+        CYASSL_LEAVE("CyaSSL_X509_ext_get_critical_by_NID", crit);
+
+        return crit;
+    }
+
+
+    int CyaSSL_X509_get_isSet_pathLength(CYASSL_X509* x509)
+    {
+        int isSet = 0;
+
+        CYASSL_ENTER("CyaSSL_X509_get_isSet_pathLength");
+
+        if (x509 != NULL)
+            isSet = x509->basicConstPlSet;
+
+        CYASSL_LEAVE("CyaSSL_X509_get_isSet_pathLength", isSet);
+
+        return isSet;
+    }
+
+
+    word32 CyaSSL_X509_get_pathLength(CYASSL_X509* x509)
+    {
+        word32 pathLength = 0;
+
+        CYASSL_ENTER("CyaSSL_X509_get_pathLength");
+
+        if (x509 != NULL)
+            pathLength = x509->pathLength;
+
+        CYASSL_LEAVE("CyaSSL_X509_get_pathLength", pathLength);
+
+        return pathLength;
+    }
+
+
+    unsigned int CyaSSL_X509_get_keyUsage(CYASSL_X509* x509)
+    {
+        word16 usage = 0;
+
+        CYASSL_ENTER("CyaSSL_X509_get_keyUsage");
+
+        if (x509 != NULL)
+            usage = x509->keyUsage;
+
+        CYASSL_LEAVE("CyaSSL_X509_get_keyUsage", usage);
+
+        return usage;
+    }
+
+
+    byte* CyaSSL_X509_get_authorityKeyID(
+                                      CYASSL_X509* x509, byte* dst, int* dstLen)
+    {
+        byte *id = NULL;
+        int copySz = 0;
+
+        CYASSL_ENTER("CyaSSL_X509_get_authorityKeyID");
+
+        if (x509 != NULL) {
+            if (x509->authKeyIdSet) {
+                copySz = min(dstLen != NULL ? *dstLen : 0,
+                                                        (int)x509->authKeyIdSz);
+                id = x509->authKeyId;
+            }
+
+            if (dst != NULL && dstLen != NULL && id != NULL && copySz > 0) {
+                XMEMCPY(dst, id, copySz);
+                id = dst;
+                *dstLen = copySz;
+            }
+        }
+
+        CYASSL_LEAVE("CyaSSL_X509_get_authorityKeyID", copySz);
+
+        return id;
+    }
+
+
+    byte* CyaSSL_X509_get_subjectKeyID(
+                                      CYASSL_X509* x509, byte* dst, int* dstLen)
+    {
+        byte *id = NULL;
+        int copySz = 0;
+
+        CYASSL_ENTER("CyaSSL_X509_get_subjectKeyID");
+
+        if (x509 != NULL) {
+            if (x509->subjKeyIdSet) {
+                copySz = min(dstLen != NULL ? *dstLen : 0,
+                                                        (int)x509->subjKeyIdSz);
+                id = x509->subjKeyId;
+            }
+
+            if (dst != NULL && dstLen != NULL && id != NULL && copySz > 0) {
+                XMEMCPY(dst, id, copySz);
+                id = dst;
+                *dstLen = copySz;
+            }
+        }
+
+        CYASSL_LEAVE("CyaSSL_X509_get_subjectKeyID", copySz);
+
+        return id;
+    }
+
+
+    int CyaSSL_X509_NAME_entry_count(CYASSL_X509_NAME* name)
+    {
+        int count = 0;
+
+        CYASSL_ENTER("CyaSSL_X509_NAME_entry_count");
+
+        if (name != NULL)
+            count = name->fullName.entryCount;
+
+        CYASSL_LEAVE("CyaSSL_X509_NAME_entry_count", count);
+        return count;
+    }
+
+
+    int CyaSSL_X509_NAME_get_text_by_NID(CYASSL_X509_NAME* name,
+                                                    int nid, char* buf, int len)
+    {
+        char *text = NULL;
+        int textSz = 0;
+
+        CYASSL_ENTER("CyaSSL_X509_NAME_get_text_by_NID");
+
+        switch (nid) {
+            case ASN_COMMON_NAME:
+                text = name->fullName.fullName + name->fullName.cnIdx;
+                textSz = name->fullName.cnLen;
+                break;
+            case ASN_SUR_NAME:
+                text = name->fullName.fullName + name->fullName.snIdx;
+                textSz = name->fullName.snLen;
+                break;
+            case ASN_SERIAL_NUMBER:
+                text = name->fullName.fullName + name->fullName.serialIdx;
+                textSz = name->fullName.serialLen;
+                break;
+            case ASN_COUNTRY_NAME:
+                text = name->fullName.fullName + name->fullName.cIdx;
+                textSz = name->fullName.cLen;
+                break;
+            case ASN_LOCALITY_NAME:
+                text = name->fullName.fullName + name->fullName.lIdx;
+                textSz = name->fullName.lLen;
+                break;
+            case ASN_STATE_NAME:
+                text = name->fullName.fullName + name->fullName.stIdx;
+                textSz = name->fullName.stLen;
+                break;
+            case ASN_ORG_NAME:
+                text = name->fullName.fullName + name->fullName.oIdx;
+                textSz = name->fullName.oLen;
+                break;
+            case ASN_ORGUNIT_NAME:
+                text = name->fullName.fullName + name->fullName.ouIdx;
+                textSz = name->fullName.ouLen;
+                break;
+            default:
+                break;
+        }
+
+        if (buf != NULL) {
+            textSz = min(textSz, len);
+            XMEMCPY(buf, text, textSz);
+            buf[textSz] = '\0';
+        }
+
+        CYASSL_LEAVE("CyaSSL_X509_NAME_get_text_by_NID", textSz);
+        return textSz;
+    }
+#endif
+
+
+    /* copy name into in buffer, at most sz bytes, if buffer is null will
+       malloc buffer, call responsible for freeing                     */
+    char* 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;
+    }
+
+
+    int CyaSSL_X509_get_signature_type(CYASSL_X509* x509)
+    {
+        int type = 0;
+
+        CYASSL_ENTER("CyaSSL_X509_get_signature_type");
+
+        if (x509 != NULL)
+            type = x509->sigOID;
+
+        return type;
+    }
+
+
+    int CyaSSL_X509_get_signature(CYASSL_X509* x509,
+                                                 unsigned char* buf, int* bufSz)
+    {
+        CYASSL_ENTER("CyaSSL_X509_get_signature");
+        if (x509 == NULL || bufSz == NULL || *bufSz < (int)x509->sig.length)
+            return SSL_FATAL_ERROR;
+
+        if (buf != NULL)
+            XMEMCPY(buf, x509->sig.buffer, x509->sig.length);
+        *bufSz = x509->sig.length;
+
+        return SSL_SUCCESS;
+    }
+
+
+    /* write X509 serial number in unsigned binary to buffer
+       buffer needs to be at least EXTERNAL_SERIAL_SIZE (32) for all cases
+       return SSL_SUCCESS on success */
+    int 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 == 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;
+    }
+
+
+    int CyaSSL_X509_version(CYASSL_X509* x509)
+    {
+        CYASSL_ENTER("CyaSSL_X509_version");
+
+        if (x509 == NULL)
+            return 0;
+
+        return x509->version;
+    }
+
+
+    const byte* CyaSSL_X509_notBefore(CYASSL_X509* x509)
+    {
+        CYASSL_ENTER("CyaSSL_X509_notBefore");
+
+        if (x509 == NULL)
+            return NULL;
+
+        return x509->notBefore;
+    }
+
+
+    const byte* CyaSSL_X509_notAfter(CYASSL_X509* x509)
+    {
+        CYASSL_ENTER("CyaSSL_X509_notAfter");
+
+        if (x509 == NULL)
+            return NULL;
+
+        return x509->notAfter;
+    }
+
+
+#ifdef CYASSL_SEP
+
+/* copy oid into in buffer, at most *inOutSz bytes, if buffer is null will
+   malloc buffer, call responsible for freeing. Actual size returned in
+   *inOutSz. Requires inOutSz be non-null */
+byte* CyaSSL_X509_get_device_type(CYASSL_X509* x509, byte* in, int *inOutSz)
+{
+    int copySz;
+
+    CYASSL_ENTER("CyaSSL_X509_get_dev_type");
+    if (inOutSz == NULL) return NULL;
+    if (!x509->deviceTypeSz) return in;
+
+    copySz = min(*inOutSz, x509->deviceTypeSz);
+
+    if (!in) {
+        in = (byte*)XMALLOC(x509->deviceTypeSz, 0, DYNAMIC_TYPE_OPENSSL);
+        if (!in) return in;
+        copySz = x509->deviceTypeSz;
+    }
+
+    XMEMCPY(in, x509->deviceType, copySz);
+    *inOutSz = copySz;
+
+    return in;
+}
+
+
+byte* CyaSSL_X509_get_hw_type(CYASSL_X509* x509, byte* in, int* inOutSz)
+{
+    int copySz;
+
+    CYASSL_ENTER("CyaSSL_X509_get_hw_type");
+    if (inOutSz == NULL) return NULL;
+    if (!x509->hwTypeSz) return in;
+
+    copySz = min(*inOutSz, x509->hwTypeSz);
+
+    if (!in) {
+        in = (byte*)XMALLOC(x509->hwTypeSz, 0, DYNAMIC_TYPE_OPENSSL);
+        if (!in) return in;
+        copySz = x509->hwTypeSz;
+    }
+
+    XMEMCPY(in, x509->hwType, copySz);
+    *inOutSz = copySz;
+
+    return in;
+}
+
+
+byte* CyaSSL_X509_get_hw_serial_number(CYASSL_X509* x509,byte* in,int* inOutSz)
+{
+    int copySz;
+
+    CYASSL_ENTER("CyaSSL_X509_get_hw_serial_number");
+    if (inOutSz == NULL) return NULL;
+    if (!x509->hwTypeSz) return in;
+
+    copySz = min(*inOutSz, x509->hwSerialNumSz);
+
+    if (!in) {
+        in = (byte*)XMALLOC(x509->hwSerialNumSz, 0, DYNAMIC_TYPE_OPENSSL);
+        if (!in) return in;
+        copySz = x509->hwSerialNumSz;
+    }
+
+    XMEMCPY(in, x509->hwSerialNum, copySz);
+    *inOutSz = copySz;
+
+    return in;
+}
+
+#endif /* CYASSL_SEP */
+
+
+CYASSL_X509* CyaSSL_X509_d2i(CYASSL_X509** x509, const byte* in, int len)
+{
+    CYASSL_X509 *newX509 = NULL;
+
+    CYASSL_ENTER("CyaSSL_X509_d2i");
+
+    if (in != NULL && len != 0) {
+        DecodedCert cert;
+
+        InitDecodedCert(&cert, (byte*)in, len, NULL);
+        if (ParseCertRelative(&cert, CERT_TYPE, 0, NULL) == 0) {
+            newX509 = (CYASSL_X509*)XMALLOC(sizeof(CYASSL_X509),
+                                                       NULL, DYNAMIC_TYPE_X509);
+            if (newX509 != NULL) {
+                InitX509(newX509, 1);
+                if (CopyDecodedToX509(newX509, &cert) != 0) {
+                    XFREE(newX509, NULL, DYNAMIC_TYPE_X509);
+                    newX509 = NULL;
+                }
+            }
+        }
+        FreeDecodedCert(&cert);
+    }
+
+    if (x509 != NULL)
+        *x509 = newX509;
+
+    return newX509;
+}
+
+
+#ifndef NO_FILESYSTEM
+
+#ifndef NO_STDIO_FILESYSTEM
+
+CYASSL_X509* CyaSSL_X509_d2i_fp(CYASSL_X509** x509, XFILE file)
+{
+    CYASSL_X509* newX509 = NULL;
+
+    CYASSL_ENTER("CyaSSL_X509_d2i_fp");
+
+    if (file != XBADFILE) {
+        byte* fileBuffer = NULL;
+        long sz = 0;
+
+        XFSEEK(file, 0, XSEEK_END);
+        sz = XFTELL(file);
+        XREWIND(file);
+
+        fileBuffer = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE);
+        if (fileBuffer != NULL) {
+            if ((int)XFREAD(fileBuffer, sz, 1, file) > 0) {
+                newX509 = CyaSSL_X509_d2i(NULL, fileBuffer, (int)sz);
+            }
+            XFREE(fileBuffer, NULL, DYNAMIC_TYPE_FILE);
+        }
+    }
+
+    if (x509 != NULL)
+        *x509 = newX509;
+
+    return newX509;
+}
+
+#endif /* NO_STDIO_FILESYSTEM */
+
+CYASSL_X509* CyaSSL_X509_load_certificate_file(const char* fname, int format)
+{
+    byte staticBuffer[FILE_BUFFER_SIZE];
+    byte* fileBuffer = staticBuffer;
+    int dynamic = 0;
+    long sz = 0;
+    XFILE file;
+    CYASSL_X509* x509 = NULL;
+    buffer der;
+
+    CYASSL_ENTER("CyaSSL_X509_load_certificate");
+
+    /* Check the inputs */
+    if ((fname == NULL) ||
+        (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM))
+        return NULL;
+
+    file = XFOPEN(fname, "rb");
+    if (file == XBADFILE) return NULL;
+    XFSEEK(file, 0, XSEEK_END);
+    sz = XFTELL(file);
+    XREWIND(file);
+
+    if (sz > (long)sizeof(staticBuffer)) {
+        fileBuffer = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE);
+        if (fileBuffer == NULL) {
+            XFCLOSE(file);
+            return NULL;
+        }
+        dynamic = 1;
+    }
+    if ((int)XFREAD(fileBuffer, sz, 1, file) < 0) {
+        XFCLOSE(file);
+        if (dynamic) XFREE(fileBuffer, NULL, DYNAMIC_TYPE_FILE);
+        return NULL;
+    }
+    XFCLOSE(file);
+
+    der.buffer = NULL;
+    der.length = 0;
+
+    if (format == SSL_FILETYPE_PEM) {
+        EncryptedInfo info;
+        int ecc = 0;
+
+        info.set = 0;
+        info.ctx = NULL;
+        info.consumed = 0;
+
+        if (PemToDer(fileBuffer, sz, CERT_TYPE, &der, NULL, &info, &ecc) != 0)
+        {
+            /* Only time this should fail, and leave `der` with a buffer
+               is when the Base64 Decode fails. Release `der.buffer` in
+               that case. */
+            if (der.buffer != NULL) {
+                XFREE(der.buffer, NULL, DYNAMIC_TYPE_CERT);
+                der.buffer = NULL;
+            }
+        }
+    }
+    else {
+        der.buffer = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_CERT);
+        if (der.buffer != NULL) {
+            XMEMCPY(der.buffer, fileBuffer, sz);
+            der.length = (word32)sz;
+        }
+    }
+    if (dynamic) XFREE(fileBuffer, NULL, DYNAMIC_TYPE_FILE);
+
+    /* At this point we want `der` to have the certificate in DER format */
+    /* ready to be decoded. */
+    if (der.buffer != NULL) {
+        DecodedCert cert;
+
+        InitDecodedCert(&cert, der.buffer, der.length, NULL);
+        if (ParseCertRelative(&cert, CERT_TYPE, 0, NULL) == 0) {
+            x509 = (CYASSL_X509*)XMALLOC(sizeof(CYASSL_X509),
+                                                       NULL, DYNAMIC_TYPE_X509);
+            if (x509 != NULL) {
+                InitX509(x509, 1);
+                if (CopyDecodedToX509(x509, &cert) != 0) {
+                    XFREE(x509, NULL, DYNAMIC_TYPE_X509);
+                    x509 = NULL;
+                }
+            }
+        }
+        FreeDecodedCert(&cert);
+
+        XFREE(der.buffer, NULL, DYNAMIC_TYPE_CERT);
+    }
+
+    return x509;
+}
+
+#endif /* NO_FILESYSTEM */
+
+#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";
+        #ifdef HAVE_BLAKE2
+                case TLS_RSA_WITH_AES_128_CBC_B2B256:
+                    return "TLS_RSA_WITH_AES_128_CBC_B2B256";
+                case TLS_RSA_WITH_AES_256_CBC_B2B256:
+                    return "TLS_RSA_WITH_AES_256_CBC_B2B256";
+        #endif
+    #ifndef NO_SHA
+                case TLS_RSA_WITH_NULL_SHA :
+                    return "TLS_RSA_WITH_NULL_SHA";
+    #endif
+                case TLS_RSA_WITH_NULL_SHA256 :
+                    return "TLS_RSA_WITH_NULL_SHA256";
+#endif /* NO_RSA */
+#ifndef NO_PSK
+                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_MD5 :
+                    return "TLS_RSA_WITH_HC_128_MD5";
+        #endif
+        #ifndef NO_SHA
+                case TLS_RSA_WITH_HC_128_SHA :
+                    return "TLS_RSA_WITH_HC_128_SHA";
+        #endif
+        #ifdef HAVE_BLAKE2
+                case TLS_RSA_WITH_HC_128_B2B256:
+                    return "TLS_RSA_WITH_HC_128_B2B256";
+        #endif
+    #endif /* NO_HC128 */
+    #ifndef NO_SHA
+        #ifndef NO_RABBIT
+                case TLS_RSA_WITH_RABBIT_SHA :
+                    return "TLS_RSA_WITH_RABBIT_SHA";
+        #endif
+        #ifdef HAVE_NTRU
+            #ifndef NO_RC4
+                case TLS_NTRU_RSA_WITH_RC4_128_SHA :
+                    return "TLS_NTRU_RSA_WITH_RC4_128_SHA";
+            #endif
+            #ifndef NO_DES3
+                case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA :
+                    return "TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA";
+            #endif
+                case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA :
+                    return "TLS_NTRU_RSA_WITH_AES_128_CBC_SHA";
+                case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA :
+                    return "TLS_NTRU_RSA_WITH_AES_256_CBC_SHA";
+        #endif /* HAVE_NTRU */
+    #endif /* NO_SHA */
+                case TLS_RSA_WITH_AES_128_GCM_SHA256 :
+                    return "TLS_RSA_WITH_AES_128_GCM_SHA256";
+                case TLS_RSA_WITH_AES_256_GCM_SHA384 :
+                    return "TLS_RSA_WITH_AES_256_GCM_SHA384";
+                case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 :
+                    return "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256";
+                case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 :
+                    return "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384";
+    #ifndef NO_SHA
+                case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA :
+                    return "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA";
+                case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA :
+                    return "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA";
+    #endif
+                case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 :
+                    return "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256";
+                case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 :
+                    return "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256";
+    #ifndef NO_SHA
+                case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA :
+                    return "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA";
+                case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA :
+                    return "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA";
+    #endif
+                case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 :
+                    return "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256";
+                case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 :
+                    return "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256";
+#endif /* NO_RSA */
+                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;
+    }
+
+
+    int CyaSSL_X509_STORE_add_cert(CYASSL_X509_STORE* store, CYASSL_X509* x509)
+    {
+        int result = SSL_FATAL_ERROR;
+
+        CYASSL_ENTER("CyaSSL_X509_STORE_add_cert");
+        if (store != NULL && store->cm != NULL && x509 != NULL) {
+            buffer derCert;
+            derCert.buffer = (byte*)XMALLOC(x509->derCert.length,
+                                                       NULL, DYNAMIC_TYPE_CERT);
+            if (derCert.buffer != NULL) {
+                derCert.length = x509->derCert.length;
+                    // AddCA() frees the buffer.
+                XMEMCPY(derCert.buffer,
+                                    x509->derCert.buffer, x509->derCert.length);
+                result = AddCA(store->cm, derCert, CYASSL_USER_CA, 1);
+                if (result != SSL_SUCCESS) result = SSL_FATAL_ERROR;
+            }
+        }
+
+        CYASSL_LEAVE("CyaSSL_X509_STORE_add_cert", result);
+        return result;
+    }
+
+
+    CYASSL_X509_STORE* CyaSSL_X509_STORE_new(void)
+    {
+        CYASSL_X509_STORE* store = NULL;
+
+        store = (CYASSL_X509_STORE*)XMALLOC(sizeof(CYASSL_X509_STORE), NULL, 0);
+        if (store != NULL) {
+            store->cm = CyaSSL_CertManagerNew();
+            if (store->cm == NULL) {
+                XFREE(store, NULL, 0);
+                store = NULL;
+            }
+        }
+
+        return store;
+    }
+
+
+    void CyaSSL_X509_STORE_free(CYASSL_X509_STORE* store)
+    {
+        if (store != NULL) {
+            if (store->cm != NULL)
+            CyaSSL_CertManagerFree(store->cm);
+            XFREE(store, NULL, 0);
+        }
+    }
+
+
+    int CyaSSL_X509_STORE_set_default_paths(CYASSL_X509_STORE* store)
+    {
+        (void)store;
+        return SSL_SUCCESS;
+    }
+
+
+    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;
+    }
+
+
+    CYASSL_X509_STORE_CTX* CyaSSL_X509_STORE_CTX_new(void)
+    {
+        CYASSL_X509_STORE_CTX* ctx = (CYASSL_X509_STORE_CTX*)XMALLOC(
+                                        sizeof(CYASSL_X509_STORE_CTX), NULL, 0);
+
+        if (ctx != NULL)
+            CyaSSL_X509_STORE_CTX_init(ctx, NULL, NULL, NULL);
+
+        return ctx;
+    }
+
+
+    int CyaSSL_X509_STORE_CTX_init(CYASSL_X509_STORE_CTX* ctx,
+         CYASSL_X509_STORE* store, CYASSL_X509* x509, STACK_OF(CYASSL_X509)* sk)
+    {
+        (void)sk;
+        if (ctx != NULL) {
+            ctx->store = store;
+            ctx->current_cert = x509;
+            ctx->domain = NULL;
+            ctx->ex_data = NULL;
+            ctx->userCtx = NULL;
+            ctx->error = 0;
+            ctx->error_depth = 0;
+            ctx->discardSessionCerts = 0;
+            return SSL_SUCCESS;
+        }
+        return SSL_FATAL_ERROR;
+    }
+
+
+    void CyaSSL_X509_STORE_CTX_free(CYASSL_X509_STORE_CTX* ctx)
+    {
+        if (ctx != NULL) {
+            if (ctx->store != NULL)
+                CyaSSL_X509_STORE_free(ctx->store);
+            if (ctx->current_cert != NULL)
+                CyaSSL_FreeX509(ctx->current_cert);
+            XFREE(ctx, NULL, 0);
+        }
+    }
+
+
+    void CyaSSL_X509_STORE_CTX_cleanup(CYASSL_X509_STORE_CTX* ctx)
+    {
+        (void)ctx;
+    }
+
+
+    int CyaSSL_X509_verify_cert(CYASSL_X509_STORE_CTX* ctx)
+    {
+        if (ctx != NULL && ctx->store != NULL && ctx->store->cm != NULL
+                                                 && ctx->current_cert != NULL) {
+            return CyaSSL_CertManagerVerifyBuffer(ctx->store->cm,
+                        ctx->current_cert->derCert.buffer,
+                        ctx->current_cert->derCert.length,
+                        SSL_FILETYPE_ASN1);
+        }
+        return SSL_FATAL_ERROR;
+    }
+
+
+    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)
+    {
+        CYASSL_EVP_PKEY* key = NULL;
+        if (x509 != NULL) {
+            key = (CYASSL_EVP_PKEY*)XMALLOC(
+                        sizeof(CYASSL_EVP_PKEY), NULL, DYNAMIC_TYPE_PUBLIC_KEY);
+            if (key != NULL) {
+                key->type = x509->pubKeyOID;
+                key->save_type = 0;
+                key->pkey.ptr = (char*)XMALLOC(
+                            x509->pubKey.length, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
+                if (key->pkey.ptr == NULL) {
+                    XFREE(key, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
+                    return NULL;
+                }
+                XMEMCPY(key->pkey.ptr,
+                                      x509->pubKey.buffer, x509->pubKey.length);
+                key->pkey_sz = x509->pubKey.length;
+                #ifdef HAVE_ECC
+                    key->pkey_curve = (int)x509->pkCurveOID;
+                #endif /* HAVE_ECC */
+            }
+        }
+        return key;
+    }
+
+
+    int 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)
+    {
+        if (key != NULL) {
+            if (key->pkey.ptr != NULL)
+                XFREE(key->pkey.ptr, NULL, 0);
+            XFREE(key, NULL, 0);
+        }
+    }
+
+
+    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);
+        if (InitRsaKey(key, NULL) != 0) {
+            CYASSL_MSG("InitRsaKey CYASSL_RSA failure");
+            XFREE(external, NULL, DYNAMIC_TYPE_RSA);
+            XFREE(key, NULL, DYNAMIC_TYPE_RSA);
+            return 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);
+            /* OpenSSL compat, no error */
+        }
+    }
+
+
+    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;
+
+                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);
+
+                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);  /* OpenSSL compat, no ret */
+        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);  /* OpenSSL compat, no ret */
+        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;
+
+#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;
+#endif
+
+            case DES_CBC_TYPE :
+                CYASSL_MSG("DES CBC");
+                return DES_BLOCK_SIZE;
+
+            case DES_EDE3_CBC_TYPE :
+                CYASSL_MSG("DES EDE3 CBC");
+                return DES_BLOCK_SIZE;
+
+            case ARC4_TYPE :
+                CYASSL_MSG("ARC4");
+                return 0;
+
+            case NULL_CIPHER_TYPE :
+                CYASSL_MSG("NULL");
+                return 0;
+
+            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;
+    }
+
+
+
+
+/* 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 */
+
+
+#ifndef NO_CERTS
+#ifdef  HAVE_PK_CALLBACKS
+
+#ifdef HAVE_ECC
+
+void  CyaSSL_CTX_SetEccSignCb(CYASSL_CTX* ctx, CallbackEccSign cb)
+{
+    if (ctx)
+        ctx->EccSignCb = cb;
+}
+
+
+void  CyaSSL_SetEccSignCtx(CYASSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->EccSignCtx = ctx;
+}
+
+
+void* CyaSSL_GetEccSignCtx(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->EccSignCtx;
+
+    return NULL;
+}
+
+
+void  CyaSSL_CTX_SetEccVerifyCb(CYASSL_CTX* ctx, CallbackEccVerify cb)
+{
+    if (ctx)
+        ctx->EccVerifyCb = cb;
+}
+
+
+void  CyaSSL_SetEccVerifyCtx(CYASSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->EccVerifyCtx = ctx;
+}
+
+
+void* CyaSSL_GetEccVerifyCtx(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->EccVerifyCtx;
+
+    return NULL;
+}
+
+#endif /* HAVE_ECC */
+
+#ifndef NO_RSA
+
+void  CyaSSL_CTX_SetRsaSignCb(CYASSL_CTX* ctx, CallbackRsaSign cb)
+{
+    if (ctx)
+        ctx->RsaSignCb = cb;
+}
+
+
+void  CyaSSL_SetRsaSignCtx(CYASSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->RsaSignCtx = ctx;
+}
+
+
+void* CyaSSL_GetRsaSignCtx(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->RsaSignCtx;
+
+    return NULL;
+}
+
+
+void  CyaSSL_CTX_SetRsaVerifyCb(CYASSL_CTX* ctx, CallbackRsaVerify cb)
+{
+    if (ctx)
+        ctx->RsaVerifyCb = cb;
+}
+
+
+void  CyaSSL_SetRsaVerifyCtx(CYASSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->RsaVerifyCtx = ctx;
+}
+
+
+void* CyaSSL_GetRsaVerifyCtx(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->RsaVerifyCtx;
+
+    return NULL;
+}
+
+void  CyaSSL_CTX_SetRsaEncCb(CYASSL_CTX* ctx, CallbackRsaEnc cb)
+{
+    if (ctx)
+        ctx->RsaEncCb = cb;
+}
+
+
+void  CyaSSL_SetRsaEncCtx(CYASSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->RsaEncCtx = ctx;
+}
+
+
+void* CyaSSL_GetRsaEncCtx(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->RsaEncCtx;
+
+    return NULL;
+}
+
+void  CyaSSL_CTX_SetRsaDecCb(CYASSL_CTX* ctx, CallbackRsaDec cb)
+{
+    if (ctx)
+        ctx->RsaDecCb = cb;
+}
+
+
+void  CyaSSL_SetRsaDecCtx(CYASSL* ssl, void *ctx)
+{
+    if (ssl)
+        ssl->RsaDecCtx = ctx;
+}
+
+
+void* CyaSSL_GetRsaDecCtx(CYASSL* ssl)
+{
+    if (ssl)
+        return ssl->RsaDecCtx;
+
+    return NULL;
+}
+
+
+#endif /* NO_RSA */
+
+#endif /* HAVE_PK_CALLBACKS */
+#endif /* NO_CERTS */
+
+
+#ifdef CYASSL_HAVE_WOLFSCEP
+    /* Used by autoconf to see if wolfSCEP is available */
+    void CyaSSL_wolfSCEP(void) {}
+#endif
+
+
+#ifdef CYASSL_HAVE_CERT_SERVICE
+    /* Used by autoconf to see if cert service is available */
+    void CyaSSL_cert_service(void) {}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tls.c	Sun Apr 20 12:40:57 2014 +0000
@@ -0,0 +1,1942 @@
+/* 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/error-ssl.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 int 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;
+    int      ret;
+    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;
+
+    ret = HmacSetKey(&hmac, hash, secret, secLen);
+    if (ret != 0)
+        return ret;
+    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);
+
+    return 0;
+}
+
+
+
+#ifndef NO_OLD_TLS
+
+/* calculate XOR for TLSv1 PRF */
+static INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha)
+{
+    word32 i;
+
+    for (i = 0; i < digLen; i++) 
+        digest[i] = md5[i] ^ sha[i];
+}
+
+
+/* compute TLSv1 PRF (pseudo random function using HMAC) */
+static int doPRF(byte* digest, word32 digLen, const byte* secret,word32 secLen,
+                 const byte* label, word32 labLen, const byte* seed,
+                 word32 seedLen)
+{
+    int    ret;
+    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 BUFFER_E;
+    if (labLen + seedLen > MAX_PRF_LABSEED)
+        return BUFFER_E;
+    if (digLen > MAX_PRF_DIG)
+        return BUFFER_E;
+
+    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);
+
+    ret = p_hash(md5_result, digLen, md5_half, half, labelSeed,
+                 labLen + seedLen, md5_mac);
+    if (ret != 0)
+        return ret;
+    ret = p_hash(sha_result, digLen, sha_half, half, labelSeed,
+                 labLen + seedLen, sha_mac);
+    if (ret != 0)
+        return ret;
+    get_xor(digest, digLen, md5_result, sha_result);
+
+    return 0;
+}
+
+#endif
+
+
+/* Wrapper to call straight thru to p_hash in TSL 1.2 cases to remove stack
+   use */
+static int PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen,
+            const byte* label, word32 labLen, const byte* seed, word32 seedLen,
+            int useAtLeastSha256, int hash_type)
+{
+    int ret = 0;
+
+    if (useAtLeastSha256) {
+        byte labelSeed[MAX_PRF_LABSEED];    /* labLen + seedLen is real size */
+
+        if (labLen + seedLen > MAX_PRF_LABSEED)
+            return BUFFER_E;
+
+        XMEMCPY(labelSeed, label, labLen);
+        XMEMCPY(labelSeed + labLen, seed, seedLen);
+
+        /* If a cipher suite wants an algorithm better than sha256, it
+         * should use better. */
+        if (hash_type < sha256_mac)
+            hash_type = sha256_mac;
+        ret = p_hash(digest, digLen, secret, secLen, labelSeed,
+                     labLen + seedLen, hash_type);
+    }
+#ifndef NO_OLD_TLS
+    else {
+        ret = doPRF(digest, digLen, secret, secLen, label, labLen, seed,
+                    seedLen);
+    }
+#endif
+
+    return ret;
+}
+
+
+#ifdef CYASSL_SHA384
+    #define HSHASH_SZ SHA384_DIGEST_SIZE
+#else
+    #define HSHASH_SZ FINISHED_SZ
+#endif
+
+
+int 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;
+
+    return PRF((byte*)hashes, TLS_FINISHED_SZ, ssl->arrays->masterSecret,
+               SECRET_LEN, side, FINISHED_LABEL_SZ, handshake_hash, hashSz,
+               IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
+}
+
+
+#ifndef NO_OLD_TLS
+
+ProtocolVersion MakeTLSv1(void)
+{
+    ProtocolVersion pv;
+    pv.major = SSLv3_MAJOR;
+    pv.minor = TLSv1_MINOR;
+
+    return pv;
+}
+
+
+ProtocolVersion MakeTLSv1_1(void)
+{
+    ProtocolVersion pv;
+    pv.major = SSLv3_MAJOR;
+    pv.minor = TLSv1_1_MINOR;
+
+    return pv;
+}
+
+#endif
+
+
+ProtocolVersion MakeTLSv1_2(void)
+{
+    ProtocolVersion pv;
+    pv.major = SSLv3_MAJOR;
+    pv.minor = TLSv1_2_MINOR;
+
+    return pv;
+}
+
+
+static const byte master_label[MASTER_LABEL_SZ + 1] = "master secret";
+static const byte key_label   [KEY_LABEL_SZ + 1]    = "key expansion";
+
+
+int DeriveTlsKeys(CYASSL* ssl)
+{
+    int ret;
+    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);
+
+    ret = PRF(key_data, length, ssl->arrays->masterSecret, SECRET_LEN, 
+              key_label, KEY_LABEL_SZ, seed, SEED_LEN, IsAtLeastTLSv1_2(ssl),
+              ssl->specs.mac_algorithm);
+    if (ret != 0)
+        return ret;
+
+    return StoreKeys(ssl, key_data);
+}
+
+
+int MakeTlsMasterSecret(CYASSL* ssl)
+{
+    int  ret;
+    byte seed[SEED_LEN];
+    
+    XMEMCPY(seed, ssl->arrays->clientRandom, RAN_LEN);
+    XMEMCPY(&seed[RAN_LEN], ssl->arrays->serverRandom, RAN_LEN);
+
+    ret = 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);
+    if (ret != 0)
+        return ret;
+
+#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);
+
+    return 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);
+
+}
+
+
+/*** next for static INLINE s copied internal.c ***/
+
+/* convert 16 bit integer to opaque */
+static INLINE void c16toa(word16 u16, byte* c)
+{
+    c[0] = (u16 >> 8) & 0xff;
+    c[1] =  u16 & 0xff;
+}
+
+#ifdef HAVE_TLS_EXTENSIONS
+/* convert opaque to 16 bit integer */
+static INLINE void ato16(const byte* c, word16* u16)
+{
+    *u16 = (c[0] << 8) | (c[1]);
+}
+
+#ifdef HAVE_SNI
+/* convert a 24 bit integer into a 32 bit one */
+static INLINE void c24to32(const word24 u24, word32* u32)
+{
+    *u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2];
+}
+#endif
+#endif
+
+/* convert 32 bit integer to opaque */
+static INLINE void c32toa(word32 u32, byte* c)
+{
+    c[0] = (u32 >> 24) & 0xff;
+    c[1] = (u32 >> 16) & 0xff;
+    c[2] = (u32 >>  8) & 0xff;
+    c[3] =  u32 & 0xff;
+}
+
+
+static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify)
+{
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        if (verify)
+            return ssl->keys.dtls_state.curSeq; /* explicit from peer */
+        else
+            return ssl->keys.dtls_sequence_number - 1; /* already incremented */
+    }
+#endif
+    if (verify)
+        return ssl->keys.peer_sequence_number++; 
+    else
+        return ssl->keys.sequence_number++; 
+}
+
+
+#ifdef CYASSL_DTLS
+
+static INLINE word32 GetEpoch(CYASSL* ssl, int verify)
+{
+    if (verify)
+        return ssl->keys.dtls_state.curEpoch;
+    else
+        return ssl->keys.dtls_epoch;
+}
+
+#endif /* CYASSL_DTLS */
+
+
+/*** end copy ***/
+
+
+/* return HMAC digest type in CyaSSL format */
+int CyaSSL_GetHmacType(CYASSL* ssl)
+{
+    if (ssl == NULL)
+        return BAD_FUNC_ARG;
+
+    switch (ssl->specs.mac_algorithm) {
+        #ifndef NO_MD5
+        case md5_mac:
+        {
+            return MD5;
+        }
+        #endif
+        #ifndef NO_SHA256
+        case sha256_mac:
+        {
+            return SHA256;
+        }
+        #endif
+        #ifdef CYASSL_SHA384
+        case sha384_mac:
+        {
+            return SHA384;
+        }
+
+        #endif
+        #ifndef NO_SHA
+        case sha_mac:
+        {
+            return SHA;
+        }
+        #endif
+        #ifdef HAVE_BLAKE2 
+        case blake2b_mac:
+        {
+            return BLAKE2B_ID; 
+        }
+        #endif
+        default:
+        {
+            return SSL_FATAL_ERROR;
+        }
+    }
+}
+
+
+int CyaSSL_SetTlsHmacInner(CYASSL* ssl, byte* inner, word32 sz, int content,
+                           int verify)
+{
+    if (ssl == NULL || inner == NULL)
+        return BAD_FUNC_ARG;
+
+    XMEMSET(inner, 0, CYASSL_TLS_HMAC_INNER_SZ);
+
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls)
+        c16toa((word16)GetEpoch(ssl, verify), inner);
+#endif
+    c32toa(GetSEQIncrement(ssl, verify), &inner[sizeof(word32)]);
+    inner[SEQ_SZ] = (byte)content;                          
+    inner[SEQ_SZ + ENUM_LEN]            = ssl->version.major;
+    inner[SEQ_SZ + ENUM_LEN + ENUM_LEN] = ssl->version.minor;
+    c16toa((word16)sz, inner + SEQ_SZ + ENUM_LEN + VERSION_SZ);
+
+    return 0;
+}
+
+
+/* TLS type HMAC */
+int TLS_hmac(CYASSL* ssl, byte* digest, const byte* in, word32 sz,
+              int content, int verify)
+{
+    Hmac hmac;
+    int  ret;
+    byte myInner[CYASSL_TLS_HMAC_INNER_SZ];
+    
+    CyaSSL_SetTlsHmacInner(ssl, myInner, sz, content, verify);
+
+    ret = HmacSetKey(&hmac, CyaSSL_GetHmacType(ssl),
+                     CyaSSL_GetMacSecret(ssl, verify), ssl->specs.hash_size);
+    if (ret != 0)
+        return ret;
+    HmacUpdate(&hmac, myInner, sizeof(myInner));
+    HmacUpdate(&hmac, in, sz);                                /* content */
+    HmacFinal(&hmac, digest);
+
+    return 0;
+}
+
+#ifdef HAVE_TLS_EXTENSIONS
+
+#define IS_OFF(semaphore, light) \
+    ((semaphore)[(light) / 8] ^  (byte) (0x01 << ((light) % 8)))
+
+#define TURN_ON(semaphore, light) \
+    ((semaphore)[(light) / 8] |= (byte) (0x01 << ((light) % 8)))
+
+static int TLSX_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
+
+void TLSX_SetResponse(CYASSL* ssl, TLSX_Type type);
+
+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;
+    }
+
+    sni->type = type;
+    sni->next = *list;
+
+#ifndef NO_CYASSL_SERVER
+    sni->options = 0;
+    sni->status  = CYASSL_SNI_NO_MATCH;
+#endif
+
+    *list = sni;
+
+    return 0;
+}
+
+static word16 TLSX_SNI_GetSize(SNI* list)
+{
+    SNI* sni;
+    word16 length = OPAQUE16_LEN; /* list length */
+
+    while ((sni = list)) {
+        list = sni->next;
+
+        length += ENUM_LEN + OPAQUE16_LEN; /* sni type + sni length */
+
+        switch (sni->type) {
+            case 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_SetStatus(TLSX* extensions, byte type, byte status)
+{
+    TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
+    SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+
+    if (sni) {
+        sni->status = status;
+        CYASSL_MSG("SNI did match!");
+    }
+}
+
+byte TLSX_SNI_Status(TLSX* extensions, byte type)
+{
+    TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
+    SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+
+    if (sni)
+        return sni->status;
+
+    return 0;
+}
+#endif
+
+static int TLSX_SNI_Parse(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)
+        return isRequest ? 0 : BUFFER_ERROR; /* not using SNI OR unexpected
+                                                SNI response from server. */
+
+    if (!isRequest)
+        return length ? BUFFER_ERROR : 0; /* SNI response must be empty!
+                                             Nothing else to do. */
+
+#ifndef NO_CYASSL_SERVER
+
+    if (OPAQUE16_LEN > length)
+        return BUFFER_ERROR;
+
+    ato16(input, &size);
+    offset += OPAQUE16_LEN;
+
+    /* validating sni list length */
+    if (length != OPAQUE16_LEN + size)
+        return BUFFER_ERROR;
+
+    for (size = 0; offset < length; offset += size) {
+        SNI *sni;
+        byte type = input[offset++];
+
+        if (offset + OPAQUE16_LEN > length)
+            return BUFFER_ERROR;
+
+        ato16(input + offset, &size);
+        offset += OPAQUE16_LEN;
+
+        if (offset + size > length)
+            return BUFFER_ERROR;
+
+        if (!(sni = TLSX_SNI_Find((SNI *) extension->data, type))) {
+            continue; /* not using this SNI type */
+        }
+
+        switch(type) {
+            case 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, input + offset, size);
+
+                    if (r != SSL_SUCCESS) return r; /* throw error */
+
+                    TLSX_SNI_SetStatus(ssl->extensions, type,
+                      matched ? CYASSL_SNI_REAL_MATCH : CYASSL_SNI_FAKE_MATCH);
+
+                } 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) */
+    do {
+        if (sni->next && sni->next->type == type) {
+            SNI *next = sni->next;
+
+            sni->next = next->next;
+            TLSX_SNI_Free(next);
+
+            break;
+        }
+    } while ((sni = sni->next));
+
+    return SSL_SUCCESS;
+}
+
+#ifndef NO_CYASSL_SERVER
+word16 TLSX_SNI_GetRequest(TLSX* extensions, byte type, void** data)
+{
+    TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
+    SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+
+    if (sni && sni->status != CYASSL_SNI_NO_MATCH) {
+        switch (sni->type) {
+            case CYASSL_SNI_HOST_NAME:
+                *data = sni->data.host_name;
+                return XSTRLEN(*data);
+        }
+    }
+
+    return 0;
+}
+
+void TLSX_SNI_SetOptions(TLSX* extensions, byte type, byte options)
+{
+    TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
+    SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+
+    if (sni)
+        sni->options = options;
+}
+
+int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
+                           byte type, byte* sni, word32* inOutSz)
+{
+    word32 offset = 0;
+    word32 len32  = 0;
+    word16 len16  = 0;
+
+    if (helloSz < RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + CLIENT_HELLO_FIRST)
+        return INCOMPLETE_DATA;
+
+    /* TLS record header */
+    if ((enum ContentType) clientHello[offset++] != handshake)
+        return BUFFER_ERROR;
+
+    if (clientHello[offset++] != SSLv3_MAJOR)
+        return BUFFER_ERROR;
+
+    if (clientHello[offset++] < TLSv1_MINOR)
+        return BUFFER_ERROR;
+
+    ato16(clientHello + offset, &len16);
+    offset += OPAQUE16_LEN;
+
+    if (offset + len16 > helloSz)
+        return INCOMPLETE_DATA;
+
+    /* Handshake header */
+    if ((enum HandShakeType) clientHello[offset] != client_hello)
+        return BUFFER_ERROR;
+
+    c24to32(clientHello + offset + 1, &len32);
+    offset += HANDSHAKE_HEADER_SZ;
+
+    if (offset + len32 > helloSz)
+        return BUFFER_ERROR;
+
+    /* client hello */
+    offset += VERSION_SZ + RAN_LEN; /* version, random */
+
+    if (helloSz < offset + clientHello[offset])
+        return BUFFER_ERROR;
+
+    offset += ENUM_LEN + clientHello[offset]; /* skip session id */
+
+    /* cypher suites */
+    if (helloSz < offset + OPAQUE16_LEN)
+        return BUFFER_ERROR;
+
+    ato16(clientHello + offset, &len16);
+    offset += OPAQUE16_LEN;
+
+    if (helloSz < offset + len16)
+        return BUFFER_ERROR;
+
+    offset += len16; /* skip cypher suites */
+
+    /* compression methods */
+    if (helloSz < offset + 1)
+        return BUFFER_ERROR;
+
+    if (helloSz < offset + clientHello[offset])
+        return BUFFER_ERROR;
+
+    offset += ENUM_LEN + clientHello[offset]; /* skip compression methods */
+
+    /* extensions */
+    if (helloSz < offset + OPAQUE16_LEN)
+        return 0; /* no extensions in client hello. */
+
+    ato16(clientHello + offset, &len16);
+    offset += OPAQUE16_LEN;
+
+    if (helloSz < offset + len16)
+        return BUFFER_ERROR;
+
+    while (len16 > OPAQUE16_LEN + OPAQUE16_LEN) {
+        word16 extType;
+        word16 extLen;
+
+        ato16(clientHello + offset, &extType);
+        offset += OPAQUE16_LEN;
+
+        ato16(clientHello + offset, &extLen);
+        offset += OPAQUE16_LEN;
+
+        if (helloSz < offset + extLen)
+            return BUFFER_ERROR;
+
+        if (extType != SERVER_NAME_INDICATION) {
+            offset += extLen; /* skip extension */
+        } else {
+            word16 listLen;
+
+            ato16(clientHello + offset, &listLen);
+            offset += OPAQUE16_LEN;
+
+            if (helloSz < offset + listLen)
+                return BUFFER_ERROR;
+
+            while (listLen > ENUM_LEN + OPAQUE16_LEN) {
+                byte   sniType = clientHello[offset++];
+                word16 sniLen;
+
+                ato16(clientHello + offset, &sniLen);
+                offset += OPAQUE16_LEN;
+
+                if (helloSz < offset + sniLen)
+                    return BUFFER_ERROR;
+
+                if (sniType != type) {
+                    offset  += sniLen;
+                    listLen -= min(ENUM_LEN + OPAQUE16_LEN + sniLen, listLen);
+                    continue;
+                }
+
+                *inOutSz = min(sniLen, *inOutSz);
+                XMEMCPY(sni, clientHello + offset, *inOutSz);
+
+                return SSL_SUCCESS;
+            }
+        }
+
+        len16 -= min(2 * OPAQUE16_LEN + extLen, len16);
+    }
+
+    return len16 ? BUFFER_ERROR : SSL_SUCCESS;
+}
+
+#endif
+
+#define SNI_FREE_ALL TLSX_SNI_FreeAll
+#define SNI_GET_SIZE TLSX_SNI_GetSize
+#define SNI_WRITE    TLSX_SNI_Write
+#define SNI_PARSE    TLSX_SNI_Parse
+
+#else
+
+#define SNI_FREE_ALL(list)
+#define SNI_GET_SIZE(list)    0
+#define SNI_WRITE(a, b)       0
+#define SNI_PARSE(a, b, c, d) 0
+
+#endif /* HAVE_SNI */
+
+#ifdef HAVE_MAX_FRAGMENT
+
+static word16 TLSX_MFL_Write(byte* data, byte* output)
+{
+    output[0] = data[0];
+
+    return ENUM_LEN;
+}
+
+static int TLSX_MFL_Parse(CYASSL* ssl, byte* input, word16 length,
+                                                                 byte isRequest)
+{
+    if (length != ENUM_LEN)
+        return BUFFER_ERROR;
+
+    switch (*input) {
+        case CYASSL_MFL_2_9 : ssl->max_fragment =  512; break;
+        case CYASSL_MFL_2_10: ssl->max_fragment = 1024; break;
+        case CYASSL_MFL_2_11: ssl->max_fragment = 2048; break;
+        case CYASSL_MFL_2_12: ssl->max_fragment = 4096; break;
+        case CYASSL_MFL_2_13: ssl->max_fragment = 8192; break;
+
+        default:
+            SendAlert(ssl, alert_fatal, illegal_parameter);
+
+            return UNKNOWN_MAX_FRAG_LEN_E;
+    }
+
+#ifndef NO_CYASSL_SERVER
+    if (isRequest) {
+        int r = TLSX_UseMaxFragment(&ssl->extensions, *input);
+
+        if (r != SSL_SUCCESS) return r; /* throw error */
+
+        TLSX_SetResponse(ssl, MAX_FRAGMENT_LENGTH);
+    }
+#endif
+
+    return 0;
+}
+
+int TLSX_UseMaxFragment(TLSX** extensions, byte mfl)
+{
+    TLSX* extension = NULL;
+    byte* data      = NULL;
+    int   ret       = 0;
+
+    if (extensions == NULL)
+        return BAD_FUNC_ARG;
+
+    if (mfl < CYASSL_MFL_2_9 || CYASSL_MFL_2_13 < mfl)
+        return BAD_FUNC_ARG;
+
+    if ((data = XMALLOC(ENUM_LEN, 0, DYNAMIC_TYPE_TLSX)) == NULL)
+        return MEMORY_E;
+
+    data[0] = mfl;
+
+    /* push new MFL extension. */
+    if ((ret = TLSX_Append(extensions, MAX_FRAGMENT_LENGTH)) != 0) {
+        XFREE(data, 0, DYNAMIC_TYPE_TLSX);
+        return ret;
+    }
+
+    /* place new mfl to extension data. */
+    extension = *extensions;
+    extension->data = (void*) data;
+
+    /* remove duplicated extensions */
+    do {
+        if (extension->next && extension->next->type == MAX_FRAGMENT_LENGTH) {
+            TLSX *next = extension->next;
+
+            extension->next = next->next;
+            next->next = NULL;
+
+            TLSX_FreeAll(next);
+
+            break;
+        }
+    } while ((extension = extension->next));
+
+    return SSL_SUCCESS;
+}
+
+
+#define MFL_FREE_ALL(data) XFREE(data, 0, DYNAMIC_TYPE_TLSX)
+#define MFL_GET_SIZE(data) ENUM_LEN
+#define MFL_WRITE          TLSX_MFL_Write
+#define MFL_PARSE          TLSX_MFL_Parse
+
+#else
+
+#define MFL_FREE_ALL(a)
+#define MFL_GET_SIZE(a)       0
+#define MFL_WRITE(a, b)       0
+#define MFL_PARSE(a, b, c, d) 0
+
+#endif /* HAVE_MAX_FRAGMENT */
+
+#ifdef HAVE_TRUNCATED_HMAC
+
+int TLSX_UseTruncatedHMAC(TLSX** extensions)
+{
+    int ret = 0;
+
+    if (extensions == NULL)
+        return BAD_FUNC_ARG;
+
+    if (!TLSX_Find(*extensions, TRUNCATED_HMAC))
+        if ((ret = TLSX_Append(extensions, TRUNCATED_HMAC)) != 0)
+            return ret;
+
+    return SSL_SUCCESS;
+}
+
+static int TLSX_THM_Parse(CYASSL* ssl, byte* input, word16 length,
+                                                                 byte isRequest)
+{
+    if (length != 0 || input == NULL)
+        return BUFFER_ERROR;
+
+#ifndef NO_CYASSL_SERVER
+    if (isRequest) {
+        int r = TLSX_UseTruncatedHMAC(&ssl->extensions);
+
+        if (r != SSL_SUCCESS) return r; /* throw error */
+
+        TLSX_SetResponse(ssl, TRUNCATED_HMAC);
+    }
+#endif
+
+    ssl->truncated_hmac = 1;
+
+    return 0;
+}
+
+#define THM_PARSE TLSX_THM_Parse
+
+#else
+
+#define THM_PARSE(a, b, c, d) 0
+
+#endif /* HAVE_TRUNCATED_HMAC */
+
+#ifdef HAVE_SUPPORTED_CURVES
+
+#ifndef HAVE_ECC
+#error "Elliptic Curves Extension requires Elliptic Curve Cryptography. \
+Use --enable-ecc in the configure script or define HAVE_ECC."
+#endif
+
+static void TLSX_EllipticCurve_FreeAll(EllipticCurve* list)
+{
+    EllipticCurve* curve;
+
+    while ((curve = list)) {
+        list = curve->next;
+        XFREE(curve, 0, DYNAMIC_TYPE_TLSX);
+    }
+}
+
+static int TLSX_EllipticCurve_Append(EllipticCurve** list, word16 name)
+{
+    EllipticCurve* curve;
+
+    if (list == NULL)
+        return BAD_FUNC_ARG;
+
+    if ((curve = XMALLOC(sizeof(EllipticCurve), 0, DYNAMIC_TYPE_TLSX)) == NULL)
+        return MEMORY_E;
+
+    curve->name = name;
+    curve->next = *list;
+
+    *list = curve;
+
+    return 0;
+}
+
+#ifndef NO_CYASSL_CLIENT
+
+static void TLSX_EllipticCurve_ValidateRequest(CYASSL* ssl, byte* semaphore)
+{
+    int i;
+
+    for (i = 0; i < ssl->suites->suiteSz; i+= 2)
+        if (ssl->suites->suites[i] == ECC_BYTE)
+            return;
+
+    /* No elliptic curve suite found */
+    TURN_ON(semaphore, ELLIPTIC_CURVES);
+}
+
+static word16 TLSX_EllipticCurve_GetSize(EllipticCurve* list)
+{
+    EllipticCurve* curve;
+    word16 length = OPAQUE16_LEN; /* list length */
+
+    while ((curve = list)) {
+        list = curve->next;
+        length += OPAQUE16_LEN; /* curve length */
+    }
+
+    return length;
+}
+
+static word16 TLSX_EllipticCurve_WriteR(EllipticCurve* curve, byte* output);
+static word16 TLSX_EllipticCurve_WriteR(EllipticCurve* curve, byte* output)
+{
+    word16 offset = 0;
+
+    if (!curve)
+        return offset;
+
+    offset = TLSX_EllipticCurve_WriteR(curve->next, output);
+    c16toa(curve->name, output + offset);
+
+    return OPAQUE16_LEN + offset;
+}
+
+static word16 TLSX_EllipticCurve_Write(EllipticCurve* list, byte* output)
+{
+    word16 length = TLSX_EllipticCurve_WriteR(list, output + OPAQUE16_LEN);
+
+    c16toa(length, output); /* writing list length */
+
+    return OPAQUE16_LEN + length;
+}
+
+#endif /* NO_CYASSL_CLIENT */
+#ifndef NO_CYASSL_SERVER
+
+static int TLSX_EllipticCurve_Parse(CYASSL* ssl, byte* input, word16 length,
+                                                                 byte isRequest)
+{
+    word16 offset;
+    word16 name;
+    int r;
+
+    (void) isRequest; /* shut up compiler! */
+
+    if (OPAQUE16_LEN > length || length % OPAQUE16_LEN)
+        return BUFFER_ERROR;
+
+    ato16(input, &offset);
+
+    /* validating curve list length */
+    if (length != OPAQUE16_LEN + offset)
+        return BUFFER_ERROR;
+
+    while (offset) {
+        ato16(input + offset, &name);
+        offset -= OPAQUE16_LEN;
+
+        r = TLSX_UseSupportedCurve(&ssl->extensions, name);
+
+        if (r != SSL_SUCCESS) return r; /* throw error */
+    }
+
+    return 0;
+}
+
+int TLSX_ValidateEllipticCurves(CYASSL* ssl, byte first, byte second) {
+    TLSX*          extension = (first == ECC_BYTE)
+                             ? TLSX_Find(ssl->extensions, ELLIPTIC_CURVES)
+                             : NULL;
+    EllipticCurve* curve     = NULL;
+    word32         oid       = 0;
+    word16         octets    = 0; /* acording to 'ecc_set_type ecc_sets[];' */
+    int            sig       = 0; /* valitade signature */
+    int            key       = 0; /* validate key       */
+
+    if (!extension)
+        return 1; /* no suite restriction */
+
+    for (curve = extension->data; curve && !(sig && key); curve = curve->next) {
+
+        switch (curve->name) {
+            case CYASSL_ECC_SECP160R1: oid = ECC_160R1; octets = 20; break;
+            case CYASSL_ECC_SECP192R1: oid = ECC_192R1; octets = 24; break;
+            case CYASSL_ECC_SECP224R1: oid = ECC_224R1; octets = 28; break;
+            case CYASSL_ECC_SECP256R1: oid = ECC_256R1; octets = 32; break;
+            case CYASSL_ECC_SECP384R1: oid = ECC_384R1; octets = 48; break;
+            case CYASSL_ECC_SECP521R1: oid = ECC_521R1; octets = 66; break;
+            default: continue; /* unsupported curve */
+        }
+
+        switch (second) {
+#ifndef NO_DSA
+            /* ECDHE_ECDSA */
+            case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+            case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+            case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+            case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+            case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+            case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+            case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+            case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+            case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+                sig |= ssl->pkCurveOID == oid;
+                key |= ssl->eccTempKeySz == octets;
+            break;
+
+            /* ECDH_ECDSA */
+            case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+            case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+            case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+            case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+            case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+            case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+            case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+                sig |= ssl->pkCurveOID == oid;
+                key |= ssl->pkCurveOID == oid;
+            break;
+#endif
+#ifndef NO_RSA
+            /* ECDHE_RSA */
+            case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+            case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+            case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+            case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+            case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+            case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+            case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+                sig = 1;
+                key |= ssl->eccTempKeySz == octets;
+            break;
+
+            /* ECDH_RSA */
+            case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+            case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+            case TLS_ECDH_RSA_WITH_RC4_128_SHA:
+            case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+            case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+            case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+            case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+            case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+                sig = 1;
+                key |= ssl->pkCurveOID == oid;
+            break;
+#endif
+            default:
+                sig = 1;
+                key = 1;
+            break;
+        }
+    }
+
+    return sig && key;
+}
+
+#endif /* NO_CYASSL_SERVER */
+
+int TLSX_UseSupportedCurve(TLSX** extensions, word16 name)
+{
+    TLSX*          extension = NULL;
+    EllipticCurve* curve     = NULL;
+    int            ret       = 0;
+
+    if (extensions == NULL)
+        return BAD_FUNC_ARG;
+
+    if ((ret = TLSX_EllipticCurve_Append(&curve, name)) != 0)
+        return ret;
+
+    extension = *extensions;
+
+    /* find EllipticCurve extension if it already exists. */
+    while (extension && extension->type != ELLIPTIC_CURVES)
+        extension = extension->next;
+
+    /* push new EllipticCurve extension if it doesn't exists. */
+    if (!extension) {
+        if ((ret = TLSX_Append(extensions, ELLIPTIC_CURVES)) != 0) {
+            XFREE(curve, 0, DYNAMIC_TYPE_TLSX);
+            return ret;
+        }
+
+        extension = *extensions;
+    }
+
+    /* push new EllipticCurve object to extension data. */
+    curve->next = (EllipticCurve*) extension->data;
+    extension->data = (void*) curve;
+
+    /* look for another curve of the same name to remove (replacement) */
+    do {
+        if (curve->next && curve->next->name == name) {
+            EllipticCurve *next = curve->next;
+
+            curve->next = next->next;
+            XFREE(next, 0, DYNAMIC_TYPE_TLSX);
+
+            break;
+        }
+    } while ((curve = curve->next));
+
+    return SSL_SUCCESS;
+}
+
+#define EC_FREE_ALL         TLSX_EllipticCurve_FreeAll
+#define EC_VALIDATE_REQUEST TLSX_EllipticCurve_ValidateRequest
+
+#ifndef NO_CYASSL_CLIENT
+#define EC_GET_SIZE TLSX_EllipticCurve_GetSize
+#define EC_WRITE    TLSX_EllipticCurve_Write
+#else
+#define EC_GET_SIZE(list)         0
+#define EC_WRITE(a, b)            0
+#endif
+
+#ifndef NO_CYASSL_SERVER
+#define EC_PARSE TLSX_EllipticCurve_Parse
+#else
+#define EC_PARSE(a, b, c, d)      0
+#endif
+
+#else
+
+#define EC_FREE_ALL(list)
+#define EC_GET_SIZE(list)         0
+#define EC_WRITE(a, b)            0
+#define EC_PARSE(a, b, c, d)      0
+#define EC_VALIDATE_REQUEST(a, b)
+
+#endif /* HAVE_SUPPORTED_CURVES */
+
+TLSX* TLSX_Find(TLSX* list, TLSX_Type type)
+{
+    TLSX* extension = list;
+
+    while (extension && extension->type != type)
+        extension = extension->next;
+
+    return extension;
+}
+
+void TLSX_FreeAll(TLSX* list)
+{
+    TLSX* extension;
+
+    while ((extension = list)) {
+        list = extension->next;
+
+        switch (extension->type) {
+            case SERVER_NAME_INDICATION:
+                SNI_FREE_ALL((SNI *) extension->data);
+                break;
+
+            case MAX_FRAGMENT_LENGTH:
+                MFL_FREE_ALL(extension->data);
+                break;
+
+            case TRUNCATED_HMAC:
+                /* Nothing to do. */
+                break;
+
+            case ELLIPTIC_CURVES:
+                EC_FREE_ALL(extension->data);
+                break;
+        }
+
+        XFREE(extension, 0, DYNAMIC_TYPE_TLSX);
+    }
+}
+
+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;
+                case MAX_FRAGMENT_LENGTH:
+                    length += MFL_GET_SIZE(extension->data);
+                    break;
+
+                case TRUNCATED_HMAC:
+                    /* empty extension. */
+                    break;
+
+                case ELLIPTIC_CURVES:
+                    length += EC_GET_SIZE((EllipticCurve *) 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;
+
+                case MAX_FRAGMENT_LENGTH:
+                    offset += MFL_WRITE((byte *) extension->data,
+                                                               output + offset);
+                    break;
+
+                case TRUNCATED_HMAC:
+                    /* empty extension. */
+                    break;
+
+                case ELLIPTIC_CURVES:
+                    offset += EC_WRITE((EllipticCurve *) 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};
+
+        EC_VALIDATE_REQUEST(ssl, semaphore);
+
+        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 */
+
+        EC_VALIDATE_REQUEST(ssl, semaphore);
+
+        if (ssl->extensions)
+            offset += TLSX_Write(ssl->extensions, output + offset,
+                                                                  semaphore, 1);
+
+        if (ssl->ctx && ssl->ctx->extensions)
+            offset += TLSX_Write(ssl->ctx->extensions, output + offset,
+                                                                  semaphore, 1);
+
+        if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz)
+        {
+            int i;
+            /* extension type */
+            c16toa(HELLO_EXT_SIG_ALGO, output + offset);
+            offset += HELLO_EXT_TYPE_SZ;
+
+            /* extension data length */
+            c16toa(OPAQUE16_LEN + ssl->suites->hashSigAlgoSz, output + offset);
+            offset += OPAQUE16_LEN;
+
+            /* sig algos length */
+            c16toa(ssl->suites->hashSigAlgoSz, output + offset);
+            offset += OPAQUE16_LEN;
+
+            /* sig algos */
+            for (i = 0; i < ssl->suites->hashSigAlgoSz; i++, offset++)
+                output[offset] = ssl->suites->hashSigAlgo[i];
+        }
+
+        if (offset > OPAQUE16_LEN)
+            c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
+    }
+
+    return offset;
+}
+
+#endif /* NO_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 BUFFER_ERROR;
+
+        ato16(input + offset, &type);
+        offset += HELLO_EXT_TYPE_SZ;
+
+        ato16(input + offset, &size);
+        offset += OPAQUE16_LEN;
+
+        if (offset + size > length)
+            return BUFFER_ERROR;
+
+        switch (type) {
+            case SERVER_NAME_INDICATION:
+                CYASSL_MSG("SNI extension received");
+
+                ret = SNI_PARSE(ssl, input + offset, size, isRequest);
+                break;
+
+            case MAX_FRAGMENT_LENGTH:
+                CYASSL_MSG("Max Fragment Length extension received");
+
+                ret = MFL_PARSE(ssl, input + offset, size, isRequest);
+                break;
+
+            case TRUNCATED_HMAC:
+                CYASSL_MSG("Truncated HMAC extension received");
+
+                ret = THM_PARSE(ssl, input + offset, size, isRequest);
+                break;
+
+            case ELLIPTIC_CURVES:
+                CYASSL_MSG("Elliptic Curves extension received");
+
+                ret = EC_PARSE(ssl, input + offset, size, isRequest);
+                break;
+
+            case HELLO_EXT_SIG_ALGO:
+                if (isRequest) {
+                    /* do not mess with offset inside the switch! */
+                    if (IsAtLeastTLSv1_2(ssl)) {
+                        ato16(input + offset, &suites->hashSigAlgoSz);
+
+                        if (suites->hashSigAlgoSz > size - OPAQUE16_LEN)
+                            return BUFFER_ERROR;
+
+                        XMEMCPY(suites->hashSigAlgo,
+                                input + offset + OPAQUE16_LEN,
+                                min(suites->hashSigAlgoSz,
+                                                        HELLO_EXT_SIGALGO_MAX));
+                    }
+                } else {
+                    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
+
+#elif defined(HAVE_SNI)             \
+   || defined(HAVE_MAX_FRAGMENT)    \
+   || defined(HAVE_TRUNCATED_HMAC)  \
+   || defined(HAVE_SUPPORTED_CURVES)
+
+#error "Using TLS extensions requires HAVE_TLS_EXTENSIONS to be defined."
+
+#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 = CYASSL_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 = CYASSL_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 = CYASSL_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      = CYASSL_SERVER_END;
+#ifndef NO_OLD_TLS
+            method->downgrade = 1;
+#endif /* !NO_OLD_TLS */
+        }
+        return method;
+    }
+
+
+
+#endif /* NO_CYASSL_SERVER */
+#endif /* NO_TLS */
+