Rough and ready port of axTLS

Files at this revision

API Documentation at this revision

Comitter:
ashleymills
Date:
Mon May 13 18:15:18 2013 +0000
Commit message:
initial commit

Changed in this revision

crypto/aes.c Show annotated file Show diff for this revision Revisions of this file
crypto/bigint.c Show annotated file Show diff for this revision Revisions of this file
crypto/bigint.h Show annotated file Show diff for this revision Revisions of this file
crypto/bigint_impl.h Show annotated file Show diff for this revision Revisions of this file
crypto/crypto.h Show annotated file Show diff for this revision Revisions of this file
crypto/crypto_misc.c Show annotated file Show diff for this revision Revisions of this file
crypto/hmac.c Show annotated file Show diff for this revision Revisions of this file
crypto/md2.c Show annotated file Show diff for this revision Revisions of this file
crypto/md5.c Show annotated file Show diff for this revision Revisions of this file
crypto/os_int.h Show annotated file Show diff for this revision Revisions of this file
crypto/rc4.c Show annotated file Show diff for this revision Revisions of this file
crypto/rsa.c Show annotated file Show diff for this revision Revisions of this file
crypto/sha1.c Show annotated file Show diff for this revision Revisions of this file
ssl/asn1.c Show annotated file Show diff for this revision Revisions of this file
ssl/cert.h Show annotated file Show diff for this revision Revisions of this file
ssl/config.h Show annotated file Show diff for this revision Revisions of this file
ssl/crypto_misc.h Show annotated file Show diff for this revision Revisions of this file
ssl/gen_cert.c Show annotated file Show diff for this revision Revisions of this file
ssl/loader.c Show annotated file Show diff for this revision Revisions of this file
ssl/openssl.c Show annotated file Show diff for this revision Revisions of this file
ssl/os_port.c Show annotated file Show diff for this revision Revisions of this file
ssl/os_port.h Show annotated file Show diff for this revision Revisions of this file
ssl/os_port_old.h Show annotated file Show diff for this revision Revisions of this file
ssl/p12.c Show annotated file Show diff for this revision Revisions of this file
ssl/private_key.h Show annotated file Show diff for this revision Revisions of this file
ssl/ssl.h Show annotated file Show diff for this revision Revisions of this file
ssl/tls1.c Show annotated file Show diff for this revision Revisions of this file
ssl/tls1.h Show annotated file Show diff for this revision Revisions of this file
ssl/tls1_clnt.c Show annotated file Show diff for this revision Revisions of this file
ssl/tls1_svr.c Show annotated file Show diff for this revision Revisions of this file
ssl/version.h Show annotated file Show diff for this revision Revisions of this file
ssl/x509.c Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/aes.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * AES implementation - this is a small code version. There are much faster
+ * versions around but they are much larger in size (i.e. they use large 
+ * submix tables).
+ */
+
+#include <string.h>
+//#include "os_port.h"
+#include "crypto.h"
+#include <lwip/def.h>
+
+/* all commented out in skeleton mode */
+#ifndef CONFIG_SSL_SKELETON_MODE
+
+#define rot1(x) (((x) << 24) | ((x) >> 8))
+#define rot2(x) (((x) << 16) | ((x) >> 16))
+#define rot3(x) (((x) <<  8) | ((x) >> 24))
+
+/* 
+ * This cute trick does 4 'mul by two' at once.  Stolen from
+ * Dr B. R. Gladman <brg@gladman.uk.net> but I'm sure the u-(u>>7) is
+ * a standard graphics trick
+ * The key to this is that we need to xor with 0x1b if the top bit is set.
+ * a 1xxx xxxx   0xxx 0xxx First we mask the 7bit,
+ * b 1000 0000   0000 0000 then we shift right by 7 putting the 7bit in 0bit,
+ * c 0000 0001   0000 0000 we then subtract (c) from (b)
+ * d 0111 1111   0000 0000 and now we and with our mask
+ * e 0001 1011   0000 0000
+ */
+#define mt  0x80808080
+#define ml  0x7f7f7f7f
+#define mh  0xfefefefe
+#define mm  0x1b1b1b1b
+#define mul2(x,t)    ((t)=((x)&mt), \
+            ((((x)+(x))&mh)^(((t)-((t)>>7))&mm)))
+
+#define inv_mix_col(x,f2,f4,f8,f9) (\
+            (f2)=mul2(x,f2), \
+            (f4)=mul2(f2,f4), \
+            (f8)=mul2(f4,f8), \
+            (f9)=(x)^(f8), \
+            (f8)=((f2)^(f4)^(f8)), \
+            (f2)^=(f9), \
+            (f4)^=(f9), \
+            (f8)^=rot3(f2), \
+            (f8)^=rot2(f4), \
+            (f8)^rot1(f9))
+
+/*
+ * AES S-box
+ */
+static const uint8_t aes_sbox[256] =
+{
+    0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,
+    0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76,
+    0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,
+    0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0,
+    0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,
+    0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15,
+    0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,
+    0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75,
+    0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,
+    0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84,
+    0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,
+    0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF,
+    0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,
+    0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8,
+    0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,
+    0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2,
+    0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,
+    0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73,
+    0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,
+    0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB,
+    0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,
+    0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79,
+    0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,
+    0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08,
+    0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,
+    0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A,
+    0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,
+    0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E,
+    0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,
+    0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF,
+    0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,
+    0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16,
+};
+
+/*
+ * AES is-box
+ */
+static const uint8_t aes_isbox[256] = 
+{
+    0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,
+    0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
+    0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,
+    0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
+    0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,
+    0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,
+    0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,
+    0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
+    0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,
+    0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
+    0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,
+    0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
+    0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,
+    0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
+    0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,
+    0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
+    0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,
+    0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
+    0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,
+    0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
+    0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,
+    0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
+    0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,
+    0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
+    0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,
+    0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
+    0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,
+    0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
+    0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,
+    0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
+    0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,
+    0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d
+};
+
+static const unsigned char Rcon[30]=
+{
+    0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
+    0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f,
+    0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4,
+    0xb3,0x7d,0xfa,0xef,0xc5,0x91,
+};
+
+/* ----- static functions ----- */
+static void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
+static void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
+
+/* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial
+   x^8+x^4+x^3+x+1 */
+static unsigned char AES_xtime(uint32_t x)
+{
+    return (x&0x80) ? (x<<1)^0x1b : x<<1;
+}
+
+/**
+ * Set up AES with the key/iv and cipher size.
+ */
+void AES_set_key(AES_CTX *ctx, const uint8_t *key, 
+        const uint8_t *iv, AES_MODE mode)
+{
+    int i, ii;
+    uint32_t *W, tmp, tmp2;
+    const unsigned char *ip;
+    int words;
+
+    switch (mode)
+    {
+        case AES_MODE_128:
+            i = 10;
+            words = 4;
+            break;
+
+        case AES_MODE_256:
+            i = 14;
+            words = 8;
+            break;
+
+        default:        /* fail silently */
+            return;
+    }
+
+    ctx->rounds = i;
+    ctx->key_size = words;
+    W = ctx->ks;
+    for (i = 0; i < words; i+=2)
+    {
+        W[i+0]=    ((uint32_t)key[ 0]<<24)|
+            ((uint32_t)key[ 1]<<16)|
+            ((uint32_t)key[ 2]<< 8)|
+            ((uint32_t)key[ 3]    );
+        W[i+1]=    ((uint32_t)key[ 4]<<24)|
+            ((uint32_t)key[ 5]<<16)|
+            ((uint32_t)key[ 6]<< 8)|
+            ((uint32_t)key[ 7]    );
+        key += 8;
+    }
+
+    ip = Rcon;
+    ii = 4 * (ctx->rounds+1);
+    for (i = words; i<ii; i++)
+    {
+        tmp = W[i-1];
+
+        if ((i % words) == 0)
+        {
+            tmp2 =(uint32_t)aes_sbox[(tmp    )&0xff]<< 8;
+            tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<<16;
+            tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<24;
+            tmp2|=(uint32_t)aes_sbox[(tmp>>24)     ];
+            tmp=tmp2^(((unsigned int)*ip)<<24);
+            ip++;
+        }
+
+        if ((words == 8) && ((i % words) == 4))
+        {
+            tmp2 =(uint32_t)aes_sbox[(tmp    )&0xff]    ;
+            tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<< 8;
+            tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<16;
+            tmp2|=(uint32_t)aes_sbox[(tmp>>24)     ]<<24;
+            tmp=tmp2;
+        }
+
+        W[i]=W[i-words]^tmp;
+    }
+
+    /* copy the iv across */
+    memcpy(ctx->iv, iv, 16);
+}
+
+/**
+ * Change a key for decryption.
+ */
+void AES_convert_key(AES_CTX *ctx)
+{
+    int i;
+    uint32_t *k,w,t1,t2,t3,t4;
+
+    k = ctx->ks;
+    k += 4;
+
+    for (i= ctx->rounds*4; i > 4; i--)
+    {
+        w= *k;
+        w = inv_mix_col(w,t1,t2,t3,t4);
+        *k++ =w;
+    }
+}
+
+/**
+ * Encrypt a byte sequence (with a block size 16) using the AES cipher.
+ */
+void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
+{
+    int i;
+    uint32_t tin[4], tout[4], iv[4];
+
+    memcpy(iv, ctx->iv, AES_IV_SIZE);
+    for (i = 0; i < 4; i++)
+        tout[i] = ntohl(iv[i]);
+
+    for (length -= AES_BLOCKSIZE; length >= 0; length -= AES_BLOCKSIZE)
+    {
+        uint32_t msg_32[4];
+        uint32_t out_32[4];
+        memcpy(msg_32, msg, AES_BLOCKSIZE);
+        msg += AES_BLOCKSIZE;
+
+        for (i = 0; i < 4; i++)
+            tin[i] = ntohl(msg_32[i])^tout[i];
+
+        AES_encrypt(ctx, tin);
+
+        for (i = 0; i < 4; i++)
+        {
+            tout[i] = tin[i]; 
+            out_32[i] = htonl(tout[i]);
+        }
+
+        memcpy(out, out_32, AES_BLOCKSIZE);
+        out += AES_BLOCKSIZE;
+    }
+
+    for (i = 0; i < 4; i++)
+        iv[i] = htonl(tout[i]);
+    memcpy(ctx->iv, iv, AES_IV_SIZE);
+}
+
+/**
+ * Decrypt a byte sequence (with a block size 16) using the AES cipher.
+ */
+void AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
+{
+    int i;
+    uint32_t tin[4], xor[4], tout[4], data[4], iv[4];
+
+    memcpy(iv, ctx->iv, AES_IV_SIZE);
+    for (i = 0; i < 4; i++)
+        xor[i] = ntohl(iv[i]);
+
+    for (length -= 16; length >= 0; length -= 16)
+    {
+        uint32_t msg_32[4];
+        uint32_t out_32[4];
+        memcpy(msg_32, msg, AES_BLOCKSIZE);
+        msg += AES_BLOCKSIZE;
+
+        for (i = 0; i < 4; i++)
+        {
+            tin[i] = ntohl(msg_32[i]);
+            data[i] = tin[i];
+        }
+
+        AES_decrypt(ctx, data);
+
+        for (i = 0; i < 4; i++)
+        {
+            tout[i] = data[i]^xor[i];
+            xor[i] = tin[i];
+            out_32[i] = htonl(tout[i]);
+        }
+
+        memcpy(out, out_32, AES_BLOCKSIZE);
+        out += AES_BLOCKSIZE;
+    }
+
+    for (i = 0; i < 4; i++)
+        iv[i] = htonl(xor[i]);
+    memcpy(ctx->iv, iv, AES_IV_SIZE);
+}
+
+/**
+ * Encrypt a single block (16 bytes) of data
+ */
+static void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
+{
+    /* To make this code smaller, generate the sbox entries on the fly.
+     * This will have a really heavy effect upon performance.
+     */
+    uint32_t tmp[4];
+    uint32_t tmp1, old_a0, a0, a1, a2, a3, row;
+    int curr_rnd;
+    int rounds = ctx->rounds; 
+    const uint32_t *k = ctx->ks;
+
+    /* Pre-round key addition */
+    for (row = 0; row < 4; row++)
+        data[row] ^= *(k++);
+
+    /* Encrypt one block. */
+    for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
+    {
+        /* Perform ByteSub and ShiftRow operations together */
+        for (row = 0; row < 4; row++)
+        {
+            a0 = (uint32_t)aes_sbox[(data[row%4]>>24)&0xFF];
+            a1 = (uint32_t)aes_sbox[(data[(row+1)%4]>>16)&0xFF];
+            a2 = (uint32_t)aes_sbox[(data[(row+2)%4]>>8)&0xFF]; 
+            a3 = (uint32_t)aes_sbox[(data[(row+3)%4])&0xFF];
+
+            /* Perform MixColumn iff not last round */
+            if (curr_rnd < (rounds - 1))
+            {
+                tmp1 = a0 ^ a1 ^ a2 ^ a3;
+                old_a0 = a0;
+                a0 ^= tmp1 ^ AES_xtime(a0 ^ a1);
+                a1 ^= tmp1 ^ AES_xtime(a1 ^ a2);
+                a2 ^= tmp1 ^ AES_xtime(a2 ^ a3);
+                a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0);
+            }
+
+            tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3);
+        }
+
+        /* KeyAddition - note that it is vital that this loop is separate from
+           the MixColumn operation, which must be atomic...*/ 
+        for (row = 0; row < 4; row++)
+            data[row] = tmp[row] ^ *(k++);
+    }
+}
+
+/**
+ * Decrypt a single block (16 bytes) of data
+ */
+static void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
+{ 
+    uint32_t tmp[4];
+    uint32_t xt0,xt1,xt2,xt3,xt4,xt5,xt6;
+    uint32_t a0, a1, a2, a3, row;
+    int curr_rnd;
+    int rounds = ctx->rounds;
+    const uint32_t *k = ctx->ks + ((rounds+1)*4);
+
+    /* pre-round key addition */
+    for (row=4; row > 0;row--)
+        data[row-1] ^= *(--k);
+
+    /* Decrypt one block */
+    for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
+    {
+        /* Perform ByteSub and ShiftRow operations together */
+        for (row = 4; row > 0; row--)
+        {
+            a0 = aes_isbox[(data[(row+3)%4]>>24)&0xFF];
+            a1 = aes_isbox[(data[(row+2)%4]>>16)&0xFF];
+            a2 = aes_isbox[(data[(row+1)%4]>>8)&0xFF];
+            a3 = aes_isbox[(data[row%4])&0xFF];
+
+            /* Perform MixColumn iff not last round */
+            if (curr_rnd<(rounds-1))
+            {
+                /* The MDS cofefficients (0x09, 0x0B, 0x0D, 0x0E)
+                   are quite large compared to encryption; this 
+                   operation slows decryption down noticeably. */
+                xt0 = AES_xtime(a0^a1);
+                xt1 = AES_xtime(a1^a2);
+                xt2 = AES_xtime(a2^a3);
+                xt3 = AES_xtime(a3^a0);
+                xt4 = AES_xtime(xt0^xt1);
+                xt5 = AES_xtime(xt1^xt2);
+                xt6 = AES_xtime(xt4^xt5);
+
+                xt0 ^= a1^a2^a3^xt4^xt6;
+                xt1 ^= a0^a2^a3^xt5^xt6;
+                xt2 ^= a0^a1^a3^xt4^xt6;
+                xt3 ^= a0^a1^a2^xt5^xt6;
+                tmp[row-1] = ((xt0<<24)|(xt1<<16)|(xt2<<8)|xt3);
+            }
+            else
+                tmp[row-1] = ((a0<<24)|(a1<<16)|(a2<<8)|a3);
+        }
+
+        for (row = 4; row > 0; row--)
+            data[row-1] = tmp[row-1] ^ *(--k);
+    }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/bigint.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,1512 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * @defgroup bigint_api Big Integer API
+ * @brief The bigint implementation as used by the axTLS project.
+ *
+ * The bigint library is for RSA encryption/decryption as well as signing.
+ * This code tries to minimise use of malloc/free by maintaining a small 
+ * cache. A bigint context may maintain state by being made "permanent". 
+ * It be be later released with a bi_depermanent() and bi_free() call.
+ *
+ * It supports the following reduction techniques:
+ * - Classical
+ * - Barrett
+ * - Montgomery
+ *
+ * It also implements the following:
+ * - Karatsuba multiplication
+ * - Squaring
+ * - Sliding window exponentiation
+ * - Chinese Remainder Theorem (implemented in rsa.c).
+ *
+ * All the algorithms used are pretty standard, and designed for different
+ * data bus sizes. Negative numbers are not dealt with at all, so a subtraction
+ * may need to be tested for negativity.
+ *
+ * This library steals some ideas from Jef Poskanzer
+ * <http://cs.marlboro.edu/term/cs-fall02/algorithms/crypto/RSA/bigint>
+ * and GMP <http://www.swox.com/gmp>. It gets most of its implementation
+ * detail from "The Handbook of Applied Cryptography"
+ * <http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf>
+ * @{
+ */
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include "os_port.h"
+#include "bigint.h"
+
+#define V1      v->comps[v->size-1]                 /**< v1 for division */
+#define V2      v->comps[v->size-2]                 /**< v2 for division */
+#define U(j)    tmp_u->comps[tmp_u->size-j-1]       /**< uj for division */
+#define Q(j)    quotient->comps[quotient->size-j-1] /**< qj for division */
+
+static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i);
+static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom);
+static bigint *alloc(BI_CTX *ctx, int size);
+static bigint *trim(bigint *bi);
+static void more_comps(bigint *bi, int n);
+#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
+    defined(CONFIG_BIGINT_MONTGOMERY)
+static bigint *comp_right_shift(bigint *biR, int num_shifts);
+static bigint *comp_left_shift(bigint *biR, int num_shifts);
+#endif
+
+#ifdef CONFIG_BIGINT_CHECK_ON
+static void check(const bigint *bi);
+#else
+#define check(A)                /**< disappears in normal production mode */
+#endif
+
+
+/**
+ * @brief Start a new bigint context.
+ * @return A bigint context.
+ */
+BI_CTX *bi_initialize(void)
+{
+    /* calloc() sets everything to zero */
+    BI_CTX *ctx = (BI_CTX *)calloc(1, sizeof(BI_CTX));
+   
+    /* the radix */
+    ctx->bi_radix = alloc(ctx, 2); 
+    ctx->bi_radix->comps[0] = 0;
+    ctx->bi_radix->comps[1] = 1;
+    bi_permanent(ctx->bi_radix);
+    return ctx;
+}
+
+/**
+ * @brief Close the bigint context and free any resources.
+ *
+ * Free up any used memory - a check is done if all objects were not 
+ * properly freed.
+ * @param ctx [in]   The bigint session context.
+ */
+void bi_terminate(BI_CTX *ctx)
+{
+    bi_depermanent(ctx->bi_radix); 
+    bi_free(ctx, ctx->bi_radix);
+
+    if (ctx->active_count != 0)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("bi_terminate: there were %d un-freed bigints\n",
+                       ctx->active_count);
+#endif
+        abort();
+    }
+
+    bi_clear_cache(ctx);
+    free(ctx);
+}
+
+/**
+ *@brief Clear the memory cache.
+ */
+void bi_clear_cache(BI_CTX *ctx)
+{
+    bigint *p, *pn;
+
+    if (ctx->free_list == NULL)
+        return;
+    
+    for (p = ctx->free_list; p != NULL; p = pn)
+    {
+        pn = p->next;
+        free(p->comps);
+        free(p);
+    }
+
+    ctx->free_count = 0;
+    ctx->free_list = NULL;
+}
+
+/**
+ * @brief Increment the number of references to this object. 
+ * It does not do a full copy.
+ * @param bi [in]   The bigint to copy.
+ * @return A reference to the same bigint.
+ */
+bigint *bi_copy(bigint *bi)
+{
+    check(bi);
+    if (bi->refs != PERMANENT)
+        bi->refs++;
+    return bi;
+}
+
+/**
+ * @brief Simply make a bigint object "unfreeable" if bi_free() is called on it.
+ *
+ * For this object to be freed, bi_depermanent() must be called.
+ * @param bi [in]   The bigint to be made permanent.
+ */
+void bi_permanent(bigint *bi)
+{
+    check(bi);
+    if (bi->refs != 1)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("bi_permanent: refs was not 1\n");
+#endif
+        abort();
+    }
+
+    bi->refs = PERMANENT;
+}
+
+/**
+ * @brief Take a permanent object and make it eligible for freedom.
+ * @param bi [in]   The bigint to be made back to temporary.
+ */
+void bi_depermanent(bigint *bi)
+{
+    check(bi);
+    if (bi->refs != PERMANENT)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("bi_depermanent: bigint was not permanent\n");
+#endif
+        abort();
+    }
+
+    bi->refs = 1;
+}
+
+/**
+ * @brief Free a bigint object so it can be used again. 
+ *
+ * The memory itself it not actually freed, just tagged as being available 
+ * @param ctx [in]   The bigint session context.
+ * @param bi [in]    The bigint to be freed.
+ */
+void bi_free(BI_CTX *ctx, bigint *bi)
+{
+    check(bi);
+    if (bi->refs == PERMANENT)
+    {
+        return;
+    }
+
+    if (--bi->refs > 0)
+    {
+        return;
+    }
+
+    bi->next = ctx->free_list;
+    ctx->free_list = bi;
+    ctx->free_count++;
+
+    if (--ctx->active_count < 0)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("bi_free: active_count went negative "
+                "- double-freed bigint?\n");
+#endif
+        abort();
+    }
+}
+
+/**
+ * @brief Convert an (unsigned) integer into a bigint.
+ * @param ctx [in]   The bigint session context.
+ * @param i [in]     The (unsigned) integer to be converted.
+ * 
+ */
+bigint *int_to_bi(BI_CTX *ctx, comp i)
+{
+    bigint *biR = alloc(ctx, 1);
+    biR->comps[0] = i;
+    return biR;
+}
+
+/**
+ * @brief Do a full copy of the bigint object.
+ * @param ctx [in]   The bigint session context.
+ * @param bi  [in]   The bigint object to be copied.
+ */
+bigint *bi_clone(BI_CTX *ctx, const bigint *bi)
+{
+    bigint *biR = alloc(ctx, bi->size);
+    check(bi);
+    memcpy(biR->comps, bi->comps, bi->size*COMP_BYTE_SIZE);
+    return biR;
+}
+
+/**
+ * @brief Perform an addition operation between two bigints.
+ * @param ctx [in]  The bigint session context.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @return The result of the addition.
+ */
+bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+    int n;
+    comp carry = 0;
+    comp *pa, *pb;
+
+    check(bia);
+    check(bib);
+
+    n = max(bia->size, bib->size);
+    more_comps(bia, n+1);
+    more_comps(bib, n);
+    pa = bia->comps;
+    pb = bib->comps;
+
+    do
+    {
+        comp  sl, rl, cy1;
+        sl = *pa + *pb++;
+        rl = sl + carry;
+        cy1 = sl < *pa;
+        carry = cy1 | (rl < sl);
+        *pa++ = rl;
+    } while (--n != 0);
+
+    *pa = carry;                  /* do overflow */
+    bi_free(ctx, bib);
+    return trim(bia);
+}
+
+/**
+ * @brief Perform a subtraction operation between two bigints.
+ * @param ctx [in]  The bigint session context.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @param is_negative [out] If defined, indicates that the result was negative.
+ * is_negative may be null.
+ * @return The result of the subtraction. The result is always positive.
+ */
+bigint *bi_subtract(BI_CTX *ctx, 
+        bigint *bia, bigint *bib, int *is_negative)
+{
+    int n = bia->size;
+    comp *pa, *pb, carry = 0;
+
+    check(bia);
+    check(bib);
+
+    more_comps(bib, n);
+    pa = bia->comps;
+    pb = bib->comps;
+
+    do 
+    {
+        comp sl, rl, cy1;
+        sl = *pa - *pb++;
+        rl = sl - carry;
+        cy1 = sl > *pa;
+        carry = cy1 | (rl > sl);
+        *pa++ = rl;
+    } while (--n != 0);
+
+    if (is_negative)    /* indicate a negative result */
+    {
+        *is_negative = carry;
+    }
+
+    bi_free(ctx, trim(bib));    /* put bib back to the way it was */
+    return trim(bia);
+}
+
+/**
+ * Perform a multiply between a bigint an an (unsigned) integer
+ */
+static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b)
+{
+    int j = 0, n = bia->size;
+    bigint *biR = alloc(ctx, n + 1);
+    comp carry = 0;
+    comp *r = biR->comps;
+    comp *a = bia->comps;
+
+    check(bia);
+
+    /* clear things to start with */
+    memset(r, 0, ((n+1)*COMP_BYTE_SIZE));
+
+    do
+    {
+        long_comp tmp = *r + (long_comp)a[j]*b + carry;
+        *r++ = (comp)tmp;              /* downsize */
+        carry = (comp)(tmp >> COMP_BIT_SIZE);
+    } while (++j < n);
+
+    *r = carry;
+    bi_free(ctx, bia);
+    return trim(biR);
+}
+
+/**
+ * @brief Does both division and modulo calculations. 
+ *
+ * Used extensively when doing classical reduction.
+ * @param ctx [in]  The bigint session context.
+ * @param u [in]    A bigint which is the numerator.
+ * @param v [in]    Either the denominator or the modulus depending on the mode.
+ * @param is_mod [n] Determines if this is a normal division (0) or a reduction
+ * (1).
+ * @return  The result of the division/reduction.
+ */
+bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod)
+{
+    int n = v->size, m = u->size-n;
+    int j = 0, orig_u_size = u->size;
+    uint8_t mod_offset = ctx->mod_offset;
+    comp d;
+    bigint *quotient, *tmp_u;
+    comp q_dash;
+
+    check(u);
+    check(v);
+
+    /* if doing reduction and we are < mod, then return mod */
+    if (is_mod && bi_compare(v, u) > 0)
+    {
+        bi_free(ctx, v);
+        return u;
+    }
+
+    quotient = alloc(ctx, m+1);
+    tmp_u = alloc(ctx, n+1);
+    v = trim(v);        /* make sure we have no leading 0's */
+    d = (comp)((long_comp)COMP_RADIX/(V1+1));
+
+    /* clear things to start with */
+    memset(quotient->comps, 0, ((quotient->size)*COMP_BYTE_SIZE));
+
+    /* normalise */
+    if (d > 1)
+    {
+        u = bi_int_multiply(ctx, u, d);
+
+        if (is_mod)
+        {
+            v = ctx->bi_normalised_mod[mod_offset];
+        }
+        else
+        {
+            v = bi_int_multiply(ctx, v, d);
+        }
+    }
+
+    if (orig_u_size == u->size)  /* new digit position u0 */
+    {
+        more_comps(u, orig_u_size + 1);
+    }
+
+    do
+    {
+        /* get a temporary short version of u */
+        memcpy(tmp_u->comps, &u->comps[u->size-n-1-j], (n+1)*COMP_BYTE_SIZE);
+
+        /* calculate q' */
+        if (U(0) == V1)
+        {
+            q_dash = COMP_RADIX-1;
+        }
+        else
+        {
+            q_dash = (comp)(((long_comp)U(0)*COMP_RADIX + U(1))/V1);
+
+            if (v->size > 1 && V2)
+            {
+                /* we are implementing the following:
+                if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - 
+                        q_dash*V1)*COMP_RADIX) + U(2))) ... */
+                comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) - 
+                                            (long_comp)q_dash*V1);
+                if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2))
+                {
+                    q_dash--;
+                }
+            }
+        }
+
+        /* multiply and subtract */
+        if (q_dash)
+        {
+            int is_negative;
+            tmp_u = bi_subtract(ctx, tmp_u, 
+                    bi_int_multiply(ctx, bi_copy(v), q_dash), &is_negative);
+            more_comps(tmp_u, n+1);
+
+            Q(j) = q_dash; 
+
+            /* add back */
+            if (is_negative)
+            {
+                Q(j)--;
+                tmp_u = bi_add(ctx, tmp_u, bi_copy(v));
+
+                /* lop off the carry */
+                tmp_u->size--;
+                v->size--;
+            }
+        }
+        else
+        {
+            Q(j) = 0; 
+        }
+
+        /* copy back to u */
+        memcpy(&u->comps[u->size-n-1-j], tmp_u->comps, (n+1)*COMP_BYTE_SIZE);
+    } while (++j <= m);
+
+    bi_free(ctx, tmp_u);
+    bi_free(ctx, v);
+
+    if (is_mod)     /* get the remainder */
+    {
+        bi_free(ctx, quotient);
+        return bi_int_divide(ctx, trim(u), d);
+    }
+    else            /* get the quotient */
+    {
+        bi_free(ctx, u);
+        return trim(quotient);
+    }
+}
+
+/*
+ * Perform an integer divide on a bigint.
+ */
+static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom)
+{
+    int i = biR->size - 1;
+    long_comp r = 0;
+
+    check(biR);
+
+    do
+    {
+        r = (r<<COMP_BIT_SIZE) + biR->comps[i];
+        biR->comps[i] = (comp)(r / denom);
+        r %= denom;
+    } while (--i >= 0);
+
+    return trim(biR);
+}
+
+#ifdef CONFIG_BIGINT_MONTGOMERY
+/**
+ * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1, 
+ * where B^-1(B-1) mod N=1. Actually, only the least significant part of 
+ * N' is needed, hence the definition N0'=N' mod b. We reproduce below the 
+ * simple algorithm from an article by Dusse and Kaliski to efficiently 
+ * find N0' from N0 and b */
+static comp modular_inverse(bigint *bim)
+{
+    int i;
+    comp t = 1;
+    comp two_2_i_minus_1 = 2;   /* 2^(i-1) */
+    long_comp two_2_i = 4;      /* 2^i */
+    comp N = bim->comps[0];
+
+    for (i = 2; i <= COMP_BIT_SIZE; i++)
+    {
+        if ((long_comp)N*t%two_2_i >= two_2_i_minus_1)
+        {
+            t += two_2_i_minus_1;
+        }
+
+        two_2_i_minus_1 <<= 1;
+        two_2_i <<= 1;
+    }
+
+    return (comp)(COMP_RADIX-t);
+}
+#endif
+
+#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
+    defined(CONFIG_BIGINT_MONTGOMERY)
+/**
+ * Take each component and shift down (in terms of components) 
+ */
+static bigint *comp_right_shift(bigint *biR, int num_shifts)
+{
+    int i = biR->size-num_shifts;
+    comp *x = biR->comps;
+    comp *y = &biR->comps[num_shifts];
+
+    check(biR);
+
+    if (i <= 0)     /* have we completely right shifted? */
+    {
+        biR->comps[0] = 0;  /* return 0 */
+        biR->size = 1;
+        return biR;
+    }
+
+    do
+    {
+        *x++ = *y++;
+    } while (--i > 0);
+
+    biR->size -= num_shifts;
+    return biR;
+}
+
+/**
+ * Take each component and shift it up (in terms of components) 
+ */
+static bigint *comp_left_shift(bigint *biR, int num_shifts)
+{
+    int i = biR->size-1;
+    comp *x, *y;
+
+    check(biR);
+
+    if (num_shifts <= 0)
+    {
+        return biR;
+    }
+
+    more_comps(biR, biR->size + num_shifts);
+
+    x = &biR->comps[i+num_shifts];
+    y = &biR->comps[i];
+
+    do
+    {
+        *x-- = *y--;
+    } while (i--);
+
+    memset(biR->comps, 0, num_shifts*COMP_BYTE_SIZE); /* zero LS comps */
+    return biR;
+}
+#endif
+
+/**
+ * @brief Allow a binary sequence to be imported as a bigint.
+ * @param ctx [in]  The bigint session context.
+ * @param data [in] The data to be converted.
+ * @param size [in] The number of bytes of data.
+ * @return A bigint representing this data.
+ */
+bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int size)
+{
+    bigint *biR = alloc(ctx, (size+COMP_BYTE_SIZE-1)/COMP_BYTE_SIZE);
+    int i, j = 0, offset = 0;
+
+    memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
+
+    for (i = size-1; i >= 0; i--)
+    {
+        biR->comps[offset] += data[i] << (j*8);
+
+        if (++j == COMP_BYTE_SIZE)
+        {
+            j = 0;
+            offset ++;
+        }
+    }
+
+    return trim(biR);
+}
+
+#ifdef CONFIG_SSL_FULL_MODE
+/**
+ * @brief The testharness uses this code to import text hex-streams and 
+ * convert them into bigints.
+ * @param ctx [in]  The bigint session context.
+ * @param data [in] A string consisting of hex characters. The characters must
+ * be in upper case.
+ * @return A bigint representing this data.
+ */
+bigint *bi_str_import(BI_CTX *ctx, const char *data)
+{
+    int size = strlen(data);
+    bigint *biR = alloc(ctx, (size+COMP_NUM_NIBBLES-1)/COMP_NUM_NIBBLES);
+    int i, j = 0, offset = 0;
+    memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
+
+    for (i = size-1; i >= 0; i--)
+    {
+        int num = (data[i] <= '9') ? (data[i] - '0') : (data[i] - 'A' + 10);
+        biR->comps[offset] += num << (j*4);
+
+        if (++j == COMP_NUM_NIBBLES)
+        {
+            j = 0;
+            offset ++;
+        }
+    }
+
+    return biR;
+}
+
+void bi_print(const char *label, bigint *x)
+{
+    int i, j;
+
+    if (x == NULL)
+    {
+        printf("%s: (null)\n", label);
+        return;
+    }
+
+    printf("%s: (size %d)\n", label, x->size);
+    for (i = x->size-1; i >= 0; i--)
+    {
+        for (j = COMP_NUM_NIBBLES-1; j >= 0; j--)
+        {
+            comp mask = 0x0f << (j*4);
+            comp num = (x->comps[i] & mask) >> (j*4);
+            putc((num <= 9) ? (num + '0') : (num + 'A' - 10), stdout);
+        }
+    }  
+
+    printf("\r\n");
+}
+#endif
+
+/**
+ * @brief Take a bigint and convert it into a byte sequence. 
+ *
+ * This is useful after a decrypt operation.
+ * @param ctx [in]  The bigint session context.
+ * @param x [in]  The bigint to be converted.
+ * @param data [out] The converted data as a byte stream.
+ * @param size [in] The maximum size of the byte stream. Unused bytes will be
+ * zeroed.
+ */
+void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size)
+{
+    int i, j, k = size-1;
+
+    check(x);
+    memset(data, 0, size);  /* ensure all leading 0's are cleared */
+
+    for (i = 0; i < x->size; i++)
+    {
+        for (j = 0; j < COMP_BYTE_SIZE; j++)
+        {
+            comp mask = 0xff << (j*8);
+            int num = (x->comps[i] & mask) >> (j*8);
+            data[k--] = num;
+
+            if (k < 0)
+            {
+                goto buf_done;
+            }
+        }
+    }
+buf_done:
+
+    bi_free(ctx, x);
+}
+
+/**
+ * @brief Pre-calculate some of the expensive steps in reduction. 
+ *
+ * This function should only be called once (normally when a session starts).
+ * When the session is over, bi_free_mod() should be called. bi_mod_power()
+ * relies on this function being called.
+ * @param ctx [in]  The bigint session context.
+ * @param bim [in]  The bigint modulus that will be used.
+ * @param mod_offset [in] There are three moduluii that can be stored - the
+ * standard modulus, and its two primes p and q. This offset refers to which
+ * modulus we are referring to.
+ * @see bi_free_mod(), bi_mod_power().
+ */
+void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset)
+{
+    int k = bim->size;
+    comp d = (comp)((long_comp)COMP_RADIX/(bim->comps[k-1]+1));
+#ifdef CONFIG_BIGINT_MONTGOMERY
+    bigint *R, *R2;
+#endif
+
+    ctx->bi_mod[mod_offset] = bim;
+    bi_permanent(ctx->bi_mod[mod_offset]);
+    ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d);
+    bi_permanent(ctx->bi_normalised_mod[mod_offset]);
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    /* set montgomery variables */
+    R = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k-1);     /* R */
+    R2 = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k*2-1);  /* R^2 */
+    ctx->bi_RR_mod_m[mod_offset] = bi_mod(ctx, R2);             /* R^2 mod m */
+    ctx->bi_R_mod_m[mod_offset] = bi_mod(ctx, R);               /* R mod m */
+
+    bi_permanent(ctx->bi_RR_mod_m[mod_offset]);
+    bi_permanent(ctx->bi_R_mod_m[mod_offset]);
+
+    ctx->N0_dash[mod_offset] = modular_inverse(ctx->bi_mod[mod_offset]);
+
+#elif defined (CONFIG_BIGINT_BARRETT)
+    ctx->bi_mu[mod_offset] = 
+        bi_divide(ctx, comp_left_shift(
+            bi_clone(ctx, ctx->bi_radix), k*2-1), ctx->bi_mod[mod_offset], 0);
+    bi_permanent(ctx->bi_mu[mod_offset]);
+#endif
+}
+
+/**
+ * @brief Used when cleaning various bigints at the end of a session.
+ * @param ctx [in]  The bigint session context.
+ * @param mod_offset [in] The offset to use.
+ * @see bi_set_mod().
+ */
+void bi_free_mod(BI_CTX *ctx, int mod_offset)
+{
+    bi_depermanent(ctx->bi_mod[mod_offset]);
+    bi_free(ctx, ctx->bi_mod[mod_offset]);
+#if defined (CONFIG_BIGINT_MONTGOMERY)
+    bi_depermanent(ctx->bi_RR_mod_m[mod_offset]);
+    bi_depermanent(ctx->bi_R_mod_m[mod_offset]);
+    bi_free(ctx, ctx->bi_RR_mod_m[mod_offset]);
+    bi_free(ctx, ctx->bi_R_mod_m[mod_offset]);
+#elif defined(CONFIG_BIGINT_BARRETT)
+    bi_depermanent(ctx->bi_mu[mod_offset]); 
+    bi_free(ctx, ctx->bi_mu[mod_offset]);
+#endif
+    bi_depermanent(ctx->bi_normalised_mod[mod_offset]); 
+    bi_free(ctx, ctx->bi_normalised_mod[mod_offset]);
+}
+
+/** 
+ * Perform a standard multiplication between two bigints.
+ *
+ * Barrett reduction has no need for some parts of the product, so ignore bits
+ * of the multiply. This routine gives Barrett its big performance
+ * improvements over Classical/Montgomery reduction methods. 
+ */
+static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, 
+        int inner_partial, int outer_partial)
+{
+    int i = 0, j;
+    int n = bia->size;
+    int t = bib->size;
+    bigint *biR = alloc(ctx, n + t);
+    comp *sr = biR->comps;
+    comp *sa = bia->comps;
+    comp *sb = bib->comps;
+
+    check(bia);
+    check(bib);
+
+    /* clear things to start with */
+    memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE));
+
+    do 
+    {
+        long_comp tmp;
+        comp carry = 0;
+        int r_index = i;
+        j = 0;
+
+        if (outer_partial && outer_partial-i > 0 && outer_partial < n)
+        {
+            r_index = outer_partial-1;
+            j = outer_partial-i-1;
+        }
+
+        do
+        {
+            if (inner_partial && r_index >= inner_partial) 
+            {
+                break;
+            }
+
+            tmp = sr[r_index] + ((long_comp)sa[j])*sb[i] + carry;
+            sr[r_index++] = (comp)tmp;              /* downsize */
+            carry = tmp >> COMP_BIT_SIZE;
+        } while (++j < n);
+
+        sr[r_index] = carry;
+    } while (++i < t);
+
+    bi_free(ctx, bia);
+    bi_free(ctx, bib);
+    return trim(biR);
+}
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+/*
+ * Karatsuba improves on regular multiplication due to only 3 multiplications 
+ * being done instead of 4. The additional additions/subtractions are O(N) 
+ * rather than O(N^2) and so for big numbers it saves on a few operations 
+ */
+static bigint *karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square)
+{
+    bigint *x0, *x1;
+    bigint *p0, *p1, *p2;
+    int m;
+
+    if (is_square)
+    {
+        m = (bia->size + 1)/2;
+    }
+    else
+    {
+        m = (max(bia->size, bib->size) + 1)/2;
+    }
+
+    x0 = bi_clone(ctx, bia);
+    x0->size = m;
+    x1 = bi_clone(ctx, bia);
+    comp_right_shift(x1, m);
+    bi_free(ctx, bia);
+
+    /* work out the 3 partial products */
+    if (is_square)
+    {
+        p0 = bi_square(ctx, bi_copy(x0));
+        p2 = bi_square(ctx, bi_copy(x1));
+        p1 = bi_square(ctx, bi_add(ctx, x0, x1));
+    }
+    else /* normal multiply */
+    {
+        bigint *y0, *y1;
+        y0 = bi_clone(ctx, bib);
+        y0->size = m;
+        y1 = bi_clone(ctx, bib);
+        comp_right_shift(y1, m);
+        bi_free(ctx, bib);
+
+        p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0));
+        p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1));
+        p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1));
+    }
+
+    p1 = bi_subtract(ctx, 
+            bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), NULL);
+
+    comp_left_shift(p1, m);
+    comp_left_shift(p2, 2*m);
+    return bi_add(ctx, p1, bi_add(ctx, p0, p2));
+}
+#endif
+
+/**
+ * @brief Perform a multiplication operation between two bigints.
+ * @param ctx [in]  The bigint session context.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @return The result of the multiplication.
+ */
+bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+    check(bia);
+    check(bib);
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+    if (min(bia->size, bib->size) < MUL_KARATSUBA_THRESH)
+    {
+        return regular_multiply(ctx, bia, bib, 0, 0);
+    }
+
+    return karatsuba(ctx, bia, bib, 0);
+#else
+    return regular_multiply(ctx, bia, bib, 0, 0);
+#endif
+}
+
+#ifdef CONFIG_BIGINT_SQUARE
+/*
+ * Perform the actual square operion. It takes into account overflow.
+ */
+static bigint *regular_square(BI_CTX *ctx, bigint *bi)
+{
+    int t = bi->size;
+    int i = 0, j;
+    bigint *biR = alloc(ctx, t*2+1);
+    comp *w = biR->comps;
+    comp *x = bi->comps;
+    long_comp carry;
+    memset(w, 0, biR->size*COMP_BYTE_SIZE);
+
+    do
+    {
+        long_comp tmp = w[2*i] + (long_comp)x[i]*x[i];
+        w[2*i] = (comp)tmp;
+        carry = tmp >> COMP_BIT_SIZE;
+
+        for (j = i+1; j < t; j++)
+        {
+            uint8_t c = 0;
+            long_comp xx = (long_comp)x[i]*x[j];
+            if ((COMP_MAX-xx) < xx)
+                c = 1;
+
+            tmp = (xx<<1);
+
+            if ((COMP_MAX-tmp) < w[i+j])
+                c = 1;
+
+            tmp += w[i+j];
+
+            if ((COMP_MAX-tmp) < carry)
+                c = 1;
+
+            tmp += carry;
+            w[i+j] = (comp)tmp;
+            carry = tmp >> COMP_BIT_SIZE;
+
+            if (c)
+                carry += COMP_RADIX;
+        }
+
+        tmp = w[i+t] + carry;
+        w[i+t] = (comp)tmp;
+        w[i+t+1] = tmp >> COMP_BIT_SIZE;
+    } while (++i < t);
+
+    bi_free(ctx, bi);
+    return trim(biR);
+}
+
+/**
+ * @brief Perform a square operation on a bigint.
+ * @param ctx [in]  The bigint session context.
+ * @param bia [in]  A bigint.
+ * @return The result of the multiplication.
+ */
+bigint *bi_square(BI_CTX *ctx, bigint *bia)
+{
+    check(bia);
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+    if (bia->size < SQU_KARATSUBA_THRESH) 
+    {
+        return regular_square(ctx, bia);
+    }
+
+    return karatsuba(ctx, bia, NULL, 1);
+#else
+    return regular_square(ctx, bia);
+#endif
+}
+#endif
+
+/**
+ * @brief Compare two bigints.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @return -1 if smaller, 1 if larger and 0 if equal.
+ */
+int bi_compare(bigint *bia, bigint *bib)
+{
+    int r, i;
+
+    check(bia);
+    check(bib);
+
+    if (bia->size > bib->size)
+        r = 1;
+    else if (bia->size < bib->size)
+        r = -1;
+    else
+    {
+        comp *a = bia->comps; 
+        comp *b = bib->comps; 
+
+        /* Same number of components.  Compare starting from the high end
+         * and working down. */
+        r = 0;
+        i = bia->size - 1;
+
+        do 
+        {
+            if (a[i] > b[i])
+            { 
+                r = 1;
+                break; 
+            }
+            else if (a[i] < b[i])
+            { 
+                r = -1;
+                break; 
+            }
+        } while (--i >= 0);
+    }
+
+    return r;
+}
+
+/*
+ * Allocate and zero more components.  Does not consume bi. 
+ */
+static void more_comps(bigint *bi, int n)
+{
+    if (n > bi->max_comps)
+    {
+        bi->max_comps = max(bi->max_comps * 2, n);
+        bi->comps = (comp*)realloc(bi->comps, bi->max_comps * COMP_BYTE_SIZE);
+    }
+
+    if (n > bi->size)
+    {
+        memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE);
+    }
+
+    bi->size = n;
+}
+
+/*
+ * Make a new empty bigint. It may just use an old one if one is available.
+ * Otherwise get one off the heap.
+ */
+static bigint *alloc(BI_CTX *ctx, int size)
+{
+    bigint *biR;
+
+    /* Can we recycle an old bigint? */
+    if (ctx->free_list != NULL)
+    {
+        biR = ctx->free_list;
+        ctx->free_list = biR->next;
+        ctx->free_count--;
+
+        if (biR->refs != 0)
+        {
+#ifdef CONFIG_SSL_FULL_MODE
+            printf("alloc: refs was not 0\n");
+#endif
+            abort();    /* create a stack trace from a core dump */
+        }
+
+        more_comps(biR, size);
+    }
+    else
+    {
+        /* No free bigints available - create a new one. */
+        biR = (bigint *)malloc(sizeof(bigint));
+        biR->comps = (comp*)malloc(size * COMP_BYTE_SIZE);
+        biR->max_comps = size;  /* give some space to spare */
+    }
+
+    biR->size = size;
+    biR->refs = 1;
+    biR->next = NULL;
+    ctx->active_count++;
+    return biR;
+}
+
+/*
+ * Work out the highest '1' bit in an exponent. Used when doing sliding-window
+ * exponentiation.
+ */
+static int find_max_exp_index(bigint *biexp)
+{
+    int i = COMP_BIT_SIZE-1;
+    comp shift = COMP_RADIX/2;
+    comp test = biexp->comps[biexp->size-1];    /* assume no leading zeroes */
+
+    check(biexp);
+
+    do
+    {
+        if (test & shift)
+        {
+            return i+(biexp->size-1)*COMP_BIT_SIZE;
+        }
+
+        shift >>= 1;
+    } while (i-- != 0);
+
+    return -1;      /* error - must have been a leading 0 */
+}
+
+/*
+ * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window
+ * exponentiation.
+ */
+static int exp_bit_is_one(bigint *biexp, int offset)
+{
+    comp test = biexp->comps[offset / COMP_BIT_SIZE];
+    int num_shifts = offset % COMP_BIT_SIZE;
+    comp shift = 1;
+    int i;
+
+    check(biexp);
+
+    for (i = 0; i < num_shifts; i++)
+    {
+        shift <<= 1;
+    }
+
+    return (test & shift) != 0;
+}
+
+#ifdef CONFIG_BIGINT_CHECK_ON
+/*
+ * Perform a sanity check on bi.
+ */
+static void check(const bigint *bi)
+{
+    if (bi->refs <= 0)
+    {
+        printf("check: zero or negative refs in bigint\n");
+        abort();
+    }
+
+    if (bi->next != NULL)
+    {
+        printf("check: attempt to use a bigint from "
+                "the free list\n");
+        abort();
+    }
+}
+#endif
+
+/*
+ * Delete any leading 0's (and allow for 0).
+ */
+static bigint *trim(bigint *bi)
+{
+    check(bi);
+
+    while (bi->comps[bi->size-1] == 0 && bi->size > 1)
+    {
+        bi->size--;
+    }
+
+    return bi;
+}
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+/**
+ * @brief Perform a single montgomery reduction.
+ * @param ctx [in]  The bigint session context.
+ * @param bixy [in]  A bigint.
+ * @return The result of the montgomery reduction.
+ */
+bigint *bi_mont(BI_CTX *ctx, bigint *bixy)
+{
+    int i = 0, n;
+    uint8_t mod_offset = ctx->mod_offset;
+    bigint *bim = ctx->bi_mod[mod_offset];
+    comp mod_inv = ctx->N0_dash[mod_offset];
+
+    check(bixy);
+
+    if (ctx->use_classical)     /* just use classical instead */
+    {
+        return bi_mod(ctx, bixy);
+    }
+
+    n = bim->size;
+
+    do
+    {
+        bixy = bi_add(ctx, bixy, comp_left_shift(
+                    bi_int_multiply(ctx, bim, bixy->comps[i]*mod_inv), i));
+    } while (++i < n);
+
+    comp_right_shift(bixy, n);
+
+    if (bi_compare(bixy, bim) >= 0)
+    {
+        bixy = bi_subtract(ctx, bixy, bim, NULL);
+    }
+
+    return bixy;
+}
+
+#elif defined(CONFIG_BIGINT_BARRETT)
+/*
+ * Stomp on the most significant components to give the illusion of a "mod base
+ * radix" operation 
+ */
+static bigint *comp_mod(bigint *bi, int mod)
+{
+    check(bi);
+
+    if (bi->size > mod)
+    {
+        bi->size = mod;
+    }
+
+    return bi;
+}
+
+/**
+ * @brief Perform a single Barrett reduction.
+ * @param ctx [in]  The bigint session context.
+ * @param bi [in]  A bigint.
+ * @return The result of the Barrett reduction.
+ */
+bigint *bi_barrett(BI_CTX *ctx, bigint *bi)
+{
+    bigint *q1, *q2, *q3, *r1, *r2, *r;
+    uint8_t mod_offset = ctx->mod_offset;
+    bigint *bim = ctx->bi_mod[mod_offset];
+    int k = bim->size;
+
+    check(bi);
+    check(bim);
+
+    /* use Classical method instead  - Barrett cannot help here */
+    if (bi->size > k*2)
+    {
+        return bi_mod(ctx, bi);
+    }
+
+    q1 = comp_right_shift(bi_clone(ctx, bi), k-1);
+
+    /* do outer partial multiply */
+    q2 = regular_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k-1); 
+    q3 = comp_right_shift(q2, k+1);
+    r1 = comp_mod(bi, k+1);
+
+    /* do inner partial multiply */
+    r2 = comp_mod(regular_multiply(ctx, q3, bim, k+1, 0), k+1);
+    r = bi_subtract(ctx, r1, r2, NULL);
+
+    /* if (r >= m) r = r - m; */
+    if (bi_compare(r, bim) >= 0)
+    {
+        r = bi_subtract(ctx, r, bim, NULL);
+    }
+
+    return r;
+}
+#endif /* CONFIG_BIGINT_BARRETT */
+
+#ifdef CONFIG_BIGINT_SLIDING_WINDOW
+/*
+ * Work out g1, g3, g5, g7... etc for the sliding-window algorithm 
+ */
+static void precompute_slide_window(BI_CTX *ctx, int window, bigint *g1)
+{
+    int k = 1, i;
+    bigint *g2;
+
+    for (i = 0; i < window-1; i++)   /* compute 2^(window-1) */
+    {
+        k <<= 1;
+    }
+
+    ctx->g = (bigint **)malloc(k*sizeof(bigint *));
+    ctx->g[0] = bi_clone(ctx, g1);
+    bi_permanent(ctx->g[0]);
+    g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0]));   /* g^2 */
+
+    for (i = 1; i < k; i++)
+    {
+        ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i-1], bi_copy(g2)));
+        bi_permanent(ctx->g[i]);
+    }
+
+    bi_free(ctx, g2);
+    ctx->window = k;
+}
+#endif
+
+/**
+ * @brief Perform a modular exponentiation.
+ *
+ * This function requires bi_set_mod() to have been called previously. This is 
+ * one of the optimisations used for performance.
+ * @param ctx [in]  The bigint session context.
+ * @param bi  [in]  The bigint on which to perform the mod power operation.
+ * @param biexp [in] The bigint exponent.
+ * @return The result of the mod exponentiation operation
+ * @see bi_set_mod().
+ */
+bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp)
+{
+    int i = find_max_exp_index(biexp), j, window_size = 1;
+    bigint *biR = int_to_bi(ctx, 1);
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    uint8_t mod_offset = ctx->mod_offset;
+    if (!ctx->use_classical)
+    {
+        /* preconvert */
+        bi = bi_mont(ctx, 
+                bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset]));    /* x' */
+        bi_free(ctx, biR);
+        biR = ctx->bi_R_mod_m[mod_offset];                              /* A */
+    }
+#endif
+
+    check(bi);
+    check(biexp);
+
+#ifdef CONFIG_BIGINT_SLIDING_WINDOW
+    for (j = i; j > 32; j /= 5) /* work out an optimum size */
+        window_size++;
+
+    /* work out the slide constants */
+    precompute_slide_window(ctx, window_size, bi);
+#else   /* just one constant */
+    ctx->g = (bigint **)malloc(sizeof(bigint *));
+    ctx->g[0] = bi_clone(ctx, bi);
+    ctx->window = 1;
+    bi_permanent(ctx->g[0]);
+#endif
+
+    /* if sliding-window is off, then only one bit will be done at a time and
+     * will reduce to standard left-to-right exponentiation */
+    do
+    {
+        if (exp_bit_is_one(biexp, i))
+        {
+            int l = i-window_size+1;
+            int part_exp = 0;
+
+            if (l < 0)  /* LSB of exponent will always be 1 */
+                l = 0;
+            else
+            {
+                while (exp_bit_is_one(biexp, l) == 0)
+                    l++;    /* go back up */
+            }
+
+            /* build up the section of the exponent */
+            for (j = i; j >= l; j--)
+            {
+                biR = bi_residue(ctx, bi_square(ctx, biR));
+                if (exp_bit_is_one(biexp, j))
+                    part_exp++;
+
+                if (j != l)
+                    part_exp <<= 1;
+            }
+
+            part_exp = (part_exp-1)/2;  /* adjust for array */
+            biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp]));
+            i = l-1;
+        }
+        else    /* square it */
+        {
+            biR = bi_residue(ctx, bi_square(ctx, biR));
+            i--;
+        }
+    } while (i >= 0);
+     
+    /* cleanup */
+    for (i = 0; i < ctx->window; i++)
+    {
+        bi_depermanent(ctx->g[i]);
+        bi_free(ctx, ctx->g[i]);
+    }
+
+    free(ctx->g);
+    bi_free(ctx, bi);
+    bi_free(ctx, biexp);
+#if defined CONFIG_BIGINT_MONTGOMERY
+    return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */
+#else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */
+    return biR;
+#endif
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * @brief Perform a modular exponentiation using a temporary modulus.
+ *
+ * We need this function to check the signatures of certificates. The modulus
+ * of this function is temporary as it's just used for authentication.
+ * @param ctx [in]  The bigint session context.
+ * @param bi  [in]  The bigint to perform the exp/mod.
+ * @param bim [in]  The temporary modulus.
+ * @param biexp [in] The bigint exponent.
+ * @return The result of the mod exponentiation operation
+ * @see bi_set_mod().
+ */
+bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp)
+{
+    bigint *biR, *tmp_biR;
+
+    /* Set up a temporary bigint context and transfer what we need between
+     * them. We need to do this since we want to keep the original modulus
+     * which is already in this context. This operation is only called when
+     * doing peer verification, and so is not expensive :-) */
+    BI_CTX *tmp_ctx = bi_initialize();
+    bi_set_mod(tmp_ctx, bi_clone(tmp_ctx, bim), BIGINT_M_OFFSET);
+    tmp_biR = bi_mod_power(tmp_ctx, 
+                bi_clone(tmp_ctx, bi), 
+                bi_clone(tmp_ctx, biexp));
+    biR = bi_clone(ctx, tmp_biR);
+    bi_free(tmp_ctx, tmp_biR);
+    bi_free_mod(tmp_ctx, BIGINT_M_OFFSET);
+    bi_terminate(tmp_ctx);
+
+    bi_free(ctx, bi);
+    bi_free(ctx, bim);
+    bi_free(ctx, biexp);
+    return biR;
+}
+#endif
+
+#ifdef CONFIG_BIGINT_CRT
+/**
+ * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts.
+ *
+ * @param ctx [in]  The bigint session context.
+ * @param bi  [in]  The bigint to perform the exp/mod.
+ * @param dP [in] CRT's dP bigint
+ * @param dQ [in] CRT's dQ bigint
+ * @param p [in] CRT's p bigint
+ * @param q [in] CRT's q bigint
+ * @param qInv [in] CRT's qInv bigint
+ * @return The result of the CRT operation
+ */
+bigint *bi_crt(BI_CTX *ctx, bigint *bi,
+        bigint *dP, bigint *dQ,
+        bigint *p, bigint *q, bigint *qInv)
+{
+    bigint *m1, *m2, *h;
+
+    /* Montgomery has a condition the 0 < x, y < m and these products violate
+     * that condition. So disable Montgomery when using CRT */
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    ctx->use_classical = 1;
+#endif
+    ctx->mod_offset = BIGINT_P_OFFSET;
+    m1 = bi_mod_power(ctx, bi_copy(bi), dP);
+
+    ctx->mod_offset = BIGINT_Q_OFFSET;
+    m2 = bi_mod_power(ctx, bi, dQ);
+
+    h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL);
+    h = bi_multiply(ctx, h, qInv);
+    ctx->mod_offset = BIGINT_P_OFFSET;
+    h = bi_residue(ctx, h);
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    ctx->use_classical = 0;         /* reset for any further operation */
+#endif
+    return bi_add(ctx, m2, bi_multiply(ctx, q, h));
+}
+#endif
+/** @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/bigint.h	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef BIGINT_HEADER
+#define BIGINT_HEADER
+
+#include "crypto.h"
+
+BI_CTX *bi_initialize(void);
+void bi_terminate(BI_CTX *ctx);
+void bi_permanent(bigint *bi);
+void bi_depermanent(bigint *bi);
+void bi_clear_cache(BI_CTX *ctx);
+void bi_free(BI_CTX *ctx, bigint *bi);
+bigint *bi_copy(bigint *bi);
+bigint *bi_clone(BI_CTX *ctx, const bigint *bi);
+void bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size);
+bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len);
+bigint *int_to_bi(BI_CTX *ctx, comp i);
+
+/* the functions that actually do something interesting */
+bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_subtract(BI_CTX *ctx, bigint *bia, 
+        bigint *bib, int *is_negative);
+bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, int is_mod);
+bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp);
+bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp);
+int bi_compare(bigint *bia, bigint *bib);
+void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset);
+void bi_free_mod(BI_CTX *ctx, int mod_offset);
+
+#ifdef CONFIG_SSL_FULL_MODE
+void bi_print(const char *label, bigint *bi);
+bigint *bi_str_import(BI_CTX *ctx, const char *data);
+#endif
+
+/**
+ * @def bi_mod
+ * Find the residue of B. bi_set_mod() must be called before hand.
+ */
+#define bi_mod(A, B)      bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1)
+
+/**
+ * bi_residue() is technically the same as bi_mod(), but it uses the
+ * appropriate reduction technique (which is bi_mod() when doing classical
+ * reduction).
+ */
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+#define bi_residue(A, B)         bi_mont(A, B)
+bigint *bi_mont(BI_CTX *ctx, bigint *bixy);
+#elif defined(CONFIG_BIGINT_BARRETT)
+#define bi_residue(A, B)         bi_barrett(A, B)
+bigint *bi_barrett(BI_CTX *ctx, bigint *bi);
+#else /* if defined(CONFIG_BIGINT_CLASSICAL) */
+#define bi_residue(A, B)         bi_mod(A, B)
+#endif
+
+#ifdef CONFIG_BIGINT_SQUARE
+bigint *bi_square(BI_CTX *ctx, bigint *bi);
+#else
+#define bi_square(A, B)     bi_multiply(A, bi_copy(B), B)
+#endif
+
+#ifdef CONFIG_BIGINT_CRT
+bigint *bi_crt(BI_CTX *ctx, bigint *bi,
+        bigint *dP, bigint *dQ,
+        bigint *p, bigint *q,
+        bigint *qInv);
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/bigint_impl.h	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef BIGINT_IMPL_HEADER
+#define BIGINT_IMPL_HEADER
+
+/* Maintain a number of precomputed variables when doing reduction */
+#define BIGINT_M_OFFSET     0    /**< Normal modulo offset. */
+#ifdef CONFIG_BIGINT_CRT
+#define BIGINT_P_OFFSET     1    /**< p modulo offset. */
+#define BIGINT_Q_OFFSET     2    /**< q module offset. */
+#define BIGINT_NUM_MODS     3    /**< The number of modulus constants used. */
+#else
+#define BIGINT_NUM_MODS     1    
+#endif
+
+
+/* Architecture specific functions for big ints */
+#if defined(CONFIG_INTEGER_8BIT)
+#define COMP_RADIX          256U       /**< Max component + 1 */
+#define COMP_MAX            0xFFFFU/**< (Max dbl comp -1) */
+#define COMP_BIT_SIZE       8   /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE      1   /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES    2   /**< Used For diagnostics only. */
+typedef uint8_t comp;            /**< A single precision component. */
+typedef uint16_t long_comp;     /**< A double precision component. */
+typedef int16_t slong_comp;     /**< A signed double precision component. */
+#elif defined(CONFIG_INTEGER_16BIT)
+#define COMP_RADIX          65536U       /**< Max component + 1 */
+#define COMP_MAX            0xFFFFFFFFU/**< (Max dbl comp -1) */
+#define COMP_BIT_SIZE       16  /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE      2   /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES    4   /**< Used For diagnostics only. */
+typedef uint16_t comp;            /**< A single precision component. */
+typedef uint32_t long_comp;     /**< A double precision component. */
+typedef int32_t slong_comp;     /**< A signed double precision component. */
+#else /* regular 32 bit */
+#ifdef WIN32
+#define COMP_RADIX          4294967296i64         
+#define COMP_MAX            0xFFFFFFFFFFFFFFFFui64
+#else
+#define COMP_RADIX          4294967296ULL         /**< Max component + 1 */
+#define COMP_MAX            0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */
+#endif
+#define COMP_BIT_SIZE       32  /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE      4   /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES    8   /**< Used For diagnostics only. */
+#include <stdint.h>
+typedef uint32_t comp;            /**< A single precision component. */
+typedef uint64_t long_comp;     /**< A double precision component. */
+typedef int64_t slong_comp;     /**< A signed double precision component. */
+#endif
+
+/**
+ * @struct  _bigint
+ * @brief A big integer basic object
+ */
+struct _bigint
+{
+    struct _bigint* next;       /**< The next bigint in the cache. */
+    short size;                 /**< The number of components in this bigint. */
+    short max_comps;            /**< The heapsize allocated for this bigint */
+    int refs;                   /**< An internal reference count. */
+    comp* comps;                /**< A ptr to the actual component data */
+};
+
+typedef struct _bigint bigint;  /**< An alias for _bigint */
+
+/**
+ * Maintains the state of the cache, and a number of variables used in 
+ * reduction.
+ */
+typedef struct /**< A big integer "session" context. */
+{
+    bigint *active_list;                    /**< Bigints currently used. */
+    bigint *free_list;                      /**< Bigints not used. */
+    bigint *bi_radix;                       /**< The radix used. */
+    bigint *bi_mod[BIGINT_NUM_MODS];        /**< modulus */
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    bigint *bi_RR_mod_m[BIGINT_NUM_MODS];   /**< R^2 mod m */
+    bigint *bi_R_mod_m[BIGINT_NUM_MODS];    /**< R mod m */
+    comp N0_dash[BIGINT_NUM_MODS];
+#elif defined(CONFIG_BIGINT_BARRETT)
+    bigint *bi_mu[BIGINT_NUM_MODS];         /**< Storage for mu */
+#endif
+    bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */
+    bigint **g;                 /**< Used by sliding-window. */
+    int window;                 /**< The size of the sliding window */
+    int active_count;           /**< Number of active bigints. */
+    int free_count;             /**< Number of free bigints. */
+
+#ifdef CONFIG_BIGINT_MONTGOMERY
+    uint8_t use_classical;      /**< Use classical reduction. */
+#endif
+    uint8_t mod_offset;         /**< The mod offset we are using */
+} BI_CTX;
+
+#ifndef WIN32
+#define max(a,b) ((a)>(b)?(a):(b))  /**< Find the maximum of 2 numbers. */
+#define min(a,b) ((a)<(b)?(a):(b))  /**< Find the minimum of 2 numbers. */
+#endif
+
+#define PERMANENT           0x7FFF55AA  /**< A magic number for permanents. */
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/crypto.h	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * @file crypto.h
+ */
+
+#ifndef HEADER_CRYPTO_H
+#define HEADER_CRYPTO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "bigint_impl.h"
+#include "bigint.h"
+
+#ifndef STDCALL
+#define STDCALL
+#endif
+#ifndef EXP_FUNC
+#define EXP_FUNC
+#endif
+
+
+/* enable features based on a 'super-set' capbaility. */
+#if defined(CONFIG_SSL_FULL_MODE) 
+#define CONFIG_SSL_ENABLE_CLIENT
+#define CONFIG_SSL_CERT_VERIFICATION
+#elif defined(CONFIG_SSL_ENABLE_CLIENT)
+#define CONFIG_SSL_CERT_VERIFICATION
+#endif
+
+/**************************************************************************
+ * AES declarations 
+ **************************************************************************/
+
+#define AES_MAXROUNDS            14
+#define AES_BLOCKSIZE           16
+#define AES_IV_SIZE             16
+
+typedef struct aes_key_st 
+{
+    uint16_t rounds;
+    uint16_t key_size;
+    uint32_t ks[(AES_MAXROUNDS+1)*8];
+    uint8_t iv[AES_IV_SIZE];
+} AES_CTX;
+
+typedef enum
+{
+    AES_MODE_128,
+    AES_MODE_256
+} AES_MODE;
+
+void AES_set_key(AES_CTX *ctx, const uint8_t *key, 
+        const uint8_t *iv, AES_MODE mode);
+void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, 
+        uint8_t *out, int length);
+void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length);
+void AES_convert_key(AES_CTX *ctx);
+
+/**************************************************************************
+ * RC4 declarations 
+ **************************************************************************/
+
+typedef struct 
+{
+    uint8_t x, y, m[256];
+} RC4_CTX;
+
+void RC4_setup(RC4_CTX *s, const uint8_t *key, int length);
+void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length);
+
+/**************************************************************************
+ * SHA1 declarations 
+ **************************************************************************/
+
+#define SHA1_SIZE   20
+
+/*
+ *  This structure will hold context information for the SHA-1
+ *  hashing operation
+ */
+typedef struct 
+{
+    uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */
+    uint32_t Length_Low;            /* Message length in bits */
+    uint32_t Length_High;           /* Message length in bits */
+    uint16_t Message_Block_Index;   /* Index into message block array   */
+    uint8_t Message_Block[64];      /* 512-bit message blocks */
+} SHA1_CTX;
+
+void SHA1_Init(SHA1_CTX *);
+void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len);
+void SHA1_Final(uint8_t *digest, SHA1_CTX *);
+
+/**************************************************************************
+ * MD2 declarations 
+ **************************************************************************/
+
+#define MD2_SIZE 16
+
+typedef struct
+{
+    unsigned char cksum[16];    /* checksum of the data block */
+    unsigned char state[48];    /* intermediate digest state */
+    unsigned char buffer[16];   /* data block being processed */
+    int left;                   /* amount of data in buffer */
+} MD2_CTX;
+
+EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx);
+EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen);
+EXP_FUNC void STDCALL MD2_Final(uint8_t *digest, MD2_CTX *ctx);
+
+/**************************************************************************
+ * MD5 declarations 
+ **************************************************************************/
+
+#define MD5_SIZE    16
+
+typedef struct 
+{
+  uint32_t state[4];        /* state (ABCD) */
+  uint32_t count[2];        /* number of bits, modulo 2^64 (lsb first) */
+  uint8_t buffer[64];       /* input buffer */
+} MD5_CTX;
+
+EXP_FUNC void STDCALL MD5_Init(MD5_CTX *);
+EXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len);
+EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *);
+
+/**************************************************************************
+ * HMAC declarations 
+ **************************************************************************/
+void hmac_md5(const uint8_t *msg, int length, const uint8_t *key, 
+        int key_len, uint8_t *digest);
+void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, 
+        int key_len, uint8_t *digest);
+
+/**************************************************************************
+ * RSA declarations 
+ **************************************************************************/
+
+typedef struct 
+{
+    bigint *m;              /* modulus */
+    bigint *e;              /* public exponent */
+    bigint *d;              /* private exponent */
+#ifdef CONFIG_BIGINT_CRT
+    bigint *p;              /* p as in m = pq */
+    bigint *q;              /* q as in m = pq */
+    bigint *dP;             /* d mod (p-1) */
+    bigint *dQ;             /* d mod (q-1) */
+    bigint *qInv;           /* q^-1 mod p */
+#endif
+    int num_octets;
+    BI_CTX *bi_ctx;
+} RSA_CTX;
+
+void RSA_priv_key_new(RSA_CTX **rsa_ctx, 
+        const uint8_t *modulus, int mod_len,
+        const uint8_t *pub_exp, int pub_len,
+        const uint8_t *priv_exp, int priv_len
+#ifdef CONFIG_BIGINT_CRT
+      , const uint8_t *p, int p_len,
+        const uint8_t *q, int q_len,
+        const uint8_t *dP, int dP_len,
+        const uint8_t *dQ, int dQ_len,
+        const uint8_t *qInv, int qInv_len
+#endif
+        );
+void RSA_pub_key_new(RSA_CTX **rsa_ctx, 
+        const uint8_t *modulus, int mod_len,
+        const uint8_t *pub_exp, int pub_len);
+void RSA_free(RSA_CTX *ctx);
+int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
+        int is_decryption);
+bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg);
+#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
+bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
+        bigint *modulus, bigint *pub_exp);
+bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg);
+int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, 
+        uint8_t *out_data, int is_signing);
+void RSA_print(const RSA_CTX *ctx);
+#endif
+
+/**************************************************************************
+ * RNG declarations 
+ **************************************************************************/
+EXP_FUNC void STDCALL RNG_initialize(void);
+EXP_FUNC void STDCALL RNG_custom_init(const uint8_t *seed_buf, int size);
+EXP_FUNC void STDCALL RNG_terminate(void);
+EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data);
+void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/crypto_misc.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * Some misc. routines to help things out
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include "os_port.h"
+#include <lwip/def.h>
+#include "sockets.h"
+#include "crypto_misc.h"
+#include "config.h"
+
+#include <time.h>
+#ifdef CONFIG_WIN32_USE_CRYPTO_LIB
+#include "wincrypt.h"
+#endif
+
+#ifndef WIN32
+static int rng_fd = -1;
+#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
+static HCRYPTPROV gCryptProv;
+#endif
+
+#if (!defined(CONFIG_USE_DEV_URANDOM) && !defined(CONFIG_WIN32_USE_CRYPTO_LIB))
+/* change to processor registers as appropriate */
+#define ENTROPY_POOL_SIZE 32
+#define ENTROPY_COUNTER1 ((((uint64_t)tv.tv_sec)<<32) | tv.tv_usec)
+#define ENTROPY_COUNTER2 rand()
+static uint8_t entropy_pool[ENTROPY_POOL_SIZE];
+#endif
+
+const char * const unsupported_str = "Error: Feature not supported\n";
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+/** 
+ * Retrieve a file and put it into memory
+ * @return The size of the file, or -1 on failure.
+ */
+int get_file(const char *filename, uint8_t **buf)
+{
+    int total_bytes = 0;
+    int bytes_read = 0; 
+    int filesize;
+    FILE *stream = fopen(filename, "rb");
+
+    if (stream == NULL)
+    {
+#ifdef CONFIG_SSL_FULL_MODE         
+        printf("file '%s' does not exist\n", filename); TTY_FLUSH();
+#endif
+        return -1;
+    }
+
+    /* Win CE doesn't support stat() */
+    fseek(stream, 0, SEEK_END);
+    filesize = ftell(stream);
+    *buf = (uint8_t *)malloc(filesize);
+    fseek(stream, 0, SEEK_SET);
+
+    do
+    {
+        bytes_read = fread(*buf+total_bytes, 1, filesize-total_bytes, stream);
+        total_bytes += bytes_read;
+    } while (total_bytes < filesize && bytes_read > 0);
+    
+    fclose(stream);
+    return filesize;
+}
+#endif
+
+/**
+ * Initialise the Random Number Generator engine.
+ * - On Win32 use the platform SDK's crypto engine.
+ * - On Linux use /dev/urandom
+ * - If none of these work then use a custom RNG.
+ */
+EXP_FUNC void STDCALL RNG_initialize()
+{
+#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
+    rng_fd = ax_open("/dev/urandom", O_RDONLY);
+#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
+    if (!CryptAcquireContext(&gCryptProv, 
+                      NULL, NULL, PROV_RSA_FULL, 0))
+    {
+        if (GetLastError() == NTE_BAD_KEYSET &&
+                !CryptAcquireContext(&gCryptProv, 
+                       NULL, 
+                       NULL, 
+                       PROV_RSA_FULL, 
+                       CRYPT_NEWKEYSET))
+        {
+            printf("CryptoLib: %x\n", unsupported_str, GetLastError());
+            exit(1);
+        }
+    }
+#else
+    /* start of with a stack to copy across */
+    int i;
+    memcpy(entropy_pool, &i, ENTROPY_POOL_SIZE);
+    srand((unsigned int)&i); 
+#endif
+}
+
+/**
+ * If no /dev/urandom, then initialise the RNG with something interesting.
+ */
+EXP_FUNC void STDCALL RNG_custom_init(const uint8_t *seed_buf, int size)
+{
+#if defined(WIN32) || defined(CONFIG_WIN32_USE_CRYPTO_LIB)
+    int i;
+
+    for (i = 0; i < ENTROPY_POOL_SIZE && i < size; i++)
+        entropy_pool[i] ^= seed_buf[i];
+#endif
+}
+
+/**
+ * Terminate the RNG engine.
+ */
+EXP_FUNC void STDCALL RNG_terminate(void)
+{
+#ifndef WIN32
+    //close(rng_fd);
+#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
+    CryptReleaseContext(gCryptProv, 0);
+#endif
+}
+
+/**
+ * Set a series of bytes with a random number. Individual bytes can be 0
+ */
+EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data)
+{   
+#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
+    /* use the Linux default */
+    read(rng_fd, rand_data, num_rand_bytes);    /* read from /dev/urandom */
+#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
+    /* use Microsoft Crypto Libraries */
+    CryptGenRandom(gCryptProv, num_rand_bytes, rand_data);
+#else   /* nothing else to use, so use a custom RNG */
+    /* The method we use when we've got nothing better. Use RC4, time 
+       and a couple of random seeds to generate a random sequence */
+    RC4_CTX rng_ctx;
+    struct timeval tv;
+    MD5_CTX rng_digest_ctx;
+    uint8_t digest[MD5_SIZE];
+    uint64_t *ep;
+    int i;
+
+    /* A proper implementation would use counters etc for entropy */
+    // XXX XXX XX X need to seed this properly
+    gettimeofday(&tv, NULL);    
+    ep = (uint64_t *)entropy_pool;
+    
+    ep[0] ^= ENTROPY_COUNTER1;
+    ep[1] ^= ENTROPY_COUNTER2; 
+    
+
+    /* use a digested version of the entropy pool as a key */
+    MD5_Init(&rng_digest_ctx);
+    MD5_Update(&rng_digest_ctx, entropy_pool, ENTROPY_POOL_SIZE);
+    MD5_Final(digest, &rng_digest_ctx);
+
+    /* come up with the random sequence */
+    RC4_setup(&rng_ctx, digest, MD5_SIZE); /* use as a key */
+    memcpy(rand_data, entropy_pool, num_rand_bytes < ENTROPY_POOL_SIZE ?
+                num_rand_bytes : ENTROPY_POOL_SIZE);
+    RC4_crypt(&rng_ctx, rand_data, rand_data, num_rand_bytes);
+
+    /* move things along */
+    for (i = ENTROPY_POOL_SIZE-1; i >= MD5_SIZE ; i--)
+        entropy_pool[i] = entropy_pool[i-MD5_SIZE];
+
+    /* insert the digest at the start of the entropy pool */
+    memcpy(entropy_pool, digest, MD5_SIZE);
+#endif
+}
+
+/**
+ * Set a series of bytes with a random number. Individual bytes are not zero.
+ */
+void get_random_NZ(int num_rand_bytes, uint8_t *rand_data)
+{
+    int i;
+    get_random(num_rand_bytes, rand_data);
+
+    for (i = 0; i < num_rand_bytes; i++)
+    {
+        while (rand_data[i] == 0)  /* can't be 0 */
+            rand_data[i] = (uint8_t)(rand());
+    }
+}
+
+/**
+ * Some useful diagnostic routines
+ */
+#if defined(CONFIG_SSL_FULL_MODE) || defined(CONFIG_DEBUG)
+int hex_finish;
+int hex_index;
+
+static void print_hex_init(int finish)
+{
+    hex_finish = finish;
+    hex_index = 0;
+}
+
+static void print_hex(uint8_t hex)
+{
+    static int column;
+
+    if (hex_index == 0)
+    {
+        column = 0;
+    }
+
+    printf("%02x ", hex);
+    if (++column == 8)
+    {
+        printf(": ");
+    }
+    else if (column >= 16)
+    {
+        printf("\r\n");
+        column = 0;
+    }
+
+    if (++hex_index >= hex_finish && column > 0)
+    {
+        printf("\r\n");
+    }
+}
+
+/**
+ * Spit out a blob of data for diagnostics. The data is is a nice column format
+ * for easy reading.
+ *
+ * @param format   [in]    The string (with possible embedded format characters)
+ * @param size     [in]    The number of numbers to print
+ * @param data     [in]    The start of data to use
+ * @param ...      [in]    Any additional arguments
+ */
+EXP_FUNC void STDCALL print_blob(const char *format, 
+        const uint8_t *data, int size, ...)
+{
+    int i;
+    char tmp[80];
+    va_list(ap);
+
+    va_start(ap, size);
+    sprintf(tmp, "%s\n", format);
+    vprintf(tmp, ap);
+    print_hex_init(size);
+    for (i = 0; i < size; i++)
+    {
+        print_hex(data[i]);
+    }
+
+    va_end(ap);
+    TTY_FLUSH();
+}
+#elif defined(WIN32)
+/* VC6.0 doesn't handle variadic macros */
+EXP_FUNC void STDCALL print_blob(const char *format, const unsigned char *data,
+        int size, ...) {}
+#endif
+
+#if defined(CONFIG_SSL_HAS_PEM) || defined(CONFIG_HTTP_HAS_AUTHORIZATION)
+/* base64 to binary lookup table */
+static const uint8_t map[128] =
+{
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
+    52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
+    255, 254, 255, 255, 255,   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, 255, 255, 255, 255, 255,
+    255,  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, 255, 255, 255, 255, 255
+};
+
+EXP_FUNC int STDCALL base64_decode(const char *in, int len,
+                    uint8_t *out, int *outlen)
+{
+    int g, t, x, y, z;
+    uint8_t c;
+    int ret = -1;
+
+    g = 3;
+    for (x = y = z = t = 0; x < len; x++)
+    {
+        if ((c = map[in[x]&0x7F]) == 0xff)
+            continue;
+
+        if (c == 254)   /* this is the end... */
+        {
+            c = 0;
+
+            if (--g < 0)
+                goto error;
+        }
+        else if (g != 3) /* only allow = at end */
+            goto error;
+
+        t = (t<<6) | c;
+
+        if (++y == 4)
+        {
+            out[z++] = (uint8_t)((t>>16)&255);
+
+            if (g > 1)
+                out[z++] = (uint8_t)((t>>8)&255);
+
+            if (g > 2)
+                out[z++] = (uint8_t)(t&255);
+
+            y = t = 0;
+        }
+
+        /* check that we don't go past the output buffer */
+        if (z > *outlen) 
+            goto error;
+    }
+
+    if (y != 0)
+        goto error;
+
+    *outlen = z;
+    ret = 0;
+
+error:
+#ifdef CONFIG_SSL_FULL_MODE
+    if (ret < 0)
+        printf("Error: Invalid base64\n"); TTY_FLUSH();
+#endif
+    TTY_FLUSH();
+    return ret;
+
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/hmac.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * HMAC implementation - This code was originally taken from RFC2104
+ * See http://www.ietf.org/rfc/rfc2104.txt and
+ * http://www.faqs.org/rfcs/rfc2202.html
+ */
+
+#include <string.h>
+#include "os_port.h"
+#include "crypto.h"
+
+/**
+ * Perform HMAC-MD5
+ * NOTE: does not handle keys larger than the block size.
+ */
+void hmac_md5(const uint8_t *msg, int length, const uint8_t *key, 
+        int key_len, uint8_t *digest)
+{
+    MD5_CTX context;
+    uint8_t k_ipad[64];
+    uint8_t k_opad[64];
+    int i;
+
+    memset(k_ipad, 0, sizeof k_ipad);
+    memset(k_opad, 0, sizeof k_opad);
+    memcpy(k_ipad, key, key_len);
+    memcpy(k_opad, key, key_len);
+
+    for (i = 0; i < 64; i++) 
+    {
+        k_ipad[i] ^= 0x36;
+        k_opad[i] ^= 0x5c;
+    }
+
+    MD5_Init(&context);
+    MD5_Update(&context, k_ipad, 64);
+    MD5_Update(&context, msg, length);
+    MD5_Final(digest, &context);
+    MD5_Init(&context);
+    MD5_Update(&context, k_opad, 64);
+    MD5_Update(&context, digest, MD5_SIZE);
+    MD5_Final(digest, &context);
+}
+
+/**
+ * Perform HMAC-SHA1
+ * NOTE: does not handle keys larger than the block size.
+ */
+void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, 
+        int key_len, uint8_t *digest)
+{
+    SHA1_CTX context;
+    uint8_t k_ipad[64];
+    uint8_t k_opad[64];
+    int i;
+
+    memset(k_ipad, 0, sizeof k_ipad);
+    memset(k_opad, 0, sizeof k_opad);
+    memcpy(k_ipad, key, key_len);
+    memcpy(k_opad, key, key_len);
+
+    for (i = 0; i < 64; i++) 
+    {
+        k_ipad[i] ^= 0x36;
+        k_opad[i] ^= 0x5c;
+    }
+
+    SHA1_Init(&context);
+    SHA1_Update(&context, k_ipad, 64);
+    SHA1_Update(&context, msg, length);
+    SHA1_Final(digest, &context);
+    SHA1_Init(&context);
+    SHA1_Update(&context, k_opad, 64);
+    SHA1_Update(&context, digest, SHA1_SIZE);
+    SHA1_Final(digest, &context);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/md2.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/*
+ *  RFC 1115/1319 compliant MD2 implementation
+ *  The MD2 algorithm was designed by Ron Rivest in 1989.
+ *
+ *  http://www.ietf.org/rfc/rfc1115.txt
+ *  http://www.ietf.org/rfc/rfc1319.txt
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include "os_port.h"
+#include "crypto.h"
+#include "config.h"
+
+/**
+ * This code is only here to enable the verification of Verisign root
+ * certificates. So only enable it for verification mode.
+ */
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+
+static const uint8_t PI_SUBST[256] =
+{
+    0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36,
+    0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3,
+    0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C,
+    0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16,
+    0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 0xBE, 0x4E,
+    0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E,
+    0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2,
+    0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
+    0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E,
+    0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 0xFF, 0x19, 0x30, 0xB3,
+    0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56,
+    0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6,
+    0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D,
+    0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65,
+    0xE6, 0x2D, 0xA8, 0x02, 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0,
+    0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
+    0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C,
+    0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E,
+    0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81,
+    0x4D, 0x52, 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA,
+    0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88,
+    0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE,
+    0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58,
+    0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
+    0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99,
+    0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14
+};
+
+/*
+ * MD2 context setup
+ */
+EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx)
+{
+    memset(ctx, 0, sizeof *ctx);
+}
+
+static void md2_process(MD2_CTX *ctx)
+{
+    int i, j;
+    uint8_t t = 0;
+
+    for (i = 0; i < 16; i++)
+    {
+        ctx->state[i + 16] = ctx->buffer[i];
+        ctx->state[i + 32] = ctx->buffer[i] ^ ctx->state[i];
+    }
+
+    for (i = 0; i < 18; i++)
+    {
+        for (j = 0; j < 48; j++)
+            t = (ctx->state[j] ^= PI_SUBST[t]);
+
+        t = (t + i) & 0xFF;
+    }
+
+    t = ctx->cksum[15];
+
+    for (i = 0; i < 16; i++)
+        t = (ctx->cksum[i] ^= PI_SUBST[ctx->buffer[i] ^ t]);
+}
+
+/*
+ * MD2 process buffer
+ */
+EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen)
+{
+    int fill;
+
+    while (ilen > 0)
+    {
+        if (ctx->left + ilen > 16)
+            fill = 16 - ctx->left;
+        else
+            fill = ilen;
+
+        memcpy(ctx->buffer + ctx->left, input, fill);
+
+        ctx->left += fill;
+        input += fill;
+        ilen  -= fill;
+
+        if (ctx->left == 16)
+        {
+            ctx->left = 0;
+            md2_process(ctx);
+        }
+    }
+}
+
+/*
+ * MD2 final digest
+ */
+EXP_FUNC void STDCALL MD2_Final(uint8_t *output, MD2_CTX *ctx)
+{
+    int i;
+    uint8_t x;
+
+    x = (uint8_t)(16 - ctx->left);
+
+    for (i = ctx->left; i < 16; i++)
+        ctx->buffer[i] = x;
+
+    md2_process(ctx);
+
+    memcpy(ctx->buffer, ctx->cksum, 16);
+    md2_process(ctx);
+
+    memcpy(output, ctx->state, 16);
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/md5.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * This file implements the MD5 algorithm as defined in RFC1321
+ */
+
+#include <string.h>
+#include "os_port.h"
+#include "crypto.h"
+
+/* Constants for MD5Transform routine.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+/* ----- static functions ----- */
+static void MD5Transform(uint32_t state[4], const uint8_t block[64]);
+static void Encode(uint8_t *output, uint32_t *input, uint32_t len);
+static void Decode(uint32_t *output, const uint8_t *input, uint32_t len);
+
+static const uint8_t PADDING[64] = 
+{
+    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.  */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+   Rotation is separate from addition to prevent recomputation.  */
+#define FF(a, b, c, d, x, s, ac) { \
+    (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) { \
+    (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) { \
+    (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) { \
+    (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+
+/**
+ * MD5 initialization - begins an MD5 operation, writing a new ctx.
+ */
+EXP_FUNC void STDCALL MD5_Init(MD5_CTX *ctx)
+{
+    ctx->count[0] = ctx->count[1] = 0;
+
+    /* Load magic initialization constants.
+     */
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xefcdab89;
+    ctx->state[2] = 0x98badcfe;
+    ctx->state[3] = 0x10325476;
+}
+
+/**
+ * Accepts an array of octets as the next portion of the message.
+ */
+EXP_FUNC void STDCALL MD5_Update(MD5_CTX *ctx, const uint8_t * msg, int len)
+{
+    uint32_t x;
+    int i, partLen;
+
+    /* Compute number of bytes mod 64 */
+    x = (uint32_t)((ctx->count[0] >> 3) & 0x3F);
+
+    /* Update number of bits */
+    if ((ctx->count[0] += ((uint32_t)len << 3)) < ((uint32_t)len << 3))
+        ctx->count[1]++;
+    ctx->count[1] += ((uint32_t)len >> 29);
+
+    partLen = 64 - x;
+
+    /* Transform as many times as possible.  */
+    if (len >= partLen) 
+    {
+        memcpy(&ctx->buffer[x], msg, partLen);
+        MD5Transform(ctx->state, ctx->buffer);
+
+        for (i = partLen; i + 63 < len; i += 64)
+            MD5Transform(ctx->state, &msg[i]);
+
+        x = 0;
+    }
+    else
+        i = 0;
+
+    /* Buffer remaining input */
+    memcpy(&ctx->buffer[x], &msg[i], len-i);
+}
+
+/**
+ * Return the 128-bit message digest into the user's array
+ */
+EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *ctx)
+{
+    uint8_t bits[8];
+    uint32_t x, padLen;
+
+    /* Save number of bits */
+    Encode(bits, ctx->count, 8);
+
+    /* Pad out to 56 mod 64.
+     */
+    x = (uint32_t)((ctx->count[0] >> 3) & 0x3f);
+    padLen = (x < 56) ? (56 - x) : (120 - x);
+    MD5_Update(ctx, PADDING, padLen);
+
+    /* Append length (before padding) */
+    MD5_Update(ctx, bits, 8);
+
+    /* Store state in digest */
+    Encode(digest, ctx->state, MD5_SIZE);
+}
+
+/**
+ * MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform(uint32_t state[4], const uint8_t block[64])
+{
+    uint32_t a = state[0], b = state[1], c = state[2], 
+             d = state[3], x[MD5_SIZE];
+
+    Decode(x, block, 64);
+
+    /* Round 1 */
+    FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+    FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+    FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+    FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+    FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+    FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+    FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+    FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+    FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+    FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+    FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+    FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+    FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+    FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+    FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+    FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+    /* Round 2 */
+    GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+    GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+    GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+    GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+    GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+    GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+    GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+    GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+    GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+    GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+    GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+    GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+    GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+    GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+    GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+    GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+    /* Round 3 */
+    HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+    HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+    HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+    HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+    HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+    HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+    HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+    HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+    HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+    HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+    HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+    HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+    HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+    HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+    HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+    HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+    /* Round 4 */
+    II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+    II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+    II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+    II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+    II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+    II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+    II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+    II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+    II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+    II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+    II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+    II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+    II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+    II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+    II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+    II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+}
+
+/**
+ * Encodes input (uint32_t) into output (uint8_t). Assumes len is
+ *   a multiple of 4.
+ */
+static void Encode(uint8_t *output, uint32_t *input, uint32_t len)
+{
+    uint32_t i, j;
+
+    for (i = 0, j = 0; j < len; i++, j += 4) 
+    {
+        output[j] = (uint8_t)(input[i] & 0xff);
+        output[j+1] = (uint8_t)((input[i] >> 8) & 0xff);
+        output[j+2] = (uint8_t)((input[i] >> 16) & 0xff);
+        output[j+3] = (uint8_t)((input[i] >> 24) & 0xff);
+    }
+}
+
+/**
+ *  Decodes input (uint8_t) into output (uint32_t). Assumes len is
+ *   a multiple of 4.
+ */
+static void Decode(uint32_t *output, const uint8_t *input, uint32_t len)
+{
+    uint32_t i, j;
+
+    for (i = 0, j = 0; j < len; i++, j += 4)
+        output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) |
+            (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/os_int.h	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * @file os_int.h
+ *
+ * Ensure a consistent bit size 
+ */
+
+#ifndef HEADER_OS_INT_H
+#define HEADER_OS_INT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(WIN32)
+typedef UINT8 uint8_t;
+typedef INT8 int8_t;
+typedef UINT16 uint16_t;
+typedef INT16 int16_t;
+typedef UINT32 uint32_t;
+typedef INT32 int32_t;
+typedef UINT64 uint64_t;
+typedef INT64 int64_t;
+#else   /* Not Win32 */
+
+#ifdef CONFIG_PLATFORM_SOLARIS
+#include <inttypes.h>
+#else
+#include <stdint.h>
+#endif /* Not Solaris */
+
+#endif /* Not Win32 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/rc4.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * An implementation of the RC4/ARC4 algorithm.
+ * Originally written by Christophe Devine.
+ */
+
+#include <string.h>
+#include "os_port.h"
+#include "crypto.h"
+
+/**
+ * Get ready for an encrypt/decrypt operation
+ */
+void RC4_setup(RC4_CTX *ctx, const uint8_t *key, int length)
+{
+    int i, j = 0, k = 0, a;
+    uint8_t *m;
+
+    ctx->x = 0;
+    ctx->y = 0;
+    m = ctx->m;
+
+    for (i = 0; i < 256; i++)
+        m[i] = i;
+
+    for (i = 0; i < 256; i++)
+    {
+        a = m[i];
+        j = (uint8_t)(j + a + key[k]);
+        m[i] = m[j]; 
+        m[j] = a;
+
+        if (++k >= length) 
+            k = 0;
+    }
+}
+
+/**
+ * Perform the encrypt/decrypt operation (can use it for either since
+ * this is a stream cipher).
+ * NOTE: *msg and *out must be the same pointer (performance tweak)
+ */
+void RC4_crypt(RC4_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
+{ 
+    int i;
+    uint8_t *m, x, y, a, b;
+
+    x = ctx->x;
+    y = ctx->y;
+    m = ctx->m;
+
+    for (i = 0; i < length; i++)
+    {
+        a = m[++x];
+        y += a;
+        m[x] = b = m[y];
+        m[y] = a;
+        out[i] ^= m[(uint8_t)(a + b)];
+    }
+
+    ctx->x = x;
+    ctx->y = y;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/rsa.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * Implements the RSA public encryption algorithm. Uses the bigint library to
+ * perform its calculations.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include "os_port.h"
+#include "crypto.h"
+
+void RSA_priv_key_new(RSA_CTX **ctx, 
+        const uint8_t *modulus, int mod_len,
+        const uint8_t *pub_exp, int pub_len,
+        const uint8_t *priv_exp, int priv_len
+#if CONFIG_BIGINT_CRT
+      , const uint8_t *p, int p_len,
+        const uint8_t *q, int q_len,
+        const uint8_t *dP, int dP_len,
+        const uint8_t *dQ, int dQ_len,
+        const uint8_t *qInv, int qInv_len
+#endif
+    )
+{
+    RSA_CTX *rsa_ctx;
+    BI_CTX *bi_ctx;
+    RSA_pub_key_new(ctx, modulus, mod_len, pub_exp, pub_len);
+    rsa_ctx = *ctx;
+    bi_ctx = rsa_ctx->bi_ctx;
+    rsa_ctx->d = bi_import(bi_ctx, priv_exp, priv_len);
+    bi_permanent(rsa_ctx->d);
+
+#ifdef CONFIG_BIGINT_CRT
+    rsa_ctx->p = bi_import(bi_ctx, p, p_len);
+    rsa_ctx->q = bi_import(bi_ctx, q, q_len);
+    rsa_ctx->dP = bi_import(bi_ctx, dP, dP_len);
+    rsa_ctx->dQ = bi_import(bi_ctx, dQ, dQ_len);
+    rsa_ctx->qInv = bi_import(bi_ctx, qInv, qInv_len);
+    bi_permanent(rsa_ctx->dP);
+    bi_permanent(rsa_ctx->dQ);
+    bi_permanent(rsa_ctx->qInv);
+    bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET);
+    bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET);
+#endif
+}
+
+void RSA_pub_key_new(RSA_CTX **ctx, 
+        const uint8_t *modulus, int mod_len,
+        const uint8_t *pub_exp, int pub_len)
+{
+    RSA_CTX *rsa_ctx;
+    BI_CTX *bi_ctx;
+
+    if (*ctx)   /* if we load multiple certs, dump the old one */
+        RSA_free(*ctx);
+
+    bi_ctx = bi_initialize();
+    *ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX));
+    rsa_ctx = *ctx;
+    rsa_ctx->bi_ctx = bi_ctx;
+    rsa_ctx->num_octets = mod_len;
+    rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len);
+    bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET);
+    rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len);
+    bi_permanent(rsa_ctx->e);
+}
+
+/**
+ * Free up any RSA context resources.
+ */
+void RSA_free(RSA_CTX *rsa_ctx)
+{
+    BI_CTX *bi_ctx;
+    if (rsa_ctx == NULL)                /* deal with ptrs that are null */
+        return;
+
+    bi_ctx = rsa_ctx->bi_ctx;
+
+    bi_depermanent(rsa_ctx->e);
+    bi_free(bi_ctx, rsa_ctx->e);
+    bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET);
+
+    if (rsa_ctx->d)
+    {
+        bi_depermanent(rsa_ctx->d);
+        bi_free(bi_ctx, rsa_ctx->d);
+#ifdef CONFIG_BIGINT_CRT
+        bi_depermanent(rsa_ctx->dP);
+        bi_depermanent(rsa_ctx->dQ);
+        bi_depermanent(rsa_ctx->qInv);
+        bi_free(bi_ctx, rsa_ctx->dP);
+        bi_free(bi_ctx, rsa_ctx->dQ);
+        bi_free(bi_ctx, rsa_ctx->qInv);
+        bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET);
+        bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET);
+#endif
+    }
+
+    bi_terminate(bi_ctx);
+    free(rsa_ctx);
+}
+
+/**
+ * @brief Use PKCS1.5 for decryption/verification.
+ * @param ctx [in] The context
+ * @param in_data [in] The data to encrypt (must be < modulus size-11)
+ * @param out_data [out] The encrypted data.
+ * @param is_decryption [in] Decryption or verify operation.
+ * @return  The number of bytes that were originally encrypted. -1 on error.
+ * @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
+ */
+int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, 
+                            uint8_t *out_data, int is_decryption)
+{
+    const int byte_size = ctx->num_octets;
+    int i, size;
+    bigint *decrypted_bi, *dat_bi;
+    uint8_t *block = (uint8_t *)alloca(byte_size);
+
+    memset(out_data, 0, byte_size); /* initialise */
+
+    /* decrypt */
+    dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+    decrypted_bi = is_decryption ?  /* decrypt or verify? */
+            RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi);
+#else   /* always a decryption */
+    decrypted_bi = RSA_private(ctx, dat_bi);
+#endif
+
+    /* convert to a normal block */
+    bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size);
+
+    i = 10; /* start at the first possible non-padded byte */
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+    if (is_decryption == 0) /* PKCS1.5 signing pads with "0xff"s */
+    {
+        while (block[i++] == 0xff && i < byte_size);
+
+        if (block[i-2] != 0xff)
+            i = byte_size;     /*ensure size is 0 */   
+    }
+    else                    /* PKCS1.5 encryption padding is random */
+#endif
+    {
+        while (block[i++] && i < byte_size);
+    }
+    size = byte_size - i;
+
+    /* get only the bit we want */
+    if (size > 0)
+        memcpy(out_data, &block[i], size);
+    
+    return size ? size : -1;
+}
+
+/**
+ * Performs m = c^d mod n
+ */
+bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg)
+{
+#ifdef CONFIG_BIGINT_CRT
+    return bi_crt(c->bi_ctx, bi_msg, c->dP, c->dQ, c->p, c->q, c->qInv);
+#else
+    BI_CTX *ctx = c->bi_ctx;
+    ctx->mod_offset = BIGINT_M_OFFSET;
+    return bi_mod_power(ctx, bi_msg, c->d);
+#endif
+}
+
+#ifdef CONFIG_SSL_FULL_MODE
+/**
+ * Used for diagnostics.
+ */
+void RSA_print(const RSA_CTX *rsa_ctx) 
+{
+    if (rsa_ctx == NULL)
+        return;
+
+    printf("-----------------   RSA DEBUG   ----------------\n");
+    printf("Size:\t%d\n", rsa_ctx->num_octets);
+    bi_print("Modulus", rsa_ctx->m);
+    bi_print("Public Key", rsa_ctx->e);
+    bi_print("Private Key", rsa_ctx->d);
+}
+#endif
+
+#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
+/**
+ * Performs c = m^e mod n
+ */
+bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg)
+{
+    c->bi_ctx->mod_offset = BIGINT_M_OFFSET;
+    return bi_mod_power(c->bi_ctx, bi_msg, c->e);
+}
+
+/**
+ * Use PKCS1.5 for encryption/signing.
+ * see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
+ */
+int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, 
+        uint8_t *out_data, int is_signing)
+{
+    int byte_size = ctx->num_octets;
+    int num_pads_needed = byte_size-in_len-3;
+    bigint *dat_bi, *encrypt_bi;
+
+    /* note: in_len+11 must be > byte_size */
+    out_data[0] = 0;     /* ensure encryption block is < modulus */
+
+    if (is_signing)
+    {
+        out_data[1] = 1;        /* PKCS1.5 signing pads with "0xff"'s */
+        memset(&out_data[2], 0xff, num_pads_needed);
+    }
+    else /* randomize the encryption padding with non-zero bytes */   
+    {
+        out_data[1] = 2;
+        get_random_NZ(num_pads_needed, &out_data[2]);
+    }
+
+    out_data[2+num_pads_needed] = 0;
+    memcpy(&out_data[3+num_pads_needed], in_data, in_len);
+
+    /* now encrypt it */
+    dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size);
+    encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) : 
+                              RSA_public(ctx, dat_bi);
+    bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size);
+
+    /* save a few bytes of memory */
+    bi_clear_cache(ctx->bi_ctx);
+    return byte_size;
+}
+
+#endif  /* CONFIG_SSL_CERT_VERIFICATION */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/sha1.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995.
+ * This code was originally taken from RFC3174
+ */
+
+#include <string.h>
+#include "os_port.h"
+#include "crypto.h"
+
+/*
+ *  Define the SHA1 circular left shift macro
+ */
+#define SHA1CircularShift(bits,word) \
+                (((word) << (bits)) | ((word) >> (32-(bits))))
+
+/* ----- static functions ----- */
+static void SHA1PadMessage(SHA1_CTX *ctx);
+static void SHA1ProcessMessageBlock(SHA1_CTX *ctx);
+
+/**
+ * Initialize the SHA1 context 
+ */
+void SHA1_Init(SHA1_CTX *ctx)
+{
+    ctx->Length_Low             = 0;
+    ctx->Length_High            = 0;
+    ctx->Message_Block_Index    = 0;
+    ctx->Intermediate_Hash[0]   = 0x67452301;
+    ctx->Intermediate_Hash[1]   = 0xEFCDAB89;
+    ctx->Intermediate_Hash[2]   = 0x98BADCFE;
+    ctx->Intermediate_Hash[3]   = 0x10325476;
+    ctx->Intermediate_Hash[4]   = 0xC3D2E1F0;
+}
+
+/**
+ * Accepts an array of octets as the next portion of the message.
+ */
+void SHA1_Update(SHA1_CTX *ctx, const uint8_t *msg, int len)
+{
+    while (len--)
+    {
+        ctx->Message_Block[ctx->Message_Block_Index++] = (*msg & 0xFF);
+        ctx->Length_Low += 8;
+
+        if (ctx->Length_Low == 0)
+            ctx->Length_High++;
+
+        if (ctx->Message_Block_Index == 64)
+            SHA1ProcessMessageBlock(ctx);
+
+        msg++;
+    }
+}
+
+/**
+ * Return the 160-bit message digest into the user's array
+ */
+void SHA1_Final(uint8_t *digest, SHA1_CTX *ctx)
+{
+    int i;
+
+    SHA1PadMessage(ctx);
+    memset(ctx->Message_Block, 0, 64);
+    ctx->Length_Low = 0;    /* and clear length */
+    ctx->Length_High = 0;
+
+    for  (i = 0; i < SHA1_SIZE; i++)
+    {
+        digest[i] = ctx->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) );
+    }
+}
+
+/**
+ * Process the next 512 bits of the message stored in the array.
+ */
+static void SHA1ProcessMessageBlock(SHA1_CTX *ctx)
+{
+    const uint32_t K[] =    {       /* Constants defined in SHA-1   */
+                            0x5A827999,
+                            0x6ED9EBA1,
+                            0x8F1BBCDC,
+                            0xCA62C1D6
+                            };
+    int        t;                 /* Loop counter                */
+    uint32_t      temp;              /* Temporary word value        */
+    uint32_t      W[80];             /* Word sequence               */
+    uint32_t      A, B, C, D, E;     /* Word buffers                */
+
+    /*
+     *  Initialize the first 16 words in the array W
+     */
+    for  (t = 0; t < 16; t++)
+    {
+        W[t] = ctx->Message_Block[t * 4] << 24;
+        W[t] |= ctx->Message_Block[t * 4 + 1] << 16;
+        W[t] |= ctx->Message_Block[t * 4 + 2] << 8;
+        W[t] |= ctx->Message_Block[t * 4 + 3];
+    }
+
+    for (t = 16; t < 80; t++)
+    {
+       W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+    }
+
+    A = ctx->Intermediate_Hash[0];
+    B = ctx->Intermediate_Hash[1];
+    C = ctx->Intermediate_Hash[2];
+    D = ctx->Intermediate_Hash[3];
+    E = ctx->Intermediate_Hash[4];
+
+    for (t = 0; t < 20; t++)
+    {
+        temp =  SHA1CircularShift(5,A) +
+                ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+
+        B = A;
+        A = temp;
+    }
+
+    for (t = 20; t < 40; t++)
+    {
+        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    for (t = 40; t < 60; t++)
+    {
+        temp = SHA1CircularShift(5,A) +
+               ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    for (t = 60; t < 80; t++)
+    {
+        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    ctx->Intermediate_Hash[0] += A;
+    ctx->Intermediate_Hash[1] += B;
+    ctx->Intermediate_Hash[2] += C;
+    ctx->Intermediate_Hash[3] += D;
+    ctx->Intermediate_Hash[4] += E;
+    ctx->Message_Block_Index = 0;
+}
+
+/*
+ * According to the standard, the message must be padded to an even
+ * 512 bits.  The first padding bit must be a '1'.  The last 64
+ * bits represent the length of the original message.  All bits in
+ * between should be 0.  This function will pad the message
+ * according to those rules by filling the Message_Block array
+ * accordingly.  It will also call the ProcessMessageBlock function
+ * provided appropriately.  When it returns, it can be assumed that
+ * the message digest has been computed.
+ *
+ * @param ctx [in, out] The SHA1 context
+ */
+static void SHA1PadMessage(SHA1_CTX *ctx)
+{
+    /*
+     *  Check to see if the current message block is too small to hold
+     *  the initial padding bits and length.  If so, we will pad the
+     *  block, process it, and then continue padding into a second
+     *  block.
+     */
+    if (ctx->Message_Block_Index > 55)
+    {
+        ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
+        while(ctx->Message_Block_Index < 64)
+        {
+            ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+        }
+
+        SHA1ProcessMessageBlock(ctx);
+
+        while (ctx->Message_Block_Index < 56)
+        {
+            ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+        }
+    }
+    else
+    {
+        ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
+        while(ctx->Message_Block_Index < 56)
+        {
+
+            ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+        }
+    }
+
+    /*
+     *  Store the message length as the last 8 octets
+     */
+    ctx->Message_Block[56] = ctx->Length_High >> 24;
+    ctx->Message_Block[57] = ctx->Length_High >> 16;
+    ctx->Message_Block[58] = ctx->Length_High >> 8;
+    ctx->Message_Block[59] = ctx->Length_High;
+    ctx->Message_Block[60] = ctx->Length_Low >> 24;
+    ctx->Message_Block[61] = ctx->Length_Low >> 16;
+    ctx->Message_Block[62] = ctx->Length_Low >> 8;
+    ctx->Message_Block[63] = ctx->Length_Low;
+    SHA1ProcessMessageBlock(ctx);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/asn1.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,567 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * Some primitive asn methods for extraction ASN.1 data.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "os_port.h"
+#include "crypto.h"
+#include "crypto_misc.h"
+#include "config.h"
+
+#define SIG_OID_PREFIX_SIZE 8
+#define SIG_IIS6_OID_SIZE   5
+#define SIG_SUBJECT_ALT_NAME_SIZE 3
+
+/* Must be an RSA algorithm with either SHA1 or MD5 for verifying to work */
+static const uint8_t sig_oid_prefix[SIG_OID_PREFIX_SIZE] = 
+{
+    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01
+};
+
+static const uint8_t sig_sha1WithRSAEncrypt[SIG_IIS6_OID_SIZE] =
+{
+    0x2b, 0x0e, 0x03, 0x02, 0x1d
+};
+
+static const uint8_t sig_subject_alt_name[SIG_SUBJECT_ALT_NAME_SIZE] =
+{
+    0x55, 0x1d, 0x11
+};
+
+/* CN, O, OU */
+static const uint8_t g_dn_types[] = { 3, 10, 11 };
+
+int get_asn1_length(const uint8_t *buf, int *offset)
+{
+    int len, i;
+
+    if (!(buf[*offset] & 0x80)) /* short form */
+    {
+        len = buf[(*offset)++];
+    }
+    else  /* long form */
+    {
+        int length_bytes = buf[(*offset)++]&0x7f;
+        len = 0;
+        for (i = 0; i < length_bytes; i++)
+        {
+            len <<= 8;
+            len += buf[(*offset)++];
+        }
+    }
+
+    return len;
+}
+
+/**
+ * Skip the ASN1.1 object type and its length. Get ready to read the object's
+ * data.
+ */
+int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type)
+{
+    if (buf[*offset] != obj_type)
+        return X509_NOT_OK;
+    (*offset)++;
+    return get_asn1_length(buf, offset);
+}
+
+/**
+ * Skip over an ASN.1 object type completely. Get ready to read the next
+ * object.
+ */
+int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type)
+{
+    int len;
+
+    if (buf[*offset] != obj_type)
+        return X509_NOT_OK;
+    (*offset)++;
+    len = get_asn1_length(buf, offset);
+    *offset += len;
+    return 0;
+}
+
+/**
+ * Read an integer value for ASN.1 data
+ * Note: This function allocates memory which must be freed by the user.
+ */
+int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object)
+{
+    int len;
+
+    if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0)
+        goto end_int_array;
+
+    if (len > 1 && buf[*offset] == 0x00)    /* ignore the negative byte */
+    {
+        len--;
+        (*offset)++;
+    }
+
+    *object = (uint8_t *)malloc(len);
+    memcpy(*object, &buf[*offset], len);
+    *offset += len;
+
+end_int_array:
+    return len;
+}
+
+/**
+ * Get all the RSA private key specifics from an ASN.1 encoded file 
+ */
+int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx)
+{
+    int offset = 7;
+    uint8_t *modulus = NULL, *priv_exp = NULL, *pub_exp = NULL;
+    int mod_len, priv_len, pub_len;
+#ifdef CONFIG_BIGINT_CRT
+    uint8_t *p = NULL, *q = NULL, *dP = NULL, *dQ = NULL, *qInv = NULL;
+    int p_len, q_len, dP_len, dQ_len, qInv_len;
+#endif
+
+    /* not in der format */
+    if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("Error: This is not a valid ASN.1 file\n");
+#endif
+        return X509_INVALID_PRIV_KEY;
+    }
+
+    /* Use the private key to mix up the RNG if possible. */
+    RNG_custom_init(buf, len);
+
+    mod_len = asn1_get_int(buf, &offset, &modulus);
+    pub_len = asn1_get_int(buf, &offset, &pub_exp);
+    priv_len = asn1_get_int(buf, &offset, &priv_exp);
+
+    if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0)
+        return X509_INVALID_PRIV_KEY;
+
+#ifdef CONFIG_BIGINT_CRT
+    p_len = asn1_get_int(buf, &offset, &p);
+    q_len = asn1_get_int(buf, &offset, &q);
+    dP_len = asn1_get_int(buf, &offset, &dP);
+    dQ_len = asn1_get_int(buf, &offset, &dQ);
+    qInv_len = asn1_get_int(buf, &offset, &qInv);
+
+    if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0)
+        return X509_INVALID_PRIV_KEY;
+
+    RSA_priv_key_new(rsa_ctx, 
+            modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len,
+            p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len);
+
+    free(p);
+    free(q);
+    free(dP);
+    free(dQ);
+    free(qInv);
+#else
+    RSA_priv_key_new(rsa_ctx, 
+            modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len);
+#endif
+
+    free(modulus);
+    free(priv_exp);
+    free(pub_exp);
+    return X509_OK;
+}
+
+/**
+ * Get the time of a certificate. Ignore hours/minutes/seconds.
+ */
+static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t)
+{
+    int ret = X509_NOT_OK, len, t_offset;
+    struct tm tm;
+
+    if (buf[(*offset)++] != ASN1_UTC_TIME)
+        goto end_utc_time;
+
+    len = get_asn1_length(buf, offset);
+    t_offset = *offset;
+
+    memset(&tm, 0, sizeof(struct tm));
+    tm.tm_year = (buf[t_offset] - '0')*10 + (buf[t_offset+1] - '0');
+
+    if (tm.tm_year <= 50)    /* 1951-2050 thing */
+    {
+        tm.tm_year += 100;
+    }
+
+    tm.tm_mon = (buf[t_offset+2] - '0')*10 + (buf[t_offset+3] - '0') - 1;
+    tm.tm_mday = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0');
+    *t = mktime(&tm);
+    *offset += len;
+    ret = X509_OK;
+
+end_utc_time:
+    return ret;
+}
+
+/**
+ * Get the version type of a certificate (which we don't actually care about)
+ */
+int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+    int ret = X509_NOT_OK;
+
+    (*offset) += 2;        /* get past explicit tag */
+    if (asn1_skip_obj(cert, offset, ASN1_INTEGER))
+        goto end_version;
+
+    ret = X509_OK;
+end_version:
+    return ret;
+}
+
+/**
+ * Retrieve the notbefore and notafter certificate times.
+ */
+int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+    return (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
+              asn1_get_utc_time(cert, offset, &x509_ctx->not_before) ||
+              asn1_get_utc_time(cert, offset, &x509_ctx->not_after));
+}
+
+/**
+ * Get the components of a distinguished name 
+ */
+static int asn1_get_oid_x520(const uint8_t *buf, int *offset)
+{
+    int dn_type = 0;
+    int len;
+
+    if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)
+        goto end_oid;
+
+    /* expect a sequence of 2.5.4.[x] where x is a one of distinguished name 
+       components we are interested in. */
+    if (len == 3 && buf[(*offset)++] == 0x55 && buf[(*offset)++] == 0x04)
+        dn_type = buf[(*offset)++];
+    else
+    {
+        *offset += len;     /* skip over it */
+    }
+
+end_oid:
+    return dn_type;
+}
+
+/**
+ * Obtain an ASN.1 printable string type.
+ */
+static int asn1_get_printable_str(const uint8_t *buf, int *offset, char **str)
+{
+    int len = X509_NOT_OK;
+    int asn1_type = buf[*offset];
+
+    /* some certs have this awful crud in them for some reason */
+    if (asn1_type != ASN1_PRINTABLE_STR &&  
+            asn1_type != ASN1_PRINTABLE_STR2 &&  
+            asn1_type != ASN1_TELETEX_STR &&  
+            asn1_type != ASN1_IA5_STR &&  
+            asn1_type != ASN1_UNICODE_STR)
+        goto end_pnt_str;
+
+    (*offset)++;
+    len = get_asn1_length(buf, offset);
+
+    if (asn1_type == ASN1_UNICODE_STR)
+    {
+        int i;
+        *str = (char *)malloc(len/2+1);     /* allow for null */
+
+        for (i = 0; i < len; i += 2)
+            (*str)[i/2] = buf[*offset + i + 1];
+
+        (*str)[len/2] = 0;                  /* null terminate */
+    }
+    else
+    {
+        *str = (char *)malloc(len+1);       /* allow for null */
+        memcpy(*str, &buf[*offset], len);
+        (*str)[len] = 0;                    /* null terminate */
+    }
+
+    *offset += len;
+
+end_pnt_str:
+    return len;
+}
+
+/**
+ * Get the subject name (or the issuer) of a certificate.
+ */
+int asn1_name(const uint8_t *cert, int *offset, char *dn[])
+{
+    int ret = X509_NOT_OK;
+    int dn_type;
+    char *tmp;
+
+    if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
+        goto end_name;
+
+    while (asn1_next_obj(cert, offset, ASN1_SET) >= 0)
+    {
+        int i, found = 0;
+
+        if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
+               (dn_type = asn1_get_oid_x520(cert, offset)) < 0)
+            goto end_name;
+
+        tmp = NULL;
+
+        if (asn1_get_printable_str(cert, offset, &tmp) < 0)
+        {
+            free(tmp);
+            goto end_name;
+        }
+
+        /* find the distinguished named type */
+        for (i = 0; i < X509_NUM_DN_TYPES; i++)
+        {
+            if (dn_type == g_dn_types[i])
+            {
+                if (dn[i] == NULL)
+                {
+                    dn[i] = tmp;
+                    found = 1;
+                    break;
+                }
+            }
+        }
+
+        if (found == 0) /* not found so get rid of it */
+        {
+            free(tmp);
+        }
+    }
+
+    ret = X509_OK;
+end_name:
+    return ret;
+}
+
+/**
+ * Read the modulus and public exponent of a certificate.
+ */
+int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+    int ret = X509_NOT_OK, mod_len, pub_len;
+    uint8_t *modulus = NULL, *pub_exp = NULL;
+
+    if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
+            asn1_skip_obj(cert, offset, ASN1_SEQUENCE) ||
+            asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0)
+        goto end_pub_key;
+
+    (*offset)++;        /* ignore the padding bit field */
+
+    if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
+        goto end_pub_key;
+
+    mod_len = asn1_get_int(cert, offset, &modulus);
+    pub_len = asn1_get_int(cert, offset, &pub_exp);
+
+    RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len);
+
+    free(modulus);
+    free(pub_exp);
+    ret = X509_OK;
+
+end_pub_key:
+    return ret;
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Read the signature of the certificate.
+ */
+int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+    int ret = X509_NOT_OK;
+
+    if (cert[(*offset)++] != ASN1_BIT_STRING)
+        goto end_sig;
+
+    x509_ctx->sig_len = get_asn1_length(cert, offset)-1;
+    (*offset)++;            /* ignore bit string padding bits */
+    x509_ctx->signature = (uint8_t *)malloc(x509_ctx->sig_len);
+    memcpy(x509_ctx->signature, &cert[*offset], x509_ctx->sig_len);
+    *offset += x509_ctx->sig_len;
+    ret = X509_OK;
+
+end_sig:
+    return ret;
+}
+
+/*
+ * Compare 2 distinguished name components for equality 
+ * @return 0 if a match
+ */
+static int asn1_compare_dn_comp(const char *dn1, const char *dn2)
+{
+    int ret;
+
+    if (dn1 == NULL && dn2 == NULL)
+        ret = 0;
+    else
+        ret = (dn1 && dn2) ? strcmp(dn1, dn2) : 1;
+
+    return ret;
+}
+
+/**
+ * Clean up all of the CA certificates.
+ */
+void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx)
+{
+    int i = 0;
+
+    if (ca_cert_ctx == NULL)
+        return;
+
+    while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
+    {
+        x509_free(ca_cert_ctx->cert[i]);
+        ca_cert_ctx->cert[i++] = NULL;
+    }
+
+    free(ca_cert_ctx);
+}
+
+/*
+ * Compare 2 distinguished names for equality 
+ * @return 0 if a match
+ */
+int asn1_compare_dn(char * const dn1[], char * const dn2[])
+{
+    int i;
+
+    for (i = 0; i < X509_NUM_DN_TYPES; i++)
+    {
+        if (asn1_compare_dn_comp(dn1[i], dn2[i]))
+            return 1;
+    }
+
+    return 0;       /* all good */
+}
+
+int asn1_find_oid(const uint8_t* cert, int* offset, 
+                    const uint8_t* oid, int oid_length)
+{
+    int seqlen;
+    if ((seqlen = asn1_next_obj(cert, offset, ASN1_SEQUENCE))> 0)
+    {
+        int end = *offset + seqlen;
+
+        while (*offset < end)
+        {
+            int type = cert[(*offset)++];
+            int length = get_asn1_length(cert, offset);
+            int noffset = *offset + length;
+
+            if (type == ASN1_SEQUENCE)
+            {
+                type = cert[(*offset)++];
+                length = get_asn1_length(cert, offset);
+
+                if (type == ASN1_OID && length == oid_length && 
+                              memcmp(cert + *offset, oid, oid_length) == 0)
+                {
+                    *offset += oid_length;
+                    return 1;
+                }
+            }
+
+            *offset = noffset;
+        }
+    }
+
+    return 0;
+}
+
+int asn1_find_subjectaltname(const uint8_t* cert, int offset)
+{
+    if (asn1_find_oid(cert, &offset, sig_subject_alt_name, 
+                                SIG_SUBJECT_ALT_NAME_SIZE))
+    {
+        return offset;
+    }
+
+    return 0;
+}
+
+#endif /* CONFIG_SSL_CERT_VERIFICATION */
+
+/**
+ * Read the signature type of the certificate. We only support RSA-MD5 and
+ * RSA-SHA1 signature types.
+ */
+int asn1_signature_type(const uint8_t *cert, 
+                                int *offset, X509_CTX *x509_ctx)
+{
+    int ret = X509_NOT_OK, len;
+
+    if (cert[(*offset)++] != ASN1_OID)
+        goto end_check_sig;
+
+    len = get_asn1_length(cert, offset);
+
+    if (len == 5 && memcmp(sig_sha1WithRSAEncrypt, &cert[*offset], 
+                                    SIG_IIS6_OID_SIZE) == 0)
+    {
+        x509_ctx->sig_type = SIG_TYPE_SHA1;
+    }
+    else
+    {
+        if (memcmp(sig_oid_prefix, &cert[*offset], SIG_OID_PREFIX_SIZE))
+            goto end_check_sig;     /* unrecognised cert type */
+
+        x509_ctx->sig_type = cert[*offset + SIG_OID_PREFIX_SIZE];
+    }
+
+    *offset += len;
+    asn1_skip_obj(cert, offset, ASN1_NULL); /* if it's there */
+    ret = X509_OK;
+
+end_check_sig:
+    return ret;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/cert.h	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,128 @@
+/*
+unsigned char default_certificate[] = {
+  0x30, 0x82, 0x01, 0xd7, 0x30, 0x82, 0x01, 0x40, 0x02, 0x09, 0x00, 0xab,
+  0x08, 0x18, 0xa7, 0x03, 0x07, 0x27, 0xfd, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+  0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x34,
+  0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x29, 0x61,
+  0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
+  0x20, 0x44, 0x6f, 0x64, 0x67, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+  0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+  0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x31, 0x32,
+  0x32, 0x36, 0x32, 0x32, 0x33, 0x33, 0x33, 0x39, 0x5a, 0x17, 0x0d, 0x32,
+  0x34, 0x30, 0x39, 0x30, 0x33, 0x32, 0x32, 0x33, 0x33, 0x33, 0x39, 0x5a,
+  0x30, 0x2c, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+  0x0d, 0x61, 0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65,
+  0x63, 0x74, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+  0x09, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 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, 0xcd, 0xfd, 0x89, 0x48, 0xbe, 0x36, 0xb9, 0x95, 0x76,
+  0xd4, 0x13, 0x30, 0x0e, 0xbf, 0xb2, 0xed, 0x67, 0x0a, 0xc0, 0x16, 0x3f,
+  0x51, 0x09, 0x9d, 0x29, 0x2f, 0xb2, 0x6d, 0x3f, 0x3e, 0x6c, 0x2f, 0x90,
+  0x80, 0xa1, 0x71, 0xdf, 0xbe, 0x38, 0xc5, 0xcb, 0xa9, 0x9a, 0x40, 0x14,
+  0x90, 0x0a, 0xf9, 0xb7, 0x07, 0x0b, 0xe1, 0xda, 0xe7, 0x09, 0xbf, 0x0d,
+  0x57, 0x41, 0x86, 0x60, 0xa1, 0xc1, 0x27, 0x91, 0x5b, 0x0a, 0x98, 0x46,
+  0x1b, 0xf6, 0xa2, 0x84, 0xf8, 0x65, 0xc7, 0xce, 0x2d, 0x96, 0x17, 0xaa,
+  0x91, 0xf8, 0x61, 0x04, 0x50, 0x70, 0xeb, 0xb4, 0x43, 0xb7, 0xdc, 0x9a,
+  0xcc, 0x31, 0x01, 0x14, 0xd4, 0xcd, 0xcc, 0xc2, 0x37, 0x6d, 0x69, 0x82,
+  0xd6, 0xc6, 0xc4, 0xbe, 0xf2, 0x34, 0xa5, 0xc9, 0xa6, 0x19, 0x53, 0x32,
+  0x7a, 0x86, 0x0e, 0x91, 0x82, 0x0f, 0xa1, 0x42, 0x54, 0xaa, 0x01, 0x02,
+  0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+  0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x40,
+  0xb4, 0x94, 0x9a, 0xa8, 0x89, 0x72, 0x1d, 0x07, 0xe5, 0xb3, 0x6b, 0x88,
+  0x21, 0xc2, 0x38, 0x36, 0x9e, 0x7a, 0x8c, 0x49, 0x48, 0x68, 0x0c, 0x06,
+  0xe8, 0xdb, 0x1f, 0x4e, 0x05, 0xe6, 0x31, 0xe3, 0xfd, 0xe6, 0x0d, 0x6b,
+  0xd8, 0x13, 0x17, 0xe0, 0x2d, 0x0d, 0xb8, 0x7e, 0xcb, 0x20, 0x6c, 0xa8,
+  0x73, 0xa7, 0xfd, 0xe3, 0xa7, 0xfa, 0xf3, 0x02, 0x60, 0x78, 0x1f, 0x13,
+  0x40, 0x45, 0xee, 0x75, 0xf5, 0x10, 0xfd, 0x8f, 0x68, 0x74, 0xd4, 0xac,
+  0xae, 0x04, 0x09, 0x55, 0x2c, 0xdb, 0xd8, 0x07, 0x07, 0x65, 0x69, 0x27,
+  0x6e, 0xbf, 0x5e, 0x61, 0x40, 0x56, 0x8b, 0xd7, 0x33, 0x3b, 0xff, 0x6e,
+  0x53, 0x7e, 0x9d, 0x3f, 0xc0, 0x40, 0x3a, 0xab, 0xa0, 0x50, 0x4e, 0x80,
+  0x47, 0x46, 0x0d, 0x1e, 0xdb, 0x4c, 0xf1, 0x1b, 0x5d, 0x3c, 0x2a, 0x54,
+  0xa7, 0x4d, 0xfa, 0x7b, 0x72, 0x66, 0xc5
+};
+unsigned int default_certificate_len = 475;
+*/
+unsigned char default_certificate[] = {
+  0x30, 0x82, 0x03, 0xb8, 0x30, 0x82, 0x03, 0x21, 0xa0, 0x03, 0x02, 0x01,
+  0x02, 0x02, 0x09, 0x00, 0xe1, 0x40, 0xf0, 0x81, 0x55, 0x5d, 0xa4, 0x8f,
+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+  0x05, 0x05, 0x00, 0x30, 0x81, 0x9a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+  0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x31, 0x0d, 0x30, 0x0b, 0x06,
+  0x03, 0x55, 0x04, 0x08, 0x13, 0x04, 0x54, 0x65, 0x73, 0x74, 0x31, 0x12,
+  0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x54, 0x65, 0x73,
+  0x74, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
+  0x55, 0x04, 0x0a, 0x13, 0x0e, 0x4e, 0x6f, 0x69, 0x73, 0x79, 0x20, 0x41,
+  0x74, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06,
+  0x03, 0x55, 0x04, 0x0b, 0x14, 0x08, 0x53, 0x65, 0x63, 0x75, 0x69, 0x72,
+  0x08, 0x08, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+  0x0c, 0x41, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x20, 0x4d, 0x69, 0x6c, 0x6c,
+  0x73, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+  0x0d, 0x01, 0x09, 0x01, 0x16, 0x16, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79,
+  0x40, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x6d, 0x69, 0x6c, 0x6c, 0x73,
+  0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x35,
+  0x31, 0x33, 0x31, 0x37, 0x35, 0x32, 0x34, 0x31, 0x5a, 0x17, 0x0d, 0x34,
+  0x36, 0x30, 0x33, 0x32, 0x31, 0x31, 0x37, 0x35, 0x32, 0x34, 0x31, 0x5a,
+  0x30, 0x81, 0x9a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+  0x13, 0x02, 0x55, 0x4b, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04,
+  0x08, 0x13, 0x04, 0x54, 0x65, 0x73, 0x74, 0x31, 0x12, 0x30, 0x10, 0x06,
+  0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x54, 0x65, 0x73, 0x74, 0x76, 0x69,
+  0x6c, 0x6c, 0x65, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a,
+  0x13, 0x0e, 0x4e, 0x6f, 0x69, 0x73, 0x79, 0x20, 0x41, 0x74, 0x6f, 0x6d,
+  0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
+  0x0b, 0x14, 0x08, 0x53, 0x65, 0x63, 0x75, 0x69, 0x72, 0x08, 0x08, 0x31,
+  0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0c, 0x41, 0x73,
+  0x68, 0x6c, 0x65, 0x79, 0x20, 0x4d, 0x69, 0x6c, 0x6c, 0x73, 0x31, 0x25,
+  0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
+  0x01, 0x16, 0x16, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x40, 0x61, 0x73,
+  0x68, 0x6c, 0x65, 0x79, 0x6d, 0x69, 0x6c, 0x6c, 0x73, 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, 0xb1, 0xe0, 0x59, 0x6a, 0x19, 0x08,
+  0x0d, 0x21, 0x98, 0x79, 0x96, 0x16, 0x2a, 0x5a, 0x5c, 0x20, 0xeb, 0x66,
+  0x1e, 0x9e, 0x1e, 0xc4, 0xef, 0x83, 0x42, 0x15, 0xd8, 0x4b, 0x14, 0xd3,
+  0xe7, 0xba, 0xc8, 0xf6, 0xb4, 0x52, 0xdf, 0x18, 0xa6, 0x6b, 0x8b, 0xca,
+  0x84, 0xdc, 0x21, 0x26, 0xfd, 0x7c, 0xde, 0xbd, 0x2b, 0x64, 0x0d, 0xd3,
+  0x20, 0x7c, 0xe7, 0x0c, 0xfc, 0x3c, 0xa9, 0x09, 0xc0, 0xa7, 0x78, 0x3d,
+  0xe9, 0x48, 0x50, 0x90, 0xd7, 0x3e, 0x46, 0x78, 0x8f, 0xfc, 0xc8, 0xb6,
+  0x89, 0x41, 0x49, 0x15, 0x47, 0x27, 0x4b, 0x46, 0xcb, 0x11, 0x82, 0xd8,
+  0x7b, 0x68, 0xb7, 0xc5, 0x64, 0x70, 0xaf, 0xe6, 0x80, 0x63, 0xfe, 0x53,
+  0x70, 0xee, 0xd2, 0xa9, 0x2c, 0x40, 0x96, 0x9c, 0xd4, 0xa1, 0xcf, 0xd4,
+  0x51, 0x9d, 0xe1, 0xa7, 0xf0, 0xfb, 0xa6, 0x49, 0x4c, 0x00, 0x05, 0xff,
+  0x8f, 0x61, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x02, 0x30,
+  0x81, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
+  0x14, 0xf1, 0x67, 0xe6, 0xd7, 0x73, 0xe7, 0x12, 0x0a, 0xe1, 0xc3, 0x5f,
+  0x34, 0x97, 0x23, 0x0d, 0xa0, 0xc6, 0x7e, 0x10, 0xe8, 0x30, 0x81, 0xcf,
+  0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xc7, 0x30, 0x81, 0xc4, 0x80,
+  0x14, 0xf1, 0x67, 0xe6, 0xd7, 0x73, 0xe7, 0x12, 0x0a, 0xe1, 0xc3, 0x5f,
+  0x34, 0x97, 0x23, 0x0d, 0xa0, 0xc6, 0x7e, 0x10, 0xe8, 0xa1, 0x81, 0xa0,
+  0xa4, 0x81, 0x9d, 0x30, 0x81, 0x9a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+  0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x31, 0x0d, 0x30, 0x0b, 0x06,
+  0x03, 0x55, 0x04, 0x08, 0x13, 0x04, 0x54, 0x65, 0x73, 0x74, 0x31, 0x12,
+  0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x54, 0x65, 0x73,
+  0x74, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
+  0x55, 0x04, 0x0a, 0x13, 0x0e, 0x4e, 0x6f, 0x69, 0x73, 0x79, 0x20, 0x41,
+  0x74, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06,
+  0x03, 0x55, 0x04, 0x0b, 0x14, 0x08, 0x53, 0x65, 0x63, 0x75, 0x69, 0x72,
+  0x08, 0x08, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+  0x0c, 0x41, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x20, 0x4d, 0x69, 0x6c, 0x6c,
+  0x73, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+  0x0d, 0x01, 0x09, 0x01, 0x16, 0x16, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79,
+  0x40, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x6d, 0x69, 0x6c, 0x6c, 0x73,
+  0x2e, 0x63, 0x6f, 0x6d, 0x82, 0x09, 0x00, 0xe1, 0x40, 0xf0, 0x81, 0x55,
+  0x5d, 0xa4, 0x8f, 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,
+  0x89, 0x79, 0xf2, 0xa8, 0xd3, 0xc7, 0x02, 0x2d, 0x02, 0x68, 0x9a, 0xf1,
+  0xa7, 0x10, 0xa2, 0x2c, 0x52, 0x12, 0xf2, 0x97, 0x39, 0x52, 0x83, 0x69,
+  0xd7, 0xe7, 0x73, 0x1f, 0xf1, 0x02, 0x5e, 0xbe, 0x5f, 0xbe, 0x94, 0xa9,
+  0x4d, 0x8f, 0xb7, 0x3c, 0x52, 0x35, 0x09, 0x0a, 0x69, 0xed, 0x5e, 0x12,
+  0xc9, 0x4d, 0x59, 0xec, 0x47, 0xfa, 0x82, 0xe5, 0x79, 0xbc, 0x17, 0x9d,
+  0xae, 0x02, 0x17, 0xb5, 0xfb, 0xca, 0xc7, 0x42, 0xf4, 0xb5, 0x48, 0x19,
+  0x1c, 0xd4, 0xd6, 0xfb, 0x2a, 0x7b, 0x0e, 0x8b, 0x56, 0xcc, 0x8e, 0x7a,
+  0xa8, 0xaf, 0x4e, 0x5a, 0xa1, 0xf1, 0x78, 0x37, 0x4d, 0x09, 0x03, 0x9a,
+  0xde, 0x4c, 0x87, 0xbe, 0xb1, 0x93, 0x1a, 0x39, 0x9a, 0xbb, 0xa0, 0x5c,
+  0xfe, 0x58, 0x71, 0x62, 0x20, 0x74, 0x04, 0xc5, 0x50, 0x6e, 0x7b, 0xad,
+  0xbe, 0xb0, 0xaa, 0x64, 0xea, 0x48, 0xa7, 0x9f
+};
+unsigned int default_certificate_len = 956;
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/config.h	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,62 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+#define CONFIG_DEBUG
+#define CONFIG_STRIP_UNWANTED_SECTIONS 1
+
+/*
+ * BigInt Options
+ */
+#define CONFIG_BIGINT_BARRETT 1
+#define CONFIG_BIGINT_CRT 1
+#define CONFIG_INTEGER_32BIT 1
+
+/*
+ * SSL Library
+ */
+#define CONFIG_SSL_ENABLE_CLIENT 1
+//#define CONFIG_SSL_SKELETON_MODE
+//#define CONFIG_SSL_PROT_LOW 1
+//#undef CONFIG_SSL_PROT_MEDIUM
+//#undef CONFIG_SSL_PROT_HIGH
+#define CONFIG_SSL_USE_DEFAULT_KEY 1
+#define CONFIG_SSL_PRIVATE_KEY_LOCATION ""
+#define CONFIG_SSL_PRIVATE_KEY_PASSWORD ""
+#define CONFIG_SSL_X509_CERT_LOCATION ""
+#undef CONFIG_SSL_GENERATE_X509_CERT
+#define CONFIG_SSL_X509_COMMON_NAME ""
+#define CONFIG_SSL_X509_ORGANIZATION_NAME ""
+#define CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME ""
+#undef CONFIG_SSL_ENABLE_V23_HANDSHAKE
+#undef CONFIG_SSL_HAS_PEM
+#undef CONFIG_SSL_USE_PKCS12
+#define CONFIG_SSL_EXPIRY_TIME 24
+#define CONFIG_X509_MAX_CA_CERTS 1
+#define CONFIG_SSL_MAX_CERTS 1
+#undef CONFIG_SSL_CTX_MUTEXING
+#undef CONFIG_USE_DEV_URANDOM
+#undef CONFIG_WIN32_USE_CRYPTO_LIB
+#undef CONFIG_OPENSSL_COMPATIBLE
+#undef CONFIG_PERFORMANCE_TESTING
+#undef CONFIG_SSL_TEST
+#undef CONFIG_AXTLSWRAP
+#undef CONFIG_AXHTTPD
+#undef CONFIG_HTTP_STATIC_BUILD
+#undef CONFIG_HTTP_HAS_CGI
+#define CONFIG_HTTP_CGI_EXTENSIONS ""
+#undef CONFIG_HTTP_ENABLE_LUA
+#define CONFIG_HTTP_LUA_PREFIX ""
+#undef CONFIG_HTTP_BUILD_LUA
+#define CONFIG_HTTP_CGI_LAUNCHER ""
+#undef CONFIG_HTTP_DIRECTORIES
+#undef CONFIG_HTTP_HAS_AUTHORIZATION
+#undef CONFIG_HTTP_HAS_IPV6
+#undef CONFIG_HTTP_ENABLE_DIFFERENT_USER
+#define CONFIG_HTTP_USER ""
+#undef CONFIG_HTTP_VERBOSE
+#undef CONFIG_HTTP_IS_DAEMON
+#define CONFIG_SSL_CERT_VERIFICATION
+#define CONFIG_SSL_FULL_MODE
+
+#define MBED
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/crypto_misc.h	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+*/
+
+/**
+ * @file crypto_misc.h
+ */
+
+#ifndef HEADER_CRYPTO_MISC_H
+#define HEADER_CRYPTO_MISC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "crypto.h"
+#include "bigint.h"
+#include "config.h"
+
+/**************************************************************************
+ * X509 declarations 
+ **************************************************************************/
+#define X509_OK                             0
+#define X509_NOT_OK                         -1
+#define X509_VFY_ERROR_NO_TRUSTED_CERT      -2
+#define X509_VFY_ERROR_BAD_SIGNATURE        -3      
+#define X509_VFY_ERROR_NOT_YET_VALID        -4
+#define X509_VFY_ERROR_EXPIRED              -5
+#define X509_VFY_ERROR_SELF_SIGNED          -6
+#define X509_VFY_ERROR_INVALID_CHAIN        -7
+#define X509_VFY_ERROR_UNSUPPORTED_DIGEST   -8
+#define X509_INVALID_PRIV_KEY               -9
+
+/*
+ * The Distinguished Name
+ */
+#define X509_NUM_DN_TYPES                   3
+#define X509_COMMON_NAME                    0
+#define X509_ORGANIZATION                   1
+#define X509_ORGANIZATIONAL_UNIT            2
+
+#include <time.h>
+
+struct _x509_ctx
+{
+    char *ca_cert_dn[X509_NUM_DN_TYPES];
+    char *cert_dn[X509_NUM_DN_TYPES];
+    char **subject_alt_dnsnames;
+    time_t not_before;
+    time_t not_after;
+    uint8_t *signature;
+    uint16_t sig_len;
+    uint8_t sig_type;
+    RSA_CTX *rsa_ctx;
+    bigint *digest;
+    struct _x509_ctx *next;
+};
+
+typedef struct _x509_ctx X509_CTX;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+typedef struct 
+{
+    X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS];
+} CA_CERT_CTX;
+#endif
+
+int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx);
+void x509_free(X509_CTX *x509_ctx);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);
+#endif
+#ifdef CONFIG_SSL_FULL_MODE
+void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx);
+const char * x509_display_error(int error);
+#endif
+
+/**************************************************************************
+ * ASN1 declarations 
+ **************************************************************************/
+#define ASN1_INTEGER            0x02
+#define ASN1_BIT_STRING         0x03
+#define ASN1_OCTET_STRING       0x04
+#define ASN1_NULL               0x05
+#define ASN1_PRINTABLE_STR2     0x0C
+#define ASN1_OID                0x06
+#define ASN1_PRINTABLE_STR2     0x0C
+#define ASN1_PRINTABLE_STR      0x13
+#define ASN1_TELETEX_STR        0x14
+#define ASN1_IA5_STR            0x16
+#define ASN1_UTC_TIME           0x17
+#define ASN1_UNICODE_STR        0x1e
+#define ASN1_SEQUENCE           0x30
+#define ASN1_CONTEXT_DNSNAME    0x82
+#define ASN1_SET                0x31
+#define ASN1_V3_DATA            0xa3
+#define ASN1_IMPLICIT_TAG       0x80
+#define ASN1_CONTEXT_DNSNAME    0x82
+#define ASN1_EXPLICIT_TAG       0xa0
+#define ASN1_V3_DATA            0xa3
+
+#define SIG_TYPE_MD2            0x02
+#define SIG_TYPE_MD5            0x04
+#define SIG_TYPE_SHA1           0x05
+
+int get_asn1_length(const uint8_t *buf, int *offset);
+int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx);
+int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type);
+int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type);
+int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object);
+int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
+int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
+int asn1_name(const uint8_t *cert, int *offset, char *dn[]);
+int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
+int asn1_find_subjectaltname(const uint8_t* cert, int offset);
+int asn1_compare_dn(char * const dn1[], char * const dn2[]);
+#endif /* CONFIG_SSL_CERT_VERIFICATION */
+int asn1_signature_type(const uint8_t *cert, 
+                                int *offset, X509_CTX *x509_ctx);
+
+/**************************************************************************
+ * MISC declarations 
+ **************************************************************************/
+#define SALT_SIZE               8
+
+extern const char * const unsupported_str;
+
+typedef void (*crypt_func)(void *, const uint8_t *, uint8_t *, int);
+typedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key, 
+        int key_len, uint8_t *digest);
+
+int get_file(const char *filename, uint8_t **buf);
+
+#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG)
+EXP_FUNC void STDCALL print_blob(const char *format, const uint8_t *data, int size, ...);
+#else
+    #define print_blob(...)
+#endif
+
+EXP_FUNC int STDCALL base64_decode(const char *in,  int len,
+                    uint8_t *out, int *outlen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/gen_cert.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+#include "config.h"
+
+#ifdef CONFIG_SSL_GENERATE_X509_CERT
+#include <string.h>
+#include <stdlib.h>
+#include "os_port.h"
+#include "ssl.h"
+
+/**
+ * Generate a basic X.509 certificate
+ */
+
+static uint8_t set_gen_length(int len, uint8_t *buf, int *offset)
+{
+    if (len < 0x80) /* short form */
+    {
+        buf[(*offset)++] = len;
+        return 1;
+    }
+    else /* long form */
+    {
+        int i, length_bytes = 0;
+
+        if (len & 0x00FF0000)
+            length_bytes = 3;
+        else if (len & 0x0000FF00)
+            length_bytes = 2;
+        else if (len & 0x000000FF)
+            length_bytes = 1;
+            
+        buf[(*offset)++] = 0x80 + length_bytes;
+
+        for (i = length_bytes-1; i >= 0; i--)
+        {
+            buf[*offset+i] = len & 0xFF;
+            len >>= 8;
+        }
+
+        *offset += length_bytes;
+        return length_bytes+1;
+    }
+}
+
+static int pre_adjust_with_size(uint8_t type,
+        int *seq_offset, uint8_t *buf, int *offset)
+{
+    buf[(*offset)++] = type;
+    *seq_offset = *offset;
+    *offset += 4;   /* fill in later */
+    return *offset;
+}
+
+static void adjust_with_size(int seq_size, int seq_start, 
+                uint8_t *buf, int *offset)
+{
+    uint8_t seq_byte_size; 
+    int orig_seq_size = seq_size;
+    int orig_seq_start = seq_start;
+
+    seq_size = *offset-seq_size;
+    seq_byte_size = set_gen_length(seq_size, buf, &seq_start);
+
+    if (seq_byte_size != 4)
+    {
+        memmove(&buf[orig_seq_start+seq_byte_size], 
+                &buf[orig_seq_size], seq_size);
+        *offset -= 4-seq_byte_size;
+    }
+}
+
+static void gen_serial_number(uint8_t *buf, int *offset)
+{
+    static const uint8_t ser_oid[] = { ASN1_INTEGER, 1, 0x7F };
+    memcpy(&buf[*offset], ser_oid , sizeof(ser_oid));
+    *offset += sizeof(ser_oid);
+}
+
+static void gen_signature_alg(uint8_t *buf, int *offset)
+{
+    /* OBJECT IDENTIFIER sha1withRSAEncryption (1 2 840 113549 1 1 5) */
+    static const uint8_t sig_oid[] = 
+    {
+        ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09, 
+        0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+        ASN1_NULL, 0x00
+    };
+
+    memcpy(&buf[*offset], sig_oid, sizeof(sig_oid));
+    *offset += sizeof(sig_oid);
+}
+
+static int gen_dn(const char *name, uint8_t dn_type, 
+                        uint8_t *buf, int *offset)
+{
+    int ret = X509_OK;
+    int name_size = strlen(name);
+
+    if (name_size > 0x70)    /* just too big */
+    {
+        ret = X509_NOT_OK;
+        goto error;
+    }
+
+    buf[(*offset)++] = ASN1_SET;
+    set_gen_length(9+name_size, buf, offset);
+    buf[(*offset)++] = ASN1_SEQUENCE;
+    set_gen_length(7+name_size, buf, offset);
+    buf[(*offset)++] = ASN1_OID;
+    buf[(*offset)++] = 3;
+    buf[(*offset)++] = 0x55;
+    buf[(*offset)++] = 0x04;
+    buf[(*offset)++] = dn_type;
+    buf[(*offset)++] = ASN1_PRINTABLE_STR;
+    buf[(*offset)++] = name_size;
+    strcpy(&buf[*offset], name);
+    *offset += name_size;
+
+error:
+    return ret;
+}
+
+static int gen_issuer(const char * dn[], uint8_t *buf, int *offset)
+{
+    int ret = X509_OK;
+    int seq_offset;
+    int seq_size = pre_adjust_with_size(
+                            ASN1_SEQUENCE, &seq_offset, buf, offset);
+    char fqdn[128]; 
+
+    /* we need the common name, so if not configured, work out the fully
+     * qualified domain name */
+    if (dn[X509_COMMON_NAME] == NULL || strlen(dn[X509_COMMON_NAME]) == 0)
+    {
+        int fqdn_len;
+        gethostname(fqdn, sizeof(fqdn));
+        fqdn_len = strlen(fqdn);
+        fqdn[fqdn_len++] = '.';
+        getdomainname(&fqdn[fqdn_len], sizeof(fqdn)-fqdn_len);
+        fqdn_len = strlen(fqdn);
+
+        if (fqdn[fqdn_len-1] == '.')    /* ensure '.' is not last char */
+            fqdn[fqdn_len-1] = 0;
+
+        dn[X509_COMMON_NAME] = fqdn;
+    }
+
+    if ((ret = gen_dn(dn[X509_COMMON_NAME], 3, buf, offset)))
+        goto error;
+
+    if (dn[X509_ORGANIZATION] != NULL && strlen(dn[X509_ORGANIZATION]) > 0)
+    {
+        if ((ret = gen_dn(dn[X509_ORGANIZATION], 10, buf, offset)))
+            goto error;
+    }
+
+    if (dn[X509_ORGANIZATIONAL_UNIT] != NULL &&
+                                strlen(dn[X509_ORGANIZATIONAL_UNIT]) > 0)
+    {
+        if ((ret = gen_dn(dn[X509_ORGANIZATIONAL_UNIT], 11, buf, offset)))
+            goto error;
+    }
+
+    adjust_with_size(seq_size, seq_offset, buf, offset);
+
+error:
+    return ret;
+}
+
+static void gen_utc_time(uint8_t *buf, int *offset)
+{
+    static const uint8_t time_seq[] = 
+    {
+        ASN1_SEQUENCE, 30, 
+        ASN1_UTC_TIME, 13, 
+        '0', '7', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z', 
+        ASN1_UTC_TIME, 13,  /* make it good for 30 or so years */
+        '3', '8', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z'
+    };
+
+    /* fixed time */
+    memcpy(&buf[*offset], time_seq, sizeof(time_seq));
+    *offset += sizeof(time_seq);
+}
+
+static void gen_pub_key2(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)
+{
+    static const uint8_t pub_key_seq[] = 
+    {
+        ASN1_INTEGER, 0x03, 0x01, 0x00, 0x01 /* INTEGER 65537 */
+    };
+
+    int seq_offset;
+    int pub_key_size = rsa_ctx->num_octets;
+    uint8_t *block = (uint8_t *)alloca(pub_key_size);
+    int seq_size = pre_adjust_with_size(
+                            ASN1_SEQUENCE, &seq_offset, buf, offset);
+    buf[(*offset)++] = ASN1_INTEGER;
+    bi_export(rsa_ctx->bi_ctx, rsa_ctx->m, block, pub_key_size);
+
+    if (*block & 0x80)  /* make integer positive */
+    {
+        set_gen_length(pub_key_size+1, buf, offset);
+        buf[(*offset)++] = 0;
+    }
+    else
+        set_gen_length(pub_key_size, buf, offset);
+
+    memcpy(&buf[*offset], block, pub_key_size);
+    *offset += pub_key_size;
+    memcpy(&buf[*offset], pub_key_seq, sizeof(pub_key_seq));
+    *offset += sizeof(pub_key_seq);
+    adjust_with_size(seq_size, seq_offset, buf, offset);
+}
+
+static void gen_pub_key1(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)
+{
+    int seq_offset;
+    int seq_size = pre_adjust_with_size(
+                            ASN1_BIT_STRING, &seq_offset, buf, offset);
+    buf[(*offset)++] = 0;   /* bit string is multiple of 8 */
+    gen_pub_key2(rsa_ctx, buf, offset);
+    adjust_with_size(seq_size, seq_offset, buf, offset);
+}
+
+static void gen_pub_key(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)
+{
+    /*  OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1) */
+    static const uint8_t rsa_enc_oid[] =
+    {
+        ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09,
+        0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+        ASN1_NULL, 0x00
+    };
+
+    int seq_offset;
+    int seq_size = pre_adjust_with_size(
+                            ASN1_SEQUENCE, &seq_offset, buf, offset);
+
+    memcpy(&buf[*offset], rsa_enc_oid, sizeof(rsa_enc_oid));
+    *offset += sizeof(rsa_enc_oid);
+    gen_pub_key1(rsa_ctx, buf, offset);
+    adjust_with_size(seq_size, seq_offset, buf, offset);
+}
+
+static void gen_signature(const RSA_CTX *rsa_ctx, const uint8_t *sha_dgst, 
+                        uint8_t *buf, int *offset)
+{
+    static const uint8_t asn1_sig[] = 
+    {
+        ASN1_SEQUENCE,  0x21, ASN1_SEQUENCE, 0x09, ASN1_OID, 0x05, 
+        0x2b, 0x0e, 0x03, 0x02, 0x1a, /* sha1 (1 3 14 3 2 26) */
+        ASN1_NULL, 0x00, ASN1_OCTET_STRING, 0x14 
+    };
+
+    uint8_t *enc_block = (uint8_t *)alloca(rsa_ctx->num_octets);
+    uint8_t *block = (uint8_t *)alloca(sizeof(asn1_sig) + SHA1_SIZE);
+    int sig_size;
+
+    /* add the digest as an embedded asn.1 sequence */
+    memcpy(block, asn1_sig, sizeof(asn1_sig));
+    memcpy(&block[sizeof(asn1_sig)], sha_dgst, SHA1_SIZE);
+
+    sig_size = RSA_encrypt(rsa_ctx, block, 
+                            sizeof(asn1_sig) + SHA1_SIZE, enc_block, 1);
+
+    buf[(*offset)++] = ASN1_BIT_STRING;
+    set_gen_length(sig_size+1, buf, offset);
+    buf[(*offset)++] = 0;   /* bit string is multiple of 8 */
+    memcpy(&buf[*offset], enc_block, sig_size);
+    *offset += sig_size;
+}
+
+static int gen_tbs_cert(const char * dn[],
+                    const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset,
+                    uint8_t *sha_dgst)
+{
+    int ret = X509_OK;
+    SHA1_CTX sha_ctx;
+    int seq_offset;
+    int begin_tbs = *offset;
+    int seq_size = pre_adjust_with_size(
+                        ASN1_SEQUENCE, &seq_offset, buf, offset);
+
+    gen_serial_number(buf, offset);
+    gen_signature_alg(buf, offset);
+
+    /* CA certicate issuer */
+    if ((ret = gen_issuer(dn, buf, offset)))
+        goto error;
+
+    gen_utc_time(buf, offset);
+
+    /* certificate issuer */
+    if ((ret = gen_issuer(dn, buf, offset)))
+        goto error;
+
+    gen_pub_key(rsa_ctx, buf, offset);
+    adjust_with_size(seq_size, seq_offset, buf, offset);
+
+    SHA1_Init(&sha_ctx);
+    SHA1_Update(&sha_ctx, &buf[begin_tbs], *offset-begin_tbs);
+    SHA1_Final(sha_dgst, &sha_ctx);
+
+error:
+    return ret;
+}
+
+/**
+ * Create a new certificate.
+ */
+EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data)
+{
+    int ret = X509_OK, offset = 0, seq_offset;
+    /* allocate enough space to load a new certificate */
+    uint8_t *buf = (uint8_t *)alloca(ssl_ctx->rsa_ctx->num_octets*2 + 512);
+    uint8_t sha_dgst[SHA1_SIZE];
+    int seq_size = pre_adjust_with_size(ASN1_SEQUENCE, 
+                                    &seq_offset, buf, &offset);
+
+    if ((ret = gen_tbs_cert(dn, ssl_ctx->rsa_ctx, buf, &offset, sha_dgst)) < 0)
+        goto error;
+
+    gen_signature_alg(buf, &offset);
+    gen_signature(ssl_ctx->rsa_ctx, sha_dgst, buf, &offset);
+    adjust_with_size(seq_size, seq_offset, buf, &offset);
+    *cert_data = (uint8_t *)malloc(offset); /* create the exact memory for it */
+    memcpy(*cert_data, buf, offset);
+
+error:
+    return ret < 0 ? ret : offset;
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/loader.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * Load certificates/keys into memory. These can be in many different formats.
+ * PEM support and other formats can be processed here.
+ *
+ * The PEM private keys may be optionally encrypted with AES128 or AES256. 
+ * The encrypted PEM keys were generated with something like:
+ *
+ * openssl genrsa -aes128 -passout pass:abcd -out axTLS.key_aes128.pem 512
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "os_port.h"
+#include "ssl.h"
+#include "config.h"
+
+static int do_obj(SSL_CTX *ssl_ctx, int obj_type, 
+                    SSLObjLoader *ssl_obj, const char *password);
+#ifdef CONFIG_SSL_HAS_PEM
+static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, 
+                        SSLObjLoader *ssl_obj, const char *password);
+#endif
+
+/*
+ * Load a file into memory that is in binary DER (or ascii PEM) format.
+ */
+EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, 
+                            const char *filename, const char *password)
+{
+#ifndef CONFIG_SSL_SKELETON_MODE
+    static const char * const begin = "-----BEGIN";
+    int ret = SSL_OK;
+    SSLObjLoader *ssl_obj = NULL;
+
+    if (filename == NULL)
+    {
+        ret = SSL_ERROR_INVALID_KEY;
+        goto error;
+    }
+
+    ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
+    ssl_obj->len = get_file(filename, &ssl_obj->buf); 
+    if (ssl_obj->len <= 0)
+    {
+        ret = SSL_ERROR_INVALID_KEY;
+        goto error;
+    }
+
+    /* is the file a PEM file? */
+    if (strstr((char *)ssl_obj->buf, begin) != NULL)
+    {
+#ifdef CONFIG_SSL_HAS_PEM
+        ret = ssl_obj_PEM_load(ssl_ctx, obj_type, ssl_obj, password);
+#else
+        printf(unsupported_str);
+        ret = SSL_ERROR_NOT_SUPPORTED;
+#endif
+    }
+    else
+        ret = do_obj(ssl_ctx, obj_type, ssl_obj, password);
+
+error:
+    ssl_obj_free(ssl_obj);
+    return ret;
+#else
+    printf(unsupported_str);
+    return SSL_ERROR_NOT_SUPPORTED;
+#endif /* CONFIG_SSL_SKELETON_MODE */
+}
+
+/*
+ * Transfer binary data into the object loader.
+ */
+EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int mem_type, 
+        const uint8_t *data, int len, const char *password)
+{
+    int ret;
+    SSLObjLoader *ssl_obj;
+
+    ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
+    ssl_obj->buf = (uint8_t *)malloc(len);
+    memcpy(ssl_obj->buf, data, len);
+    ssl_obj->len = len;
+    ret = do_obj(ssl_ctx, mem_type, ssl_obj, password);
+    ssl_obj_free(ssl_obj);
+    return ret;
+}
+
+/*
+ * Actually work out what we are doing 
+ */
+static int do_obj(SSL_CTX *ssl_ctx, int obj_type, 
+                    SSLObjLoader *ssl_obj, const char *password)
+{
+    int ret = SSL_OK;
+
+    switch (obj_type)
+    {
+        case SSL_OBJ_RSA_KEY:
+            ret = add_private_key(ssl_ctx, ssl_obj);
+            break;
+
+        case SSL_OBJ_X509_CERT:
+            ret = add_cert(ssl_ctx, ssl_obj->buf, ssl_obj->len);
+            break;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+        case SSL_OBJ_X509_CACERT:
+            add_cert_auth(ssl_ctx, ssl_obj->buf, ssl_obj->len);
+            break;
+#endif
+
+#ifdef CONFIG_SSL_USE_PKCS12
+        case SSL_OBJ_PKCS8:
+            ret = pkcs8_decode(ssl_ctx, ssl_obj, password);
+            break;
+
+        case SSL_OBJ_PKCS12:
+            ret = pkcs12_decode(ssl_ctx, ssl_obj, password);
+            break;
+#endif
+        default:
+            printf(unsupported_str);
+            ret = SSL_ERROR_NOT_SUPPORTED;
+            break;
+    }
+
+    return ret;
+}
+
+/*
+ * Clean up our mess.
+ */
+void ssl_obj_free(SSLObjLoader *ssl_obj)
+{
+    if (ssl_obj)
+    {
+        free(ssl_obj->buf);
+        free(ssl_obj);
+    }
+}
+
+/*
+ * Support for PEM encoded keys/certificates.
+ */
+#ifdef CONFIG_SSL_HAS_PEM
+
+#define NUM_PEM_TYPES               4
+#define IV_SIZE                     16
+#define IS_RSA_PRIVATE_KEY          0
+#define IS_ENCRYPTED_PRIVATE_KEY    1
+#define IS_PRIVATE_KEY              2
+#define IS_CERTIFICATE              3
+
+static const char * const begins[NUM_PEM_TYPES] =
+{
+    "-----BEGIN RSA PRIVATE KEY-----",
+    "-----BEGIN ENCRYPTED PRIVATE KEY-----",
+    "-----BEGIN PRIVATE KEY-----",
+    "-----BEGIN CERTIFICATE-----",
+};
+
+static const char * const ends[NUM_PEM_TYPES] =
+{
+    "-----END RSA PRIVATE KEY-----",
+    "-----END ENCRYPTED PRIVATE KEY-----",
+    "-----END PRIVATE KEY-----",
+    "-----END CERTIFICATE-----",
+};
+
+static const char * const aes_str[2] =
+{
+    "DEK-Info: AES-128-CBC,",
+    "DEK-Info: AES-256-CBC," 
+};
+
+/**
+ * Take a base64 blob of data and decrypt it (using AES) into its 
+ * proper ASN.1 form.
+ */
+static int pem_decrypt(const char *where, const char *end,
+                        const char *password, SSLObjLoader *ssl_obj)
+{
+    int ret = -1;
+    int is_aes_256 = 0;
+    char *start = NULL;
+    uint8_t iv[IV_SIZE];
+    int i, pem_size;
+    MD5_CTX md5_ctx;
+    AES_CTX aes_ctx;
+    uint8_t key[32];        /* AES256 size */
+
+    if (password == NULL || strlen(password) == 0)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("Error: Need a password for this PEM file\n"); TTY_FLUSH();
+#endif
+        goto error;
+    }
+
+    if ((start = strstr((const char *)where, aes_str[0])))         /* AES128? */
+    {
+        start += strlen(aes_str[0]);
+    }
+    else if ((start = strstr((const char *)where, aes_str[1])))    /* AES256? */
+    {
+        is_aes_256 = 1;
+        start += strlen(aes_str[1]);
+    }
+    else 
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("Error: Unsupported password cipher\n"); TTY_FLUSH();
+#endif
+        goto error;
+    }
+
+    /* convert from hex to binary - assumes uppercase hex */
+    for (i = 0; i < IV_SIZE; i++)
+    {
+        char c = *start++ - '0';
+        iv[i] = (c > 9 ? c + '0' - 'A' + 10 : c) << 4;
+        c = *start++ - '0';
+        iv[i] += (c > 9 ? c + '0' - 'A' + 10 : c);
+    }
+
+    while (*start == '\r' || *start == '\n')
+        start++;
+
+    /* turn base64 into binary */
+    pem_size = (int)(end-start);
+    if (base64_decode(start, pem_size, ssl_obj->buf, &ssl_obj->len) != 0)
+        goto error;
+
+    /* work out the key */
+    MD5_Init(&md5_ctx);
+    MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password));
+    MD5_Update(&md5_ctx, iv, SALT_SIZE);
+    MD5_Final(key, &md5_ctx);
+
+    if (is_aes_256)
+    {
+        MD5_Init(&md5_ctx);
+        MD5_Update(&md5_ctx, key, MD5_SIZE);
+        MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password));
+        MD5_Update(&md5_ctx, iv, SALT_SIZE);
+        MD5_Final(&key[MD5_SIZE], &md5_ctx);
+    }
+
+    /* decrypt using the key/iv */
+    AES_set_key(&aes_ctx, key, iv, is_aes_256 ? AES_MODE_256 : AES_MODE_128);
+    AES_convert_key(&aes_ctx);
+    AES_cbc_decrypt(&aes_ctx, ssl_obj->buf, ssl_obj->buf, ssl_obj->len);
+    ret = 0;
+
+error:
+    return ret; 
+}
+
+/**
+ * Take a base64 blob of data and turn it into its proper ASN.1 form.
+ */
+static int new_pem_obj(SSL_CTX *ssl_ctx, int is_cacert, char *where, 
+                    int remain, const char *password)
+{
+    int ret = SSL_ERROR_BAD_CERTIFICATE;
+    SSLObjLoader *ssl_obj = NULL;
+
+    while (remain > 0)
+    {
+        int i, pem_size, obj_type;
+        char *start = NULL, *end = NULL;
+
+        for (i = 0; i < NUM_PEM_TYPES; i++)
+        {
+            if ((start = strstr(where, begins[i])) &&
+                    (end = strstr(where, ends[i])))
+            {
+                remain -= (int)(end-where);
+                start += strlen(begins[i]);
+                pem_size = (int)(end-start);
+
+                ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
+
+                /* 4/3 bigger than what we need but so what */
+                ssl_obj->buf = (uint8_t *)calloc(1, pem_size);
+                ssl_obj->len = pem_size;
+
+                if (i == IS_RSA_PRIVATE_KEY && 
+                            strstr(start, "Proc-Type:") && 
+                            strstr(start, "4,ENCRYPTED"))
+                {
+                    /* check for encrypted PEM file */
+                    if (pem_decrypt(start, end, password, ssl_obj) < 0)
+                    {
+                        ret = SSL_ERROR_BAD_CERTIFICATE;
+                        goto error;
+                    }
+                }
+                else 
+                {
+                    ssl_obj->len = pem_size;
+                    if (base64_decode(start, pem_size, 
+                                ssl_obj->buf, &ssl_obj->len) != 0)
+                    {
+                        ret = SSL_ERROR_BAD_CERTIFICATE;
+                        goto error;
+                    }
+                }
+
+                switch (i)
+                {
+                    case IS_RSA_PRIVATE_KEY:
+                        obj_type = SSL_OBJ_RSA_KEY;
+                        break;
+
+                    case IS_ENCRYPTED_PRIVATE_KEY:
+                    case IS_PRIVATE_KEY:
+                        obj_type = SSL_OBJ_PKCS8;
+                        break;
+
+                    case IS_CERTIFICATE:
+                        obj_type = is_cacert ?
+                                        SSL_OBJ_X509_CACERT : SSL_OBJ_X509_CERT;
+                        break;
+
+                    default:
+                        ret = SSL_ERROR_BAD_CERTIFICATE;
+                        goto error;
+                }
+
+                /* In a format we can now understand - so process it */
+                if ((ret = do_obj(ssl_ctx, obj_type, ssl_obj, password)))
+                    goto error;
+
+                end += strlen(ends[i]);
+                remain -= strlen(ends[i]);
+                while (remain > 0 && (*end == '\r' || *end == '\n'))
+                {
+                    end++;
+                    remain--;
+                }
+
+                where = end;
+                break;
+            }
+        }
+
+        ssl_obj_free(ssl_obj);
+        ssl_obj = NULL;
+        if (start == NULL)
+           break;
+    }
+error:
+    ssl_obj_free(ssl_obj);
+    return ret;
+}
+
+/*
+ * Load a file into memory that is in ASCII PEM format.
+ */
+static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, 
+                        SSLObjLoader *ssl_obj, const char *password)
+{
+    char *start;
+
+    /* add a null terminator */
+    ssl_obj->len++;
+    ssl_obj->buf = (uint8_t *)realloc(ssl_obj->buf, ssl_obj->len);
+    ssl_obj->buf[ssl_obj->len-1] = 0;
+    start = (char *)ssl_obj->buf;
+    return new_pem_obj(ssl_ctx, obj_type == SSL_OBJ_X509_CACERT,
+                                start, ssl_obj->len, password);
+}
+#endif /* CONFIG_SSL_HAS_PEM */
+
+/**
+ * Load the key/certificates in memory depending on compile-time and user
+ * options. 
+ */
+int load_key_certs(SSL_CTX *ssl_ctx)
+{
+    printf("loading key certs\r\n");
+    int ret = SSL_OK;
+    uint32_t options = ssl_ctx->options;
+#ifdef CONFIG_SSL_GENERATE_X509_CERT 
+    uint8_t *cert_data = NULL;
+    int cert_size;
+    static const char *dn[] = 
+    {
+        CONFIG_SSL_X509_COMMON_NAME,
+        CONFIG_SSL_X509_ORGANIZATION_NAME,
+        CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME
+    };
+#endif
+
+    /* do the private key first */
+    if (strlen(CONFIG_SSL_PRIVATE_KEY_LOCATION) > 0)
+    {
+        if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, 
+                                CONFIG_SSL_PRIVATE_KEY_LOCATION,
+                                CONFIG_SSL_PRIVATE_KEY_PASSWORD)) < 0)
+            goto error;
+    }
+    else if (!(options & SSL_NO_DEFAULT_KEY))
+    {
+#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)
+        static const    /* saves a few more bytes */
+#include "private_key.h"
+        ssl_obj_memory_load(ssl_ctx, SSL_OBJ_RSA_KEY, default_private_key,
+                default_private_key_len, NULL); 
+#endif
+    }
+
+    /* now load the certificate */
+#ifdef CONFIG_SSL_GENERATE_X509_CERT 
+    if ((cert_size = ssl_x509_create(ssl_ctx, 0, dn, &cert_data)) < 0)
+    {
+        ret = cert_size;
+        goto error;
+    }
+
+    ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, cert_data, cert_size, NULL);
+    free(cert_data);
+#else
+    if (strlen(CONFIG_SSL_X509_CERT_LOCATION))
+    {
+        if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, 
+                                CONFIG_SSL_X509_CERT_LOCATION, NULL)) < 0)
+            goto error;
+    }
+    else if (!(options & SSL_NO_DEFAULT_KEY))
+    {
+#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)
+        static const    /* saves a few bytes and RAM */
+#include "cert.h"
+        ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, 
+                    default_certificate, default_certificate_len, NULL);
+#endif
+    }
+#endif
+
+error:
+#ifdef CONFIG_SSL_FULL_MODE
+    if (ret)
+    {
+        printf("Error: Certificate or key not loaded\n"); TTY_FLUSH();
+    }
+#endif
+
+    return ret;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/openssl.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/*
+ * Enable a subset of openssl compatible functions. We don't aim to be 100%
+ * compatible - just to be able to do basic ports etc.
+ *
+ * Only really tested on mini_httpd, so I'm not too sure how extensive this
+ * port is.
+ */
+
+#include "config.h"
+
+#ifdef CONFIG_OPENSSL_COMPATIBLE
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "os_port.h"
+#include "ssl.h"
+
+#define OPENSSL_CTX_ATTR  ((OPENSSL_CTX *)ssl_ctx->bonus_attr)
+
+static char *key_password = NULL;
+
+void *SSLv23_server_method(void) { return NULL; }
+void *SSLv3_server_method(void) { return NULL; }
+void *TLSv1_server_method(void) { return NULL; }
+void *SSLv23_client_method(void) { return NULL; }
+void *SSLv3_client_method(void) { return NULL; }
+void *TLSv1_client_method(void) { return NULL; }
+
+typedef void * (*ssl_func_type_t)(void);
+typedef void * (*bio_func_type_t)(void);
+
+typedef struct
+{
+    ssl_func_type_t ssl_func_type;
+} OPENSSL_CTX;
+
+SSL_CTX * SSL_CTX_new(ssl_func_type_t meth)
+{
+    SSL_CTX *ssl_ctx = ssl_ctx_new(0, 5);
+    ssl_ctx->bonus_attr = malloc(sizeof(OPENSSL_CTX));
+    OPENSSL_CTX_ATTR->ssl_func_type = meth;
+    return ssl_ctx;
+}
+
+void SSL_CTX_free(SSL_CTX * ssl_ctx)
+{
+    free(ssl_ctx->bonus_attr);
+    ssl_ctx_free(ssl_ctx);
+}
+
+SSL * SSL_new(SSL_CTX *ssl_ctx)
+{
+    SSL *ssl;
+    ssl_func_type_t ssl_func_type;
+
+    ssl = ssl_new(ssl_ctx, -1);        /* fd is set later */
+    ssl_func_type = OPENSSL_CTX_ATTR->ssl_func_type;
+
+#ifdef CONFIG_SSL_ENABLE_CLIENT
+    if (ssl_func_type == SSLv23_client_method ||
+        ssl_func_type == SSLv3_client_method ||
+        ssl_func_type == TLSv1_client_method)
+    {
+        SET_SSL_FLAG(SSL_IS_CLIENT);
+    }
+    else
+#endif
+    {
+        ssl->next_state = HS_CLIENT_HELLO;
+    }
+
+    return ssl;
+}
+
+int SSL_set_fd(SSL *s, int fd)
+{
+    s->client_fd = fd;
+    return 1;   /* always succeeds */
+}
+
+int SSL_accept(SSL *ssl)
+{
+    while (ssl_read(ssl, NULL) == SSL_OK)
+    {
+        if (ssl->next_state == HS_CLIENT_HELLO)
+            return 1;   /* we're done */
+    }
+
+    return -1;
+}
+
+#ifdef CONFIG_SSL_ENABLE_CLIENT
+int SSL_connect(SSL *ssl)
+{
+    return do_client_connect(ssl) == SSL_OK ? 1 : -1;
+}
+#endif
+
+void SSL_free(SSL *ssl)
+{
+    ssl_free(ssl);
+}
+
+int SSL_read(SSL *ssl, void *buf, int num)
+{
+    uint8_t *read_buf;
+    int ret;
+
+    while ((ret = ssl_read(ssl, &read_buf)) == SSL_OK);
+
+    if (ret > SSL_OK)
+    {
+        memcpy(buf, read_buf, ret > num ? num : ret);
+    }
+
+    return ret;
+}
+
+int SSL_write(SSL *ssl, const void *buf, int num)
+{
+    return ssl_write(ssl, buf, num);
+}
+
+int SSL_CTX_use_certificate_file(SSL_CTX *ssl_ctx, const char *file, int type)
+{
+    return (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, file, NULL) == SSL_OK);
+}
+
+int SSL_CTX_use_PrivateKey_file(SSL_CTX *ssl_ctx, const char *file, int type)
+{
+    return (ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, file, key_password) == SSL_OK);
+}
+
+int SSL_CTX_use_certificate_ASN1(SSL_CTX *ssl_ctx, int len, const uint8_t *d)
+{
+    return (ssl_obj_memory_load(ssl_ctx, 
+                        SSL_OBJ_X509_CERT, d, len, NULL) == SSL_OK);
+}
+
+int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx,
+                                            unsigned int sid_ctx_len)
+{
+    return 1;
+}
+
+int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx)
+{
+    return 1;
+}
+
+int SSL_CTX_use_certificate_chain_file(SSL_CTX *ssl_ctx, const char *file)
+{
+    return (ssl_obj_load(ssl_ctx, 
+                        SSL_OBJ_X509_CERT, file, NULL) == SSL_OK);
+}
+
+int SSL_shutdown(SSL *ssl)
+{
+    return 1;
+}
+
+/*** get/set session ***/
+SSL_SESSION *SSL_get1_session(SSL *ssl)
+{
+    return (SSL_SESSION *)ssl_get_session_id(ssl); /* note: wrong cast */
+}
+
+int SSL_set_session(SSL *ssl, SSL_SESSION *session)
+{
+    memcpy(ssl->session_id, (uint8_t *)session, SSL_SESSION_ID_SIZE);
+    return 1;
+}
+
+void SSL_SESSION_free(SSL_SESSION *session) { }
+/*** end get/set session ***/
+
+long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
+{
+    return 0;
+}
+
+void SSL_CTX_set_verify(SSL_CTX *ctx, int mode,
+                                 int (*verify_callback)(int, void *)) { }
+
+void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth) { }
+
+int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
+                                           const char *CApath)
+{
+    return 1;
+}
+
+void *SSL_load_client_CA_file(const char *file)
+{
+    return (void *)file;
+}
+
+void SSL_CTX_set_client_CA_list(SSL_CTX *ssl_ctx, void *file) 
+{ 
+
+    ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, (const char *)file, NULL);
+}
+
+void SSLv23_method(void) { }
+
+void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, void *cb) { }
+
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u) 
+{ 
+    key_password = (char *)u;
+}
+
+int SSL_peek(SSL *ssl, void *buf, int num)
+{
+    memcpy(buf, ssl->bm_data, num);
+    return num;
+}
+
+void SSL_set_bio(SSL *ssl, void *rbio, void *wbio) { }
+
+long SSL_get_verify_result(const SSL *ssl)
+{
+    return ssl_handshake_status(ssl);
+}
+
+int SSL_state(SSL *ssl)
+{
+    return 0x03; // ok state
+}
+
+/** end of could do better list */
+
+void *SSL_get_peer_certificate(const SSL *ssl)
+{
+    return &ssl->ssl_ctx->certs[0];
+}
+
+int SSL_clear(SSL *ssl)
+{
+    return 1;
+}
+
+
+int SSL_CTX_check_private_key(const SSL_CTX *ctx)
+{
+    return 1;
+}
+
+int SSL_CTX_set_cipher_list(SSL *s, const char *str)
+{
+    return 1;
+}
+
+int SSL_get_error(const SSL *ssl, int ret)
+{
+    ssl_display_error(ret);
+    return 0;   /* TODO: return proper return code */
+}
+
+void SSL_CTX_set_options(SSL_CTX *ssl_ctx, int option) {}
+int SSL_library_init(void ) { return 1; }
+void SSL_load_error_strings(void ) {}
+void ERR_print_errors_fp(FILE *fp) {}
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+long SSL_CTX_get_timeout(const SSL_CTX *ssl_ctx) { 
+                            return CONFIG_SSL_EXPIRY_TIME*3600; }
+long SSL_CTX_set_timeout(SSL_CTX *ssl_ctx, long t) { 
+                            return SSL_CTX_get_timeout(ssl_ctx); }
+#endif
+void BIO_printf(FILE *f, const char *format, ...)
+{
+    va_list(ap);
+    va_start(ap, format);
+    vfprintf(f, format, ap);
+    va_end(ap);
+}
+
+void* BIO_s_null(void) { return NULL; }
+FILE *BIO_new(bio_func_type_t func)
+{
+    if (func == BIO_s_null)
+        return fopen("/dev/null", "r");
+    else
+        return NULL;
+}
+
+FILE *BIO_new_fp(FILE *stream, int close_flag) { return stream; }
+int BIO_free(FILE *a) { if (a != stdout && a != stderr) fclose(a); return 1; }
+
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/os_port.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * @file os_port.c
+ *
+ * OS specific functions.
+ */
+#include <time.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include "os_port.h"
+#include <stdio.h>
+#include "sockets.h"
+
+#ifdef MBED
+/**
+ * gettimeofday() not in mbed 
+ */
+EXP_FUNC void STDCALL gettimeofday(struct timeval* t, void* timezone)
+{       
+    t->tv_sec = time(NULL);
+    t->tv_usec = 0;                         /* 1sec precision only */ 
+
+}
+
+#endif
+
+#ifdef WIN32
+/**
+ * gettimeofday() not in Win32 
+ */
+EXP_FUNC void STDCALL gettimeofday(struct timeval* t, void* timezone)
+{       
+#if defined(_WIN32_WCE)
+    t->tv_sec = time(NULL);
+    t->tv_usec = 0;                         /* 1sec precision only */ 
+#else
+    struct _timeb timebuffer;
+    _ftime(&timebuffer);
+    t->tv_sec = (long)timebuffer.time;
+    t->tv_usec = 1000 * timebuffer.millitm; /* 1ms precision */
+#endif
+}
+
+
+/**
+ * strcasecmp() not in Win32
+ */
+EXP_FUNC int STDCALL strcasecmp(const char *s1, const char *s2)
+{
+    while (tolower(*s1) == tolower(*s2++))
+    {
+        if (*s1++ == '\0')
+        {
+            return 0;
+        }
+    }
+
+    return *(unsigned char *)s1 - *(unsigned char *)(s2 - 1);
+}
+
+
+EXP_FUNC int STDCALL getdomainname(char *buf, int buf_size)
+{
+    HKEY hKey;
+    unsigned long datatype;
+    unsigned long bufferlength = buf_size;
+
+    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+            TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"),
+                        0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
+        return -1;
+
+    RegQueryValueEx(hKey, "Domain", NULL, &datatype, buf, &bufferlength);
+    RegCloseKey(hKey);
+    return 0; 
+}
+#endif
+
+#undef malloc
+#undef realloc
+#undef calloc
+
+static const char * out_of_mem_str = "out of memory";
+static const char * file_open_str = "Could not open file \"%s\"";
+
+/* 
+ * Some functions that call display some error trace and then call abort().
+ * This just makes life much easier on embedded systems, since we're 
+ * suffering major trauma...
+ */
+EXP_FUNC void * STDCALL ax_malloc(size_t s)
+{
+    void *x;
+
+    if ((x = malloc(s)) == NULL)
+        exit_now(out_of_mem_str);
+
+    return x;
+}
+
+EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s)
+{
+    void *x;
+
+    if ((x = realloc(y, s)) == NULL)
+        exit_now(out_of_mem_str);
+
+    return x;
+}
+
+EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s)
+{
+    void *x;
+  
+    if ((x = calloc(n, s)) == NULL) {
+        exit_now(out_of_mem_str);
+    }
+
+    return x;
+}
+/*
+EXP_FUNC int STDCALL ax_open(const char *pathname, int flags)
+{
+    int x;
+
+    if ((x = open(pathname, flags)) < 0)
+        exit_now(file_open_str, pathname);
+
+    return x;
+}
+*/
+
+/**
+ * This is a call which will deliberately exit an application, but will
+ * display some information before dying.
+ */
+void exit_now(const char *format, ...)
+{
+    va_list argp;
+
+    va_start(argp, format);
+    vfprintf(stderr, format, argp);
+    va_end(argp);
+    abort();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/os_port.h	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,36 @@
+#ifndef HEADER_OS_PORT_H
+#define HEADER_OS_PORT_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "config.h"
+
+//#include <Thread.h>
+#define SSL_CTX_MUTEX_TYPE          //Mutex
+#define SSL_CTX_MUTEX_INIT(A)       //pthread_mutex_init(&A, NULL)
+#define SSL_CTX_MUTEX_DESTROY(A)    //pthread_mutex_destroy(&A)
+#define SSL_CTX_LOCK(A)             //pthread_mutex_lock(&A)
+#define SSL_CTX_UNLOCK(A)           //pthread_mutex_unlock(&A)
+
+#define malloc(A)       ax_malloc(A)
+#ifndef realloc
+#define realloc(A,B)    ax_realloc(A,B)
+#endif
+#define calloc(A,B)     ax_calloc(A,B)
+
+#define STDCALL
+#define EXP_FUNC
+EXP_FUNC void * STDCALL ax_malloc(size_t s);
+EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s);
+EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s);
+//EXP_FUNC int STDCALL ax_open(const char *pathname, int flags); 
+
+#define SOCKET_READ(A,B,C)      lwip_recv(A,B,C,0)
+#define SOCKET_WRITE(A,B,C)     lwip_send(A,B,C,0)
+#define SOCKET_CLOSE(A)         closesocket(A)
+#define TTY_FLUSH()
+#ifdef __cplusplus
+}
+#endif
+#endif 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/os_port_old.h	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * @file os_port.h
+ *
+ * Some stuff to minimise the differences between windows and linux/unix
+ */
+
+#ifndef HEADER_OS_PORT_H
+#define HEADER_OS_PORT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "os_int.h"
+#include <stdio.h>
+
+#if defined(WIN32)
+#define STDCALL                 __stdcall
+#define EXP_FUNC                __declspec(dllexport)
+#else
+#define STDCALL
+#define EXP_FUNC
+#endif
+
+#if defined(_WIN32_WCE)
+#undef WIN32
+#define WIN32
+#endif
+
+#ifdef WIN32
+
+/* Windows CE stuff */
+#if defined(_WIN32_WCE)
+#include <basetsd.h>
+#define abort()                 exit(1)
+#else
+#include <io.h>
+#include <process.h>
+#include <sys/timeb.h>
+#include <fcntl.h>
+#endif      /* _WIN32_WCE */
+
+#include <winsock.h>
+#include <direct.h>
+#undef getpid
+#undef open
+#undef close
+#undef sleep
+#undef gettimeofday
+#undef dup2
+#undef unlink
+
+#define SOCKET_READ(A,B,C)      recv(A,B,C,0)
+#define SOCKET_WRITE(A,B,C)     send(A,B,C,0)
+#define SOCKET_CLOSE(A)         closesocket(A)
+#define srandom(A)              srand(A)
+#define random()                rand()
+#define getpid()                _getpid()
+#define snprintf                _snprintf
+#define open(A,B)               _open(A,B)
+#define dup2(A,B)               _dup2(A,B)
+#define unlink(A)               _unlink(A)
+#define close(A)                _close(A)
+#define read(A,B,C)             _read(A,B,C)
+#define write(A,B,C)            _write(A,B,C)
+#define sleep(A)                Sleep(A*1000)
+#define usleep(A)               Sleep(A/1000)
+#define strdup(A)               _strdup(A)
+#define chroot(A)               _chdir(A)
+#define chdir(A)                _chdir(A)
+#define alloca(A)               _alloca(A)
+
+
+#ifndef lseek
+#define lseek(A,B,C)            _lseek(A,B,C)
+
+#endif
+
+/* This fix gets around a problem where a win32 application on a cygwin xterm
+   doesn't display regular output (until a certain buffer limit) - but it works
+   fine under a normal DOS window. This is a hack to get around the issue - 
+   see http://www.khngai.com/emacs/tty.php  */
+#define TTY_FLUSH()             if (!_isatty(_fileno(stdout))) fflush(stdout);
+
+/*
+ * automatically build some library dependencies.
+ */
+#pragma comment(lib, "WS2_32.lib")
+#pragma comment(lib, "AdvAPI32.lib")
+
+typedef int socklen_t;
+
+EXP_FUNC void STDCALL gettimeofday(struct timeval* t,void* timezone);
+EXP_FUNC int STDCALL strcasecmp(const char *s1, const char *s2);
+EXP_FUNC int STDCALL getdomainname(char *buf, int buf_size);
+
+#else   /* Not Win32 */
+
+//#include <unistd.h>
+//#include <pwd.h>
+//#include <netdb.h>
+//#include <dirent.h>
+//#include <fcntl.h>
+#include <errno.h>
+//#include <sys/stat.h>
+#include <time.h>
+#include <socket.h>
+//#include <sys/wait.h>
+#include <netinet/in.h>
+#include <inet.h>
+
+#define SOCKET_READ(A,B,C)      read(A,B,C)
+#define SOCKET_WRITE(A,B,C)     write(A,B,C)
+#define SOCKET_CLOSE(A)         if (A >= 0) close(A)
+#define TTY_FLUSH()
+
+#endif  /* Not Win32 */
+
+/* some functions to mutate the way these work */
+#define malloc(A)       ax_malloc(A)
+#ifndef realloc
+#define realloc(A,B)    ax_realloc(A,B)
+#endif
+#define calloc(A,B)     ax_calloc(A,B)
+
+EXP_FUNC void * STDCALL ax_malloc(size_t s);
+EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s);
+EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s);
+EXP_FUNC int STDCALL ax_open(const char *pathname, int flags); 
+
+#ifdef CONFIG_PLATFORM_LINUX
+void exit_now(const char *format, ...) __attribute((noreturn));
+#else
+void exit_now(const char *format, ...);
+#endif
+
+/* Mutexing definitions */
+#if defined(CONFIG_SSL_CTX_MUTEXING)
+#if defined(WIN32)
+#define SSL_CTX_MUTEX_TYPE          HANDLE
+#define SSL_CTX_MUTEX_INIT(A)       A=CreateMutex(0, FALSE, 0)
+#define SSL_CTX_MUTEX_DESTROY(A)    CloseHandle(A)
+#define SSL_CTX_LOCK(A)             WaitForSingleObject(A, INFINITE)
+#define SSL_CTX_UNLOCK(A)           ReleaseMutex(A)
+#else 
+#include <pthread.h>
+#define SSL_CTX_MUTEX_TYPE          pthread_mutex_t
+#define SSL_CTX_MUTEX_INIT(A)       pthread_mutex_init(&A, NULL)
+#define SSL_CTX_MUTEX_DESTROY(A)    pthread_mutex_destroy(&A)
+#define SSL_CTX_LOCK(A)             pthread_mutex_lock(&A)
+#define SSL_CTX_UNLOCK(A)           pthread_mutex_unlock(&A)
+#endif
+#else   /* no mutexing */
+#define SSL_CTX_MUTEX_INIT(A)
+#define SSL_CTX_MUTEX_DESTROY(A)
+#define SSL_CTX_LOCK(A)
+#define SSL_CTX_UNLOCK(A)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/p12.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * Process PKCS#8/PKCS#12 keys.
+ *
+ * The decoding of a PKCS#12 key is fairly specific - this code was tested on a
+ * key generated with:
+ *
+ * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem
+ * -keypbe PBE-SHA1-RC4-128 -certpbe PBE-SHA1-RC4-128 
+ * -name "p12_withoutCA" -out axTLS.withoutCA.p12 -password pass:abcd
+ *
+ * or with a certificate chain:
+ *
+ * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem
+ * -certfile axTLS.ca_x509.pem -keypbe PBE-SHA1-RC4-128 -certpbe
+ * PBE-SHA1-RC4-128 -name "p12_withCA" -out axTLS.withCA.p12 -password pass:abcd
+ *
+ * Note that the PBE has to be specified with PBE-SHA1-RC4-128. The
+ * private/public keys/certs have to use RSA encryption. Both the integrity
+ * and privacy passwords are the same.
+ *
+ * The PKCS#8 files were generated with something like:
+ *
+ * PEM format:
+ * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -v1
+ * PBE-SHA1-RC4-128 -out axTLS.encrypted_pem.p8
+ *
+ * DER format:
+ * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -outform DER
+ * -v1 PBE-SHA1-RC4-128 -out axTLS.encrypted.p8
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "os_port.h"
+#include "ssl.h"
+
+/* all commented out if not used */
+#ifdef CONFIG_SSL_USE_PKCS12
+
+#define BLOCK_SIZE          64
+#define PKCS12_KEY_ID       1
+#define PKCS12_IV_ID        2
+#define PKCS12_MAC_ID       3
+
+static char *make_uni_pass(const char *password, int *uni_pass_len);
+static int p8_decrypt(const char *uni_pass, int uni_pass_len, 
+                        const uint8_t *salt, int iter, 
+                        uint8_t *priv_key, int priv_key_len, int id);
+static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key);
+static int get_pbe_params(uint8_t *buf, int *offset, 
+        const uint8_t **salt, int *iterations);
+
+/*
+ * Take a raw pkcs8 block and then decrypt it and turn it into a normal key.
+ */
+int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)
+{
+    uint8_t *buf = ssl_obj->buf;
+    int len, offset = 0;
+    int iterations;
+    int ret = SSL_NOT_OK;
+    uint8_t *version = NULL;
+    const uint8_t *salt;
+    uint8_t *priv_key;
+    int uni_pass_len;
+    char *uni_pass = make_uni_pass(password, &uni_pass_len);
+
+    if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("Error: Invalid p8 ASN.1 file\n");
+#endif
+        goto error;
+    }
+
+    /* unencrypted key? */
+    if (asn1_get_int(buf, &offset, &version) > 0 && *version == 0)
+    {
+        ret = p8_add_key(ssl_ctx, buf);
+        goto error;
+    }
+
+    if (get_pbe_params(buf, &offset, &salt, &iterations) < 0)
+        goto error;
+
+    if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
+        goto error;
+
+    priv_key = &buf[offset];
+
+    p8_decrypt(uni_pass, uni_pass_len, salt, 
+                        iterations, priv_key, len, PKCS12_KEY_ID);
+    ret = p8_add_key(ssl_ctx, priv_key);
+
+error:
+    free(version);
+    free(uni_pass);
+    return ret;
+}
+
+/*
+ * Take the unencrypted pkcs8 and turn it into a private key 
+ */
+static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key)
+{
+    uint8_t *buf = priv_key;
+    int len, offset = 0;
+    int ret = SSL_NOT_OK;
+
+    /* Skip the preamble and go straight to the private key.
+       We only support rsaEncryption (1.2.840.113549.1.1.1)  */
+    if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+            asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 ||
+            asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+            (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
+        goto error;
+
+    ret = asn1_get_private_key(&buf[offset], len, &ssl_ctx->rsa_ctx);
+
+error:
+    return ret;
+}
+
+/*
+ * Create the unicode password 
+ */
+static char *make_uni_pass(const char *password, int *uni_pass_len)
+{
+    int pass_len = 0, i;
+    char *uni_pass;
+
+    if (password == NULL)
+    {
+        password = "";
+    }
+
+    uni_pass = (char *)malloc((strlen(password)+1)*2);
+
+    /* modify the password into a unicode version */
+    for (i = 0; i < (int)strlen(password); i++)
+    {
+        uni_pass[pass_len++] = 0;
+        uni_pass[pass_len++] = password[i];
+    }
+
+    uni_pass[pass_len++] = 0;       /* null terminate */
+    uni_pass[pass_len++] = 0;
+    *uni_pass_len = pass_len;
+    return uni_pass;
+}
+
+/*
+ * Decrypt a pkcs8 block.
+ */
+static int p8_decrypt(const char *uni_pass, int uni_pass_len,
+                        const uint8_t *salt, int iter, 
+                        uint8_t *priv_key, int priv_key_len, int id)
+{
+    uint8_t p[BLOCK_SIZE*2];
+    uint8_t d[BLOCK_SIZE];
+    uint8_t Ai[SHA1_SIZE];
+    SHA1_CTX sha_ctx;
+    RC4_CTX rc4_ctx;
+    int i;
+
+    for (i = 0; i < BLOCK_SIZE; i++)
+    {
+        p[i] = salt[i % SALT_SIZE];
+        p[BLOCK_SIZE+i] = uni_pass[i % uni_pass_len];
+        d[i] = id;
+    }
+
+    /* get the key - no IV since we are using RC4 */
+    SHA1_Init(&sha_ctx);
+    SHA1_Update(&sha_ctx, d, sizeof(d));
+    SHA1_Update(&sha_ctx, p, sizeof(p));
+    SHA1_Final(Ai, &sha_ctx);
+
+    for (i = 1; i < iter; i++)
+    {
+        SHA1_Init(&sha_ctx);
+        SHA1_Update(&sha_ctx, Ai, SHA1_SIZE);
+        SHA1_Final(Ai, &sha_ctx);
+    }
+
+    /* do the decryption */
+    if (id == PKCS12_KEY_ID)
+    {
+        RC4_setup(&rc4_ctx, Ai, 16);
+        RC4_crypt(&rc4_ctx, priv_key, priv_key, priv_key_len);
+    }
+    else  /* MAC */
+        memcpy(priv_key, Ai, SHA1_SIZE);
+
+    return 0;
+}
+
+/*
+ * Take a raw pkcs12 block and the decrypt it and turn it into a certificate(s)
+ * and keys.
+ */
+int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)
+{
+    uint8_t *buf = ssl_obj->buf;
+    int len, iterations, auth_safes_start, 
+              auth_safes_end, auth_safes_len, key_offset, offset = 0;
+    int all_certs = 0;
+    uint8_t *version = NULL, *auth_safes = NULL, *cert, *orig_mac;
+    uint8_t key[SHA1_SIZE];
+    uint8_t mac[SHA1_SIZE];
+    const uint8_t *salt;
+    int uni_pass_len, ret = SSL_OK;
+    char *uni_pass = make_uni_pass(password, &uni_pass_len);
+    static const uint8_t pkcs_data[] = /* pkc7 data */
+        { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 };
+    static const uint8_t pkcs_encrypted[] = /* pkc7 encrypted */
+        { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06 };
+    static const uint8_t pkcs8_key_bag[] = /* 1.2.840.113549.1.12.10.1.2 */
+        { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02 };
+
+    if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("Error: Invalid p12 ASN.1 file\n");
+#endif
+        goto error;
+    }
+
+    if (asn1_get_int(buf, &offset, &version) < 0 || *version != 3)
+    {
+        ret = SSL_ERROR_INVALID_VERSION;
+        goto error;
+    }
+
+    /* remove all the boring pcks7 bits */
+    if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || 
+                (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
+                len != sizeof(pkcs_data) || 
+                memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
+        goto error;
+
+    offset += len;
+
+    if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
+            asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0)
+        goto error;
+
+    /* work out the MAC start/end points (done on AuthSafes) */
+    auth_safes_start = offset;
+    auth_safes_end = offset;
+    if (asn1_skip_obj(buf, &auth_safes_end, ASN1_SEQUENCE) < 0)
+        goto error;
+
+    auth_safes_len = auth_safes_end - auth_safes_start;
+    auth_safes = malloc(auth_safes_len);
+
+    memcpy(auth_safes, &buf[auth_safes_start], auth_safes_len);
+
+    if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+            asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+            (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
+            (len != sizeof(pkcs_encrypted) || 
+            memcmp(&buf[offset], pkcs_encrypted, sizeof(pkcs_encrypted))))
+        goto error;
+
+    offset += len;
+
+    if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
+            asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+            asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 ||
+            asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+            (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
+            len != sizeof(pkcs_data) || 
+            memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
+        goto error;
+
+    offset += len;
+
+    /* work out the salt for the certificate */
+    if (get_pbe_params(buf, &offset, &salt, &iterations) < 0 ||
+            (len = asn1_next_obj(buf, &offset, ASN1_IMPLICIT_TAG)) < 0)
+        goto error;
+
+    /* decrypt the certificate */
+    cert = &buf[offset];
+    if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert, 
+                            len, PKCS12_KEY_ID)) < 0)
+        goto error;
+
+    offset += len;
+
+    /* load the certificate */
+    key_offset = 0;
+    all_certs = asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE);
+
+    /* keep going until all certs are loaded */
+    while (key_offset < all_certs)
+    {
+        int cert_offset = key_offset;
+
+        if (asn1_skip_obj(cert, &cert_offset, ASN1_SEQUENCE) < 0 ||
+                asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 ||
+                asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 ||
+                asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 ||
+                asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 ||
+                asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 ||
+                asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 ||
+                (len = asn1_next_obj(cert, &key_offset, ASN1_OCTET_STRING)) < 0)
+            goto error;
+
+        if ((ret = add_cert(ssl_ctx, &cert[key_offset], len)) < 0)
+            goto error;
+
+        key_offset = cert_offset;
+    }
+
+    if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+            (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
+            len != sizeof(pkcs_data) || 
+            memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
+        goto error;
+
+    offset += len;
+
+    if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
+            asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0 ||
+            asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+            asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+            (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
+            (len != sizeof(pkcs8_key_bag)) || 
+            memcmp(&buf[offset], pkcs8_key_bag, sizeof(pkcs8_key_bag)))
+        goto error;
+
+    offset += len;
+
+    /* work out the salt for the private key */
+    if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
+            asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+            get_pbe_params(buf, &offset, &salt, &iterations) < 0 ||
+            (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
+        goto error;
+
+    /* decrypt the private key */
+    cert = &buf[offset];
+    if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert, 
+                            len, PKCS12_KEY_ID)) < 0)
+        goto error;
+
+    offset += len;
+
+    /* load the private key */
+    if ((ret = p8_add_key(ssl_ctx, cert)) < 0)
+        goto error;
+
+    /* miss out on friendly name, local key id etc */
+    if (asn1_skip_obj(buf, &offset, ASN1_SET) < 0)
+        goto error;
+
+    /* work out the MAC */
+    if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+            asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+            asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+            (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 ||
+            len != SHA1_SIZE)
+        goto error;
+
+    orig_mac = &buf[offset];
+    offset += len;
+
+    /* get the salt */
+    if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || len != 8)
+        goto error;
+
+    salt = &buf[offset];
+
+    /* work out what the mac should be */
+    if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, 
+                            key, SHA1_SIZE, PKCS12_MAC_ID)) < 0)
+        goto error;
+
+    hmac_sha1(auth_safes, auth_safes_len, key, SHA1_SIZE, mac);
+
+    if (memcmp(mac, orig_mac, SHA1_SIZE))
+    {
+        ret = SSL_ERROR_INVALID_HMAC;                  
+        goto error;
+    }
+
+error:
+    free(version);
+    free(uni_pass);
+    free(auth_safes);
+    return ret;
+}
+
+/*
+ * Retrieve the salt/iteration details from a PBE block.
+ */
+static int get_pbe_params(uint8_t *buf, int *offset, 
+        const uint8_t **salt, int *iterations)
+{
+    static const uint8_t pbeSH1RC4[] = /* pbeWithSHAAnd128BitRC4  */
+            { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x01 };
+
+    int i, len;
+    uint8_t *iter = NULL;
+    int error_code = SSL_ERROR_NOT_SUPPORTED;
+
+    /* Get the PBE type */
+    if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 ||
+            (len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)
+        goto error;
+
+    /* we expect pbeWithSHAAnd128BitRC4 (1.2.840.113549.1.12.1.1) 
+       which is the only algorithm we support */
+    if (len != sizeof(pbeSH1RC4) || 
+                    memcmp(&buf[*offset], pbeSH1RC4, sizeof(pbeSH1RC4)))
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("Error: pkcs8/pkcs12 must use \"PBE-SHA1-RC4-128\"\n");
+#endif
+        goto error;
+    }
+
+    *offset += len;
+
+    if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 ||
+            (len = asn1_next_obj(buf, offset, ASN1_OCTET_STRING)) < 0 || 
+            len != 8)
+        goto error;
+
+    *salt = &buf[*offset];
+    *offset += len;
+
+    if ((len = asn1_get_int(buf, offset, &iter)) < 0)
+        goto error;
+
+    *iterations = 0;
+    for (i = 0; i < len; i++)
+    {
+        (*iterations) <<= 8;
+        (*iterations) += iter[i];
+    }
+
+    free(iter);
+    error_code = SSL_OK;       /* got here - we are ok */
+
+error:
+    return error_code;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/private_key.h	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,54 @@
+unsigned char default_private_key[] = {
+  0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xcd,
+  0xfd, 0x89, 0x48, 0xbe, 0x36, 0xb9, 0x95, 0x76, 0xd4, 0x13, 0x30, 0x0e,
+  0xbf, 0xb2, 0xed, 0x67, 0x0a, 0xc0, 0x16, 0x3f, 0x51, 0x09, 0x9d, 0x29,
+  0x2f, 0xb2, 0x6d, 0x3f, 0x3e, 0x6c, 0x2f, 0x90, 0x80, 0xa1, 0x71, 0xdf,
+  0xbe, 0x38, 0xc5, 0xcb, 0xa9, 0x9a, 0x40, 0x14, 0x90, 0x0a, 0xf9, 0xb7,
+  0x07, 0x0b, 0xe1, 0xda, 0xe7, 0x09, 0xbf, 0x0d, 0x57, 0x41, 0x86, 0x60,
+  0xa1, 0xc1, 0x27, 0x91, 0x5b, 0x0a, 0x98, 0x46, 0x1b, 0xf6, 0xa2, 0x84,
+  0xf8, 0x65, 0xc7, 0xce, 0x2d, 0x96, 0x17, 0xaa, 0x91, 0xf8, 0x61, 0x04,
+  0x50, 0x70, 0xeb, 0xb4, 0x43, 0xb7, 0xdc, 0x9a, 0xcc, 0x31, 0x01, 0x14,
+  0xd4, 0xcd, 0xcc, 0xc2, 0x37, 0x6d, 0x69, 0x82, 0xd6, 0xc6, 0xc4, 0xbe,
+  0xf2, 0x34, 0xa5, 0xc9, 0xa6, 0x19, 0x53, 0x32, 0x7a, 0x86, 0x0e, 0x91,
+  0x82, 0x0f, 0xa1, 0x42, 0x54, 0xaa, 0x01, 0x02, 0x03, 0x01, 0x00, 0x01,
+  0x02, 0x81, 0x81, 0x00, 0x95, 0xaa, 0x6e, 0x11, 0xf5, 0x6a, 0x8b, 0xa2,
+  0xc6, 0x48, 0xc6, 0x7c, 0x37, 0x6b, 0x1f, 0x55, 0x10, 0x76, 0x26, 0x24,
+  0xc3, 0xf2, 0x5c, 0x5a, 0xdd, 0x2e, 0xf3, 0xa4, 0x1e, 0xbc, 0x7b, 0x1c,
+  0x80, 0x10, 0x85, 0xbc, 0xd8, 0x45, 0x3c, 0xb8, 0xb2, 0x06, 0x53, 0xb5,
+  0xd5, 0x7a, 0xe7, 0x0e, 0x92, 0xe6, 0x42, 0xc2, 0xe2, 0x2a, 0xd5, 0xd1,
+  0x03, 0x9f, 0x6f, 0x53, 0x74, 0x68, 0x72, 0x8e, 0xbf, 0x03, 0xbb, 0xab,
+  0xbd, 0xa1, 0xf9, 0x81, 0x7d, 0x12, 0xd4, 0x9d, 0xb6, 0xae, 0x4c, 0xad,
+  0xca, 0xa8, 0xc9, 0x80, 0x8d, 0x0d, 0xd5, 0xd0, 0xa1, 0xbf, 0xec, 0x60,
+  0x48, 0x49, 0xed, 0x97, 0x0f, 0x5e, 0xed, 0xfc, 0x39, 0x15, 0x96, 0x9e,
+  0x5d, 0xe2, 0xb4, 0x5d, 0x2e, 0x04, 0xdc, 0x08, 0xa2, 0x65, 0x29, 0x2d,
+  0x37, 0xfb, 0x62, 0x90, 0x1b, 0x7b, 0xe5, 0x3a, 0x58, 0x05, 0x55, 0xc1,
+  0x02, 0x41, 0x00, 0xfc, 0x69, 0x28, 0xc9, 0xa8, 0xc4, 0x5c, 0xe3, 0xd0,
+  0x5e, 0xaa, 0xda, 0xde, 0x87, 0x74, 0xdb, 0xcb, 0x40, 0x78, 0x8e, 0x1d,
+  0x12, 0x96, 0x16, 0x61, 0x3f, 0xb3, 0x3e, 0xa3, 0x0d, 0xdc, 0x49, 0xa5,
+  0x25, 0x87, 0xc5, 0x97, 0x85, 0x9d, 0xbb, 0xb4, 0xf0, 0x44, 0xfd, 0x6c,
+  0xe8, 0xd2, 0x8c, 0xec, 0x33, 0x81, 0x46, 0x1e, 0x10, 0x12, 0x33, 0x16,
+  0x95, 0x00, 0x4f, 0x75, 0xb4, 0xe5, 0x79, 0x02, 0x41, 0x00, 0xd0, 0xeb,
+  0x65, 0x07, 0x10, 0x3b, 0xd9, 0x03, 0xeb, 0xdc, 0x6f, 0x4b, 0x8f, 0xc3,
+  0x87, 0xce, 0x76, 0xd6, 0xc5, 0x14, 0x21, 0x4e, 0xe7, 0x4f, 0x1b, 0xe8,
+  0x05, 0xf8, 0x84, 0x1a, 0xe0, 0xc5, 0xd6, 0xe3, 0x08, 0xb3, 0x54, 0x57,
+  0x02, 0x1f, 0xd4, 0xd9, 0xfb, 0xff, 0x40, 0xb1, 0x56, 0x1c, 0x60, 0xf7,
+  0xac, 0x91, 0xf3, 0xd3, 0xc6, 0x7f, 0x84, 0xfd, 0x84, 0x9d, 0xea, 0x26,
+  0xee, 0xc9, 0x02, 0x41, 0x00, 0xa6, 0xcf, 0x1c, 0x6c, 0x81, 0x03, 0x1c,
+  0x5c, 0x56, 0x05, 0x6a, 0x26, 0x70, 0xef, 0xd6, 0x13, 0xb7, 0x74, 0x28,
+  0xf7, 0xca, 0x50, 0xd1, 0x2d, 0x83, 0x21, 0x64, 0xe4, 0xdd, 0x3f, 0x38,
+  0xb8, 0xd6, 0xd2, 0x41, 0xb3, 0x1c, 0x9a, 0xea, 0x0d, 0xf5, 0xda, 0xdf,
+  0xcd, 0x17, 0x9f, 0x9a, 0x1e, 0x15, 0xaf, 0x48, 0x1c, 0xbd, 0x9b, 0x63,
+  0x5b, 0xad, 0xed, 0xd4, 0xa1, 0xae, 0xa9, 0x59, 0x09, 0x02, 0x40, 0x4e,
+  0x08, 0xce, 0xa8, 0x8f, 0xc0, 0xba, 0xf3, 0x83, 0x02, 0xc8, 0x33, 0x62,
+  0x14, 0x77, 0xc2, 0x7f, 0x93, 0x02, 0xf3, 0xdc, 0xe9, 0x1a, 0xee, 0xea,
+  0x8e, 0x84, 0xc4, 0x69, 0x9b, 0x9c, 0x7f, 0x69, 0x1f, 0x4e, 0x1d, 0xa5,
+  0x90, 0x06, 0x44, 0x1b, 0x7d, 0xfc, 0x69, 0x40, 0x21, 0xbc, 0xf7, 0x46,
+  0xa4, 0xdc, 0x39, 0x7b, 0xe8, 0x8b, 0x49, 0x10, 0x44, 0x9d, 0x67, 0x5a,
+  0x91, 0x86, 0x39, 0x02, 0x40, 0x41, 0x2c, 0x4e, 0xfe, 0xd9, 0x90, 0x89,
+  0x00, 0x5c, 0x94, 0x0a, 0x4a, 0x7e, 0x1b, 0x1a, 0x80, 0x06, 0x01, 0x37,
+  0xda, 0x50, 0x61, 0x9d, 0x9c, 0xfe, 0x25, 0x7f, 0xd8, 0xd4, 0xc4, 0x9e,
+  0x81, 0xf2, 0x0c, 0x1e, 0x38, 0x21, 0x1e, 0x90, 0x3f, 0xd4, 0xba, 0x6c,
+  0x53, 0xcb, 0xf0, 0x77, 0x79, 0x9b, 0xf1, 0xfa, 0x3f, 0x81, 0xdc, 0xf3,
+  0x21, 0x02, 0x6d, 0xb7, 0x95, 0xc3, 0x2e, 0xce, 0xd5
+};
+unsigned int default_private_key_len = 609;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/ssl.h	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * @mainpage axTLS API
+ *
+ * @image html axolotl.jpg
+ *
+ * The axTLS library has features such as:
+ * - The TLSv1 SSL client/server protocol
+ * - No requirement to use any openssl libraries.
+ * - A choice between AES block (128/256 bit) and RC4 (128 bit) stream ciphers.
+ * - RSA encryption/decryption with variable sized keys (up to 4096 bits).
+ * - Certificate chaining and peer authentication.
+ * - Session resumption, session renegotiation.
+ * - ASN.1, X.509, PKCS#8, PKCS#12 keys/certificates with DER/PEM encoding.
+ * - Highly configurable compile time options.
+ * - Portable across many platforms (written in ANSI C), and has language
+ * bindings in C, C#, VB.NET, Java, Perl and Lua.
+ * - Partial openssl API compatibility (via a wrapper).
+ * - A very small footprint (around 50-60kB for the library in 'server-only' 
+ *   mode).
+ * - No dependencies on sockets - can use serial connections for example.
+ * - A very simple API - ~ 20 functions/methods.
+ *
+ * A list of these functions/methods are described below.
+ *
+ *  @ref c_api 
+ *
+ *  @ref bigint_api 
+ *
+ *  @ref csharp_api 
+ *
+ *  @ref java_api 
+ */
+#ifndef HEADER_SSL_H
+#define HEADER_SSL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+
+/* need to predefine before ssl_lib.h gets to it */
+#define SSL_SESSION_ID_SIZE                     32
+
+#include "tls1.h"
+
+/* The optional parameters that can be given to the client/server SSL engine */
+#define SSL_CLIENT_AUTHENTICATION               0x00010000
+#define SSL_SERVER_VERIFY_LATER                 0x00020000
+#define SSL_NO_DEFAULT_KEY                      0x00040000
+#define SSL_DISPLAY_STATES                      0x00080000
+#define SSL_DISPLAY_BYTES                       0x00100000
+#define SSL_DISPLAY_CERTS                       0x00200000
+#define SSL_DISPLAY_RSA                         0x00400000
+#define SSL_CONNECT_IN_PARTS                    0x00800000
+
+/* errors that can be generated */
+#define SSL_OK                                  0
+#define SSL_NOT_OK                              -1
+#define SSL_ERROR_DEAD                          -2
+#define SSL_CLOSE_NOTIFY                        -3
+#define SSL_ERROR_CONN_LOST                     -256
+#define SSL_ERROR_SOCK_SETUP_FAILURE            -258
+#define SSL_ERROR_INVALID_HANDSHAKE             -260
+#define SSL_ERROR_INVALID_PROT_MSG              -261
+#define SSL_ERROR_INVALID_HMAC                  -262
+#define SSL_ERROR_INVALID_VERSION               -263
+#define SSL_ERROR_INVALID_SESSION               -265
+#define SSL_ERROR_NO_CIPHER                     -266
+#define SSL_ERROR_BAD_CERTIFICATE               -268
+#define SSL_ERROR_INVALID_KEY                   -269
+#define SSL_ERROR_FINISHED_INVALID              -271
+#define SSL_ERROR_NO_CERT_DEFINED               -272
+#define SSL_ERROR_NO_CLIENT_RENOG               -273
+#define SSL_ERROR_NOT_SUPPORTED                 -274
+#define SSL_X509_OFFSET                         -512
+#define SSL_X509_ERROR(A)                       (SSL_X509_OFFSET+A)
+
+/* alert types that are recognized */
+#define SSL_ALERT_TYPE_WARNING                  1
+#define SLL_ALERT_TYPE_FATAL                    2
+
+/* these are all the alerts that are recognized */
+#define SSL_ALERT_CLOSE_NOTIFY                  0
+#define SSL_ALERT_UNEXPECTED_MESSAGE            10
+#define SSL_ALERT_BAD_RECORD_MAC                20
+#define SSL_ALERT_HANDSHAKE_FAILURE             40
+#define SSL_ALERT_BAD_CERTIFICATE               42
+#define SSL_ALERT_ILLEGAL_PARAMETER             47
+#define SSL_ALERT_DECODE_ERROR                  50
+#define SSL_ALERT_DECRYPT_ERROR                 51
+#define SSL_ALERT_INVALID_VERSION               70
+#define SSL_ALERT_NO_RENEGOTIATION              100
+
+/* The ciphers that are supported */
+#define SSL_AES128_SHA                          0x2f
+#define SSL_AES256_SHA                          0x35
+#define SSL_RC4_128_SHA                         0x05
+#define SSL_RC4_128_MD5                         0x04
+
+/* build mode ids' */
+#define SSL_BUILD_SKELETON_MODE                 0x01
+#define SSL_BUILD_SERVER_ONLY                   0x02
+#define SSL_BUILD_ENABLE_VERIFICATION           0x03
+#define SSL_BUILD_ENABLE_CLIENT                 0x04
+#define SSL_BUILD_FULL_MODE                     0x05
+
+/* offsets to retrieve configuration information */
+#define SSL_BUILD_MODE                          0
+#define SSL_MAX_CERT_CFG_OFFSET                 1
+#define SSL_MAX_CA_CERT_CFG_OFFSET              2
+#define SSL_HAS_PEM                             3
+
+/* default session sizes */
+#define SSL_DEFAULT_SVR_SESS                    5
+#define SSL_DEFAULT_CLNT_SESS                   1
+
+/* X.509/X.520 distinguished name types */
+#define SSL_X509_CERT_COMMON_NAME               0
+#define SSL_X509_CERT_ORGANIZATION              1
+#define SSL_X509_CERT_ORGANIZATIONAL_NAME       2
+#define SSL_X509_CA_CERT_COMMON_NAME            3
+#define SSL_X509_CA_CERT_ORGANIZATION           4
+#define SSL_X509_CA_CERT_ORGANIZATIONAL_NAME    5
+
+/* SSL object loader types */
+#define SSL_OBJ_X509_CERT                       1
+#define SSL_OBJ_X509_CACERT                     2
+#define SSL_OBJ_RSA_KEY                         3
+#define SSL_OBJ_PKCS8                           4
+#define SSL_OBJ_PKCS12                          5
+
+/**
+ * @defgroup c_api Standard C API
+ * @brief The standard interface in C.
+ * @{
+ */
+
+/**
+ * @brief Establish a new client/server context.
+ *
+ * This function is called before any client/server SSL connections are made. 
+ *
+ * Each new connection will use the this context's private key and 
+ * certificate chain. If a different certificate chain is required, then a 
+ * different context needs to be be used.
+ *
+ * There are two threading models supported - a single thread with one
+ * SSL_CTX can support any number of SSL connections - and multiple threads can 
+ * support one SSL_CTX object each (the default). But if a single SSL_CTX 
+ * object uses many SSL objects in individual threads, then the 
+ * CONFIG_SSL_CTX_MUTEXING option needs to be configured.
+ *
+ * @param options [in]  Any particular options. At present the options
+ * supported are:
+ * - SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if the server
+ * authentication fails. The certificate can be authenticated later with a
+ * call to ssl_verify_cert().
+ * - SSL_CLIENT_AUTHENTICATION (server only): Enforce client authentication
+ * i.e. each handshake will include a "certificate request" message from the
+ * server. Only available if verification has been enabled.
+ * - SSL_DISPLAY_BYTES (full mode build only): Display the byte sequences
+ * during the handshake.
+ * - SSL_DISPLAY_STATES (full mode build only): Display the state changes
+ * during the handshake.
+ * - SSL_DISPLAY_CERTS (full mode build only): Display the certificates that
+ * are passed during a handshake.
+ * - SSL_DISPLAY_RSA (full mode build only): Display the RSA key details that
+ * are passed during a handshake.
+ * - SSL_CONNECT_IN_PARTS (client only): To use a non-blocking version of 
+ * ssl_client_new().
+ * @param num_sessions [in] The number of sessions to be used for session
+ * caching. If this value is 0, then there is no session caching. This option
+ * is not used in skeleton mode.
+ * @return A client/server context.
+ */
+EXP_FUNC SSL_CTX * STDCALL ssl_ctx_new(uint32_t options, int num_sessions);
+
+/**
+ * @brief Remove a client/server context.
+ *
+ * Frees any used resources used by this context. Each connection will be 
+ * sent a "Close Notify" alert (if possible).
+ * @param ssl_ctx [in] The client/server context.
+ */
+EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx);
+
+/**
+ * @brief (server only) Establish a new SSL connection to an SSL client.
+ *
+ * It is up to the application to establish the logical connection (whether it
+ * is  a socket, serial connection etc).
+ * @param ssl_ctx [in] The server context.
+ * @param client_fd [in] The client's file descriptor. 
+ * @return An SSL object reference.
+ */
+EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd);
+
+/**
+ * @brief (client only) Establish a new SSL connection to an SSL server.
+ *
+ * It is up to the application to establish the initial logical connection 
+ * (whether it is  a socket, serial connection etc).
+ *
+ * This is a normally a blocking call - it will finish when the handshake is 
+ * complete (or has failed). To use in non-blocking mode, set 
+ * SSL_CONNECT_IN_PARTS in ssl_ctx_new().
+ * @param ssl_ctx [in] The client context.
+ * @param client_fd [in] The client's file descriptor.
+ * @param session_id [in] A 32 byte session id for session resumption. This 
+ * can be null if no session resumption is being used or required. This option
+ * is not used in skeleton mode.
+ * @param sess_id_size The size of the session id (max 32)
+ * @return An SSL object reference. Use ssl_handshake_status() to check 
+ * if a handshake succeeded.
+ */
+EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const uint8_t *session_id, uint8_t sess_id_size);
+
+/**
+ * @brief Free any used resources on this connection. 
+ 
+ * A "Close Notify" message is sent on this connection (if possible). It is up 
+ * to the application to close the socket or file descriptor.
+ * @param ssl [in] The ssl object reference.
+ */
+EXP_FUNC void STDCALL ssl_free(SSL *ssl);
+
+/**
+ * @brief Read the SSL data stream.
+ * If the socket is non-blocking and data is blocked then SSO_OK will be
+ * returned.
+ * @param ssl [in] An SSL object reference.
+ * @param in_data [out] If the read was successful, a pointer to the read
+ * buffer will be here. Do NOT ever free this memory as this buffer is used in
+ * sucessive calls. If the call was unsuccessful, this value will be null.
+ * @return The number of decrypted bytes:
+ * - if > 0, then the handshaking is complete and we are returning the number 
+ *   of decrypted bytes. 
+ * - SSL_OK if the handshaking stage is successful (but not yet complete).  
+ * - < 0 if an error.
+ * @see ssl.h for the error code list.
+ * @note Use in_data before doing any successive ssl calls.
+ */
+EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data);
+
+/**
+ * @brief Write to the SSL data stream. 
+ * if the socket is non-blocking and data is blocked then a check is made
+ * to ensure that all data is sent (i.e. blocked mode is forced).
+ * @param ssl [in] An SSL obect reference.
+ * @param out_data [in] The data to be written
+ * @param out_len [in] The number of bytes to be written.
+ * @return The number of bytes sent, or if < 0 if an error.
+ * @see ssl.h for the error code list.
+ */
+EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len);
+
+/**
+ * @brief Find an ssl object based on a file descriptor.
+ *
+ * Goes through the list of SSL objects maintained in a client/server context
+ * to look for a file descriptor match.
+ * @param ssl_ctx [in] The client/server context.
+ * @param client_fd [in]  The file descriptor.
+ * @return A reference to the SSL object. Returns null if the object could not 
+ * be found.
+ */
+EXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd);
+
+/**
+ * @brief Get the session id for a handshake. 
+ * 
+ * This will be a 32 byte sequence and is available after the first
+ * handshaking messages are sent.
+ * @param ssl [in] An SSL object reference.
+ * @return The session id as a 32 byte sequence.
+ * @note A SSLv23 handshake may have only 16 valid bytes.
+ */
+EXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl);
+
+/**
+ * @brief Get the session id size for a handshake. 
+ * 
+ * This will normally be 32 but could be 0 (no session id) or something else.
+ * @param ssl [in] An SSL object reference.
+ * @return The size of the session id.
+ */
+EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl);
+
+/**
+ * @brief Return the cipher id (in the SSL form).
+ * @param ssl [in] An SSL object reference.
+ * @return The cipher id. This will be one of the following:
+ * - SSL_AES128_SHA (0x2f)
+ * - SSL_AES256_SHA (0x35)
+ * - SSL_RC4_128_SHA (0x05)
+ * - SSL_RC4_128_MD5 (0x04)
+ */
+EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl);
+
+/**
+ * @brief Return the status of the handshake.
+ * @param ssl [in] An SSL object reference.
+ * @return SSL_OK if the handshake is complete and ok. 
+ * @see ssl.h for the error code list.
+ */
+EXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl);
+
+/**
+ * @brief Retrieve various parameters about the axTLS engine.
+ * @param offset [in] The configuration offset. It will be one of the following:
+ * - SSL_BUILD_MODE The build mode. This will be one of the following:
+ *   - SSL_BUILD_SERVER_ONLY            (basic server mode)
+ *   - SSL_BUILD_ENABLE_VERIFICATION    (server can do client authentication)
+ *   - SSL_BUILD_ENABLE_CLIENT          (client/server capabilties)
+ *   - SSL_BUILD_FULL_MODE              (client/server with diagnostics)
+ *   - SSL_BUILD_SKELETON_MODE          (skeleton mode)
+ * - SSL_MAX_CERT_CFG_OFFSET The maximum number of certificates allowed.
+ * - SSL_MAX_CA_CERT_CFG_OFFSET The maximum number of CA certificates allowed.
+ * - SSL_HAS_PEM                        1 if supported
+ * @return The value of the requested parameter.
+ */
+EXP_FUNC int STDCALL ssl_get_config(int offset);
+
+/**
+ * @brief Display why the handshake failed.
+ *
+ * This call is only useful in a 'full mode' build. The output is to stdout.
+ * @param error_code [in] An error code.
+ * @see ssl.h for the error code list.
+ */
+EXP_FUNC void STDCALL ssl_display_error(int error_code);
+
+/**
+ * @brief Authenticate a received certificate.
+ * 
+ * This call is usually made by a client after a handshake is complete and the
+ * context is in SSL_SERVER_VERIFY_LATER mode.
+ * @param ssl [in] An SSL object reference.
+ * @return SSL_OK if the certificate is verified.
+ */
+EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl);
+
+/**
+ * @brief Retrieve an X.509 distinguished name component.
+ * 
+ * When a handshake is complete and a certificate has been exchanged, then the
+ * details of the remote certificate can be retrieved.
+ *
+ * This will usually be used by a client to check that the server's common 
+ * name matches the URL.
+ *
+ * @param ssl [in] An SSL object reference.
+ * @param component [in] one of:
+ * - SSL_X509_CERT_COMMON_NAME
+ * - SSL_X509_CERT_ORGANIZATION
+ * - SSL_X509_CERT_ORGANIZATIONAL_NAME
+ * - SSL_X509_CA_CERT_COMMON_NAME
+ * - SSL_X509_CA_CERT_ORGANIZATION
+ * - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME
+ * @return The appropriate string (or null if not defined)
+ * @note Verification build mode must be enabled.
+ */
+EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component);
+
+/**
+ * @brief Retrieve a Subject Alternative DNSName
+ *
+ * When a handshake is complete and a certificate has been exchanged, then the
+ * details of the remote certificate can be retrieved.
+ *
+ * This will usually be used by a client to check that the server's DNS  
+ * name matches the URL.
+ *
+ * @param ssl [in] An SSL object reference.
+ * @param dnsindex [in] The index of the DNS name to retrieve.
+ * @return The appropriate string (or null if not defined)
+ * @note Verification build mode must be enabled.
+ */
+EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int dnsindex);
+
+/**
+ * @brief Force the client to perform its handshake again.
+ *
+ * For a client this involves sending another "client hello" message.
+ * For the server is means sending a "hello request" message.
+ *
+ * This is a blocking call on the client (until the handshake completes).
+ *
+ * @param ssl [in] An SSL object reference.
+ * @return SSL_OK if renegotiation instantiation was ok
+ */
+EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl);
+
+/**
+ * @brief Process a file that is in binary DER or ASCII PEM format.
+ *
+ * These are temporary objects that are used to load private keys,
+ * certificates etc into memory.
+ * @param ssl_ctx [in] The client/server context.
+ * @param obj_type [in] The format of the file. Can be one of:
+ * - SSL_OBJ_X509_CERT (no password required)
+ * - SSL_OBJ_X509_CACERT (no password required)
+ * - SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported)
+ * - SSL_OBJ_PKCS8 (RC4-128 encrypted data supported)
+ * - SSL_OBJ_PKCS12 (RC4-128 encrypted data supported)
+ *
+ * PEM files are automatically detected (if supported). The object type is
+ * also detected, and so is not relevant for these types of files.
+ * @param filename [in] The location of a file in DER/PEM format.
+ * @param password [in] The password used. Can be null if not required.
+ * @return SSL_OK if all ok
+ * @note Not available in skeleton build mode.
+ */
+EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, const char *filename, const char *password);
+
+/**
+ * @brief Process binary data.
+ *
+ * These are temporary objects that are used to load private keys,
+ * certificates etc into memory.
+ * @param ssl_ctx [in] The client/server context.
+ * @param obj_type [in] The format of the memory data.
+ * @param data [in] The binary data to be loaded.
+ * @param len [in] The amount of data to be loaded.
+ * @param password [in] The password used. Can be null if not required.
+ * @return SSL_OK if all ok
+ * @see ssl_obj_load for more details on obj_type.
+ */
+EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int obj_type, const uint8_t *data, int len, const char *password);
+
+#ifdef CONFIG_SSL_GENERATE_X509_CERT
+/**
+ * @brief Create an X.509 certificate. 
+ * 
+ * This certificate is a self-signed v1 cert with a fixed start/stop validity 
+ * times. It is signed with an internal private key in ssl_ctx.
+ *
+ * @param ssl_ctx [in] The client/server context.
+ * @param options [in] Not used yet.
+ * @param dn [in] An array of distinguished name strings. The array is defined
+ * by:
+ * - SSL_X509_CERT_COMMON_NAME (0)
+ *      - If SSL_X509_CERT_COMMON_NAME is empty or not defined, then the 
+ *        hostname will be used.
+ * - SSL_X509_CERT_ORGANIZATION (1)
+ *      - If SSL_X509_CERT_ORGANIZATION is empty or not defined, then $USERNAME 
+ *        will be used.
+ * - SSL_X509_CERT_ORGANIZATIONAL_NAME (2)
+ *      - SSL_X509_CERT_ORGANIZATIONAL_NAME is optional.
+ * @param cert_data [out] The certificate as a sequence of bytes.
+ * @return < 0 if an error, or the size of the certificate in bytes.
+ * @note cert_data must be freed when there is no more need for it.
+ */
+EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data);
+#endif
+
+/**
+ * @brief Return the axTLS library version as a string.
+ */
+EXP_FUNC const char * STDCALL ssl_version(void);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/tls1.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,2196 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * Common ssl/tlsv1 code to both the client and server implementations.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include "lwip/sockets.h"
+#include "os_port.h"
+#include "ssl.h"
+#include "arch.h"
+
+/* The session expiry time */
+#define SSL_EXPIRY_TIME     (CONFIG_SSL_EXPIRY_TIME*3600)
+
+static const uint8_t g_hello_request[] = { HS_HELLO_REQUEST, 0, 0, 0 };
+static const uint8_t g_chg_cipher_spec_pkt[] = { 1 };
+static const char * server_finished = "server finished";
+static const char * client_finished = "client finished";
+
+static int do_handshake(SSL *ssl, uint8_t *buf, int read_len);
+static int set_key_block(SSL *ssl, int is_write);
+static int verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len);
+static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt);
+static int send_raw_packet(SSL *ssl, uint8_t protocol);
+
+/**
+ * The server will pick the cipher based on the order that the order that the
+ * ciphers are listed. This order is defined at compile time.
+ */
+#ifdef CONFIG_SSL_SKELETON_MODE
+const uint8_t ssl_prot_prefs[NUM_PROTOCOLS] = 
+{ SSL_RC4_128_SHA };
+#else
+static void session_free(SSL_SESSION *ssl_sessions[], int sess_index);
+
+const uint8_t ssl_prot_prefs[NUM_PROTOCOLS] = 
+#ifdef CONFIG_SSL_PROT_LOW                  /* low security, fast speed */
+{ SSL_RC4_128_SHA, SSL_AES128_SHA, SSL_AES256_SHA, SSL_RC4_128_MD5 };
+#elif CONFIG_SSL_PROT_MEDIUM                /* medium security, medium speed */
+{ SSL_AES128_SHA, SSL_AES256_SHA, SSL_RC4_128_SHA, SSL_RC4_128_MD5 };    
+#else /* CONFIG_SSL_PROT_HIGH */            /* high security, low speed */
+{ SSL_AES256_SHA, SSL_AES128_SHA, SSL_RC4_128_SHA, SSL_RC4_128_MD5 };
+#endif
+#endif /* CONFIG_SSL_SKELETON_MODE */
+
+/**
+ * The cipher map containing all the essentials for each cipher.
+ */
+#ifdef CONFIG_SSL_SKELETON_MODE
+static const cipher_info_t cipher_info[NUM_PROTOCOLS] = 
+{
+    {   /* RC4-SHA */
+        SSL_RC4_128_SHA,                /* RC4-SHA */
+        16,                             /* key size */
+        0,                              /* iv size */ 
+        2*(SHA1_SIZE+16),               /* key block size */
+        0,                              /* no padding */
+        SHA1_SIZE,                      /* digest size */
+        hmac_sha1,                      /* hmac algorithm */
+        (crypt_func)RC4_crypt,          /* encrypt */
+        (crypt_func)RC4_crypt           /* decrypt */
+    },
+};
+#else
+static const cipher_info_t cipher_info[NUM_PROTOCOLS] = 
+{
+    {   /* AES128-SHA */
+        SSL_AES128_SHA,                 /* AES128-SHA */
+        16,                             /* key size */
+        16,                             /* iv size */ 
+        2*(SHA1_SIZE+16+16),            /* key block size */
+        16,                             /* block padding size */
+        SHA1_SIZE,                      /* digest size */
+        hmac_sha1,                      /* hmac algorithm */
+        (crypt_func)AES_cbc_encrypt,    /* encrypt */
+        (crypt_func)AES_cbc_decrypt     /* decrypt */
+    },
+    {   /* AES256-SHA */
+        SSL_AES256_SHA,                 /* AES256-SHA */
+        32,                             /* key size */
+        16,                             /* iv size */ 
+        2*(SHA1_SIZE+32+16),            /* key block size */
+        16,                             /* block padding size */
+        SHA1_SIZE,                      /* digest size */
+        hmac_sha1,                      /* hmac algorithm */
+        (crypt_func)AES_cbc_encrypt,    /* encrypt */
+        (crypt_func)AES_cbc_decrypt     /* decrypt */
+    },       
+    {   /* RC4-SHA */
+        SSL_RC4_128_SHA,                /* RC4-SHA */
+        16,                             /* key size */
+        0,                              /* iv size */ 
+        2*(SHA1_SIZE+16),               /* key block size */
+        0,                              /* no padding */
+        SHA1_SIZE,                      /* digest size */
+        hmac_sha1,                      /* hmac algorithm */
+        (crypt_func)RC4_crypt,          /* encrypt */
+        (crypt_func)RC4_crypt           /* decrypt */
+    },
+    /*
+     * This protocol is from SSLv2 days and is unlikely to be used - but was
+     * useful for testing different possible digest algorithms.
+     */
+    {   /* RC4-MD5 */
+        SSL_RC4_128_MD5,                /* RC4-MD5 */
+        16,                             /* key size */
+        0,                              /* iv size */ 
+        2*(MD5_SIZE+16),                /* key block size */
+        0,                              /* no padding */
+        MD5_SIZE,                       /* digest size */
+        hmac_md5,                       /* hmac algorithm */
+        (crypt_func)RC4_crypt,          /* encrypt */
+        (crypt_func)RC4_crypt           /* decrypt */
+    },
+};
+#endif
+
+static void prf(const uint8_t *sec, int sec_len, uint8_t *seed, int seed_len,
+        uint8_t *out, int olen);
+static const cipher_info_t *get_cipher_info(uint8_t cipher);
+static void increment_read_sequence(SSL *ssl);
+static void increment_write_sequence(SSL *ssl);
+static void add_hmac_digest(SSL *ssl, int snd, uint8_t *hmac_header,
+        const uint8_t *buf, int buf_len, uint8_t *hmac_buf);
+
+/* win32 VC6.0 doesn't have variadic macros */
+#if defined(WIN32) && !defined(CONFIG_SSL_FULL_MODE)
+void DISPLAY_BYTES(SSL *ssl, const char *format, 
+        const uint8_t *data, int size, ...) {}
+#endif
+
+/**
+ * Establish a new client/server context.
+ */
+EXP_FUNC SSL_CTX *STDCALL ssl_ctx_new(uint32_t options, int num_sessions)
+{
+    SSL_CTX *ssl_ctx = (SSL_CTX *)calloc(1, sizeof (SSL_CTX));
+    ssl_ctx->options = options;
+    RNG_initialize();
+
+    if (load_key_certs(ssl_ctx) < 0)
+    {
+        printf("error loading key certs\r\n");
+        free(ssl_ctx);  /* can't load our key/certificate pair, so die */
+        return NULL;
+    }
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+    ssl_ctx->num_sessions = num_sessions;
+#endif
+
+    SSL_CTX_MUTEX_INIT(ssl_ctx->mutex);
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+    if (num_sessions)
+    {
+        ssl_ctx->ssl_sessions = (SSL_SESSION **)
+                        calloc(1, num_sessions*sizeof(SSL_SESSION *));
+    }
+#endif
+
+    return ssl_ctx;
+}
+
+/*
+ * Remove a client/server context.
+ */
+EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx)
+{
+    SSL *ssl;
+    int i;
+
+    if (ssl_ctx == NULL)
+        return;
+
+    ssl = ssl_ctx->head;
+
+    /* clear out all the ssl entries */
+    while (ssl)
+    {
+        SSL *next = ssl->next;
+        ssl_free(ssl);
+        ssl = next;
+    }
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+    /* clear out all the sessions */
+    for (i = 0; i < ssl_ctx->num_sessions; i++)
+        session_free(ssl_ctx->ssl_sessions, i);
+
+    free(ssl_ctx->ssl_sessions);
+#endif
+
+    i = 0;
+    while (i < CONFIG_SSL_MAX_CERTS && ssl_ctx->certs[i].buf)
+    {
+        free(ssl_ctx->certs[i].buf);
+        ssl_ctx->certs[i++].buf = NULL;
+    }
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+    remove_ca_certs(ssl_ctx->ca_cert_ctx);
+#endif
+    ssl_ctx->chain_length = 0;
+    SSL_CTX_MUTEX_DESTROY(ssl_ctx->mutex);
+    RSA_free(ssl_ctx->rsa_ctx);
+    RNG_terminate();
+    free(ssl_ctx);
+}
+
+/*
+ * Free any used resources used by this connection.
+ */
+EXP_FUNC void STDCALL ssl_free(SSL *ssl)
+{
+    SSL_CTX *ssl_ctx;
+
+    if (ssl == NULL)        /* just ignore null pointers */
+        return;
+
+    /* only notify if we weren't notified first */
+    /* spec says we must notify when we are dying */
+    if (!IS_SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY))
+      send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY);
+
+    ssl_ctx = ssl->ssl_ctx;
+
+    SSL_CTX_LOCK(ssl_ctx->mutex);
+
+    /* adjust the server SSL list */
+    if (ssl->prev)
+        ssl->prev->next = ssl->next;
+    else
+        ssl_ctx->head = ssl->next;
+
+    if (ssl->next)
+        ssl->next->prev = ssl->prev;
+    else
+        ssl_ctx->tail = ssl->prev;
+
+    SSL_CTX_UNLOCK(ssl_ctx->mutex);
+
+    /* may already be free - but be sure */
+    free(ssl->encrypt_ctx);
+    free(ssl->decrypt_ctx);
+    disposable_free(ssl);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+    x509_free(ssl->x509_ctx);
+#endif
+
+    free(ssl);
+}
+
+/*
+ * Read the SSL connection and send any alerts for various errors.
+ */
+EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data)
+{
+    int ret = basic_read(ssl, in_data);
+
+    /* check for return code so we can send an alert */
+    if (ret < SSL_OK && ret != SSL_CLOSE_NOTIFY)
+    {
+        if (ret != SSL_ERROR_CONN_LOST)
+        {
+            send_alert(ssl, ret);
+#ifndef CONFIG_SSL_SKELETON_MODE
+            /* something nasty happened, so get rid of this session */
+            kill_ssl_session(ssl->ssl_ctx->ssl_sessions, ssl);
+#endif
+        }
+    }
+
+    return ret;
+}
+
+/*
+ * Write application data to the client
+ */
+EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len)
+{
+    int n = out_len, nw, i, tot = 0;
+
+    /* maximum size of a TLS packet is around 16kB, so fragment */
+    do 
+    {
+        nw = n;
+
+        if (nw > RT_MAX_PLAIN_LENGTH)    /* fragment if necessary */
+            nw = RT_MAX_PLAIN_LENGTH;
+
+        if ((i = send_packet(ssl, PT_APP_PROTOCOL_DATA, 
+                                            &out_data[tot], nw)) <= 0)
+        {
+            out_len = i;    /* an error */
+            break;
+        }
+
+        tot += i;
+        n -= i;
+    } while (n > 0);
+
+    return out_len;
+}
+
+/**
+ * Add a certificate to the certificate chain.
+ */
+int add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len)
+{
+    int ret = SSL_ERROR_NO_CERT_DEFINED, i = 0;
+    SSL_CERT *ssl_cert;
+    X509_CTX *cert = NULL;
+    int offset;
+
+    while (ssl_ctx->certs[i].buf && i < CONFIG_SSL_MAX_CERTS) 
+        i++;
+
+    if (i == CONFIG_SSL_MAX_CERTS) /* too many certs */
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("Error: maximum number of certs added (%d) - change of "
+                "compile-time configuration required\n",
+                CONFIG_SSL_MAX_CERTS);
+#endif
+        goto error;
+    }
+
+    if ((ret = x509_new(buf, &offset, &cert)))
+        goto error;
+
+#if defined (CONFIG_SSL_FULL_MODE)
+    if (ssl_ctx->options & SSL_DISPLAY_CERTS)
+        x509_print(cert, NULL);
+#endif
+
+    ssl_cert = &ssl_ctx->certs[i];
+    ssl_cert->size = len;
+    ssl_cert->buf = (uint8_t *)malloc(len);
+    memcpy(ssl_cert->buf, buf, len);
+    ssl_ctx->chain_length++;
+    len -= offset;
+    ret = SSL_OK;           /* ok so far */
+
+    /* recurse? */
+    if (len > 0)
+    {
+        ret = add_cert(ssl_ctx, &buf[offset], len);
+    }
+
+error:
+    x509_free(cert);        /* don't need anymore */
+    return ret;
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Add a certificate authority.
+ */
+int add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len)
+{
+    int ret = SSL_OK; /* ignore errors for now */
+    int i = 0;
+    CA_CERT_CTX *ca_cert_ctx;
+
+    if (ssl_ctx->ca_cert_ctx == NULL)
+        ssl_ctx->ca_cert_ctx = (CA_CERT_CTX *)calloc(1, sizeof(CA_CERT_CTX));
+
+    ca_cert_ctx = ssl_ctx->ca_cert_ctx;
+
+    while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) 
+        i++;
+
+    while (len > 0)
+    {
+        int offset;
+        if (i >= CONFIG_X509_MAX_CA_CERTS)
+        {
+#ifdef CONFIG_SSL_FULL_MODE
+            printf("Error: maximum number of CA certs added (%d) - change of "
+                    "compile-time configuration required\n", 
+                    CONFIG_X509_MAX_CA_CERTS);
+#endif
+            break;
+        }
+
+
+        /* ignore the return code */
+        if (x509_new(buf, &offset, &ca_cert_ctx->cert[i]) == X509_OK)
+        {
+#if defined (CONFIG_SSL_FULL_MODE)
+            if (ssl_ctx->options & SSL_DISPLAY_CERTS)
+                x509_print(ca_cert_ctx->cert[i], NULL);
+#endif
+        }
+
+        i++;
+        len -= offset;
+    }
+
+    return ret;
+}
+
+/*
+ * Retrieve an X.509 distinguished name component
+ */
+EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component)
+{
+    if (ssl->x509_ctx == NULL)
+        return NULL;
+
+    switch (component)
+    {
+        case SSL_X509_CERT_COMMON_NAME:
+            return ssl->x509_ctx->cert_dn[X509_COMMON_NAME];
+
+        case SSL_X509_CERT_ORGANIZATION:
+            return ssl->x509_ctx->cert_dn[X509_ORGANIZATION];
+
+        case SSL_X509_CERT_ORGANIZATIONAL_NAME:       
+            return ssl->x509_ctx->cert_dn[X509_ORGANIZATIONAL_UNIT];
+
+        case SSL_X509_CA_CERT_COMMON_NAME:
+            return ssl->x509_ctx->ca_cert_dn[X509_COMMON_NAME];
+
+        case SSL_X509_CA_CERT_ORGANIZATION:
+            return ssl->x509_ctx->ca_cert_dn[X509_ORGANIZATION];
+
+        case SSL_X509_CA_CERT_ORGANIZATIONAL_NAME:       
+            return ssl->x509_ctx->ca_cert_dn[X509_ORGANIZATIONAL_UNIT];
+
+        default:
+            return NULL;
+    }
+}
+
+/*
+ * Retrieve a "Subject Alternative Name" from a v3 certificate
+ */
+EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl,
+        int dnsindex)
+{
+    int i;
+
+    if (ssl->x509_ctx == NULL || ssl->x509_ctx->subject_alt_dnsnames == NULL)
+        return NULL;
+
+    for (i = 0; i < dnsindex; ++i)
+    {
+        if (ssl->x509_ctx->subject_alt_dnsnames[i] == NULL)
+            return NULL;
+    }
+
+    return ssl->x509_ctx->subject_alt_dnsnames[dnsindex];
+}
+
+#endif /* CONFIG_SSL_CERT_VERIFICATION */
+
+/*
+ * Find an ssl object based on the client's file descriptor.
+ */
+EXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd)
+{
+    SSL *ssl;
+
+    SSL_CTX_LOCK(ssl_ctx->mutex);
+    ssl = ssl_ctx->head;
+
+    /* search through all the ssl entries */
+    while (ssl)
+    {
+        if (ssl->client_fd == client_fd)
+        {
+            SSL_CTX_UNLOCK(ssl_ctx->mutex);
+            return ssl;
+        }
+
+        ssl = ssl->next;
+    }
+
+    SSL_CTX_UNLOCK(ssl_ctx->mutex);
+    return NULL;
+}
+
+/*
+ * Force the client to perform its handshake again.
+ */
+EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl)
+{
+    int ret = SSL_OK;
+
+    disposable_new(ssl);
+#ifdef CONFIG_SSL_ENABLE_CLIENT
+    if (IS_SET_SSL_FLAG(SSL_IS_CLIENT))
+    {
+        ret = do_client_connect(ssl);
+    }
+    else
+#endif
+    {
+        send_packet(ssl, PT_HANDSHAKE_PROTOCOL, 
+                g_hello_request, sizeof(g_hello_request));
+        SET_SSL_FLAG(SSL_NEED_RECORD);
+    }
+
+    return ret;
+}
+
+/**
+ * @brief Get what we need for key info.
+ * @param cipher    [in]    The cipher information we are after
+ * @param key_size  [out]   The key size for the cipher
+ * @param iv_size   [out]   The iv size for the cipher
+ * @return  The amount of key information we need.
+ */
+static const cipher_info_t *get_cipher_info(uint8_t cipher)
+{
+    int i;
+
+    for (i = 0; i < NUM_PROTOCOLS; i++)
+    {
+        if (cipher_info[i].cipher == cipher)
+        {
+            return &cipher_info[i];
+        }
+    }
+
+    return NULL;  /* error */
+}
+
+/*
+ * Get a new ssl context for a new connection.
+ */
+SSL *ssl_new(SSL_CTX *ssl_ctx, int client_fd)
+{
+    SSL *ssl = (SSL *)calloc(1, sizeof(SSL));;
+    ssl->ssl_ctx = ssl_ctx;
+    ssl->need_bytes = SSL_RECORD_SIZE;      /* need a record */
+    ssl->client_fd = client_fd;
+    ssl->flag = SSL_NEED_RECORD;
+    ssl->bm_data = ssl->bm_all_data+BM_RECORD_OFFSET; /* space at the start */
+    ssl->hs_status = SSL_NOT_OK;            /* not connected */
+#ifdef CONFIG_ENABLE_VERIFICATION
+    ssl->ca_cert_ctx = ssl_ctx->ca_cert_ctx;
+#endif
+    disposable_new(ssl);
+
+    /* a bit hacky but saves a few bytes of memory */
+    ssl->flag |= ssl_ctx->options;
+    SSL_CTX_LOCK(ssl_ctx->mutex);
+
+    if (ssl_ctx->head == NULL)
+    {
+        ssl_ctx->head = ssl;
+        ssl_ctx->tail = ssl;
+    }
+    else
+    {
+        ssl->prev = ssl_ctx->tail;
+        ssl_ctx->tail->next = ssl;
+        ssl_ctx->tail = ssl;
+    }
+
+    SSL_CTX_UNLOCK(ssl_ctx->mutex);
+    return ssl;
+}
+
+/*
+ * Add a private key to a context.
+ */
+int add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj)
+{
+    int ret = SSL_OK;
+
+    /* get the private key details */
+    if (asn1_get_private_key(ssl_obj->buf, ssl_obj->len, &ssl_ctx->rsa_ctx))
+    {
+        ret = SSL_ERROR_INVALID_KEY;
+        goto error;
+    }
+
+error:
+    return ret;
+}
+
+/** 
+ * Increment the read sequence number (as a 64 bit endian indepenent #)
+ */     
+static void increment_read_sequence(SSL *ssl)
+{
+    int i;
+
+    for (i = 7; i >= 0; i--) 
+    {       
+        if (++ssl->read_sequence[i])
+            break;
+    }
+}
+            
+/**
+ * Increment the read sequence number (as a 64 bit endian indepenent #)
+ */      
+static void increment_write_sequence(SSL *ssl)
+{        
+    int i;                  
+         
+    for (i = 7; i >= 0; i--)
+    {                       
+        if (++ssl->write_sequence[i])
+            break;
+    }                       
+}
+
+/**
+ * Work out the HMAC digest in a packet.
+ */
+static void add_hmac_digest(SSL *ssl, int mode, uint8_t *hmac_header,
+        const uint8_t *buf, int buf_len, uint8_t *hmac_buf)
+{
+    int hmac_len = buf_len + 8 + SSL_RECORD_SIZE;
+    uint8_t *t_buf = (uint8_t *)alloca(hmac_len+10);
+
+    memcpy(t_buf, (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE) ? 
+                    ssl->write_sequence : ssl->read_sequence, 8);
+    memcpy(&t_buf[8], hmac_header, SSL_RECORD_SIZE);
+    memcpy(&t_buf[8+SSL_RECORD_SIZE], buf, buf_len);
+
+    ssl->cipher_info->hmac(t_buf, hmac_len, 
+            (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_READ) ? 
+                ssl->server_mac : ssl->client_mac, 
+            ssl->cipher_info->digest_size, hmac_buf);
+
+#if 0
+    print_blob("record", hmac_header, SSL_RECORD_SIZE);
+    print_blob("buf", buf, buf_len);
+    if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE)
+    {
+        print_blob("write seq", ssl->write_sequence, 8);
+    }
+    else
+    {
+        print_blob("read seq", ssl->read_sequence, 8);
+    }
+
+    if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_READ)
+    {
+        print_blob("server mac", 
+                ssl->server_mac, ssl->cipher_info->digest_size);
+    }
+    else
+    {
+        print_blob("client mac", 
+                ssl->client_mac, ssl->cipher_info->digest_size);
+    }
+    print_blob("hmac", hmac_buf, SHA1_SIZE);
+#endif
+}
+
+/**
+ * Verify that the digest of a packet is correct.
+ */
+static int verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len)
+{   
+    uint8_t hmac_buf[SHA1_SIZE];
+    int hmac_offset;
+   
+    if (ssl->cipher_info->padding_size)
+    {
+        int last_blk_size = buf[read_len-1], i;
+        hmac_offset = read_len-last_blk_size-ssl->cipher_info->digest_size-1;
+
+        /* guard against a timing attack - make sure we do the digest */
+        if (hmac_offset < 0)
+        {
+            hmac_offset = 0;
+        }
+        else
+        {
+            /* already looked at last byte */
+            for (i = 1; i < last_blk_size; i++)
+            {
+                if (buf[read_len-i] != last_blk_size)
+                {
+                    hmac_offset = 0;
+                    break;
+                }
+            }
+        }
+    }
+    else /* stream cipher */
+    {
+        hmac_offset = read_len - ssl->cipher_info->digest_size;
+
+        if (hmac_offset < 0)
+        {
+            hmac_offset = 0;
+        }
+    }
+
+    /* sanity check the offset */
+    ssl->hmac_header[3] = hmac_offset >> 8;      /* insert size */
+    ssl->hmac_header[4] = hmac_offset & 0xff;
+    add_hmac_digest(ssl, mode, ssl->hmac_header, buf, hmac_offset, hmac_buf);
+
+    if (memcmp(hmac_buf, &buf[hmac_offset], ssl->cipher_info->digest_size))
+    {
+        return SSL_ERROR_INVALID_HMAC;
+    }
+
+    return hmac_offset;
+}
+
+/**
+ * Add a packet to the end of our sent and received packets, so that we may use
+ * it to calculate the hash at the end.
+ */
+void add_packet(SSL *ssl, const uint8_t *pkt, int len)
+{
+    MD5_Update(&ssl->dc->md5_ctx, pkt, len);
+    SHA1_Update(&ssl->dc->sha1_ctx, pkt, len);
+}
+
+/**
+ * Work out the MD5 PRF.
+ */
+static void p_hash_md5(const uint8_t *sec, int sec_len, 
+        uint8_t *seed, int seed_len, uint8_t *out, int olen)
+{
+    uint8_t a1[128];
+
+    /* A(1) */
+    hmac_md5(seed, seed_len, sec, sec_len, a1);
+    memcpy(&a1[MD5_SIZE], seed, seed_len);
+    hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out);
+
+    while (olen > MD5_SIZE)
+    {
+        uint8_t a2[MD5_SIZE];
+        out += MD5_SIZE;
+        olen -= MD5_SIZE;
+
+        /* A(N) */
+        hmac_md5(a1, MD5_SIZE, sec, sec_len, a2);
+        memcpy(a1, a2, MD5_SIZE);
+
+        /* work out the actual hash */
+        hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out);
+    }
+}
+
+/**
+ * Work out the SHA1 PRF.
+ */
+static void p_hash_sha1(const uint8_t *sec, int sec_len, 
+        uint8_t *seed, int seed_len, uint8_t *out, int olen)
+{
+    uint8_t a1[128];
+
+    /* A(1) */
+    hmac_sha1(seed, seed_len, sec, sec_len, a1);
+    memcpy(&a1[SHA1_SIZE], seed, seed_len);
+    hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out);
+
+    while (olen > SHA1_SIZE)
+    {
+        uint8_t a2[SHA1_SIZE];
+        out += SHA1_SIZE;
+        olen -= SHA1_SIZE;
+
+        /* A(N) */
+        hmac_sha1(a1, SHA1_SIZE, sec, sec_len, a2);
+        memcpy(a1, a2, SHA1_SIZE);
+
+        /* work out the actual hash */
+        hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out);
+    }
+}
+
+/**
+ * Work out the PRF.
+ */
+static void prf(const uint8_t *sec, int sec_len, uint8_t *seed, int seed_len,
+        uint8_t *out, int olen)
+{
+    int len, i;
+    const uint8_t *S1, *S2;
+    uint8_t xbuf[256]; /* needs to be > the amount of key data */
+    uint8_t ybuf[256]; /* needs to be > the amount of key data */
+
+    len = sec_len/2;
+    S1 = sec;
+    S2 = &sec[len];
+    len += (sec_len & 1); /* add for odd, make longer */
+
+    p_hash_md5(S1, len, seed, seed_len, xbuf, olen);
+    p_hash_sha1(S2, len, seed, seed_len, ybuf, olen);
+
+    for (i = 0; i < olen; i++)
+        out[i] = xbuf[i] ^ ybuf[i];
+}
+
+/**
+ * Generate a master secret based on the client/server random data and the
+ * premaster secret.
+ */
+void generate_master_secret(SSL *ssl, const uint8_t *premaster_secret)
+{
+    uint8_t buf[128];   /* needs to be > 13+32+32 in size */
+    strcpy((char *)buf, "master secret");
+    memcpy(&buf[13], ssl->dc->client_random, SSL_RANDOM_SIZE);
+    memcpy(&buf[45], ssl->dc->server_random, SSL_RANDOM_SIZE);
+    prf(premaster_secret, SSL_SECRET_SIZE, buf, 77, ssl->dc->master_secret,
+            SSL_SECRET_SIZE);
+}
+
+/**
+ * Generate a 'random' blob of data used for the generation of keys.
+ */
+static void generate_key_block(uint8_t *client_random, uint8_t *server_random,
+        uint8_t *master_secret, uint8_t *key_block, int key_block_size)
+{
+    uint8_t buf[128];
+    strcpy((char *)buf, "key expansion");
+    memcpy(&buf[13], server_random, SSL_RANDOM_SIZE);
+    memcpy(&buf[45], client_random, SSL_RANDOM_SIZE);
+    prf(master_secret, SSL_SECRET_SIZE, buf, 77, key_block, key_block_size);
+}
+
+/** 
+ * Calculate the digest used in the finished message. This function also
+ * doubles up as a certificate verify function.
+ */
+void finished_digest(SSL *ssl, const char *label, uint8_t *digest)
+{
+    uint8_t mac_buf[128]; 
+    uint8_t *q = mac_buf;
+    MD5_CTX md5_ctx = ssl->dc->md5_ctx;
+    SHA1_CTX sha1_ctx = ssl->dc->sha1_ctx;
+
+    if (label)
+    {
+        strcpy((char *)q, label);
+        q += strlen(label);
+    }
+
+    MD5_Final(q, &md5_ctx);
+    q += MD5_SIZE;
+    
+    SHA1_Final(q, &sha1_ctx);
+    q += SHA1_SIZE;
+
+    if (label)
+    {
+        prf(ssl->dc->master_secret, SSL_SECRET_SIZE, mac_buf, (int)(q-mac_buf),
+            digest, SSL_FINISHED_HASH_SIZE);
+    }
+    else    /* for use in a certificate verify */
+    {
+        memcpy(digest, mac_buf, MD5_SIZE + SHA1_SIZE);
+    }
+
+#if 0
+    printf("label: %s\r\n", label);
+    print_blob("master secret", ssl->dc->master_secret, 48);
+    print_blob("mac_buf", mac_buf, q-mac_buf);
+    print_blob("finished digest", digest, SSL_FINISHED_HASH_SIZE);
+#endif
+}   
+    
+/**
+ * Retrieve (and initialise) the context of a cipher.
+ */
+static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt)
+{
+    switch (ssl->cipher)
+    {
+#ifndef CONFIG_SSL_SKELETON_MODE
+        case SSL_AES128_SHA:
+            {
+                AES_CTX *aes_ctx = (AES_CTX *)malloc(sizeof(AES_CTX));
+                AES_set_key(aes_ctx, key, iv, AES_MODE_128);
+
+                if (is_decrypt)
+                {
+                    AES_convert_key(aes_ctx);
+                }
+
+                return (void *)aes_ctx;
+            }
+
+        case SSL_AES256_SHA:
+            {
+                AES_CTX *aes_ctx = (AES_CTX *)malloc(sizeof(AES_CTX));
+                AES_set_key(aes_ctx, key, iv, AES_MODE_256);
+
+                if (is_decrypt)
+                {
+                    AES_convert_key(aes_ctx);
+                }
+
+                return (void *)aes_ctx;
+            }
+
+        case SSL_RC4_128_MD5:
+#endif
+        case SSL_RC4_128_SHA:
+            {
+                RC4_CTX *rc4_ctx = (RC4_CTX *)malloc(sizeof(RC4_CTX));
+                RC4_setup(rc4_ctx, key, 16);
+                return (void *)rc4_ctx;
+            }
+    }
+
+    return NULL;    /* its all gone wrong */
+}
+
+/**
+ * Send a packet over the socket.
+ */
+static int send_raw_packet(SSL *ssl, uint8_t protocol)
+{
+   
+    uint8_t *rec_buf = ssl->bm_all_data;
+    int pkt_size = SSL_RECORD_SIZE+ssl->bm_index;
+    int sent = 0;
+    int ret = SSL_OK;
+    rec_buf[0] = protocol;
+    rec_buf[1] = 0x03;      /* version = 3.1 or higher */
+    rec_buf[2] = ssl->version & 0x0f;
+    rec_buf[3] = ssl->bm_index >> 8;
+    rec_buf[4] = ssl->bm_index & 0xff;
+
+    DISPLAY_BYTES(ssl, "sending %d bytes", ssl->bm_all_data, 
+                             pkt_size, pkt_size);
+
+    while (sent < pkt_size)
+    {
+        ret = SOCKET_WRITE(ssl->client_fd, 
+                        &ssl->bm_all_data[sent], pkt_size-sent);
+        if (ret >= 0)
+            sent += ret;
+        else
+        {
+
+#ifdef WIN32
+            if (GetLastError() != WSAEWOULDBLOCK)
+#else
+            if (errno != EAGAIN && errno != EWOULDBLOCK)
+#endif
+                return SSL_ERROR_CONN_LOST;
+        }
+
+        /* keep going until the write buffer has some space */
+        if (sent != pkt_size)
+        {
+            fd_set wfds;
+            FD_ZERO(&wfds);
+            FD_SET(ssl->client_fd, &wfds);
+
+            /* block and wait for it */
+            if (lwip_select(ssl->client_fd + 1, NULL, &wfds, NULL, NULL) < 0)
+                return SSL_ERROR_CONN_LOST;
+            
+        }
+    }
+
+    SET_SSL_FLAG(SSL_NEED_RECORD);  /* reset for next time */
+    ssl->bm_index = 0;
+
+    if (protocol != PT_APP_PROTOCOL_DATA)  
+    {
+        /* always return SSL_OK during handshake */   
+        ret = SSL_OK;
+    }
+
+    return ret;
+}
+
+/**
+ * Send an encrypted packet with padding bytes if necessary.
+ */
+int send_packet(SSL *ssl, uint8_t protocol, const uint8_t *in, int length)
+{
+    int ret, msg_length = 0;
+
+    /* if our state is bad, don't bother */
+    if (ssl->hs_status == SSL_ERROR_DEAD)
+        return SSL_ERROR_CONN_LOST;
+
+    if (in) /* has the buffer already been initialised? */
+    {
+        memcpy(ssl->bm_data, in, length);
+    }
+
+    msg_length += length;
+
+    if (IS_SET_SSL_FLAG(SSL_TX_ENCRYPTED))
+    {
+        int mode = IS_SET_SSL_FLAG(SSL_IS_CLIENT) ? 
+                            SSL_CLIENT_WRITE : SSL_SERVER_WRITE;
+        uint8_t hmac_header[SSL_RECORD_SIZE] = 
+        {
+            protocol, 
+            0x03, /* version = 3.1 or higher */
+            ssl->version & 0x0f,
+            msg_length >> 8,
+            msg_length & 0xff 
+        };
+
+        if (protocol == PT_HANDSHAKE_PROTOCOL)
+        {
+            DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0);
+
+            if (ssl->bm_data[0] != HS_HELLO_REQUEST)
+            {
+                add_packet(ssl, ssl->bm_data, msg_length);
+            }
+        }
+
+        /* add the packet digest */
+        add_hmac_digest(ssl, mode, hmac_header, ssl->bm_data, msg_length, 
+                                                &ssl->bm_data[msg_length]);
+        msg_length += ssl->cipher_info->digest_size;
+
+        /* add padding? */
+        if (ssl->cipher_info->padding_size)
+        {
+            int last_blk_size = msg_length%ssl->cipher_info->padding_size;
+            int pad_bytes = ssl->cipher_info->padding_size - last_blk_size;
+
+            /* ensure we always have at least 1 padding byte */
+            if (pad_bytes == 0)
+                pad_bytes += ssl->cipher_info->padding_size;
+
+            memset(&ssl->bm_data[msg_length], pad_bytes-1, pad_bytes);
+            msg_length += pad_bytes;
+        }
+
+        DISPLAY_BYTES(ssl, "unencrypted write", ssl->bm_data, msg_length);
+        increment_write_sequence(ssl);
+
+        /* add the explicit IV for TLS1.1 */
+        if (ssl->version >= SSL_PROTOCOL_VERSION1_1 &&
+                        ssl->cipher_info->iv_size)
+        {
+            uint8_t iv_size = ssl->cipher_info->iv_size;
+            uint8_t *t_buf = alloca(msg_length + iv_size);
+            memcpy(t_buf + iv_size, ssl->bm_data, msg_length);
+            get_random(iv_size, t_buf);
+            msg_length += iv_size;
+            memcpy(ssl->bm_data, t_buf, msg_length);
+        }
+
+        /* now encrypt the packet */
+        ssl->cipher_info->encrypt(ssl->encrypt_ctx, ssl->bm_data, 
+                                            ssl->bm_data, msg_length);
+    }
+    else if (protocol == PT_HANDSHAKE_PROTOCOL)
+    {
+        DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0);
+
+        if (ssl->bm_data[0] != HS_HELLO_REQUEST)
+        {
+            add_packet(ssl, ssl->bm_data, length);
+        }
+    }
+
+    ssl->bm_index = msg_length;
+    if ((ret = send_raw_packet(ssl, protocol)) <= 0)
+        return ret;
+
+    return length;  /* just return what we wanted to send */
+}
+
+/**
+ * Work out the cipher keys we are going to use for this session based on the
+ * master secret.
+ */
+static int set_key_block(SSL *ssl, int is_write)
+{
+    const cipher_info_t *ciph_info = get_cipher_info(ssl->cipher);
+    uint8_t *q;
+    uint8_t client_key[32], server_key[32]; /* big enough for AES256 */
+    uint8_t client_iv[16], server_iv[16];   /* big enough for AES128/256 */
+    int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+
+    if (ciph_info == NULL)
+        return -1;
+
+    /* only do once in a handshake */
+    if (ssl->dc->key_block == NULL)
+    {
+        ssl->dc->key_block = (uint8_t *)malloc(ciph_info->key_block_size);
+
+#if 0
+        print_blob("client", ssl->dc->client_random, 32);
+        print_blob("server", ssl->dc->server_random, 32);
+        print_blob("master", ssl->dc->master_secret, SSL_SECRET_SIZE);
+#endif
+        generate_key_block(ssl->dc->client_random, ssl->dc->server_random,
+            ssl->dc->master_secret, ssl->dc->key_block, 
+            ciph_info->key_block_size);
+#if 0
+        print_blob("keyblock", ssl->dc->key_block, ciph_info->key_block_size);
+#endif
+    }
+
+    q = ssl->dc->key_block;
+
+    if ((is_client && is_write) || (!is_client && !is_write))
+    {
+        memcpy(ssl->client_mac, q, ciph_info->digest_size);
+    }
+
+    q += ciph_info->digest_size;
+
+    if ((!is_client && is_write) || (is_client && !is_write))
+    {
+        memcpy(ssl->server_mac, q, ciph_info->digest_size);
+    }
+
+    q += ciph_info->digest_size;
+    memcpy(client_key, q, ciph_info->key_size);
+    q += ciph_info->key_size;
+    memcpy(server_key, q, ciph_info->key_size);
+    q += ciph_info->key_size;
+
+#ifndef CONFIG_SSL_SKELETON_MODE 
+    if (ciph_info->iv_size)    /* RC4 has no IV, AES does */
+    {
+        memcpy(client_iv, q, ciph_info->iv_size);
+        q += ciph_info->iv_size;
+        memcpy(server_iv, q, ciph_info->iv_size);
+        q += ciph_info->iv_size;
+    }
+#endif
+
+    free(is_write ? ssl->encrypt_ctx : ssl->decrypt_ctx);
+
+    /* now initialise the ciphers */
+    if (is_client)
+    {
+        finished_digest(ssl, server_finished, ssl->dc->final_finish_mac);
+
+        if (is_write)
+            ssl->encrypt_ctx = crypt_new(ssl, client_key, client_iv, 0);
+        else
+            ssl->decrypt_ctx = crypt_new(ssl, server_key, server_iv, 1);
+    }
+    else
+    {
+        finished_digest(ssl, client_finished, ssl->dc->final_finish_mac);
+
+        if (is_write)
+            ssl->encrypt_ctx = crypt_new(ssl, server_key, server_iv, 0);
+        else
+            ssl->decrypt_ctx = crypt_new(ssl, client_key, client_iv, 1);
+    }
+
+    ssl->cipher_info = ciph_info;
+    return 0;
+}
+
+/**
+ * Read the SSL connection.
+ */
+int basic_read(SSL *ssl, uint8_t **in_data)
+{
+    int ret = SSL_OK;
+    int read_len, is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+    uint8_t *buf = ssl->bm_data;
+
+    read_len = SOCKET_READ(ssl->client_fd, &buf[ssl->bm_read_index], 
+                            ssl->need_bytes-ssl->got_bytes);
+
+    if (read_len < 0) 
+    {
+#ifdef WIN32
+        if (GetLastError() == WSAEWOULDBLOCK)
+#else
+        if (errno == EAGAIN || errno == EWOULDBLOCK)
+#endif
+            return 0;
+    }
+
+    /* connection has gone, so die */
+    if (read_len <= 0)
+    {
+        ret = SSL_ERROR_CONN_LOST;
+        ssl->hs_status = SSL_ERROR_DEAD;  /* make sure it stays dead */
+        goto error;
+    }
+
+    DISPLAY_BYTES(ssl, "received %d bytes", 
+            &ssl->bm_data[ssl->bm_read_index], read_len, read_len);
+
+    ssl->got_bytes += read_len;
+    ssl->bm_read_index += read_len;
+
+    /* haven't quite got what we want, so try again later */
+    if (ssl->got_bytes < ssl->need_bytes)
+        return SSL_OK;
+
+    read_len = ssl->got_bytes;
+    ssl->got_bytes = 0;
+
+    if (IS_SET_SSL_FLAG(SSL_NEED_RECORD))
+    {
+        /* check for sslv2 "client hello" */
+        if (buf[0] & 0x80 && buf[2] == 1)
+        {
+#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE
+            uint8_t version = (buf[3] << 4) + buf[4];
+            DISPLAY_BYTES(ssl, "ssl2 record", buf, 5);
+
+            /* should be v3.1 (TLSv1) or better  */
+            ssl->version = ssl->client_version = version;
+
+            if (version > SSL_PROTOCOL_VERSION_MAX)
+            {
+                /* use client's version */
+                ssl->version = SSL_PROTOCOL_VERSION_MAX;
+            }
+            else if (version < SSL_PROTOCOL_MIN_VERSION)  
+            {
+                ret = SSL_ERROR_INVALID_VERSION;
+                ssl_display_error(ret);
+                return ret;
+            }
+
+            add_packet(ssl, &buf[2], 3);
+            ret = process_sslv23_client_hello(ssl); 
+#else
+            printf("Error: no SSLv23 handshaking allowed\n"); TTY_FLUSH();
+            ret = SSL_ERROR_NOT_SUPPORTED;
+#endif
+            goto error; /* not an error - just get out of here */
+        }
+
+        ssl->need_bytes = (buf[3] << 8) + buf[4];
+
+        /* do we violate the spec with the message size?  */
+        if (ssl->need_bytes > RT_MAX_PLAIN_LENGTH+RT_EXTRA-BM_RECORD_OFFSET)
+        {
+            ret = SSL_ERROR_INVALID_PROT_MSG;              
+            goto error;
+        }
+
+        CLR_SSL_FLAG(SSL_NEED_RECORD);
+        memcpy(ssl->hmac_header, buf, 3);       /* store for hmac */
+        ssl->record_type = buf[0];
+        goto error;                         /* no error, we're done */
+    }
+
+    /* for next time - just do it now in case of an error */
+    SET_SSL_FLAG(SSL_NEED_RECORD);
+    ssl->need_bytes = SSL_RECORD_SIZE;
+
+    /* decrypt if we need to */
+    if (IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED))
+    {
+        ssl->cipher_info->decrypt(ssl->decrypt_ctx, buf, buf, read_len);
+
+        if (ssl->version >= SSL_PROTOCOL_VERSION1_1 &&
+                        ssl->cipher_info->iv_size)
+        {
+            buf += ssl->cipher_info->iv_size;
+            read_len -= ssl->cipher_info->iv_size;
+        }
+
+        read_len = verify_digest(ssl, 
+                is_client ? SSL_CLIENT_READ : SSL_SERVER_READ, buf, read_len);
+
+        /* does the hmac work? */
+        if (read_len < 0)
+        {
+            ret = read_len;
+            goto error;
+        }
+
+        DISPLAY_BYTES(ssl, "decrypted", buf, read_len);
+        increment_read_sequence(ssl);
+    }
+
+    /* The main part of the SSL packet */
+    switch (ssl->record_type)
+    {
+        case PT_HANDSHAKE_PROTOCOL:
+            if (ssl->dc != NULL)
+            {
+                ssl->dc->bm_proc_index = 0;
+                ret = do_handshake(ssl, buf, read_len);
+            }
+            else /* no client renegotiation allowed */
+            {
+                ret = SSL_ERROR_NO_CLIENT_RENOG;              
+                goto error;
+            }
+            break;
+
+        case PT_CHANGE_CIPHER_SPEC:
+            if (ssl->next_state != HS_FINISHED)
+            {
+                ret = SSL_ERROR_INVALID_HANDSHAKE;
+                goto error;
+            }
+
+            /* all encrypted from now on */
+            SET_SSL_FLAG(SSL_RX_ENCRYPTED);
+            if (set_key_block(ssl, 0) < 0)
+            {
+                ret = SSL_ERROR_INVALID_HANDSHAKE;
+                goto error;
+            }
+            
+            memset(ssl->read_sequence, 0, 8);
+            break;
+
+        case PT_APP_PROTOCOL_DATA:
+            if (in_data)
+            {
+                *in_data = buf;   /* point to the work buffer */
+                (*in_data)[read_len] = 0;  /* null terminate just in case */
+            }
+
+            ret = read_len;
+            break;
+
+        case PT_ALERT_PROTOCOL:
+            /* return the alert # with alert bit set */
+            if(buf[0] == SSL_ALERT_TYPE_WARNING &&
+               buf[1] == SSL_ALERT_CLOSE_NOTIFY)
+            {
+              ret = SSL_CLOSE_NOTIFY;
+              send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY);
+              SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY);
+            }
+            else 
+            {
+                ret = -buf[1]; 
+                DISPLAY_ALERT(ssl, buf[1]);
+            }
+
+            break;
+
+        default:
+            ret = SSL_ERROR_INVALID_PROT_MSG;
+            break;
+    }
+
+error:
+    ssl->bm_read_index = 0;          /* reset to go again */
+
+    if (ret < SSL_OK && in_data)/* if all wrong, then clear this buffer ptr */
+        *in_data = NULL;
+
+    return ret;
+}
+
+/**
+ * Do some basic checking of data and then perform the appropriate handshaking.
+ */
+static int do_handshake(SSL *ssl, uint8_t *buf, int read_len)
+{
+    int hs_len = (buf[2]<<8) + buf[3];
+    uint8_t handshake_type = buf[0];
+    int ret = SSL_OK;
+    int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+
+    /* some integrity checking on the handshake */
+    PARANOIA_CHECK(read_len-SSL_HS_HDR_SIZE, hs_len);
+
+    if (handshake_type != ssl->next_state)
+    {
+        /* handle a special case on the client */
+        if (!is_client || handshake_type != HS_CERT_REQ ||
+                        ssl->next_state != HS_SERVER_HELLO_DONE)
+        {
+            ret = SSL_ERROR_INVALID_HANDSHAKE;
+            goto error;
+        }
+    }
+
+    hs_len += SSL_HS_HDR_SIZE;  /* adjust for when adding packets */
+    ssl->bm_index = hs_len;     /* store the size and check later */
+    DISPLAY_STATE(ssl, 0, handshake_type, 0);
+
+    if (handshake_type != HS_CERT_VERIFY && handshake_type != HS_HELLO_REQUEST)
+        add_packet(ssl, buf, hs_len); 
+
+#if defined(CONFIG_SSL_ENABLE_CLIENT)
+    ret = is_client ? 
+        do_clnt_handshake(ssl, handshake_type, buf, hs_len) :
+        do_svr_handshake(ssl, handshake_type, buf, hs_len);
+#else
+    ret = do_svr_handshake(ssl, handshake_type, buf, hs_len);
+#endif
+
+    /* just use recursion to get the rest */
+    if (hs_len < read_len && ret == SSL_OK)
+        ret = do_handshake(ssl, &buf[hs_len], read_len-hs_len);
+
+error:
+    return ret;
+}
+
+/**
+ * Sends the change cipher spec message. We have just read a finished message
+ * from the client.
+ */
+int send_change_cipher_spec(SSL *ssl)
+{
+    int ret = send_packet(ssl, PT_CHANGE_CIPHER_SPEC, 
+            g_chg_cipher_spec_pkt, sizeof(g_chg_cipher_spec_pkt));
+    SET_SSL_FLAG(SSL_TX_ENCRYPTED);
+
+    if (ret >= 0 && set_key_block(ssl, 1) < 0)
+        ret = SSL_ERROR_INVALID_HANDSHAKE;
+
+    memset(ssl->write_sequence, 0, 8);
+    return ret;
+}
+
+/**
+ * Send a "finished" message
+ */
+int send_finished(SSL *ssl)
+{
+    uint8_t buf[SSL_FINISHED_HASH_SIZE+4] = {
+        HS_FINISHED, 0, 0, SSL_FINISHED_HASH_SIZE };
+
+    /* now add the finished digest mac (12 bytes) */
+    finished_digest(ssl, 
+        IS_SET_SSL_FLAG(SSL_IS_CLIENT) ?
+                    client_finished : server_finished, &buf[4]);
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+    /* store in the session cache */
+    if (!IS_SET_SSL_FLAG(SSL_SESSION_RESUME) && ssl->ssl_ctx->num_sessions)
+    {
+        memcpy(ssl->session->master_secret,
+                ssl->dc->master_secret, SSL_SECRET_SIZE);
+    }
+#endif
+
+    return send_packet(ssl, PT_HANDSHAKE_PROTOCOL,
+                                buf, SSL_FINISHED_HASH_SIZE+4);
+}
+
+/**
+ * Send an alert message.
+ * Return 1 if the alert was an "error".
+ */
+int send_alert(SSL *ssl, int error_code)
+{
+    int alert_num = 0;
+    int is_warning = 0;
+    uint8_t buf[2];
+
+    /* Don't bother we're already dead */
+    if (ssl->hs_status == SSL_ERROR_DEAD)
+    {
+        return SSL_ERROR_CONN_LOST;
+    }
+
+#ifdef CONFIG_SSL_FULL_MODE
+    if (IS_SET_SSL_FLAG(SSL_DISPLAY_STATES))
+        ssl_display_error(error_code);
+#endif
+
+    switch (error_code)
+    {
+        case SSL_ALERT_CLOSE_NOTIFY:
+            is_warning = 1;
+            alert_num = SSL_ALERT_CLOSE_NOTIFY;
+            break;
+
+        case SSL_ERROR_CONN_LOST:       /* don't send alert just yet */
+            is_warning = 1;
+            break;
+
+        case SSL_ERROR_INVALID_HANDSHAKE:
+        case SSL_ERROR_INVALID_PROT_MSG:
+            alert_num = SSL_ALERT_HANDSHAKE_FAILURE;
+            break;
+
+        case SSL_ERROR_INVALID_HMAC:
+        case SSL_ERROR_FINISHED_INVALID:
+            alert_num = SSL_ALERT_BAD_RECORD_MAC;
+            break;
+
+        case SSL_ERROR_INVALID_VERSION:
+            alert_num = SSL_ALERT_INVALID_VERSION;
+            break;
+
+        case SSL_ERROR_INVALID_SESSION:
+        case SSL_ERROR_NO_CIPHER:
+        case SSL_ERROR_INVALID_KEY:
+            alert_num = SSL_ALERT_ILLEGAL_PARAMETER;
+            break;
+
+        case SSL_ERROR_BAD_CERTIFICATE:
+            alert_num = SSL_ALERT_BAD_CERTIFICATE;
+            break;
+
+        case SSL_ERROR_NO_CLIENT_RENOG:
+            alert_num = SSL_ALERT_NO_RENEGOTIATION;
+            break;
+
+        default:
+            /* a catch-all for any badly verified certificates */
+            alert_num = (error_code <= SSL_X509_OFFSET) ?  
+                SSL_ALERT_BAD_CERTIFICATE : SSL_ALERT_UNEXPECTED_MESSAGE;
+            break;
+    }
+
+    buf[0] = is_warning ? 1 : 2;
+    buf[1] = alert_num;
+    send_packet(ssl, PT_ALERT_PROTOCOL, buf, sizeof(buf));
+    DISPLAY_ALERT(ssl, alert_num);
+    return is_warning ? 0 : 1;
+}
+
+/**
+ * Process a client finished message.
+ */
+int process_finished(SSL *ssl, uint8_t *buf, int hs_len)
+{
+    int ret = SSL_OK;
+    int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+    int resume = IS_SET_SSL_FLAG(SSL_SESSION_RESUME);
+
+    PARANOIA_CHECK(ssl->bm_index, SSL_FINISHED_HASH_SIZE+4);
+
+    /* check that we all work before we continue */
+    if (memcmp(ssl->dc->final_finish_mac, &buf[4], SSL_FINISHED_HASH_SIZE))
+        return SSL_ERROR_FINISHED_INVALID;
+
+    if ((!is_client && !resume) || (is_client && resume))
+    {
+        if ((ret = send_change_cipher_spec(ssl)) == SSL_OK)
+            ret = send_finished(ssl);
+    }
+
+    /* if we ever renegotiate */
+    ssl->next_state = is_client ? HS_HELLO_REQUEST : HS_CLIENT_HELLO;  
+    ssl->hs_status = ret;  /* set the final handshake status */
+
+error:
+    return ret;
+}
+
+/**
+ * Send a certificate.
+ */
+int send_certificate(SSL *ssl)
+{
+    int i = 0;
+    uint8_t *buf = ssl->bm_data;
+    int offset = 7;
+    int chain_length;
+
+    buf[0] = HS_CERTIFICATE;
+    buf[1] = 0;
+    buf[4] = 0;
+
+    while (i < ssl->ssl_ctx->chain_length)
+    {
+        SSL_CERT *cert = &ssl->ssl_ctx->certs[i];
+        buf[offset++] = 0;        
+        buf[offset++] = cert->size >> 8;        /* cert 1 length */
+        buf[offset++] = cert->size & 0xff;
+        memcpy(&buf[offset], cert->buf, cert->size);
+        offset += cert->size;
+        i++;
+    }
+
+    chain_length = offset - 7;
+    buf[5] = chain_length >> 8;        /* cert chain length */
+    buf[6] = chain_length & 0xff;
+    chain_length += 3;
+    buf[2] = chain_length >> 8;        /* handshake length */
+    buf[3] = chain_length & 0xff;
+    ssl->bm_index = offset;
+    return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset);
+}
+
+/**
+ * Create a blob of memory that we'll get rid of once the handshake is
+ * complete.
+ */
+void disposable_new(SSL *ssl)
+{
+    if (ssl->dc == NULL)
+    {
+        ssl->dc = (DISPOSABLE_CTX *)calloc(1, sizeof(DISPOSABLE_CTX));
+        MD5_Init(&ssl->dc->md5_ctx);
+        SHA1_Init(&ssl->dc->sha1_ctx);
+    }
+}
+
+/**
+ * Remove the temporary blob of memory.
+ */
+void disposable_free(SSL *ssl)
+{
+    if (ssl->dc)
+    {
+        free(ssl->dc->key_block);
+        memset(ssl->dc, 0, sizeof(DISPOSABLE_CTX));
+        free(ssl->dc);
+        ssl->dc = NULL;
+    }
+
+}
+
+#ifndef CONFIG_SSL_SKELETON_MODE     /* no session resumption in this mode */
+/**
+ * Find if an existing session has the same session id. If so, use the
+ * master secret from this session for session resumption.
+ */
+SSL_SESSION *ssl_session_update(int max_sessions, SSL_SESSION *ssl_sessions[], 
+        SSL *ssl, const uint8_t *session_id)
+{
+    time_t tm = time(NULL);
+    time_t oldest_sess_time = tm;
+    SSL_SESSION *oldest_sess = NULL;
+    int i;
+
+    /* no sessions? Then bail */
+    if (max_sessions == 0)
+        return NULL;
+
+    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+    if (session_id)
+    {
+        for (i = 0; i < max_sessions; i++)
+        {
+            if (ssl_sessions[i])
+            {
+                /* kill off any expired sessions (including those in 
+                   the future) */
+                if ((tm > ssl_sessions[i]->conn_time + SSL_EXPIRY_TIME) ||
+                            (tm < ssl_sessions[i]->conn_time))
+                {
+                    session_free(ssl_sessions, i);
+                    continue;
+                }
+
+                /* if the session id matches, it must still be less than 
+                   the expiry time */
+                if (memcmp(ssl_sessions[i]->session_id, session_id,
+                                                SSL_SESSION_ID_SIZE) == 0)
+                {
+                    ssl->session_index = i;
+                    memcpy(ssl->dc->master_secret, 
+                            ssl_sessions[i]->master_secret, SSL_SECRET_SIZE);
+                    SET_SSL_FLAG(SSL_SESSION_RESUME);
+                    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+                    return ssl_sessions[i];  /* a session was found */
+                }
+            }
+        }
+    }
+
+    /* If we've got here, no matching session was found - so create one */
+    for (i = 0; i < max_sessions; i++)
+    {
+        if (ssl_sessions[i] == NULL)
+        {
+            /* perfect, this will do */
+            ssl_sessions[i] = (SSL_SESSION *)calloc(1, sizeof(SSL_SESSION));
+            ssl_sessions[i]->conn_time = tm;
+            ssl->session_index = i;
+            SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+            return ssl_sessions[i]; /* return the session object */
+        }
+        else if (ssl_sessions[i]->conn_time <= oldest_sess_time)
+        {
+            /* find the oldest session */
+            oldest_sess_time = ssl_sessions[i]->conn_time;
+            oldest_sess = ssl_sessions[i];
+            ssl->session_index = i;
+        }
+    }
+
+    /* ok, we've used up all of our sessions. So blow the oldest session away */
+    oldest_sess->conn_time = tm;
+    memset(oldest_sess->session_id, 0, sizeof(SSL_SESSION_ID_SIZE));
+    memset(oldest_sess->master_secret, 0, sizeof(SSL_SECRET_SIZE));
+    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+    return oldest_sess;
+}
+
+/**
+ * Free an existing session.
+ */
+static void session_free(SSL_SESSION *ssl_sessions[], int sess_index)
+{
+    if (ssl_sessions[sess_index])
+    {
+        free(ssl_sessions[sess_index]);
+        ssl_sessions[sess_index] = NULL;
+    }
+}
+
+/**
+ * This ssl object doesn't want this session anymore.
+ */
+void kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl)
+{
+    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+
+    if (ssl->ssl_ctx->num_sessions)
+    {
+        session_free(ssl_sessions, ssl->session_index);
+        ssl->session = NULL;
+    }
+
+    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+}
+#endif /* CONFIG_SSL_SKELETON_MODE */
+
+/*
+ * Get the session id for a handshake. This will be a 32 byte sequence.
+ */
+EXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl)
+{
+    return ssl->session_id;
+}
+
+/*
+ * Get the session id size for a handshake. 
+ */
+EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl)
+{
+    return ssl->sess_id_size;
+}
+
+/*
+ * Return the cipher id (in the SSL form).
+ */
+EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl)
+{
+    return ssl->cipher;
+}
+
+/*
+ * Return the status of the handshake.
+ */
+EXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl)
+{
+    return ssl->hs_status;
+}
+
+/*
+ * Retrieve various parameters about the SSL engine.
+ */
+EXP_FUNC int STDCALL ssl_get_config(int offset)
+{
+    switch (offset)
+    {
+        /* return the appropriate build mode */
+        case SSL_BUILD_MODE:
+#if defined(CONFIG_SSL_FULL_MODE)
+            return SSL_BUILD_FULL_MODE;
+#elif defined(CONFIG_SSL_ENABLE_CLIENT)
+            return SSL_BUILD_ENABLE_CLIENT;
+#elif defined(CONFIG_ENABLE_VERIFICATION)
+            return SSL_BUILD_ENABLE_VERIFICATION;
+#elif defined(CONFIG_SSL_SERVER_ONLY )
+            return SSL_BUILD_SERVER_ONLY;
+#else 
+            return SSL_BUILD_SKELETON_MODE;
+#endif
+
+        case SSL_MAX_CERT_CFG_OFFSET:
+            return CONFIG_SSL_MAX_CERTS;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+        case SSL_MAX_CA_CERT_CFG_OFFSET:
+            return CONFIG_X509_MAX_CA_CERTS;
+#endif
+#ifdef CONFIG_SSL_HAS_PEM
+        case SSL_HAS_PEM:
+            return 1;
+#endif
+        default:
+            return 0;
+    }
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Authenticate a received certificate.
+ */
+EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl)
+{
+    int ret;
+    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+    ret = x509_verify(ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx);
+    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+
+    if (ret)        /* modify into an SSL error type */
+    {
+        ret = SSL_X509_ERROR(ret);
+    }
+
+    return ret;
+}
+
+/**
+ * Process a certificate message.
+ */
+int process_certificate(SSL *ssl, X509_CTX **x509_ctx)
+{
+    int ret = SSL_OK;
+    uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
+    int pkt_size = ssl->bm_index;
+    int cert_size, offset = 5;
+    int total_cert_size = (buf[offset]<<8) + buf[offset+1];
+    int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+    X509_CTX **chain = x509_ctx;
+    offset += 2;
+
+    PARANOIA_CHECK(total_cert_size, offset);
+
+    while (offset < total_cert_size)
+    {
+        offset++;       /* skip empty char */
+        cert_size = (buf[offset]<<8) + buf[offset+1];
+        offset += 2;
+        
+        if (x509_new(&buf[offset], NULL, chain))
+        {
+            ret = SSL_ERROR_BAD_CERTIFICATE;
+            goto error;
+        }
+
+        chain = &((*chain)->next);
+        offset += cert_size;
+    }
+
+    PARANOIA_CHECK(pkt_size, offset);
+
+    /* if we are client we can do the verify now or later */
+    if (is_client && !IS_SET_SSL_FLAG(SSL_SERVER_VERIFY_LATER))
+    {
+        ret = ssl_verify_cert(ssl);
+    }
+
+    ssl->next_state = is_client ? HS_SERVER_HELLO_DONE : HS_CLIENT_KEY_XCHG;
+    ssl->dc->bm_proc_index += offset;
+error:
+    return ret;
+}
+
+#endif /* CONFIG_SSL_CERT_VERIFICATION */
+
+/**
+ * Debugging routine to display SSL handshaking stuff.
+ */
+#ifdef CONFIG_SSL_FULL_MODE
+/**
+ * Debugging routine to display SSL states.
+ */
+void DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok)
+{
+    const char *str;
+
+    if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES))
+        return;
+
+    printf(not_ok ? "Error - invalid State:\t" : "State:\t");
+    printf(is_send ? "sending " : "receiving ");
+
+    switch (state)
+    {
+        case HS_HELLO_REQUEST:
+            str = "Hello Request (0)";
+            break;
+
+        case HS_CLIENT_HELLO:
+            str = "Client Hello (1)";
+            break;
+
+        case HS_SERVER_HELLO:
+            str = "Server Hello (2)";
+            break;
+
+        case HS_CERTIFICATE:
+            str = "Certificate (11)";
+            break;
+
+        case HS_SERVER_KEY_XCHG:
+            str = "Certificate Request (12)";
+            break;
+
+        case HS_CERT_REQ:
+            str = "Certificate Request (13)";
+            break;
+
+        case HS_SERVER_HELLO_DONE:
+            str = "Server Hello Done (14)";
+            break;
+
+        case HS_CERT_VERIFY:
+            str = "Certificate Verify (15)";
+            break;
+
+        case HS_CLIENT_KEY_XCHG:
+            str = "Client Key Exchange (16)";
+            break;
+
+        case HS_FINISHED:
+            str = "Finished (16)";
+            break;
+
+        default:
+            str = "Error (Unknown)";
+            
+            break;
+    }
+
+    printf("%s\r\n", str);
+    TTY_FLUSH();
+}
+
+/**
+ * Debugging routine to display RSA objects
+ */
+void DISPLAY_RSA(SSL *ssl, const RSA_CTX *rsa_ctx)
+{
+    if (!IS_SET_SSL_FLAG(SSL_DISPLAY_RSA))
+        return;
+
+    RSA_print(rsa_ctx);
+    TTY_FLUSH();
+}
+
+/**
+ * Debugging routine to display SSL handshaking bytes.
+ */
+void DISPLAY_BYTES(SSL *ssl, const char *format, 
+        const uint8_t *data, int size, ...)
+{
+    va_list(ap);
+
+    if (!IS_SET_SSL_FLAG(SSL_DISPLAY_BYTES))
+        return;
+
+    va_start(ap, size);
+    print_blob(format, data, size, va_arg(ap, char *));
+    va_end(ap);
+    TTY_FLUSH();
+}
+
+/**
+ * Debugging routine to display SSL handshaking errors.
+ */
+EXP_FUNC void STDCALL ssl_display_error(int error_code)
+{
+    if (error_code == SSL_OK)
+        return;
+
+    printf("Error: ");
+
+    /* X509 error? */
+    if (error_code < SSL_X509_OFFSET)
+    {
+        printf("%s\r\n", x509_display_error(error_code - SSL_X509_OFFSET));
+        return;
+    }
+
+    /* SSL alert error code */
+    if (error_code > SSL_ERROR_CONN_LOST)
+    {
+        printf("SSL error %d\n", -error_code);
+        return;
+    }
+
+    switch (error_code)
+    {
+        case SSL_ERROR_DEAD:
+            printf("connection dead");
+            break;
+
+        case SSL_ERROR_INVALID_HANDSHAKE:
+            printf("invalid handshake");
+            break;
+
+        case SSL_ERROR_INVALID_PROT_MSG:
+            printf("invalid protocol message");
+            break;
+
+        case SSL_ERROR_INVALID_HMAC:
+            printf("invalid mac");
+            break;
+
+        case SSL_ERROR_INVALID_VERSION:
+            printf("invalid version");
+            break;
+
+        case SSL_ERROR_INVALID_SESSION:
+            printf("invalid session");
+            break;
+
+        case SSL_ERROR_NO_CIPHER:
+            printf("no cipher");
+            break;
+
+        case SSL_ERROR_CONN_LOST:
+            printf("connection lost");
+            break;
+
+        case SSL_ERROR_BAD_CERTIFICATE:
+            printf("bad certificate");
+            break;
+
+        case SSL_ERROR_INVALID_KEY:
+            printf("invalid key");
+            break;
+
+        case SSL_ERROR_FINISHED_INVALID:
+            printf("finished invalid");
+            break;
+
+        case SSL_ERROR_NO_CERT_DEFINED:
+            printf("no certificate defined");
+            break;
+
+        case SSL_ERROR_NO_CLIENT_RENOG:
+            printf("client renegotiation not supported");
+            break;
+            
+        case SSL_ERROR_NOT_SUPPORTED:
+            printf("Option not supported");
+            break;
+
+        default:
+            printf("undefined as yet - %d", error_code);
+            break;
+    }
+
+    printf("\r\n");
+    TTY_FLUSH();
+}
+
+/**
+ * Debugging routine to display alerts.
+ */
+void DISPLAY_ALERT(SSL *ssl, int alert)
+{
+    if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES))
+        return;
+
+    printf("Alert: ");
+
+    switch (alert)
+    {
+        case SSL_ALERT_CLOSE_NOTIFY:
+            printf("close notify");
+            break;
+
+        case SSL_ALERT_INVALID_VERSION:
+            printf("invalid version");
+            break;
+
+        case SSL_ALERT_BAD_CERTIFICATE:
+            printf("bad certificate");
+            break;
+
+        case SSL_ALERT_UNEXPECTED_MESSAGE:
+            printf("unexpected message");
+            break;
+
+        case SSL_ALERT_BAD_RECORD_MAC:
+            printf("bad record mac");
+            break;
+
+        case SSL_ALERT_HANDSHAKE_FAILURE:
+            printf("handshake failure");
+            break;
+
+        case SSL_ALERT_ILLEGAL_PARAMETER:
+            printf("illegal parameter");
+            break;
+
+        case SSL_ALERT_DECODE_ERROR:
+            printf("decode error");
+            break;
+
+        case SSL_ALERT_DECRYPT_ERROR:
+            printf("decrypt error");
+            break;
+
+        case SSL_ALERT_NO_RENEGOTIATION:
+            printf("no renegotiation");
+            break;
+
+        default:
+            printf("alert - (unknown %d)", alert);
+            break;
+    }
+
+    printf("\r\n");
+    TTY_FLUSH();
+}
+
+#endif /* CONFIG_SSL_FULL_MODE */
+
+/**
+ * Return the version of this library.
+ */
+EXP_FUNC const char  * STDCALL ssl_version()
+{
+    static const char * axtls_version = AXTLS_VERSION;
+    return axtls_version;
+}
+
+/**
+ * Enable the various language bindings to work regardless of the
+ * configuration - they just return an error statement and a bad return code.
+ */
+#if !defined(CONFIG_SSL_FULL_MODE)
+EXP_FUNC void STDCALL ssl_display_error(int error_code) {}
+#endif
+
+#ifdef CONFIG_BINDINGS
+#if !defined(CONFIG_SSL_ENABLE_CLIENT)
+EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const
+        uint8_t *session_id, uint8_t sess_id_size)
+{
+    printf(unsupported_str);
+    return NULL;
+}
+#endif
+
+#if !defined(CONFIG_SSL_CERT_VERIFICATION)
+EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl)
+{
+    printf(unsupported_str);
+    return -1;
+}
+
+
+EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component)
+{
+    printf(unsupported_str);
+    return NULL;
+}
+
+EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int index)
+{
+    printf(unsupported_str);
+    return NULL;
+}
+
+#endif  /* CONFIG_SSL_CERT_VERIFICATION */
+
+#endif /* CONFIG_BINDINGS */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/tls1.h	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * @file tls1.h
+ *
+ * @brief The definitions for the TLS library.
+ */
+#ifndef HEADER_SSL_LIB_H
+#define HEADER_SSL_LIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "version.h"
+#include "os_int.h"
+#include "crypto.h"
+#include "crypto_misc.h"
+
+#include "config.h"
+
+#define SSL_PROTOCOL_MIN_VERSION    0x31   /* TLS v1.0 */
+#define SSL_PROTOCOL_MINOR_VERSION  0x02   /* TLS v1.1 */
+#define SSL_PROTOCOL_VERSION_MAX    0x32   /* TLS v1.1 */
+#define SSL_PROTOCOL_VERSION1_1     0x32   /* TLS v1.1 */
+#define SSL_RANDOM_SIZE             32
+#define SSL_SECRET_SIZE             48
+#define SSL_FINISHED_HASH_SIZE      12
+#define SSL_RECORD_SIZE             5
+#define SSL_SERVER_READ             0
+#define SSL_SERVER_WRITE            1
+#define SSL_CLIENT_READ             2
+#define SSL_CLIENT_WRITE            3
+#define SSL_HS_HDR_SIZE             4
+
+/* the flags we use while establishing a connection */
+#define SSL_NEED_RECORD             0x0001
+#define SSL_TX_ENCRYPTED            0x0002 
+#define SSL_RX_ENCRYPTED            0x0004
+#define SSL_SESSION_RESUME          0x0008
+#define SSL_IS_CLIENT               0x0010
+#define SSL_HAS_CERT_REQ            0x0020
+#define SSL_SENT_CLOSE_NOTIFY       0x0040
+
+/* some macros to muck around with flag bits */
+#define SET_SSL_FLAG(A)             (ssl->flag |= A)
+#define CLR_SSL_FLAG(A)             (ssl->flag &= ~A)
+#define IS_SET_SSL_FLAG(A)          (ssl->flag & A)
+
+#define MAX_KEY_BYTE_SIZE           512     /* for a 4096 bit key */
+#define RT_MAX_PLAIN_LENGTH         2048//16384
+#define RT_EXTRA                    512//1024
+#define BM_RECORD_OFFSET            5
+
+#ifdef CONFIG_SSL_SKELETON_MODE
+#define NUM_PROTOCOLS               1
+#else
+#define NUM_PROTOCOLS               4
+#endif
+
+#define PARANOIA_CHECK(A, B)        if (A < B) { \
+    ret = SSL_ERROR_INVALID_HANDSHAKE; goto error; }
+
+/* protocol types */
+enum
+{
+    PT_CHANGE_CIPHER_SPEC = 20,
+    PT_ALERT_PROTOCOL,
+    PT_HANDSHAKE_PROTOCOL,
+    PT_APP_PROTOCOL_DATA
+};
+
+/* handshaking types */
+enum
+{
+    HS_HELLO_REQUEST,
+    HS_CLIENT_HELLO,
+    HS_SERVER_HELLO,
+    HS_CERTIFICATE = 11,
+    HS_SERVER_KEY_XCHG,
+    HS_CERT_REQ,
+    HS_SERVER_HELLO_DONE,
+    HS_CERT_VERIFY,
+    HS_CLIENT_KEY_XCHG,
+    HS_FINISHED = 20
+};
+
+typedef struct 
+{
+    uint8_t cipher;
+    uint8_t key_size;
+    uint8_t iv_size;
+    uint8_t key_block_size;
+    uint8_t padding_size;
+    uint8_t digest_size;
+    hmac_func hmac;
+    crypt_func encrypt;
+    crypt_func decrypt;
+} cipher_info_t;
+
+struct _SSLObjLoader 
+{
+    uint8_t *buf;
+    int len;
+};
+
+typedef struct _SSLObjLoader SSLObjLoader;
+
+typedef struct 
+{
+    time_t conn_time;
+    uint8_t session_id[SSL_SESSION_ID_SIZE];
+    uint8_t master_secret[SSL_SECRET_SIZE];
+} SSL_SESSION;
+
+typedef struct
+{
+    uint8_t *buf;
+    int size;
+} SSL_CERT;
+
+typedef struct
+{
+    MD5_CTX md5_ctx;
+    SHA1_CTX sha1_ctx;
+    uint8_t final_finish_mac[SSL_FINISHED_HASH_SIZE];
+    uint8_t *key_block;
+    uint8_t master_secret[SSL_SECRET_SIZE];
+    uint8_t client_random[SSL_RANDOM_SIZE]; /* client's random sequence */
+    uint8_t server_random[SSL_RANDOM_SIZE]; /* server's random sequence */
+    uint16_t bm_proc_index;
+} DISPOSABLE_CTX;
+
+struct _SSL
+{
+    uint32_t flag;
+    uint16_t need_bytes;
+    uint16_t got_bytes;
+    uint8_t record_type;
+    uint8_t cipher;
+    uint8_t sess_id_size;
+    uint8_t version;
+    uint8_t client_version;
+    int16_t next_state;
+    int16_t hs_status;
+    DISPOSABLE_CTX *dc;         /* temporary data which we'll get rid of soon */
+    int client_fd;
+    const cipher_info_t *cipher_info;
+    void *encrypt_ctx;
+    void *decrypt_ctx;
+    uint8_t bm_all_data[RT_MAX_PLAIN_LENGTH+RT_EXTRA];
+    uint8_t *bm_data;
+    uint16_t bm_index;
+    uint16_t bm_read_index;
+    struct _SSL *next;                  /* doubly linked list */
+    struct _SSL *prev;
+    struct _SSL_CTX *ssl_ctx;           /* back reference to a clnt/svr ctx */
+#ifndef CONFIG_SSL_SKELETON_MODE
+    uint16_t session_index;
+    SSL_SESSION *session;
+#endif
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+    X509_CTX *x509_ctx;
+#endif
+
+    uint8_t session_id[SSL_SESSION_ID_SIZE]; 
+    uint8_t client_mac[SHA1_SIZE];  /* for HMAC verification */
+    uint8_t server_mac[SHA1_SIZE];  /* for HMAC verification */
+    uint8_t read_sequence[8];       /* 64 bit sequence number */
+    uint8_t write_sequence[8];      /* 64 bit sequence number */
+    uint8_t hmac_header[SSL_RECORD_SIZE];    /* rx hmac */
+};
+
+typedef struct _SSL SSL;
+
+struct _SSL_CTX
+{
+    uint32_t options;
+    uint8_t chain_length;
+    RSA_CTX *rsa_ctx;
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+    CA_CERT_CTX *ca_cert_ctx;
+#endif
+    SSL *head;
+    SSL *tail;
+    SSL_CERT certs[CONFIG_SSL_MAX_CERTS];
+#ifndef CONFIG_SSL_SKELETON_MODE
+    uint16_t num_sessions;
+    SSL_SESSION **ssl_sessions;
+#endif
+#ifdef CONFIG_SSL_CTX_MUTEXING
+    SSL_CTX_MUTEX_TYPE mutex;
+#endif
+#ifdef CONFIG_OPENSSL_COMPATIBLE
+    void *bonus_attr;
+#endif
+};
+
+typedef struct _SSL_CTX SSL_CTX;
+
+/* backwards compatibility */
+typedef struct _SSL_CTX SSLCTX;
+
+extern const uint8_t ssl_prot_prefs[NUM_PROTOCOLS];
+
+SSL *ssl_new(SSL_CTX *ssl_ctx, int client_fd);
+void disposable_new(SSL *ssl);
+void disposable_free(SSL *ssl);
+int send_packet(SSL *ssl, uint8_t protocol, 
+        const uint8_t *in, int length);
+int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len);
+int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len);
+int process_finished(SSL *ssl, uint8_t *buf, int hs_len);
+int process_sslv23_client_hello(SSL *ssl);
+int send_alert(SSL *ssl, int error_code);
+int send_finished(SSL *ssl);
+int send_certificate(SSL *ssl);
+int basic_read(SSL *ssl, uint8_t **in_data);
+int send_change_cipher_spec(SSL *ssl);
+void finished_digest(SSL *ssl, const char *label, uint8_t *digest);
+void generate_master_secret(SSL *ssl, const uint8_t *premaster_secret);
+void add_packet(SSL *ssl, const uint8_t *pkt, int len);
+int add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len);
+int add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj);
+void ssl_obj_free(SSLObjLoader *ssl_obj);
+int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password);
+int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password);
+int load_key_certs(SSL_CTX *ssl_ctx);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+int add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len);
+void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx);
+#endif
+#ifdef CONFIG_SSL_ENABLE_CLIENT
+int do_client_connect(SSL *ssl);
+#endif
+
+#ifdef CONFIG_SSL_FULL_MODE
+void DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok);
+void DISPLAY_BYTES(SSL *ssl, const char *format, 
+        const uint8_t *data, int size, ...);
+void DISPLAY_CERT(SSL *ssl, const X509_CTX *x509_ctx);
+void DISPLAY_RSA(SSL *ssl,  const RSA_CTX *rsa_ctx);
+void DISPLAY_ALERT(SSL *ssl, int alert);
+#else
+#define DISPLAY_STATE(A,B,C,D)
+#define DISPLAY_CERT(A,B)
+#define DISPLAY_RSA(A,B)
+#define DISPLAY_ALERT(A, B)
+#ifdef WIN32
+void DISPLAY_BYTES(SSL *ssl, const char *format,/* win32 has no variadic macros */
+        const uint8_t *data, int size, ...);
+#else
+#define DISPLAY_BYTES(A,B,C,D,...)
+#endif
+#endif
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+int process_certificate(SSL *ssl, X509_CTX **x509_ctx);
+#endif
+
+SSL_SESSION *ssl_session_update(int max_sessions, 
+        SSL_SESSION *ssl_sessions[], SSL *ssl,
+        const uint8_t *session_id);
+void kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/tls1_clnt.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <stdio.h>
+#include "os_port.h"
+#include "ssl.h"
+
+#ifdef CONFIG_SSL_ENABLE_CLIENT        /* all commented out if no client */
+
+static int send_client_hello(SSL *ssl);
+static int process_server_hello(SSL *ssl);
+static int process_server_hello_done(SSL *ssl);
+static int send_client_key_xchg(SSL *ssl);
+static int process_cert_req(SSL *ssl);
+static int send_cert_verify(SSL *ssl);
+
+/*
+ * Establish a new SSL connection to an SSL server.
+ */
+EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const
+        uint8_t *session_id, uint8_t sess_id_size)
+{
+    SSL *ssl = ssl_new(ssl_ctx, client_fd);
+    ssl->version = SSL_PROTOCOL_VERSION_MAX; /* try top version first */
+
+    if (session_id && ssl_ctx->num_sessions)
+    {
+        if (sess_id_size > SSL_SESSION_ID_SIZE) /* validity check */
+        {
+            ssl_free(ssl);
+            return NULL;
+        }
+
+        memcpy(ssl->session_id, session_id, sess_id_size);
+        ssl->sess_id_size = sess_id_size;
+        SET_SSL_FLAG(SSL_SESSION_RESUME);   /* just flag for later */
+    }
+
+    SET_SSL_FLAG(SSL_IS_CLIENT);
+    do_client_connect(ssl);
+    return ssl;
+}
+
+/*
+ * Process the handshake record.
+ */
+int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len)
+{
+    int ret;
+
+    /* To get here the state must be valid */
+    switch (handshake_type)
+    {
+        case HS_SERVER_HELLO:
+            ret = process_server_hello(ssl);
+            break;
+
+        case HS_CERTIFICATE:
+            ret = process_certificate(ssl, &ssl->x509_ctx);
+            break;
+
+        case HS_SERVER_HELLO_DONE:
+            if ((ret = process_server_hello_done(ssl)) == SSL_OK)
+            {
+                if (IS_SET_SSL_FLAG(SSL_HAS_CERT_REQ))
+                {
+                    if ((ret = send_certificate(ssl)) == SSL_OK &&
+                        (ret = send_client_key_xchg(ssl)) == SSL_OK)
+                    {
+                        send_cert_verify(ssl);
+                    }
+                }
+                else
+                {
+                    ret = send_client_key_xchg(ssl);
+                }
+
+                if (ret == SSL_OK && 
+                     (ret = send_change_cipher_spec(ssl)) == SSL_OK)
+                {
+                    ret = send_finished(ssl);
+                }
+            }
+            break;
+
+        case HS_CERT_REQ:
+            ret = process_cert_req(ssl);
+            break;
+
+        case HS_FINISHED:
+            ret = process_finished(ssl, buf, hs_len);
+            disposable_free(ssl);   /* free up some memory */
+            /* note: client renegotiation is not allowed after this */
+            break;
+
+        case HS_HELLO_REQUEST:
+            disposable_new(ssl);
+            ret = do_client_connect(ssl);
+            break;
+
+        default:
+            ret = SSL_ERROR_INVALID_HANDSHAKE;
+            break;
+    }
+
+    return ret;
+}
+
+/*
+ * Do the handshaking from the beginning.
+ */
+int do_client_connect(SSL *ssl)
+{
+    int ret = SSL_OK;
+
+    send_client_hello(ssl);                 /* send the client hello */
+    ssl->bm_read_index = 0;
+    ssl->next_state = HS_SERVER_HELLO;
+    ssl->hs_status = SSL_NOT_OK;            /* not connected */
+
+    /* sit in a loop until it all looks good */
+    if (!IS_SET_SSL_FLAG(SSL_CONNECT_IN_PARTS))
+    {
+        while (ssl->hs_status != SSL_OK)
+        {
+            ret = ssl_read(ssl, NULL);
+            
+            if (ret < SSL_OK)
+                break;
+        }
+
+        ssl->hs_status = ret;            /* connected? */    
+    }
+
+    return ret;
+}
+
+/*
+ * Send the initial client hello.
+ */
+static int send_client_hello(SSL *ssl)
+{
+    uint8_t *buf = ssl->bm_data;
+    time_t tm = time(NULL);
+    uint8_t *tm_ptr = &buf[6]; /* time will go here */
+    int i, offset;
+
+    buf[0] = HS_CLIENT_HELLO;
+    buf[1] = 0;
+    buf[2] = 0;
+    /* byte 3 is calculated later */
+    buf[4] = 0x03;
+    buf[5] = ssl->version & 0x0f;
+
+    /* client random value - spec says that 1st 4 bytes are big endian time */
+    *tm_ptr++ = (uint8_t)(((long)tm & 0xff000000) >> 24);
+    *tm_ptr++ = (uint8_t)(((long)tm & 0x00ff0000) >> 16);
+    *tm_ptr++ = (uint8_t)(((long)tm & 0x0000ff00) >> 8);
+    *tm_ptr++ = (uint8_t)(((long)tm & 0x000000ff));
+    get_random(SSL_RANDOM_SIZE-4, &buf[10]);
+    memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE);
+    offset = 6 + SSL_RANDOM_SIZE;
+
+    /* give session resumption a go */
+    if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME))    /* set initially by user */
+    {
+        buf[offset++] = ssl->sess_id_size;
+        memcpy(&buf[offset], ssl->session_id, ssl->sess_id_size);
+        offset += ssl->sess_id_size;
+        CLR_SSL_FLAG(SSL_SESSION_RESUME);       /* clear so we can set later */
+    }
+    else
+    {
+        /* no session id - because no session resumption just yet */
+        buf[offset++] = 0;
+    }
+
+    buf[offset++] = 0;              /* number of ciphers */
+    buf[offset++] = NUM_PROTOCOLS*2;/* number of ciphers */
+
+    /* put all our supported protocols in our request */
+    for (i = 0; i < NUM_PROTOCOLS; i++)
+    {
+        buf[offset++] = 0;          /* cipher we are using */
+        buf[offset++] = ssl_prot_prefs[i];
+    }
+
+    buf[offset++] = 1;              /* no compression */
+    buf[offset++] = 0;
+    buf[3] = offset - 4;            /* handshake size */
+
+    return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset);
+}
+
+/*
+ * Process the server hello.
+ */
+static int process_server_hello(SSL *ssl)
+{
+    uint8_t *buf = ssl->bm_data;
+    int pkt_size = ssl->bm_index;
+    int num_sessions = ssl->ssl_ctx->num_sessions;
+    uint8_t sess_id_size;
+    int offset, ret = SSL_OK;
+
+    /* check that we are talking to a TLSv1 server */
+    uint8_t version = (buf[4] << 4) + buf[5];
+    if (version > SSL_PROTOCOL_VERSION_MAX)
+    {
+        version = SSL_PROTOCOL_VERSION_MAX;
+    }
+    else if (ssl->version < SSL_PROTOCOL_MIN_VERSION)
+    {
+        ret = SSL_ERROR_INVALID_VERSION;
+        ssl_display_error(ret);
+        goto error;
+    }
+
+    ssl->version = version;
+
+    /* get the server random value */
+    memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE);
+    offset = 6 + SSL_RANDOM_SIZE; /* skip of session id size */
+    sess_id_size = buf[offset++];
+
+    if (sess_id_size > SSL_SESSION_ID_SIZE)
+    {
+        ret = SSL_ERROR_INVALID_SESSION;
+        goto error;
+    }
+
+    if (num_sessions)
+    {
+        ssl->session = ssl_session_update(num_sessions,
+                ssl->ssl_ctx->ssl_sessions, ssl, &buf[offset]);
+        memcpy(ssl->session->session_id, &buf[offset], sess_id_size);
+
+        /* pad the rest with 0's */
+        if (sess_id_size < SSL_SESSION_ID_SIZE)
+        {
+            memset(&ssl->session->session_id[sess_id_size], 0,
+                SSL_SESSION_ID_SIZE-sess_id_size);
+        }
+    }
+
+    memcpy(ssl->session_id, &buf[offset], sess_id_size);
+    ssl->sess_id_size = sess_id_size;
+    offset += sess_id_size;
+
+    /* get the real cipher we are using */
+    ssl->cipher = buf[++offset];
+    ssl->next_state = IS_SET_SSL_FLAG(SSL_SESSION_RESUME) ? 
+                                        HS_FINISHED : HS_CERTIFICATE;
+
+    offset++;   // skip the compr
+    PARANOIA_CHECK(pkt_size, offset);
+    ssl->dc->bm_proc_index = offset+1; 
+
+error:
+    return ret;
+}
+
+/**
+ * Process the server hello done message.
+ */
+static int process_server_hello_done(SSL *ssl)
+{
+    ssl->next_state = HS_FINISHED;
+    return SSL_OK;
+}
+
+/*
+ * Send a client key exchange message.
+ */
+static int send_client_key_xchg(SSL *ssl)
+{
+    uint8_t *buf = ssl->bm_data;
+    uint8_t premaster_secret[SSL_SECRET_SIZE];
+    int enc_secret_size = -1;
+
+    buf[0] = HS_CLIENT_KEY_XCHG;
+    buf[1] = 0;
+
+    premaster_secret[0] = 0x03; /* encode the version number */
+    premaster_secret[1] = SSL_PROTOCOL_MINOR_VERSION; /* must be TLS 1.1 */
+    get_random(SSL_SECRET_SIZE-2, &premaster_secret[2]);
+    DISPLAY_RSA(ssl, ssl->x509_ctx->rsa_ctx);
+
+    /* rsa_ctx->bi_ctx is not thread-safe */
+    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+    enc_secret_size = RSA_encrypt(ssl->x509_ctx->rsa_ctx, premaster_secret,
+            SSL_SECRET_SIZE, &buf[6], 0);
+    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+
+    buf[2] = (enc_secret_size + 2) >> 8;
+    buf[3] = (enc_secret_size + 2) & 0xff;
+    buf[4] = enc_secret_size >> 8;
+    buf[5] = enc_secret_size & 0xff;
+
+    generate_master_secret(ssl, premaster_secret);
+    return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, enc_secret_size+6);
+}
+
+/*
+ * Process the certificate request.
+ */
+static int process_cert_req(SSL *ssl)
+{
+    uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
+    int ret = SSL_OK;
+    int offset = (buf[2] << 4) + buf[3];
+    int pkt_size = ssl->bm_index;
+
+    /* don't do any processing - we will send back an RSA certificate anyway */
+    ssl->next_state = HS_SERVER_HELLO_DONE;
+    SET_SSL_FLAG(SSL_HAS_CERT_REQ);
+    ssl->dc->bm_proc_index += offset;
+    PARANOIA_CHECK(pkt_size, offset);
+error:
+    return ret;
+}
+
+/*
+ * Send a certificate verify message.
+ */
+static int send_cert_verify(SSL *ssl)
+{
+    uint8_t *buf = ssl->bm_data;
+    uint8_t dgst[MD5_SIZE+SHA1_SIZE];
+    RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx;
+    int n = 0, ret;
+
+    DISPLAY_RSA(ssl, rsa_ctx);
+
+    buf[0] = HS_CERT_VERIFY;
+    buf[1] = 0;
+
+    finished_digest(ssl, NULL, dgst);   /* calculate the digest */
+
+    /* rsa_ctx->bi_ctx is not thread-safe */
+    if (rsa_ctx)
+    {
+        SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+        n = RSA_encrypt(rsa_ctx, dgst, sizeof(dgst), &buf[6], 1);
+        SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+
+        if (n == 0)
+        {
+            ret = SSL_ERROR_INVALID_KEY;
+            goto error;
+        }
+    }
+    
+    buf[4] = n >> 8;        /* add the RSA size (not officially documented) */
+    buf[5] = n & 0xff;
+    n += 2;
+    buf[2] = n >> 8;
+    buf[3] = n & 0xff;
+    ret = send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, n+4);
+
+error:
+    return ret;
+}
+
+#endif      /* CONFIG_SSL_ENABLE_CLIENT */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/tls1_svr.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "os_port.h"
+#include "ssl.h"
+
+static const uint8_t g_hello_done[] = { HS_SERVER_HELLO_DONE, 0, 0, 0 };
+
+static int process_client_hello(SSL *ssl);
+static int send_server_hello_sequence(SSL *ssl);
+static int send_server_hello(SSL *ssl);
+static int send_server_hello_done(SSL *ssl);
+static int process_client_key_xchg(SSL *ssl);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+static int send_certificate_request(SSL *ssl);
+static int process_cert_verify(SSL *ssl);
+#endif
+
+/*
+ * Establish a new SSL connection to an SSL client.
+ */
+EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd)
+{
+    SSL *ssl;
+
+    ssl = ssl_new(ssl_ctx, client_fd);
+    ssl->next_state = HS_CLIENT_HELLO;
+
+#ifdef CONFIG_SSL_FULL_MODE
+    if (ssl_ctx->chain_length == 0)
+        printf("Warning - no server certificate defined\n"); TTY_FLUSH();
+#endif
+
+    return ssl;
+}
+
+/*
+ * Process the handshake record.
+ */
+int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len)
+{
+    int ret = SSL_OK;
+    ssl->hs_status = SSL_NOT_OK;            /* not connected */
+
+    /* To get here the state must be valid */
+    switch (handshake_type)
+    {
+        case HS_CLIENT_HELLO:
+            if ((ret = process_client_hello(ssl)) == SSL_OK)
+                ret = send_server_hello_sequence(ssl);
+            break;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+        case HS_CERTIFICATE:/* the client sends its cert */
+            ret = process_certificate(ssl, &ssl->x509_ctx);
+
+            if (ret == SSL_OK)    /* verify the cert */
+            { 
+                int cert_res;
+                cert_res = x509_verify(
+                        ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx);
+                ret = (cert_res == 0) ? SSL_OK : SSL_X509_ERROR(cert_res);
+            }
+            break;
+
+        case HS_CERT_VERIFY:    
+            ret = process_cert_verify(ssl);
+            add_packet(ssl, buf, hs_len);   /* needs to be done after */
+            break;
+#endif
+        case HS_CLIENT_KEY_XCHG:
+            ret = process_client_key_xchg(ssl);
+            break;
+
+        case HS_FINISHED:
+            ret = process_finished(ssl, buf, hs_len);
+            disposable_free(ssl);   /* free up some memory */
+            break;
+    }
+
+    return ret;
+}
+
+/* 
+ * Process a client hello message.
+ */
+static int process_client_hello(SSL *ssl)
+{
+    uint8_t *buf = ssl->bm_data;
+    uint8_t *record_buf = ssl->hmac_header;
+    int pkt_size = ssl->bm_index;
+    int i, j, cs_len, id_len, offset = 6 + SSL_RANDOM_SIZE;
+    int ret = SSL_OK;
+    
+    uint8_t version = (buf[4] << 4) + buf[5];
+    ssl->version = ssl->client_version = version;
+
+    if (version > SSL_PROTOCOL_VERSION_MAX)
+    {
+        /* use client's version instead */
+        ssl->version = SSL_PROTOCOL_VERSION_MAX; 
+    }
+    else if (version < SSL_PROTOCOL_MIN_VERSION)  /* old version supported? */
+    {
+        ret = SSL_ERROR_INVALID_VERSION;
+        ssl_display_error(ret);
+        goto error;
+    }
+
+    memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE);
+
+    /* process the session id */
+    id_len = buf[offset++];
+    if (id_len > SSL_SESSION_ID_SIZE)
+    {
+        return SSL_ERROR_INVALID_SESSION;
+    }
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+    ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions,
+            ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL);
+#endif
+
+    offset += id_len;
+    cs_len = (buf[offset]<<8) + buf[offset+1];
+    offset += 3;        /* add 1 due to all cipher suites being 8 bit */
+
+    PARANOIA_CHECK(pkt_size, offset);
+
+    /* work out what cipher suite we are going to use - client defines 
+       the preference */
+    for (i = 0; i < cs_len; i += 2)
+    {
+        for (j = 0; j < NUM_PROTOCOLS; j++)
+        {
+            if (ssl_prot_prefs[j] == buf[offset+i])   /* got a match? */
+            {
+                ssl->cipher = ssl_prot_prefs[j];
+                goto do_state;
+            }
+        }
+    }
+
+    /* ouch! protocol is not supported */
+    ret = SSL_ERROR_NO_CIPHER;
+
+do_state:
+error:
+    return ret;
+}
+
+#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE
+/*
+ * Some browsers use a hybrid SSLv2 "client hello" 
+ */
+int process_sslv23_client_hello(SSL *ssl)
+{
+    uint8_t *buf = ssl->bm_data;
+    int bytes_needed = ((buf[0] & 0x7f) << 8) + buf[1];
+    int ret = SSL_OK;
+
+    /* we have already read 3 extra bytes so far */
+    int read_len = SOCKET_READ(ssl->client_fd, buf, bytes_needed-3);
+    int cs_len = buf[1];
+    int id_len = buf[3];
+    int ch_len = buf[5];
+    int i, j, offset = 8;   /* start at first cipher */
+    int random_offset = 0;
+
+    DISPLAY_BYTES(ssl, "received %d bytes", buf, read_len, read_len);
+    
+    add_packet(ssl, buf, read_len);
+
+    /* connection has gone, so die */
+    if (bytes_needed < 0)
+    {
+        return SSL_ERROR_CONN_LOST;
+    }
+
+    /* now work out what cipher suite we are going to use */
+    for (j = 0; j < NUM_PROTOCOLS; j++)
+    {
+        for (i = 0; i < cs_len; i += 3)
+        {
+            if (ssl_prot_prefs[j] == buf[offset+i])
+            {
+                ssl->cipher = ssl_prot_prefs[j];
+                goto server_hello;
+            }
+        }
+    }
+
+    /* ouch! protocol is not supported */
+    ret = SSL_ERROR_NO_CIPHER;
+    goto error;
+
+server_hello:
+    /* get the session id */
+    offset += cs_len - 2;   /* we've gone 2 bytes past the end */
+#ifndef CONFIG_SSL_SKELETON_MODE
+    ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions,
+            ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL);
+#endif
+
+    /* get the client random data */
+    offset += id_len;
+
+    /* random can be anywhere between 16 and 32 bytes long - so it is padded
+     * with 0's to the left */
+    if (ch_len == 0x10)
+    {
+        random_offset += 0x10;
+    }
+
+    memcpy(&ssl->dc->client_random[random_offset], &buf[offset], ch_len);
+    ret = send_server_hello_sequence(ssl);
+
+error:
+    return ret;
+}
+#endif
+
+/*
+ * Send the entire server hello sequence
+ */
+static int send_server_hello_sequence(SSL *ssl)
+{
+    int ret;
+
+    if ((ret = send_server_hello(ssl)) == SSL_OK)
+    {
+#ifndef CONFIG_SSL_SKELETON_MODE
+        /* resume handshake? */
+        if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME))
+        {
+            if ((ret = send_change_cipher_spec(ssl)) == SSL_OK)
+            {
+                ret = send_finished(ssl);
+                ssl->next_state = HS_FINISHED;
+            }
+        }
+        else 
+#endif
+        if ((ret = send_certificate(ssl)) == SSL_OK)
+        {
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+            /* ask the client for its certificate */
+            if (IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION))
+            {
+                if ((ret = send_certificate_request(ssl)) == SSL_OK)
+                {
+                    ret = send_server_hello_done(ssl);
+                    ssl->next_state = HS_CERTIFICATE;
+                }
+            }
+            else
+#endif
+            {
+                ret = send_server_hello_done(ssl);
+                ssl->next_state = HS_CLIENT_KEY_XCHG;
+            }
+        }
+    }
+
+    return ret;
+}
+
+/*
+ * Send a server hello message.
+ */
+static int send_server_hello(SSL *ssl)
+{
+    uint8_t *buf = ssl->bm_data;
+    int offset = 0;
+
+    buf[0] = HS_SERVER_HELLO;
+    buf[1] = 0;
+    buf[2] = 0;
+    /* byte 3 is calculated later */
+    buf[4] = 0x03;
+    buf[5] = ssl->version & 0x0f;
+
+    /* server random value */
+    get_random(SSL_RANDOM_SIZE, &buf[6]);
+    memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE);
+    offset = 6 + SSL_RANDOM_SIZE;
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+    if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME))
+    {
+        /* retrieve id from session cache */
+        buf[offset++] = SSL_SESSION_ID_SIZE;
+        memcpy(&buf[offset], ssl->session->session_id, SSL_SESSION_ID_SIZE);
+        memcpy(ssl->session_id, ssl->session->session_id, SSL_SESSION_ID_SIZE);
+        ssl->sess_id_size = SSL_SESSION_ID_SIZE;
+        offset += SSL_SESSION_ID_SIZE;
+    }
+    else    /* generate our own session id */
+#endif
+    {
+#ifndef CONFIG_SSL_SKELETON_MODE
+        buf[offset++] = SSL_SESSION_ID_SIZE;
+        get_random(SSL_SESSION_ID_SIZE, &buf[offset]);
+        memcpy(ssl->session_id, &buf[offset], SSL_SESSION_ID_SIZE);
+        ssl->sess_id_size = SSL_SESSION_ID_SIZE;
+
+        /* store id in session cache */
+        if (ssl->ssl_ctx->num_sessions)
+        {
+            memcpy(ssl->session->session_id, 
+                    ssl->session_id, SSL_SESSION_ID_SIZE);
+        }
+
+        offset += SSL_SESSION_ID_SIZE;
+#else
+        buf[offset++] = 0;  /* don't bother with session id in skelton mode */
+#endif
+    }
+
+    buf[offset++] = 0;      /* cipher we are using */
+    buf[offset++] = ssl->cipher;
+    buf[offset++] = 0;      /* no compression */
+    buf[3] = offset - 4;    /* handshake size */
+    return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset);
+}
+
+/*
+ * Send the server hello done message.
+ */
+static int send_server_hello_done(SSL *ssl)
+{
+    return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, 
+                            g_hello_done, sizeof(g_hello_done));
+}
+
+/*
+ * Pull apart a client key exchange message. Decrypt the pre-master key (using
+ * our RSA private key) and then work out the master key. Initialise the
+ * ciphers.
+ */
+static int process_client_key_xchg(SSL *ssl)
+{
+    uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
+    int pkt_size = ssl->bm_index;
+    int premaster_size, secret_length = (buf[2] << 8) + buf[3];
+    uint8_t premaster_secret[MAX_KEY_BYTE_SIZE];
+    RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx;
+    int offset = 4;
+    int ret = SSL_OK;
+    
+    if (rsa_ctx == NULL)
+    {
+        ret = SSL_ERROR_NO_CERT_DEFINED;
+        goto error;
+    }
+
+    /* is there an extra size field? */
+    if ((secret_length - 2) == rsa_ctx->num_octets)
+        offset += 2;
+
+    PARANOIA_CHECK(pkt_size, rsa_ctx->num_octets+offset);
+
+    /* rsa_ctx->bi_ctx is not thread-safe */
+    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+    premaster_size = RSA_decrypt(rsa_ctx, &buf[offset], premaster_secret, 1);
+    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+
+    if (premaster_size != SSL_SECRET_SIZE || 
+            premaster_secret[0] != 0x03 ||  /* must be the same as client
+                                               offered version */
+                premaster_secret[1] != (ssl->client_version & 0x0f))
+    {
+        /* guard against a Bleichenbacher attack */
+        get_random(SSL_SECRET_SIZE, premaster_secret);
+        /* and continue - will die eventually when checking the mac */
+    }
+
+#if 0
+    print_blob("pre-master", premaster_secret, SSL_SECRET_SIZE);
+#endif
+
+    generate_master_secret(ssl, premaster_secret);
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+    ssl->next_state = IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION) ?  
+                                            HS_CERT_VERIFY : HS_FINISHED;
+#else
+    ssl->next_state = HS_FINISHED; 
+#endif
+
+    ssl->dc->bm_proc_index += rsa_ctx->num_octets+offset;
+error:
+    return ret;
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+static const uint8_t g_cert_request[] = { HS_CERT_REQ, 0, 0, 4, 1, 0, 0, 0 };
+
+/*
+ * Send the certificate request message.
+ */
+static int send_certificate_request(SSL *ssl)
+{
+    return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, 
+            g_cert_request, sizeof(g_cert_request));
+}
+
+/*
+ * Ensure the client has the private key by first decrypting the packet and
+ * then checking the packet digests.
+ */
+static int process_cert_verify(SSL *ssl)
+{
+    uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
+    int pkt_size = ssl->bm_index;
+    uint8_t dgst_buf[MAX_KEY_BYTE_SIZE];
+    uint8_t dgst[MD5_SIZE+SHA1_SIZE];
+    X509_CTX *x509_ctx = ssl->x509_ctx;
+    int ret = SSL_OK;
+    int n;
+
+    PARANOIA_CHECK(pkt_size, x509_ctx->rsa_ctx->num_octets+6);
+    DISPLAY_RSA(ssl, x509_ctx->rsa_ctx);
+
+    /* rsa_ctx->bi_ctx is not thread-safe */
+    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+    n = RSA_decrypt(x509_ctx->rsa_ctx, &buf[6], dgst_buf, 0);
+    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+
+    if (n != SHA1_SIZE + MD5_SIZE)
+    {
+        ret = SSL_ERROR_INVALID_KEY;
+        goto end_cert_vfy;
+    }
+
+    finished_digest(ssl, NULL, dgst);       /* calculate the digest */
+    if (memcmp(dgst_buf, dgst, MD5_SIZE + SHA1_SIZE))
+    {
+        ret = SSL_ERROR_INVALID_KEY;
+    }
+
+end_cert_vfy:
+    ssl->next_state = HS_FINISHED;
+error:
+    return ret;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/version.h	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,1 @@
+#define AXTLS_VERSION    "1.4.9"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssl/x509.c	Mon May 13 18:15:18 2013 +0000
@@ -0,0 +1,561 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the axTLS project nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+/**
+ * @file x509.c
+ * 
+ * Certificate processing.
+ */
+
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "os_port.h"
+#include "crypto_misc.h"
+#include "sockets.h"
+#include "config.h"
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Retrieve the signature from a certificate.
+ */
+static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len)
+{
+    int offset = 0;
+    const uint8_t *ptr = NULL;
+
+    if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 || 
+            asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))
+        goto end_get_sig;
+
+    if (asn1_sig[offset++] != ASN1_OCTET_STRING)
+        goto end_get_sig;
+    *len = get_asn1_length(asn1_sig, &offset);
+    ptr = &asn1_sig[offset];          /* all ok */
+
+end_get_sig:
+    return ptr;
+}
+
+#endif
+
+/**
+ * Construct a new x509 object.
+ * @return 0 if ok. < 0 if there was a problem.
+ */
+int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
+{
+    int begin_tbs, end_tbs;
+    int ret = X509_NOT_OK, offset = 0, cert_size = 0;
+    X509_CTX *x509_ctx;
+    BI_CTX *bi_ctx;
+
+    *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX));
+    x509_ctx = *ctx;
+
+    /* get the certificate size */
+    asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE); 
+
+    if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
+        goto end_cert;
+
+    begin_tbs = offset;         /* start of the tbs */
+    end_tbs = begin_tbs;        /* work out the end of the tbs */
+    asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE);
+
+    if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
+        goto end_cert;
+
+    if (cert[offset] == ASN1_EXPLICIT_TAG)   /* optional version */
+    {
+        if (asn1_version(cert, &offset, x509_ctx))
+            goto end_cert;
+    }
+
+    if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */ 
+            asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
+        goto end_cert;
+
+    /* make sure the signature is ok */
+    if (asn1_signature_type(cert, &offset, x509_ctx))
+    {
+        ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST;
+        goto end_cert;
+    }
+
+    if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) || 
+            asn1_validity(cert, &offset, x509_ctx) ||
+            asn1_name(cert, &offset, x509_ctx->cert_dn) ||
+            asn1_public_key(cert, &offset, x509_ctx))
+    {
+        goto end_cert;
+    }
+
+    bi_ctx = x509_ctx->rsa_ctx->bi_ctx;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */
+    /* use the appropriate signature algorithm (SHA1/MD5/MD2) */
+    if (x509_ctx->sig_type == SIG_TYPE_MD5)
+    {
+        MD5_CTX md5_ctx;
+        uint8_t md5_dgst[MD5_SIZE];
+        MD5_Init(&md5_ctx);
+        MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
+        MD5_Final(md5_dgst, &md5_ctx);
+        x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE);
+    }
+    else if (x509_ctx->sig_type == SIG_TYPE_SHA1)
+    {
+        SHA1_CTX sha_ctx;
+        uint8_t sha_dgst[SHA1_SIZE];
+        SHA1_Init(&sha_ctx);
+        SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
+        SHA1_Final(sha_dgst, &sha_ctx);
+        x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE);
+    }
+    else if (x509_ctx->sig_type == SIG_TYPE_MD2)
+    {
+        MD2_CTX md2_ctx;
+        uint8_t md2_dgst[MD2_SIZE];
+        MD2_Init(&md2_ctx);
+        MD2_Update(&md2_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
+        MD2_Final(md2_dgst, &md2_ctx);
+        x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE);
+    }
+
+    if (cert[offset] == ASN1_V3_DATA)
+    {
+        int suboffset;
+
+        ++offset;
+        get_asn1_length(cert, &offset);
+
+        if ((suboffset = asn1_find_subjectaltname(cert, offset)) > 0)
+        {
+            if (asn1_next_obj(cert, &suboffset, ASN1_OCTET_STRING) > 0)
+            {
+                int altlen;
+
+                if ((altlen = asn1_next_obj(cert, 
+                                            &suboffset, ASN1_SEQUENCE)) > 0)
+                {
+                    int endalt = suboffset + altlen;
+                    int totalnames = 0;
+
+                    while (suboffset < endalt)
+                    {
+                        int type = cert[suboffset++];
+                        int dnslen = get_asn1_length(cert, &suboffset);
+
+                        if (type == ASN1_CONTEXT_DNSNAME)
+                        {
+                            x509_ctx->subject_alt_dnsnames = (char**)
+                                    realloc(x509_ctx->subject_alt_dnsnames, 
+                                       (totalnames + 2) * sizeof(char*));
+                            x509_ctx->subject_alt_dnsnames[totalnames] = 
+                                    (char*)malloc(dnslen + 1);
+                            x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL;
+                            memcpy(x509_ctx->subject_alt_dnsnames[totalnames], 
+                                    cert + suboffset, dnslen);
+                            x509_ctx->subject_alt_dnsnames[
+                                    totalnames][dnslen] = 0;
+                            ++totalnames;
+                        }
+
+                        suboffset += dnslen;
+                    }
+                }
+            }
+        }
+    }
+
+    offset = end_tbs;   /* skip the rest of v3 data */
+    if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || 
+            asn1_signature(cert, &offset, x509_ctx))
+        goto end_cert;
+#endif
+    ret = X509_OK;
+end_cert:
+    if (len)
+    {
+        *len = cert_size;
+    }
+
+    if (ret)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("Error: Invalid X509 ASN.1 file (%s)\n",
+                        x509_display_error(ret));
+#endif
+        x509_free(x509_ctx);
+        *ctx = NULL;
+    }
+
+    return ret;
+}
+
+/**
+ * Free an X.509 object's resources.
+ */
+void x509_free(X509_CTX *x509_ctx)
+{
+    X509_CTX *next;
+    int i;
+
+    if (x509_ctx == NULL)       /* if already null, then don't bother */
+        return;
+
+    for (i = 0; i < X509_NUM_DN_TYPES; i++)
+    {
+        free(x509_ctx->ca_cert_dn[i]);
+        free(x509_ctx->cert_dn[i]);
+    }
+
+    free(x509_ctx->signature);
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION 
+    if (x509_ctx->digest)
+    {
+        bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest);
+    }
+
+    if (x509_ctx->subject_alt_dnsnames)
+    {
+        for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i)
+            free(x509_ctx->subject_alt_dnsnames[i]);
+
+        free(x509_ctx->subject_alt_dnsnames);
+    }
+#endif
+
+    RSA_free(x509_ctx->rsa_ctx);
+    next = x509_ctx->next;
+    free(x509_ctx);
+    x509_free(next);        /* clear the chain */
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Take a signature and decrypt it.
+ */
+static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
+        bigint *modulus, bigint *pub_exp)
+{
+    int i, size;
+    bigint *decrypted_bi, *dat_bi;
+    bigint *bir = NULL;
+    uint8_t *block = (uint8_t *)alloca(sig_len);
+
+    /* decrypt */
+    dat_bi = bi_import(ctx, sig, sig_len);
+    ctx->mod_offset = BIGINT_M_OFFSET;
+
+    /* convert to a normal block */
+    decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp);
+
+    bi_export(ctx, decrypted_bi, block, sig_len);
+    ctx->mod_offset = BIGINT_M_OFFSET;
+
+    i = 10; /* start at the first possible non-padded byte */
+    while (block[i++] && i < sig_len);
+    size = sig_len - i;
+
+    /* get only the bit we want */
+    if (size > 0)
+    {
+        int len;
+        const uint8_t *sig_ptr = get_signature(&block[i], &len);
+
+        if (sig_ptr)
+        {
+            bir = bi_import(ctx, sig_ptr, len);
+        }
+    }
+
+    /* save a few bytes of memory */
+    bi_clear_cache(ctx);
+    return bir;
+}
+
+/**
+ * Do some basic checks on the certificate chain.
+ *
+ * Certificate verification consists of a number of checks:
+ * - The date of the certificate is after the start date.
+ * - The date of the certificate is before the finish date.
+ * - A root certificate exists in the certificate store.
+ * - That the certificate(s) are not self-signed.
+ * - The certificate chain is valid.
+ * - The signature of the certificate is valid.
+ */
+int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert) 
+{
+    int ret = X509_OK, i = 0;
+    bigint *cert_sig;
+    X509_CTX *next_cert = NULL;
+    BI_CTX *ctx = NULL;
+    bigint *mod = NULL, *expn = NULL;
+    int match_ca_cert = 0;
+    struct timeval tv;
+    uint8_t is_self_signed = 0;
+
+    if (cert == NULL)
+    {
+        ret = X509_VFY_ERROR_NO_TRUSTED_CERT;       
+        goto end_verify;
+    }
+
+    /* a self-signed certificate that is not in the CA store - use this 
+       to check the signature */
+    if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0)
+    {
+        printf("self signed cert\r\n");
+        is_self_signed = 1;
+        ctx = cert->rsa_ctx->bi_ctx;
+        mod = cert->rsa_ctx->m;
+        expn = cert->rsa_ctx->e;
+    }
+
+    gettimeofday(&tv, NULL);
+    
+    /* check the not before date */
+    if (tv.tv_sec < cert->not_before)
+    {
+        ret = X509_VFY_ERROR_NOT_YET_VALID;
+        goto end_verify;
+    }
+
+    /* check the not after date */
+    if (tv.tv_sec > cert->not_after)
+    {
+        ret = X509_VFY_ERROR_EXPIRED;
+        goto end_verify;
+    }
+
+    next_cert = cert->next;
+
+    /* last cert in the chain - look for a trusted cert */
+    if (next_cert == NULL)
+    {
+       if (ca_cert_ctx != NULL) 
+       {
+            /* go thu the CA store */
+            while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
+            {
+                if (asn1_compare_dn(cert->ca_cert_dn,
+                                            ca_cert_ctx->cert[i]->cert_dn) == 0)
+                {
+                    /* use this CA certificate for signature verification */
+                    match_ca_cert = 1;
+                    ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx;
+                    mod = ca_cert_ctx->cert[i]->rsa_ctx->m;
+                    expn = ca_cert_ctx->cert[i]->rsa_ctx->e;
+                    break;
+                }
+
+                i++;
+            }
+        }
+
+        /* couldn't find a trusted cert (& let self-signed errors 
+           be returned) */
+        if (!match_ca_cert && !is_self_signed)
+        {
+            ret = X509_VFY_ERROR_NO_TRUSTED_CERT;       
+            goto end_verify;
+        }
+    }
+    else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0)
+    {
+        /* check the chain */
+        ret = X509_VFY_ERROR_INVALID_CHAIN;
+        goto end_verify;
+    }
+    else /* use the next certificate in the chain for signature verify */
+    {
+        ctx = next_cert->rsa_ctx->bi_ctx;
+        mod = next_cert->rsa_ctx->m;
+        expn = next_cert->rsa_ctx->e;
+    }
+
+    /* cert is self signed */
+    if (!match_ca_cert && is_self_signed)
+    {
+        ret = X509_VFY_ERROR_SELF_SIGNED;
+        goto end_verify;
+    }
+
+    /* check the signature */
+    cert_sig = sig_verify(ctx, cert->signature, cert->sig_len, 
+                        bi_clone(ctx, mod), bi_clone(ctx, expn));
+
+    if (cert_sig && cert->digest)
+    {
+        if (bi_compare(cert_sig, cert->digest) != 0)
+            ret = X509_VFY_ERROR_BAD_SIGNATURE;
+
+
+        bi_free(ctx, cert_sig);
+    }
+    else
+    {
+        ret = X509_VFY_ERROR_BAD_SIGNATURE;
+    }
+
+    if (ret)
+        goto end_verify;
+
+    /* go down the certificate chain using recursion. */
+    if (next_cert != NULL)
+    {
+        ret = x509_verify(ca_cert_ctx, next_cert);
+    }
+
+end_verify:
+    return ret;
+}
+#endif
+
+#if defined (CONFIG_SSL_FULL_MODE)
+/**
+ * Used for diagnostics.
+ */
+static const char *not_part_of_cert = "<Not Part Of Certificate>";
+void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx) 
+{
+    if (cert == NULL)
+        return;
+
+    printf("=== CERTIFICATE ISSUED TO ===\n");
+    printf("Common Name (CN):\t\t");
+    printf("%s\r\n", cert->cert_dn[X509_COMMON_NAME] ?
+                    cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert);
+
+    printf("Organization (O):\t\t");
+    printf("%s\r\n", cert->cert_dn[X509_ORGANIZATION] ?
+        cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert);
+
+    printf("Organizational Unit (OU):\t");
+    printf("%s\r\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ?
+        cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
+
+    printf("=== CERTIFICATE ISSUED BY ===\r\n");
+    printf("Common Name (CN):\t\t");
+    printf("%s\r\n", cert->ca_cert_dn[X509_COMMON_NAME] ?
+                    cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert);
+
+    printf("Organization (O):\t\t");
+    printf("%s\r\n", cert->ca_cert_dn[X509_ORGANIZATION] ?
+        cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert);
+
+    printf("Organizational Unit (OU):\t");
+    printf("%s\r\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] ?
+        cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
+
+    printf("Not Before:\t\t\t%s\r\n", ctime(&cert->not_before));
+    printf("Not After:\t\t\t%s\r\n", ctime(&cert->not_after));
+    printf("RSA bitsize:\t\t\t%d\r\n", cert->rsa_ctx->num_octets*8);
+    printf("Sig Type:\t\t\t");
+    switch (cert->sig_type)
+    {
+        case SIG_TYPE_MD5:
+            printf("MD5\r\n");
+            break;
+        case SIG_TYPE_SHA1:
+            printf("SHA1\r\n");
+            break;
+        case SIG_TYPE_MD2:
+            printf("MD2\r\n");
+            break;
+        default:
+            printf("Unrecognized: %d\r\n", cert->sig_type);
+            break;
+    }
+
+    if (ca_cert_ctx)
+    {
+        printf("Verify:\t\t\t\t%s\r\n",
+                x509_display_error(x509_verify(ca_cert_ctx, cert)));
+    }
+
+#if 0
+    print_blob("Signature", cert->signature, cert->sig_len);
+    bi_print("Modulus", cert->rsa_ctx->m);
+    bi_print("Pub Exp", cert->rsa_ctx->e);
+#endif
+
+    if (ca_cert_ctx)
+    {
+        x509_print(cert->next, ca_cert_ctx);
+    }
+
+    TTY_FLUSH();
+}
+
+const char * x509_display_error(int error)
+{
+    switch (error)
+    {
+        case X509_OK:
+            return "Certificate verify successful";
+
+        case X509_NOT_OK:
+            return "X509 not ok";
+
+        case X509_VFY_ERROR_NO_TRUSTED_CERT:
+            return "No trusted cert is available";
+
+        case X509_VFY_ERROR_BAD_SIGNATURE:
+            return "Bad signature";
+
+        case X509_VFY_ERROR_NOT_YET_VALID:
+            return "Cert is not yet valid";
+
+        case X509_VFY_ERROR_EXPIRED:
+            return "Cert has expired";
+
+        case X509_VFY_ERROR_SELF_SIGNED:
+            return "Cert is self-signed";
+
+        case X509_VFY_ERROR_INVALID_CHAIN:
+            return "Chain is invalid (check order of certs)";
+
+        case X509_VFY_ERROR_UNSUPPORTED_DIGEST:
+            return "Unsupported digest";
+
+        case X509_INVALID_PRIV_KEY:
+            return "Invalid private key";
+
+        default:
+            return "Unknown";
+    }
+}
+#endif      /* CONFIG_SSL_FULL_MODE */
+