This is a fork of the mbed port of axTLS

Dependents:   TLS_axTLS-Example HTTPSClientExample

Overview

This library is a fork from the mbed port of axTLS. It attempts to :

  • reduce the usage of dynamic memory
  • verify certificates with key size up to 2048 bits
  • provide a simple interface

Encryption

This library uses either RC4 or AES for encryption.

Memory usage

During the establishment of a connection, about 10KB of memory is allocated dynamically (it depends on certificates). Once the connection is established, the memory consumption is relatively low. This means that your program must not use too much static memory or allocate memory before you establish a TLS connection.

Certificates

Certificates are the major source of problem and will often be the reason why your program will crash. Due to memory constraint, there are some limitations on certificates :

  • Each certificate must not be bigger than 2KB
  • TLS client can only handle a chain of up to three certificates (excluding the root certificate). This means that the server must not send more than three certificates.

Also, this library can only load certificates following these specifications :

  • encoded in binary DER format (PKCS1)
  • The public key must use RSA only

Once the connection is established, you should free all loaded certificates by calling CertificateManager::clear(). This will free a few kilobytes (it depends on your certificates). In addition, to enable certificate verification during the connection, this library has a "precomputed mode". This mode uses much less memory than a normal certificate verification.

Normal mode

You need to copy the root certificate in binary-DER format on the mbed. Then in your code, let's say that your root certificate is saved on the mbed as "root.der", assuming that you include CertificateManager.h and that you created a LocalFileSystem, you can load this certificate as this ;

Load root certificate

CertificateManager::add("/local/root.der");
CertificateManager::load();

Do not forget that this mode takes quite a lot of memory ( the memory peak is high while verifying certificates) and will only work if the key size is not bigger than 1024 bits (otherwise it will crash while verifying certificates).

Precomputed mode

In this mode, you need to save the entire chain of certificates (in binary-DER format) including the root certificate on the mbed. In practice, this means that you must first retrieve all certificates that the server sends during a connection and then find the right root certificate. In your code, you must call CertificateManager::add for each certificate and in the right order : from the server certificate to the root certificate. Here is how you shoud load certificates in this mode :

Loadcertificates in precomputed mode

CertificateManager::add("/local/server1.der");
CertificateManager::add("/local/server2.der");
CertificateManager::add("/local/server3.der");
CertificateManager::add("/local/root.der");
CertificateManager::load(true);

Using this mode, you should be able to verify certificates with key size up to 2048 bits.

How do I find these certificates ?

I posted an entry in my notebook detailing how to get certificates from a server. You should be able to get all certificates you need except the root certificate. Here is a way how to get the root certificate on windows :

  1. Open (double-click) the last certificate sent by the server
  2. Go to details panel and click on the entry called Issuer. The first line gives you the name of this certificate and the second line indicates the company who created this certificate
  3. Open firefox
  4. Go to options, advanced panel and click on View Certificates
  5. Go to Authorities panel
  6. Choose the certificate whose name match the issuer of the last certificate sent by the server
  7. Export this certificate to binary-DER format.

Connect to mbed.org !

Import programTLS_axTLS-Example

Establishing a connection to mbed.org using TLS

Files at this revision

API Documentation at this revision

Comitter:
feb11
Date:
Thu Sep 12 15:18:04 2013 +0000
Commit message:
intial import

Changed in this revision

CertificateManager.cpp Show annotated file Show diff for this revision Revisions of this file
CertificateManager.h Show annotated file Show diff for this revision Revisions of this file
TLSConnection.cpp Show annotated file Show diff for this revision Revisions of this file
TLSConnection.h Show annotated file Show diff for this revision Revisions of this file
axTLS/crypto/aes.c Show annotated file Show diff for this revision Revisions of this file
axTLS/crypto/bigint.c Show annotated file Show diff for this revision Revisions of this file
axTLS/crypto/bigint.h Show annotated file Show diff for this revision Revisions of this file
axTLS/crypto/bigint_impl.h Show annotated file Show diff for this revision Revisions of this file
axTLS/crypto/crypto.h Show annotated file Show diff for this revision Revisions of this file
axTLS/crypto/crypto_misc.c Show annotated file Show diff for this revision Revisions of this file
axTLS/crypto/hmac.c Show annotated file Show diff for this revision Revisions of this file
axTLS/crypto/md2.c Show annotated file Show diff for this revision Revisions of this file
axTLS/crypto/md5.c Show annotated file Show diff for this revision Revisions of this file
axTLS/crypto/os_int.h Show annotated file Show diff for this revision Revisions of this file
axTLS/crypto/rc4.c Show annotated file Show diff for this revision Revisions of this file
axTLS/crypto/rsa.c Show annotated file Show diff for this revision Revisions of this file
axTLS/crypto/sha1.c Show annotated file Show diff for this revision Revisions of this file
axTLS/ssl/asn1.c Show annotated file Show diff for this revision Revisions of this file
axTLS/ssl/config.h Show annotated file Show diff for this revision Revisions of this file
axTLS/ssl/crypto_misc.h Show annotated file Show diff for this revision Revisions of this file
axTLS/ssl/openssl.c Show annotated file Show diff for this revision Revisions of this file
axTLS/ssl/os_port.c Show annotated file Show diff for this revision Revisions of this file
axTLS/ssl/os_port.h Show annotated file Show diff for this revision Revisions of this file
axTLS/ssl/os_port_old.h Show annotated file Show diff for this revision Revisions of this file
axTLS/ssl/p12.c Show annotated file Show diff for this revision Revisions of this file
axTLS/ssl/ssl.h Show annotated file Show diff for this revision Revisions of this file
axTLS/ssl/tls1.c Show annotated file Show diff for this revision Revisions of this file
axTLS/ssl/tls1.h Show annotated file Show diff for this revision Revisions of this file
axTLS/ssl/tls1_clnt.c Show annotated file Show diff for this revision Revisions of this file
axTLS/ssl/tls1_svr.c Show annotated file Show diff for this revision Revisions of this file
axTLS/ssl/version.h Show annotated file Show diff for this revision Revisions of this file
axTLS/ssl/x509.c Show annotated file Show diff for this revision Revisions of this file
cert_manager.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CertificateManager.cpp	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,307 @@
+#include "CertificateManager.h"
+#include "axTLS/crypto/bigint.h"
+#include "cert_manager.h"
+#include "axTLS/ssl/crypto_misc.h"
+
+CertificateManager::CertificateManager():
+    files(),
+    certs(NULL),
+    precomputedCerts()
+{
+}
+
+CertificateManager::~CertificateManager()
+{
+    clear();
+}
+
+CertificateManager& CertificateManager::instance()
+{
+    static CertificateManager cm;
+    return cm;
+}
+
+void CertificateManager::add(const char *fileName)
+{
+    CertificateManager::instance().files.push_back(fileName);
+}
+
+bool CertificateManager::load(bool precompute)
+{
+    if(precompute)
+        return CertificateManager::instance().loadPrecomputeCertificates();
+    else
+        return CertificateManager::instance().loadCertificates();
+}
+
+bool CertificateManager::loadCertificates()
+{
+    X509_CTX *cert = certs;
+    for(std::list<std::string>::iterator itor = files.begin();
+            itor != files.end();
+            ++itor) {
+        FILE *fp = fopen(itor->c_str(), "r");
+        if(fp == NULL)
+            return false;
+
+        fseek(fp, 0, SEEK_END);
+        int length = ftell(fp);
+        fseek(fp, 0, SEEK_SET);
+        uint8_t *data = new uint8_t[length];
+        fread(data, sizeof(uint8_t), length, fp);
+        fclose(fp);
+
+        if(x509_new(data, NULL, &cert) != 0) {
+            x509_free(certs);
+            delete[] data;
+            return false;
+        }
+
+        delete[] data;
+        cert = cert->next;
+    }
+    files.clear();
+    return true;
+}
+
+/* Check cert1 with cert2
+*/
+bool CertificateManager::check(X509_CTX *cert1, X509_CTX* cert2)
+{
+    if(asn1_compare_dn(cert1->ca_cert_dn, cert2->cert_dn))
+        return false;
+    if (time(NULL) < cert1->not_before)
+        return false;
+    if (time(NULL) > cert1->not_after)
+        return false;
+
+    /* Cannot check : takes too much memory
+    BI_CTX *ctx = cert2->rsa_ctx->bi_ctx;
+    bigint *mod = bi_clone(ctx, cert2->rsa_ctx->m);
+    bigint *expn = bi_clone(ctx , cert2->rsa_ctx->e);
+    bigint *digest = sig_verify(ctx, cert1->signature, cert1->sig_len, mod, expn);
+    if(digest && cert1->digest)
+    {
+        if(bi_compare(digest, cert1->digest) != 0)
+        {
+            bi_free(ctx, digest);
+            return false;
+        }
+        bi_free(ctx, digest);
+    }
+    else
+        return false;
+    */
+    return true;
+}
+
+bool CertificateManager::loadPrecomputeCertificates()
+{
+    if(files.size() < 2)
+        return false;
+    precomputedCerts.reserve(files.size()-1);
+    X509_CTX *cert1 = NULL, *cert2 = NULL;
+
+    // load cert1
+    FILE *fp = fopen(files.front().c_str(), "r");
+    if(fp == NULL) {
+        printf("Could not open file %s\n", files.front().c_str());
+        clear();
+        return false;
+    }
+    files.pop_front();
+
+    fseek(fp, 0, SEEK_END);
+    int length = ftell(fp);
+    fseek(fp, 0, SEEK_SET);
+    uint8_t *data = new uint8_t[length];
+    fread(data, sizeof(uint8_t), length, fp);
+    fclose(fp);
+
+    if(x509_new(data, NULL, &cert1) != 0) {
+        delete[] data;
+        clear();
+        return false;
+    }
+    delete[] data;
+
+    while(!files.empty()) {
+        // load cert2
+        fp = fopen(files.front().c_str(), "r");
+        if(fp == NULL) {
+            printf("Could not open file %s\n", files.front().c_str());
+            x509_free(cert1);
+            clear();
+            return false;
+        }
+        files.pop_front();
+
+        fseek(fp, 0, SEEK_END);
+        length = ftell(fp);
+        fseek(fp, 0, SEEK_SET);
+        data = new uint8_t[length];
+        fread(data, sizeof(uint8_t), length, fp);
+        fclose(fp);
+
+        if(x509_new(data, NULL, &cert2) != 0) {
+            x509_free(cert1);
+            delete[] data;
+            clear();
+            return false;
+        }
+        delete[] data;
+
+
+        if(!check(cert1, cert2)) {
+            printf("Certificates verification failed\n");
+            x509_free(cert1);
+            x509_free(cert2);
+            clear();
+            return false;
+        }
+
+
+        // Create certificate
+        PrecomputedCertificate pc;
+        memset(&pc, 0, sizeof(PrecomputedCertificate));
+        for(int i = 0; i < X509_NUM_DN_TYPES; ++i) {
+            if(cert1->ca_cert_dn[i] != NULL) {
+                pc.ca_cert_dn[i] = new char[strlen(cert1->ca_cert_dn[i])+1];
+                strcpy(pc.ca_cert_dn[i], cert1->ca_cert_dn[i]);
+            }
+            if(cert1->cert_dn[i] != NULL) {
+                pc.cert_dn[i] = new char[strlen(cert1->cert_dn[i])+1];
+                strcpy(pc.cert_dn[i], cert1->cert_dn[i]);
+            }
+        }
+
+        uint8_t buffer[512];
+        uint16_t paddingLength;
+        bi_permanent(cert1->digest);
+        bi_export(cert1->rsa_ctx->bi_ctx, cert1->digest, buffer, 512);
+        bi_depermanent(cert1->digest);
+
+        paddingLength = 0;
+        while(buffer[paddingLength] == 0 && paddingLength < 512) paddingLength++;
+        pc.digest_len = 512 - paddingLength;
+        pc.digest = new uint8_t[pc.digest_len];
+        memcpy(pc.digest, &buffer[paddingLength], pc.digest_len);
+
+        bi_export(cert2->rsa_ctx->bi_ctx, cert2->rsa_ctx->m, buffer, 512);
+
+        paddingLength = 0;
+        while(buffer[paddingLength] == 0) paddingLength++;
+        pc.mod_len = 512 - paddingLength;
+        pc.mod = new uint8_t[pc.mod_len];
+        memcpy(pc.mod, &buffer[paddingLength], pc.mod_len);
+
+
+        bi_export(cert2->rsa_ctx->bi_ctx, cert2->rsa_ctx->e, buffer, 512);
+        paddingLength = 0;
+        while(buffer[paddingLength] == 0) paddingLength++;
+        pc.expn_len = 512 - paddingLength;
+        pc.expn = new uint8_t[pc.expn_len];
+        memcpy(pc.expn, &buffer[paddingLength], pc.expn_len);
+
+        pc.sig = new uint8_t[cert1->sig_len];
+        pc.sig_len = cert1->sig_len;
+        memcpy(pc.sig, cert1->signature, pc.sig_len);
+
+
+        precomputedCerts.push_back(pc);
+
+        x509_free(cert1);
+        cert1 = cert2;
+    }
+    x509_free(cert2);
+    certs = NULL;
+    return true;
+}
+
+void CertificateManager::clear()
+{
+    CertificateManager &cm = CertificateManager::instance();
+    cm.files.clear();
+    x509_free(cm.certs);
+    cm.certs = NULL;
+    for(int i = 0; i < cm.precomputedCerts.size(); ++i) {
+        for(int j = 0; j < X509_NUM_DN_TYPES; ++j) {
+            delete cm.precomputedCerts[i].cert_dn[j];
+            delete cm.precomputedCerts[i].ca_cert_dn[j];
+        }
+
+        delete[] cm.precomputedCerts[i].sig;
+        delete[] cm.precomputedCerts[i].mod;
+        delete[] cm.precomputedCerts[i].expn;
+        delete[] cm.precomputedCerts[i].digest;
+    }
+    cm.precomputedCerts.clear();
+}
+
+extern "C" char is_precomputed(void)
+{
+    return CertificateManager::instance().precomputedCerts.size() > 0 ? 1 : 0;
+}
+
+extern "C" PrecomputedCertificate get_precomputed_cert(char *cert_dn[], char *ca_cert_dn[])
+{
+    std::vector<PrecomputedCertificate> &precomputedCerts = CertificateManager::instance().precomputedCerts;
+
+    for(int i = 0; i < precomputedCerts.size(); ++i) {
+
+        PrecomputedCertificate pc = precomputedCerts[i];
+        int j = 0;
+        for(; j < X509_NUM_DN_TYPES; ++j) {
+
+            if( (cert_dn[j] == NULL && pc.cert_dn[j] != NULL)
+                    ||  (cert_dn[j] != NULL && pc.cert_dn[j] == NULL)
+                    ||  (ca_cert_dn[j] == NULL && pc.ca_cert_dn[j] != NULL)
+                    ||  (ca_cert_dn[j] != NULL && pc.ca_cert_dn[j] == NULL))
+                break;
+
+            if(cert_dn[j] && pc.cert_dn[j]) {
+                if(strcmp(cert_dn[j], pc.cert_dn[j]))
+                    break;
+            }
+
+            if(ca_cert_dn[j] && pc.ca_cert_dn[j]) {
+                if(strcmp(ca_cert_dn[j], pc.ca_cert_dn[j]))
+                    break;
+            }
+        }
+        if(j == X509_NUM_DN_TYPES)
+            return pc;
+    }
+
+    PrecomputedCertificate pc;
+    memset(&pc, 0, sizeof(PrecomputedCertificate));
+    return pc;
+}
+
+
+extern "C" X509_CTX* get_cert(char *ca_cert_dn[])
+{
+    X509_CTX *cert = CertificateManager::instance().certs;
+
+    while(1) {
+        if(cert == NULL)
+            return NULL;
+        int i = 0;
+        for(; i < X509_NUM_DN_TYPES; ++i) {
+            if(strcmp(ca_cert_dn[i], cert->cert_dn[i]))
+                break;
+        }
+        if(i == X509_NUM_DN_TYPES)
+            return cert;
+        cert = cert->next;
+    }
+}
+
+
+extern "C" void cert_manager_clear(void)
+{
+    CertificateManager::clear();
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CertificateManager.h	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,81 @@
+#ifndef CERTIFICATE_MANAGER_H
+#define CERTIFICATE_MANAGER_H
+
+#include "mbed.h"
+#include <vector>
+#include <list>
+#include <string>
+#include "axTLS/ssl/crypto_misc.h"
+#include "cert_manager.h"
+
+
+/** This class is in charge of loading and storing certificates.
+
+    Example:
+    @code
+    #include "mbed.h"
+    #include "CertificateManager.h
+    LocalFileSystem local("/local/");
+
+    int main(void)
+    {
+        CertificateManager::add("/local/root.der");
+        if(!CertificateManager::load())
+            printf("Error while loading certificates\n");
+
+        return 0;
+    }
+    @endcode
+*/
+class CertificateManager
+{
+public :
+
+    friend char is_precomputed(void);
+    friend PrecomputedCertificate get_precomputed_cert(char *cert_dn[], char *ca_cert_dn[]);
+    friend X509_CTX* get_cert(char *ca_cert_dn[]);
+
+    /** Add a certificate to load.
+
+        \param fileName Certificate's filename.
+        \note This function does not load the certificate
+        and does not check if the file exists.
+    */
+    static void add(const char *fileName);
+
+    /** Load certificates.
+
+        \param precompute Tells the certificate manager how to load
+        certificates.
+        \return True if certificates were loaded with
+        success, false otherwise.
+
+        \note If the loading fails, everything is cleared. So,
+        you have to add again all certificates you need.
+    */
+    static bool load(const bool precompute = false);
+
+    /** Clear everything.
+        \note This function should be called once a TLS
+        connection is established with success.
+    */
+    static void clear();
+
+private :
+
+    CertificateManager();
+    ~CertificateManager();
+    static CertificateManager& instance();
+
+    bool loadCertificates();
+    bool loadPrecomputeCertificates();
+    bool check(X509_CTX *cert1, X509_CTX* cert2);
+
+    std::list<std::string> files;
+    X509_CTX *certs;
+    std::vector<PrecomputedCertificate> precomputedCerts;
+};
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TLSConnection.cpp	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,75 @@
+#include "TLSConnection.h"
+#include <stdlib.h>
+#include <stdio.h>
+const static int HTTPS_PORT = 443;
+
+TLSConnection::TLSConnection():
+    Socket(),
+    Endpoint(),
+    _is_connected(false),
+    _ssl_ctx(),
+    _ssl()
+{
+}
+
+bool TLSConnection::connect(const char *host)
+{
+    if (init_socket(SOCK_STREAM) < 0)
+        return false;
+
+    if (set_address(host, HTTPS_PORT) != 0)
+        return false;
+
+    if (lwip_connect(_sock_fd, (const struct sockaddr *) &_remoteHost, sizeof(_remoteHost)) < 0) {
+        close();
+        return false;
+    }
+
+    if(ssl_ctx_new(&_ssl_ctx, 0, SSL_DEFAULT_CLNT_SESS) != &_ssl_ctx)
+        return false;
+
+    _ssl.ssl_ctx = &_ssl_ctx;
+
+    if(ssl_client_new(&_ssl, _sock_fd, NULL, 0) == NULL) {
+        close();
+        return false;
+    }
+    if(_ssl.hs_status != SSL_OK) {
+        close();
+        return false;
+    }
+
+    _is_connected = true;
+
+    return true;
+}
+
+bool TLSConnection::is_connected(void)
+{
+    return _is_connected;
+}
+
+int TLSConnection::send_all(char *data, int length)
+{
+    if ((_sock_fd < 0) || !_is_connected)
+        return -1;
+
+    return ssl_write(&_ssl, (uint8_t*)data, length);
+}
+
+int TLSConnection::receive(char *data, int length)
+{
+    return ssl_read(&_ssl, (uint8_t*)data, length);
+}
+
+bool TLSConnection::close(bool shutdown)
+{
+    if(!_is_connected)
+        return true;
+
+    _is_connected = false;
+    ssl_ctx_free(_ssl.ssl_ctx);
+
+    return Socket::close(shutdown) == 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TLSConnection.h	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,73 @@
+#ifndef TLSCONNECTION_H
+#define TLSCONNECTION_H
+
+#include "Socket/Socket.h"
+#include "Socket/Endpoint.h"
+#include "axTLS/ssl/ssl.h"
+
+/** This class provides a user-friendly interface for the
+    axTLS library.
+*/
+class TLSConnection : public Socket, public Endpoint
+{
+public :
+
+    TLSConnection();
+
+    /** This function tries to establish a TLS connection
+        with the given host.
+        It will first try to establish a TCP connection on
+        port 443 with the host. Then, it runs the TLS 
+        handshake protocol.
+
+        \param host A valid hostname (e.g. "mbed.org")
+        \return True if it managed to establish a connection
+        with the host. False otherwise.
+    */
+    bool connect(const char *host);
+
+    /** Indicates whether a connection is established or not.
+
+        \return true if a connection is established, otherwise
+       returns false.
+    */
+    bool is_connected(void);
+
+    /** Sends some data to the host. This method does not return
+        until length bytes have been sent.
+
+        \param data A pointer to some data
+        \param length Number of bytes to send
+        \return Number of bytes sent, or -1 if an error occured.
+    */
+    int send_all(char *data, int length);
+
+    /** Receive some data from the host.
+
+        \param data
+        \param length Maximum number of bytes to receive
+        \return Number of bytes read in range 0..length, or -1
+        if an error occured.
+    */
+    int receive(char *data, int length);
+
+    /** Close the connection.
+
+        \param shutdown
+        \return True if the connection was closed with success,
+        false otherwise. If no connection was established,
+        returns true immediately.
+    */
+    bool close(bool shutdown = true);
+
+private :
+
+    bool _is_connected;
+
+    SSL_CTX _ssl_ctx;
+    SSL _ssl;
+};
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/axTLS/crypto/aes.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,462 @@
+/*
+ * 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/axTLS/crypto/bigint.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,1515 @@
+/*
+ * 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);
+    }
+    bigint* a = bi_clone(ctx, bi);
+    q1 = comp_right_shift(a, 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 */
+            bigint* a = bi_multiply(ctx, biR, ctx->g[part_exp]);
+            biR = bi_residue(ctx, a);
+            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/axTLS/crypto/bigint.h	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,109 @@
+/*
+ * 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
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#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
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/axTLS/crypto/bigint_impl.h	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,135 @@
+/*
+ * 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/axTLS/crypto/crypto.h	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,238 @@
+/*
+ * 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) 
+
+#ifndef CONFIG_SSL_ENABLE_CLIENT
+#define CONFIG_SSL_ENABLE_CLIENT
+#endif
+
+#ifndef CONFIG_SSL_CERT_VERIFICATION
+#define CONFIG_SSL_CERT_VERIFICATION
+#endif
+
+#elif defined(CONFIG_SSL_ENABLE_CLIENT) && !defined(CONFIG_SSL_CERT_VERIFICATION)
+#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
+#define MAX_KEYBLOCK_SIZE 136
+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/axTLS/crypto/crypto_misc.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,377 @@
+/*
+ * 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/axTLS/crypto/hmac.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,107 @@
+/*
+ * 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/axTLS/crypto/md2.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,165 @@
+/*
+ * 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/axTLS/crypto/md5.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,296 @@
+/*
+ * 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/axTLS/crypto/os_int.h	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,69 @@
+/*
+ * 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/axTLS/crypto/rc4.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,94 @@
+/*
+ * 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/axTLS/crypto/rsa.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,272 @@
+/*
+ * 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)
+{
+    printf("RSA private\n");
+#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/axTLS/crypto/sha1.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,251 @@
+/*
+ * 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/axTLS/ssl/asn1.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,586 @@
+/*
+ * 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"
+
+#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 };
+
+static const uint8_t rsaOID[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
+
+
+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;
+    int offset2 = 0, oid_len = 0;
+    uint8_t *modulus = NULL, *pub_exp = NULL;
+ 
+    if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
+        goto end_pub_key;
+    
+    offset2 = *offset;
+    if(asn1_next_obj(cert, &offset2, ASN1_SEQUENCE) < 0)
+        goto end_pub_key;
+    oid_len = asn1_next_obj(cert, &offset2, ASN1_OID);
+    if(oid_len < 0)
+        goto end_pub_key;
+    if(memcmp(rsaOID, &cert[offset2], oid_len))
+    {
+        printf("Only RSA public key algorithm is supported\n");
+        goto end_pub_key;
+    }
+    
+    if (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/axTLS/ssl/config.h	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,63 @@
+#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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/axTLS/ssl/crypto_misc.h	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,181 @@
+/*
+ * 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 "config.h"
+#include "crypto.h"
+#include "bigint.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
+#define X509_KEY_SIZE_TOO_BIG               -10
+
+/*
+ * 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 PrecomputedCertificate;
+typedef struct PrecomputedCertificate PrecomputedCertificate;
+
+
+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;
+typedef struct 
+{
+    X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS];
+} CA_CERT_CTX;
+
+
+int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx);
+void x509_free(X509_CTX *x509_ctx);
+int x509_verify(PrecomputedCertificate *cert);
+bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
+        bigint *modulus, bigint *pub_exp);
+
+#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/axTLS/ssl/openssl.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,325 @@
+/*
+ * 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/axTLS/ssl/os_port.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,281 @@
+/*
+ * 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"
+
+static int memory_buf[400];
+static char enable = 0;
+static int nb_entries = 0;
+
+void disable_memory_buf(void)
+{
+    enable = 0;
+}
+void enable_memory_buf(void)
+{
+    enable = 1;
+}
+void init_memory_buf(void)
+{
+    for(int i = 0; i < 400; i += 2)
+    {
+        memory_buf[i] = -1;
+        memory_buf[i+1] = 0;
+    }
+}   
+void print_buf_stats(void)
+{
+    if(enable)
+    {
+        int used = 0;
+        for(int i = 1; i < 400; i += 2)
+            used += memory_buf[i];
+        printf("%d\n", used);
+    }
+}
+
+void print_all_buf_stats(void)
+{       
+    int used = 0;
+    for(int i = 1; i < 400; i += 2)
+        used += memory_buf[i];
+    printf("used: %d bytes\n", used);
+    
+    for(int i = 0; i < 400; i += 2)
+        if(memory_buf[i] != -1)
+            printf("ptr:%X, size:%d\n", memory_buf[i], memory_buf[i+1]);
+}
+
+static void add_entry(void *x, size_t s, const char* f, const int l)
+{
+    nb_entries++;
+    for(int i = 0; i < 400; i += 2)
+    {
+        if(memory_buf[i] == -1)
+        {
+            if(enable)
+                printf("new ptr:%X, size:%d at %s:%d\n", x, s, f, l); 
+            memory_buf[i] = (int)(x);
+            memory_buf[i+1] = s;
+            return;
+        }
+    }
+    if(enable)
+        printf("No space left in buffer\n"); 
+}
+
+static void remove_entry(void *x, const char* f, const int l)
+{
+    nb_entries--;
+    for(int i = 0; i < 400; i += 2)
+    {
+        if(memory_buf[i] == (int)(x))
+        {
+            if(enable)
+                printf("free ptr:%X, size:%d at %s:%d\n", memory_buf[i], memory_buf[i+1], f, l); 
+            memory_buf[i] = -1;
+            memory_buf[i+1] = 0;
+            return;
+        }
+    }
+    if(enable)
+        printf("not found\n");
+}
+
+#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
+#undef free
+
+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, const char* f, const int l)
+{
+    if(enable)  
+        printf("malloc\t");
+
+    void *x;
+
+    if ((x = malloc(s)) == NULL)
+        exit_now(out_of_mem_str);
+    add_entry(x,s, f, l);
+    print_buf_stats();
+
+    return x;
+}
+
+EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s, const char* f, const int l)
+{
+    if(enable)  
+        printf("realloc\t");
+
+    void *x;
+
+    if ((x = realloc(y, s)) == NULL)
+        exit_now(out_of_mem_str);
+    remove_entry(y, f, l);
+    add_entry(x,s, f, l);
+    print_buf_stats();
+    return x;
+}
+
+EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s, const char* f, const int l)
+{
+    if(enable)  
+        printf("calloc\t");
+    void *x;
+  
+    if ((x = calloc(n, s)) == NULL) {
+        exit_now(out_of_mem_str);
+    }
+
+    add_entry(x,n*s, f, l);
+    print_buf_stats();
+    return x;
+}
+
+EXP_FUNC void STDCALL ax_free(void *y, const char* f, const int l)
+{
+    if(enable)  
+        printf("free\t");
+        
+    remove_entry(y, f, l);
+    print_buf_stats();
+    free(y);
+}
+/*
+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/axTLS/ssl/os_port.h	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,50 @@
+#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, __FILE__, __LINE__)
+#ifndef realloc
+#define realloc(A,B)    ax_realloc(A,B, __FILE__, __LINE__)
+#endif
+#define calloc(A,B)     ax_calloc(A,B, __FILE__, __LINE__)
+#define free(A)         ax_free(A, __FILE__, __LINE__)
+
+#define STDCALL
+#define EXP_FUNC
+struct timeval;
+EXP_FUNC void STDCALL gettimeofday(struct timeval* t,void* timezone);
+
+void init_memory_buf(void);
+void disable_memory_buf(void);
+void enable_memory_buf(void);
+void print_buf_stats(void);
+void print_all_buf_stats(void);
+
+EXP_FUNC void * STDCALL ax_malloc(size_t s, const char* f, const int l);
+EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s, const char* f, const int l);
+EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s, const char* f, const int l);
+EXP_FUNC void   STDCALL ax_free(void *y, const char* f, const int l);
+
+void exit_now(const char *format, ...);
+
+//EXP_FUNC int STDCALL ax_open(const char *pathname, int flags); 
+
+#define SOCKET_READ(A,B,C)      lwip_read(A,B,C)
+#define SOCKET_WRITE(A,B,C)     lwip_write(A,B,C)
+#define SOCKET_CLOSE(A)         closesocket(A)
+#define TTY_FLUSH()
+#ifdef __cplusplus
+}
+#endif
+#endif 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/axTLS/ssl/os_port_old.h	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,196 @@
+/*
+ * 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/axTLS/ssl/p12.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,485 @@
+/*
+ * 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/axTLS/ssl/ssl.h	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,503 @@
+/*
+ * 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(SSL_CTX *ssl_ctx, 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 *ssl, 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, PrecomputedCertificate *cert);
+
+/**
+ * @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/axTLS/ssl/tls1.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,2379 @@
+/*
+ * 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"
+#include "../../cert_manager.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_RC4_128_SHA SSL_AES128_SHA, SSL_AES256_SHA, SSL_RC4_128_SHA, SSL_RC4_128_MD5*/ };    
+#else /* CONFIG_SSL_PROT_HIGH */            /* high security, low speed */
+{ SSL_RC4_128_SHA 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(SSL_CTX *ssl_ctx, uint32_t options, int num_sessions)
+{
+    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;
+
+#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 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->ssl_ctx);
+    //free(ssl);
+}
+
+/*
+ * 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;
+}
+
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+
+/*
+ * 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 *ssl, int client_fd)
+{
+    SSL_CTX* ssl_ctx = ssl->ssl_ctx;
+    ssl->need_bytes = SSL_RECORD_SIZE;      /* need a record */
+    ssl->client_fd = 0;
+    ssl->flag = SSL_NEED_RECORD;
+    ssl->bm_data = ssl->bm_all_data + BM_RECORD_OFFSET; 
+    ssl->bm_remaining_bytes = 0;
+    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->encrypt_ctx = NULL;
+    ssl->decrypt_ctx = NULL;
+    
+    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
+            {
+                printf("send_raw_packet 1\n");
+                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(FD_SETSIZE, NULL, &wfds, NULL, NULL) < 0)
+            {
+                printf("send_raw_packet 2\n");
+                return SSL_ERROR_CONN_LOST;
+            }
+        }
+    }
+    fd_set wfds;
+    FD_ZERO(&wfds);
+    FD_SET(ssl->client_fd, &wfds);
+    
+    /* block and wait for it */
+    if (lwip_select(FD_SETSIZE, NULL, &wfds, NULL, NULL) < 0)
+    {
+        printf("send_raw_packet 3\n");
+        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)
+    {
+        printf("bad hs_status\n");
+        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;
+
+    uint8_t key_tmp[MAX_KEYBLOCK_SIZE] = {0};
+    /* only do once in a handshake */
+    if (memcmp(ssl->dc->key_block, key_tmp, MAX_KEYBLOCK_SIZE) == 0)
+    {
+#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
+
+    if( (is_write ? ssl->encrypt_ctx : ssl->decrypt_ctx) != NULL)
+        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;
+}
+
+/** 
+  * Blocking read 
+  * data must be valid buffer of size length at least
+  * length 
+  */
+int basic_read2(SSL *ssl, uint8_t *data, uint32_t length)
+{
+    if(data == NULL)
+        return -1;
+
+    int ret = 0;
+    
+    do
+    {
+        fd_set rfds;
+        FD_ZERO(&rfds);
+        FD_SET(ssl->client_fd, &rfds);
+        
+        /* block and wait for it */
+        if (lwip_select(FD_SETSIZE, &rfds, NULL, NULL, NULL) < 0)
+            return SSL_ERROR_CONN_LOST;
+
+        int read_len = SOCKET_READ(ssl->client_fd, &data[ret], length-ret);
+
+        if (read_len < 0) 
+        {
+    
+#ifdef WIN32
+            if (GetLastError() == WSAEWOULDBLOCK)
+#else
+            if (errno == EAGAIN || errno == EWOULDBLOCK)
+#endif
+                continue;
+        }
+    
+        /* connection has gone, so die */
+        if (read_len <= 0)
+        {
+            printf("SSL_ERROR_CONN_LOST\n");
+            ssl->hs_status = SSL_ERROR_DEAD;  /* make sure it stays dead */
+            return SSL_ERROR_CONN_LOST;
+        }
+                
+        ret += read_len;
+
+    }while(ret < length);
+    DISPLAY_BYTES(ssl, "received %d bytes", data, ret, ret);
+    return ret;
+}
+
+int read_record(SSL *ssl)
+{
+    if(!IS_SET_SSL_FLAG(SSL_NEED_RECORD))
+        return 0;
+    uint8_t record[SSL_RECORD_SIZE];
+    int ret = basic_read2(ssl, record, SSL_RECORD_SIZE);
+    if(ret != SSL_RECORD_SIZE)
+        return ret;
+
+       /* check for sslv2 "client hello" */
+    if (record[0] & 0x80 && record[2] == 1)
+    {
+#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE
+        uint8_t version = (record[3] << 4) + record[4];
+        DISPLAY_BYTES(ssl, "ssl2 record", record, 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, &record[2], 3);
+        ret = process_sslv23_client_hello(ssl); 
+#else
+        printf("Error: no SSLv23 handshaking allowed\n"); TTY_FLUSH();
+        ret = SSL_ERROR_NOT_SUPPORTED;
+#endif
+        return ret;
+    }
+
+    ssl->need_bytes = (record[3] << 8) + record[4];
+
+    memcpy(ssl->hmac_header, record, 3);       /* store for hmac */
+    ssl->record_type = record[0];
+    CLR_SSL_FLAG(SSL_NEED_RECORD);
+    if(ssl->record_type == PT_APP_PROTOCOL_DATA)
+    {   
+        ssl->need_bytes -= ssl->cipher_info->digest_size;
+        if(ssl->cipher == SSL_AES256_SHA || ssl->cipher == SSL_AES128_SHA)
+        {
+            // discard IV
+            basic_read2(ssl, ssl->bm_all_data + ssl->bm_index, AES_BLOCKSIZE);
+            ssl->bm_remaining_bytes = basic_decrypt(ssl, ssl->bm_all_data + ssl->bm_index, AES_BLOCKSIZE);
+            ssl->need_bytes -= AES_BLOCKSIZE;
+        }
+
+    }   
+    return SSL_OK;
+}
+
+int basic_decrypt(SSL *ssl, uint8_t *buf, int len)
+{
+   if (IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED))
+    {
+        ssl->cipher_info->decrypt(ssl->decrypt_ctx, buf, buf, len);
+
+        if (ssl->version >= SSL_PROTOCOL_VERSION1_1 &&
+                        ssl->cipher_info->iv_size)
+        {
+            buf += ssl->cipher_info->iv_size;
+            len -= ssl->cipher_info->iv_size;
+        }
+
+        if(ssl->record_type != PT_APP_PROTOCOL_DATA)
+           len = verify_digest(ssl, 
+                    IS_SET_SSL_FLAG(SSL_IS_CLIENT) ? SSL_CLIENT_READ : SSL_SERVER_READ, buf, len);
+        
+        /* does the hmac work? */
+        if (len < 0)
+        {
+            return len;
+        }
+
+        DISPLAY_BYTES(ssl, "decrypted", buf, len);
+        increment_read_sequence(ssl);
+    }
+    return len;
+}
+
+int ssl_read(SSL *ssl, uint8_t *in_data, int len)
+{
+    if(len <= 0 || in_data == NULL)
+        return 0;
+   
+    if(IS_SET_SSL_FLAG(SSL_NEED_RECORD))
+    {
+        read_record(ssl);
+    }
+   
+    return process_data(ssl, in_data, len);
+}
+
+int process_data(SSL* ssl, uint8_t *in_data, int len)
+{
+    int ret = 0;
+    /* 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, NULL, 0);
+                SET_SSL_FLAG(SSL_NEED_RECORD);
+                return ret;
+            }
+            else /* no client renegotiation allowed */
+            {
+                SET_SSL_FLAG(SSL_NEED_RECORD);
+                return SSL_ERROR_NO_CLIENT_RENOG;              
+            }
+
+        case PT_CHANGE_CIPHER_SPEC:
+        
+            if(basic_read2(ssl, ssl->bm_data, ssl->need_bytes) != ssl->need_bytes)
+                return -1;
+                
+            ret = basic_decrypt(ssl, ssl->bm_data, ssl->need_bytes);
+            if(ret < 0)
+                return -1;
+
+            if (ssl->next_state != HS_FINISHED)
+            {
+                return SSL_ERROR_INVALID_HANDSHAKE;
+            }
+
+            /* all encrypted from now on */
+            SET_SSL_FLAG(SSL_RX_ENCRYPTED);
+            if (set_key_block(ssl, 0) < 0)
+            {
+                return SSL_ERROR_INVALID_HANDSHAKE;
+            }
+            
+            memset(ssl->read_sequence, 0, 8);
+            SET_SSL_FLAG(SSL_NEED_RECORD);
+            break;
+
+        case PT_APP_PROTOCOL_DATA:
+           if(len <= 0)
+                return 0;
+            if(ssl->need_bytes == 0)
+                return 0;
+            if (in_data)
+            {
+                uint16_t index = ssl->bm_index % 2048;
+                if(ssl->bm_remaining_bytes == 0)
+                {
+                    int read_len = len;
+                    if(read_len > 2048-index)
+                        read_len = 2048-index;
+                    if(read_len > ssl->need_bytes)
+                        read_len = ssl->need_bytes;
+                        
+                    // check if using a block cipher
+                    if(ssl->cipher == SSL_AES256_SHA || ssl->cipher == SSL_AES128_SHA)
+                    {
+                        read_len = AES_BLOCKSIZE;
+                    }
+                    
+                    int ret = basic_read2(ssl, ssl->bm_all_data + index, read_len);
+                    if(ret != read_len)
+                        return 0;
+
+                    ssl->bm_remaining_bytes = basic_decrypt(ssl, ssl->bm_all_data + index, read_len);
+                    
+                    if(ssl->cipher == SSL_AES256_SHA || ssl->cipher == SSL_AES128_SHA)
+                    {
+                        ssl->bm_remaining_bytes  = AES_BLOCKSIZE;
+                    }
+                    if(ssl->need_bytes < ssl->bm_remaining_bytes)
+                    {
+                        ssl->bm_remaining_bytes = ssl->need_bytes;   
+                        ssl->need_bytes = 0;
+                    }
+                    else
+                        ssl->need_bytes -= ssl->bm_remaining_bytes;
+                }
+                if(len > ssl->bm_remaining_bytes)
+                    len = ssl->bm_remaining_bytes;
+                memcpy(in_data, ssl->bm_all_data+index, len);
+                ssl->bm_index += len;
+                ssl->bm_remaining_bytes -= len;
+                
+                if(ssl->need_bytes == 0)
+                {
+                    // skip digest
+                    uint8_t buf_tmp[SHA1_SIZE];
+                    if(ssl->cipher == SSL_AES256_SHA || ssl->cipher == SSL_AES128_SHA)
+                    {
+                        basic_read2(ssl, buf_tmp, AES_BLOCKSIZE);
+                        basic_decrypt(ssl, buf_tmp, AES_BLOCKSIZE);
+                    }
+                    else
+                    {
+                        basic_read2(ssl, buf_tmp, ssl->cipher_info->digest_size);
+                        basic_decrypt(ssl, buf_tmp, ssl->cipher_info->digest_size);
+                    }
+                    SET_SSL_FLAG(SSL_NEED_RECORD);
+                }
+                if(ssl->bm_index >= 2048)
+                    ssl->bm_index = 0;
+                return len;
+            }
+            return 0;
+            
+        case PT_ALERT_PROTOCOL:
+            if(basic_read2(ssl, ssl->bm_data, ssl->need_bytes) != ssl->need_bytes)
+                return -1;
+            ret = basic_decrypt(ssl, ssl->bm_data, ssl->need_bytes);
+            if(ret < 0)
+               return -1; 
+            
+            SET_SSL_FLAG(SSL_NEED_RECORD);
+
+            /* return the alert # with alert bit set */
+            if(ssl->bm_data[0] == SSL_ALERT_TYPE_WARNING &&
+               ssl->bm_data[1] == SSL_ALERT_CLOSE_NOTIFY)
+            {
+                send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY);
+                SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY);
+                return SSL_CLOSE_NOTIFY;
+            }
+            else 
+            {
+                ret = -ssl->bm_data[1];
+                DISPLAY_ALERT(ssl, -ret);
+                return ret;
+            }
+
+        default:
+            return SSL_ERROR_INVALID_PROT_MSG;
+
+    }
+    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)
+{
+    uint8_t hs_hdr[SSL_HS_HDR_SIZE];
+    if (IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED))
+    {
+        if(basic_read2(ssl, ssl->bm_data, ssl->need_bytes) != ssl->need_bytes)
+            return -1;
+        ssl->need_bytes = basic_decrypt(ssl, ssl->bm_data, ssl->need_bytes);        
+        buf = ssl->bm_data;
+        if(ssl->cipher == SSL_AES256_SHA || ssl->cipher == SSL_AES128_SHA)
+        {
+            buf += ssl->cipher_info->iv_size;
+            add_packet(ssl, ssl->bm_data, ssl->cipher_info->iv_size); 
+        }
+    }
+    else
+    {
+        if(basic_read2(ssl, hs_hdr, SSL_HS_HDR_SIZE) != SSL_HS_HDR_SIZE)
+            return -1;
+        buf = hs_hdr;
+    }
+
+    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)
+        {
+            return SSL_ERROR_INVALID_HANDSHAKE;
+        }
+    }
+
+    //hs_len += SSL_HS_HDR_SIZE;  /* adjust for when adding packets */
+    ssl->bm_index = hs_len+SSL_HS_HDR_SIZE;     /* 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, SSL_HS_HDR_SIZE); 
+    }
+    
+    if(!IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED))
+    {
+        if(hs_len != 0 && handshake_type != HS_CERTIFICATE)
+        {
+            if(basic_read2(ssl, ssl->bm_data, hs_len) != hs_len)
+                return -1;
+            hs_len = basic_decrypt(ssl, ssl->bm_data, hs_len);
+            if(hs_len < 0)
+                return -1; 
+            
+            buf = ssl->bm_data;
+            if (handshake_type != HS_CERT_VERIFY && handshake_type != HS_HELLO_REQUEST)
+                add_packet(ssl, buf, hs_len);
+        }
+    }
+    
+    else if (handshake_type != HS_CERT_VERIFY && handshake_type != HS_HELLO_REQUEST)
+    {
+        add_packet(ssl,buf+SSL_HS_HDR_SIZE, 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
+
+
+    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)
+{
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+    if(IS_SET_SSL_FLAG(SSL_IS_CLIENT))
+    {
+        x509_free(ssl->x509_ctx);
+        ssl->x509_ctx = NULL;   
+    }
+#endif
+
+    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 is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+    int ret = SSL_OK;
+    int resume = IS_SET_SSL_FLAG(SSL_SESSION_RESUME);
+
+    PARANOIA_CHECK(ssl->bm_index, SSL_FINISHED_HASH_SIZE);
+
+    /* 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));
+        memset(ssl->dc->key_block, 0, MAX_KEYBLOCK_SIZE);
+        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, PrecomputedCertificate *cert)
+{
+    int ret;
+    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+    ret = x509_verify(cert);
+    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+    if (ret)        /* modify into an SSL error type */
+    {   
+        printf("%s\n", x509_display_error(ret));
+        ret = SSL_X509_ERROR(ret);
+    }
+    return ret;
+}
+
+int read_certificate(SSL *ssl)
+{
+    uint8_t cert_hdr[3];
+
+    if(basic_read2(ssl, cert_hdr, 3) != 3)
+        return SSL_NOT_OK;
+
+
+    add_packet(ssl, cert_hdr, 3);
+
+    uint16_t cert_size = (cert_hdr[1]<<8) + cert_hdr[2];
+    if(cert_size > RT_MAX_PLAIN_LENGTH)
+        return SSL_NOT_OK;
+
+    if(basic_read2(ssl, ssl->bm_data, cert_size) != cert_size)
+        return SSL_NOT_OK;
+
+    add_packet(ssl, ssl->bm_data, cert_size);
+
+    return cert_size+3; // cert_size + header_size
+}
+
+
+static void load_cert(PrecomputedCertificate *pc, X509_CTX *cert)
+{
+    
+    for(int i = 0; i < X509_NUM_DN_TYPES; ++i)
+    {
+        pc->cert_dn[i] = malloc(strlen(cert->cert_dn[i])+1);
+        pc->ca_cert_dn[i] = malloc(strlen(cert->ca_cert_dn[i])+1);
+        strcpy(pc->cert_dn[i], cert->cert_dn[i]);
+        strcpy(pc->ca_cert_dn[i], cert->ca_cert_dn[i]);
+    }
+    
+    pc->sig_len = cert->sig_len;
+    pc->sig = malloc(cert->sig_len);
+    memcpy(pc->sig, cert->signature, cert->sig_len);
+    
+    uint8_t buffer[256];
+    int paddingLength = 0;
+    
+    bi_permanent(cert->digest);
+    bi_export(cert->rsa_ctx->bi_ctx, cert->digest, buffer, 256);
+    bi_depermanent(cert->digest);
+    while(paddingLength < 256 && buffer[paddingLength] == 0) paddingLength++;
+    pc->digest_len = 256 - paddingLength;
+    pc->digest = malloc(pc->digest_len);
+    memcpy(pc->digest, &buffer[paddingLength], pc->digest_len);
+    
+    paddingLength = 0;
+    bi_export(cert->rsa_ctx->bi_ctx, cert->rsa_ctx->e, buffer, 256);
+    while(paddingLength < 256 && buffer[paddingLength] == 0) paddingLength++;
+    pc->expn_len = 256 - paddingLength;
+    pc->expn = malloc(pc->expn_len);
+    memcpy(pc->expn, &buffer[paddingLength], pc->expn_len); 
+    
+    paddingLength = 0;
+    bi_export(cert->rsa_ctx->bi_ctx, cert->rsa_ctx->m, buffer, 256);
+    while(paddingLength < 256 && buffer[paddingLength] == 0) paddingLength++;
+    pc->mod_len = 256 - paddingLength;
+    pc->mod = malloc(pc->mod_len);
+    memcpy(pc->mod, &buffer[paddingLength], pc->mod_len); 
+}
+
+/**
+ * Process a certificate message.
+ */
+int process_certificate(SSL *ssl, X509_CTX **x509_ctx)
+{
+    int ret = SSL_OK;
+    
+    uint8_t cert_hdr[3];
+    if(basic_read2(ssl, cert_hdr, 3) != 3)
+    {
+        ret = SSL_NOT_OK;
+        return ret;
+    }
+
+    add_packet(ssl, cert_hdr, 3);
+    int len = 5;
+    int cert_size;
+    int total_cert_size = (cert_hdr[1]<<8) + cert_hdr[2];
+    int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+    X509_CTX *cert = NULL;
+    len += 2;
+    PrecomputedCertificate pc[3];
+    memset(pc, 0, 3*sizeof(PrecomputedCertificate));
+    int pc_index = 0;
+    PARANOIA_CHECK(total_cert_size, 3);
+
+
+    while (len < total_cert_size)
+    {
+        cert_size = read_certificate(ssl);
+        if(cert_size < 0)
+        {
+            ret = cert_size;
+            goto error;
+        }
+        if(cert->sig_len * 8 > 2048)
+        {
+            ret =  SSL_X509_ERROR(X509_KEY_SIZE_TOO_BIG);
+            goto error;
+        }
+
+        if (x509_new(ssl->bm_data, NULL, &cert))
+            return SSL_ERROR_BAD_CERTIFICATE;
+        
+        if (is_client && !IS_SET_SSL_FLAG(SSL_SERVER_VERIFY_LATER))
+        {
+            /* check the not before date */
+            struct timeval tv;
+            gettimeofday(&tv, NULL);
+            if (tv.tv_sec < cert->not_before)
+            {
+               ret = SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID);
+               x509_free(cert);
+               goto error;
+            }
+            /* check the not after date */ 
+            if (tv.tv_sec > cert->not_after)
+            {
+                ret = SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED);
+                x509_free(cert);
+                goto error;
+            }
+        
+            if(pc_index > 2)
+            {
+                x509_free(cert);
+                goto error;
+            }
+            
+            load_cert(&pc[pc_index], cert);  
+                  
+            if(pc_index != 0)
+                pc[pc_index-1].next = &pc[pc_index];
+            
+            pc_index++;
+        }
+        if(len > 7)
+        {
+            cert->next = NULL;
+            x509_free(cert);
+        }
+        else
+        {
+            *x509_ctx = cert;
+            cert = cert->next;
+        }
+        len += cert_size;
+    }
+    (*x509_ctx)->next = NULL;
+    /* 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, pc);
+    }
+    
+    ssl->next_state = is_client ? HS_SERVER_HELLO_DONE : HS_CLIENT_KEY_XCHG;
+    ssl->dc->bm_proc_index += len;
+    
+error:
+    for(int i = 0; i < pc_index; ++i)
+    {
+        for(int j = 0; j < X509_NUM_DN_TYPES; ++j)
+        {
+            free(pc[i].cert_dn[j]);
+            free(pc[i].ca_cert_dn[j]);
+        }
+        free(pc[i].sig);
+        free(pc[i].digest);
+        free(pc[i].expn);
+        free(pc[i].mod);
+    }
+    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, PrecomputedCertificate *cert)
+{
+    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/axTLS/ssl/tls1.h	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,307 @@
+/*
+ * 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           256     /* for a 2048 bit key */
+#define RT_MAX_PLAIN_LENGTH         2048//16384
+#define RT_EXTRA                    256//1024
+#define BM_RECORD_OFFSET            5
+#define BM_ALL_DATA_SIZE            (RT_MAX_PLAIN_LENGTH+RT_EXTRA-BM_RECORD_OFFSET)
+
+#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[MAX_KEYBLOCK_SIZE];
+    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;
+    void *connection;
+    const cipher_info_t *cipher_info;
+    void *encrypt_ctx;
+    void *decrypt_ctx;
+    uint8_t bm_all_data[RT_MAX_PLAIN_LENGTH];
+    uint8_t *bm_data;
+    uint16_t bm_index;
+    uint16_t bm_remaining_bytes;
+    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 *ssl, 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_read2(SSL *ssl, uint8_t *data, uint32_t length);
+int read_record(SSL *ssl);
+int basic_decrypt(SSL *ssl, uint8_t *buf, int len);
+int process_data(SSL* ssl, uint8_t *in_data, int len);
+int ssl_read(SSL *ssl, uint8_t *in_data, int len);
+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/axTLS/ssl/tls1_clnt.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,399 @@
+/*
+ * 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 *ssl, int client_fd, const
+        uint8_t *session_id, uint8_t sess_id_size)
+{
+    SSL_CTX *ssl_ctx = ssl->ssl_ctx;
+    ssl_new(ssl, 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_remaining_bytes = 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 = read_record(ssl);
+            if (ret < SSL_OK)
+                break;
+            ret = process_data(ssl, NULL, 0);
+            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[0] << 4) + buf[1];
+    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[2], SSL_RANDOM_SIZE);
+    offset = 2 + 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/axTLS/ssl/tls1_svr.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,480 @@
+/*
+ * 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, 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 = 0;
+              
+              /*  cert_res = x509_verify(
+                        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;
+    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/axTLS/ssl/version.h	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,3 @@
+#define AXTLS_VERSION    "1.4.9"
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/axTLS/ssl/x509.c	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,571 @@
+/*
+ * 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
+#include "../../cert_manager.h"
+
+/**
+ * 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.
+ */
+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 = 0;
+        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(PrecomputedCertificate *cert) 
+{
+
+    int ret = X509_OK;
+    PrecomputedCertificate *next_cert = NULL;
+    int match_ca_cert = 0;
+    uint8_t is_self_signed = 0;
+    uint8_t *mod = NULL, *expn = NULL;
+    bigint *bi_mod = NULL, *bi_expn = NULL;
+    BI_CTX *bi_ctx = NULL;
+    char precomputed = is_precomputed();
+
+    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)
+    {
+        is_self_signed = 1;
+        if(precomputed)
+        {
+            mod = cert->mod;
+            expn = cert->expn;
+        }
+        else
+        {
+            bi_ctx = bi_initialize();
+            bi_mod = bi_import(bi_ctx, cert->mod, cert->mod_len);
+            bi_expn = bi_import(bi_ctx, cert->expn, cert->expn_len);
+        }
+    }    
+
+    next_cert = cert->next;
+
+    /* last cert in the chain - look for a trusted cert */
+    if (next_cert == NULL)
+    {
+        if(precomputed)
+        {
+            PrecomputedCertificate tmp = get_precomputed_cert(cert->cert_dn, cert->ca_cert_dn);
+            mod = tmp.mod;
+            expn = tmp.expn;
+        }
+        else
+        {
+            X509_CTX *root = get_cert(cert->ca_cert_dn);
+            bi_ctx = root->rsa_ctx->bi_ctx;
+            bi_mod = bi_clone(bi_ctx,root->rsa_ctx->m);
+            bi_expn = bi_clone(bi_ctx, root->rsa_ctx->e);
+        }
+    }
+    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 */
+    {
+        if(precomputed)
+        {
+            mod = next_cert->mod;
+            expn = next_cert->expn;
+        }
+        else
+        {
+            bi_ctx = bi_initialize();
+            bi_mod = bi_import(bi_ctx, next_cert->mod, next_cert->mod_len);
+            bi_expn = bi_import(bi_ctx, next_cert->expn, next_cert->expn_len);
+        }
+    }
+
+    /* cert is self signed */
+    if (!match_ca_cert && is_self_signed)
+    {
+        ret = X509_VFY_ERROR_SELF_SIGNED;
+        goto end_verify;
+    }
+
+    /* check the signature */
+    if(precomputed)
+    {
+        PrecomputedCertificate pc = get_precomputed_cert(cert->cert_dn, cert->ca_cert_dn);
+        
+        if(memcmp(cert->sig, pc.sig, pc.sig_len)
+        || memcmp(cert->digest, pc.digest, pc.digest_len)
+        || memcmp(mod, pc.mod, pc.mod_len)
+        || memcmp(expn, pc.expn, pc.expn_len))
+            ret = X509_VFY_ERROR_BAD_SIGNATURE;
+    }
+    else
+    {
+        bigint* cert_sig = sig_verify(bi_ctx, cert->sig, cert->sig_len, 
+                           bi_mod, bi_expn);        
+        
+        if (cert_sig && cert->digest)
+        {
+            uint8_t paddingLength = 0;
+            uint8_t digest[64];
+            bi_export(bi_ctx, cert_sig, digest, sizeof(digest));
+            while(digest[paddingLength] == 0) paddingLength++;
+            uint8_t digest_len = 64 - paddingLength;
+            if (memcmp(digest, cert->digest, digest_len) != 0)
+                ret = X509_VFY_ERROR_BAD_SIGNATURE;
+        }
+        else
+        {
+            ret = X509_VFY_ERROR_BAD_SIGNATURE;
+        }
+        if(is_self_signed || next_cert != NULL)
+            bi_terminate(bi_ctx);
+    }
+    
+
+    if (ret)
+        goto end_verify;
+
+    /* go down the certificate chain using recursion. */
+    if (next_cert != NULL)
+    {
+        ret = x509_verify(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(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";
+            
+        case X509_KEY_SIZE_TOO_BIG:
+            return "Only keys less or equal to 1024 bits are supported";
+            
+        default:
+            return "Unknown";
+    }
+}
+#endif      /* CONFIG_SSL_FULL_MODE */
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cert_manager.h	Thu Sep 12 15:18:04 2013 +0000
@@ -0,0 +1,45 @@
+#ifndef CERT_MANAGER_H
+#define CERT_MANAGER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "axTLS/ssl/crypto_misc.h"
+
+
+    struct PrecomputedCertificate {
+        char *ca_cert_dn[X509_NUM_DN_TYPES];
+        char *cert_dn[X509_NUM_DN_TYPES];
+        uint8_t *sig;
+        uint16_t sig_len;
+        uint8_t *mod;
+        uint16_t mod_len;
+        uint8_t *expn;
+        uint16_t expn_len;
+        uint8_t *digest;
+        uint16_t digest_len;
+        PrecomputedCertificate *next;
+    };
+    typedef struct PrecomputedCertificate PrecomputedCertificate;
+
+
+    /*
+        This is the C API of CertificateManager. These functions are
+        used by axTLS to access certificates that have been loaded.
+    */
+    char is_precomputed(void);
+    PrecomputedCertificate get_precomputed_cert(char *cert_dn[], char *ca_cert_dn[]);
+    X509_CTX* get_cert(char *ca_cert_dn[]);
+    void cert_manager_clear(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
+
+