- Renamed include directory to polarssl

diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e9a7de9
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,155 @@
+

+= Version 0.9 released on 2008-03-16

+

+    * Added support for ciphersuite: SSL_RSA_AES_128_SHA

+    * Enabled support for large files by default in aescrypt2.c

+    * Preliminary openssl wrapper contributed by David Barrett

+    * Fixed a bug in ssl_write() that caused the same payload to

+      be sent twice in non-blocking mode when send returns EAGAIN

+    * Fixed ssl_parse_client_hello(): session id and challenge must

+      not be swapped in the SSLv2 ClientHello (found by Greg Robson)

+    * Added user-defined callback debug function (Krystian Kolodziej)

+    * Before freeing a certificate, properly zero out all cert. data

+    * Fixed the "mode" parameter so that encryption/decryption are

+      not swapped on PadLock; also fixed compilation on older versions

+      of gcc (bug reported by David Barrett)

+    * Correctly handle the case in padlock_xcryptcbc() when input or

+      ouput data is non-aligned by falling back to the software

+      implementation, as VIA Nehemiah cannot handle non-aligned buffers

+    * Fixed a memory leak in x509parse_crt() which was reported by Greg

+      Robson-Garth; some x509write.c fixes by Pascal Vizeli, thanks to

+      Matthew Page who reported several bugs

+    * Fixed x509_get_ext() to accept some rare certificates which have

+      an INTEGER instead of a BOOLEAN for BasicConstraints::cA.

+    * Added support on the client side for the TLS "hostname" extension

+      (patch contributed by David Patino)

+    * Make x509parse_verify() return BADCERT_CN_MISMATCH when an empty

+      string is passed as the CN (bug reported by spoofy)

+    * Added an option to enable/disable the BN assembly code

+    * Updated rsa_check_privkey() to verify that (D*E) = 1 % (P-1)*(Q-1)

+    * Disabled obsolete hash functions by default (MD2, MD4); updated

+      selftest and benchmark to not test ciphers that have been disabled

+    * Updated x509parse_cert_info() to correctly display byte 0 of the

+      serial number, setup correct server port in the ssl client example

+    * Fixed a critical denial-of-service with X.509 cert. verification:

+      peer may cause xyssl to loop indefinitely by sending a certificate

+      for which the RSA signature check fails (bug reported by Benoit)

+    * Added test vectors for: AES-CBC, AES-CFB, DES-CBC and 3DES-CBC,

+      HMAC-MD5, HMAC-SHA1, HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512

+    * Fixed HMAC-SHA-384 and HMAC-SHA-512 (thanks to Josh Sinykin)

+    * Modified ssl_parse_client_key_exchange() to protect against

+      Daniel Bleichenbacher attack on PKCS#1 v1.5 padding, as well

+      as the Klima-Pokorny-Rosa extension of Bleichenbacher's attack

+    * Updated rsa_gen_key() so that ctx->N is always nbits in size

+    * Fixed assembly PPC compilation errors on Mac OS X, thanks to

+      David Barrett and Dusan Semen

+

+= Version 0.8 released on 2007-10-20

+

+    * Modified the HMAC functions to handle keys larger

+      than 64 bytes, thanks to Stephane Desneux and gary ng

+    * Fixed ssl_read_record() to properly update the handshake

+      message digests, which fixes IE6/IE7 client authentication

+    * Cleaned up the XYSSL* #defines, suggested by Azriel Fasten

+    * Fixed net_recv(), thanks to Lorenz Schori and Egon Kocjan

+    * Added user-defined callbacks for handling I/O and sessions

+    * Added lots of debugging output in the SSL/TLS functions

+    * Added preliminary X.509 cert. writing by Pascal Vizeli

+    * Added preliminary support for the VIA PadLock routines

+    * Added AES-CFB mode of operation, contributed by chmike

+    * Added an SSL/TLS stress testing program (ssl_test.c)

+    * Updated the RSA PKCS#1 code to allow choosing between

+      RSA_PUBLIC and RSA_PRIVATE, as suggested by David Barrett

+    * Updated ssl_read() to skip 0-length records from OpenSSL

+    * Fixed the make install target to comply with *BSD make

+    * Fixed a bug in mpi_read_binary() on 64-bit platforms

+    * mpi_is_prime() speedups, thanks to Kevin McLaughlin

+    * Fixed a long standing memory leak in mpi_is_prime()

+    * Replaced realloc with malloc in mpi_grow(), and set

+      the sign of zero as positive in mpi_init() (reported

+      by Jonathan M. McCune)

+

+= Version 0.7 released on 2007-07-07

+

+    * Added support for the MicroBlaze soft-core processor

+    * Fixed a bug in ssl_tls.c which sometimes prevented SSL

+      connections from being established with non-blocking I/O

+    * Fixed a couple bugs in the VS6 and UNIX Makefiles

+    * Fixed the "PIC register ebx clobbered in asm" bug

+    * Added HMAC starts/update/finish support functions

+    * Added the SHA-224, SHA-384 and SHA-512 hash functions

+    * Fixed the net_set_*block routines, thanks to Andreas

+    * Added a few demonstration programs: md5sum, sha1sum,

+      dh_client, dh_server, rsa_genkey, rsa_sign, rsa_verify

+    * Added new bignum import and export helper functions

+    * Rewrote README.txt in program/ssl/ca to better explain

+      how to create a test PKI

+

+= Version 0.6 released on 2007-04-01

+

+    * Ciphers used in SSL/TLS can now be disabled at compile

+      time, to reduce the memory footprint on embedded systems

+    * Added multiply assembly code for the TriCore and modified

+      havege_struct for this processor, thanks to David Patiño

+    * Added multiply assembly code for 64-bit PowerPCs,

+      thanks to Peking University and the OSU Open Source Lab

+    * Added experimental support of Quantum Cryptography

+    * Added support for autoconf, contributed by Arnaud Cornet

+    * Fixed "long long" compilation issues on IA-64 and PPC64

+    * Fixed a bug introduced in xyssl-0.5/timing.c: hardclock

+      was not being correctly defined on ARM and MIPS

+

+= Version 0.5 released on 2007-03-01

+

+    * Added multiply assembly code for SPARC and Alpha

+    * Added (beta) support for non-blocking I/O operations

+    * Implemented session resuming and client authentication

+    * Fixed some portability issues on WinCE, MINIX 3, Plan9

+      (thanks to Benjamin Newman), HP-UX, FreeBSD and Solaris

+    * Improved the performance of the EDH key exchange

+    * Fixed a bug that caused valid packets with a payload

+      size of 16384 bytes to be rejected

+

+= Version 0.4 released on 2007-02-01

+

+    * Added support for Ephemeral Diffie-Hellman key exchange

+    * Added multiply asm code for SSE2, ARM, PPC, MIPS and M68K

+    * Various improvement to the modular exponentiation code

+    * Rewrote the headers to generate the API docs with doxygen

+    * Fixed a bug in ssl_encrypt_buf (incorrect padding was

+      generated) and in ssl_parse_client_hello (max. client

+      version was not properly set), thanks to Didier Rebeix

+    * Fixed another bug in ssl_parse_client_hello: clients with

+      cipherlists larger than 96 bytes were incorrectly rejected

+    * Fixed a couple memory leak in x509_read.c

+

+= Version 0.3 released on 2007-01-01

+

+    * Added server-side SSLv3 and TLSv1.0 support

+    * Multiple fixes to enhance the compatibility with g++,

+      thanks to Xosé Antón Otero Ferreira

+    * Fixed a bug in the CBC code, thanks to dowst; also,

+      the bignum code is no longer dependant on long long

+    * Updated rsa_pkcs1_sign to handle arbitrary large inputs

+    * Updated timing.c for improved compatibility with i386

+      and 486 processors, thanks to Arnaud Cornet

+

+= Version 0.2 released on 2006-12-01

+

+    * Updated timing.c to support ARM and MIPS arch

+    * Updated the MPI code to support 8086 on MSVC 1.5

+    * Added the copyright notice at the top of havege.h

+    * Fixed a bug in sha2_hmac, thanks to newsoft/Wenfang Zhang

+    * Fixed a bug reported by Adrian Rüegsegger in x509_read_key

+    * Fixed a bug reported by Torsten Lauter in ssl_read_record

+    * Fixed a bug in rsa_check_privkey that would wrongly cause

+      valid RSA keys to be dismissed (thanks to oldwolf)

+    * Fixed a bug in mpi_is_prime that caused some primes to fail

+      the Miller-Rabin primality test

+

+    I'd also like to thank Younès Hafri for the CRUX linux port,

+    Khalil Petit who added XySSL into pkgsrc and Arnaud Cornet

+    who maintains the Debian package :-)

+

+= Version 0.1 released on 2006-11-01

+

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..69ee049
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,30 @@
+
+DESTDIR=/usr/local
+PREFIX=xyssl_
+
+.SILENT:
+
+all:
+	cd library  && make all && cd ..
+	cd programs && make all && cd ..
+
+install:
+	mkdir -p $(DESTDIR)/include/xyssl
+	cp -r include/xyssl $(DESTDIR)/include
+	
+	mkdir -p $(DESTDIR)/lib
+	cp library/libxyssl.* $(DESTDIR)/lib
+	
+	mkdir -p $(DESTDIR)/bin
+	for p in programs/*/* ; do              \
+	    if [ -x $$p ] && [ ! -d $$p ] ;     \
+	    then                                \
+	        f=$(PREFIX)`basename $$p` ;     \
+	        cp $$p $(DESTDIR)/bin/$$f ;     \
+	    fi                                  \
+	done
+
+clean:
+	cd library  && make clean && cd ..
+	cd programs && make clean && cd ..
+
diff --git a/XySSL.png b/XySSL.png
new file mode 100644
index 0000000..f631a3b
--- /dev/null
+++ b/XySSL.png
Binary files differ
diff --git a/contrib/indent.sh b/contrib/indent.sh
new file mode 100755
index 0000000..5e2a6d1
--- /dev/null
+++ b/contrib/indent.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+indent --blank-lines-after-declarations         \
+       --blank-lines-after-procedures           \
+       --swallow-optional-blank-lines           \
+       --blank-lines-before-block-comments      \
+       --format-all-comments                    \
+       --format-first-column-comments           \
+       --comment-delimiters-on-blank-lines      \
+       --start-left-side-of-comments            \
+       --braces-after-if-line                   \
+       --braces-after-struct-decl-line          \
+       --brace-indent 0                         \
+       --dont-cuddle-else                       \
+       --dont-cuddle-do-while                   \
+       --case-indentation 4                     \
+       --case-brace-indentation 0               \
+       --dont-space-special-semicolon           \
+       --no-space-after-function-call-names     \
+       --no-space-after-casts                   \
+       --no-space-after-for                     \
+       --no-space-after-if                      \
+       --no-space-after-while                   \
+       --space-after-parentheses                \
+       --no-blank-lines-after-commas            \
+       --break-function-decl-args               \
+       --dont-break-function-decl-args-end      \
+       --dont-break-procedure-type              \
+       --indent-level 4                         \
+       --continue-at-parentheses                \
+       "$@"
+
diff --git a/include/polarssl/aes.h b/include/polarssl/aes.h
new file mode 100644
index 0000000..85f7851
--- /dev/null
+++ b/include/polarssl/aes.h
@@ -0,0 +1,103 @@
+/**
+ * \file aes.h
+ */
+#ifndef XYSSL_AES_H
+#define XYSSL_AES_H
+
+#define AES_ENCRYPT     1
+#define AES_DECRYPT     0
+
+/**
+ * \brief          AES context structure
+ */
+typedef struct
+{
+    int nr;                     /*!<  number of rounds  */
+    unsigned long *rk;          /*!<  AES round keys    */
+    unsigned long buf[68];      /*!<  unaligned data    */
+}
+aes_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          AES key schedule (encryption)
+ *
+ * \param ctx      AES context to be initialized
+ * \param key      encryption key
+ * \param keysize  must be 128, 192 or 256
+ */
+void aes_setkey_enc( aes_context *ctx, unsigned char *key, int keysize );
+
+/**
+ * \brief          AES key schedule (decryption)
+ *
+ * \param ctx      AES context to be initialized
+ * \param key      decryption key
+ * \param keysize  must be 128, 192 or 256
+ */
+void aes_setkey_dec( aes_context *ctx, unsigned char *key, int keysize );
+
+/**
+ * \brief          AES-ECB block encryption/decryption
+ *
+ * \param ctx      AES context
+ * \param mode     AES_ENCRYPT or AES_DECRYPT
+ * \param input    16-byte input block
+ * \param output   16-byte output block
+ */
+void aes_crypt_ecb( aes_context *ctx,
+                    int mode,
+                    unsigned char input[16],
+                    unsigned char output[16] );
+
+/**
+ * \brief          AES-CBC buffer encryption/decryption
+ *
+ * \param ctx      AES context
+ * \param mode     AES_ENCRYPT or AES_DECRYPT
+ * \param length   length of the input data
+ * \param iv       initialization vector (updated after use)
+ * \param input    buffer holding the input data
+ * \param output   buffer holding the output data
+ */
+void aes_crypt_cbc( aes_context *ctx,
+                    int mode,
+                    int length,
+                    unsigned char iv[16],
+                    unsigned char *input,
+                    unsigned char *output );
+
+/**
+ * \brief          AES-CFB128 buffer encryption/decryption
+ *
+ * \param ctx      AES context
+ * \param mode     AES_ENCRYPT or AES_DECRYPT
+ * \param length   length of the input data
+ * \param iv_off   offset in IV (updated after use)
+ * \param iv       initialization vector (updated after use)
+ * \param input    buffer holding the input data
+ * \param output   buffer holding the output data
+ */
+void aes_crypt_cfb128( aes_context *ctx,
+                       int mode,
+                       int length,
+                       int *iv_off,
+                       unsigned char iv[16],
+                       unsigned char *input,
+                       unsigned char *output );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int aes_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* aes.h */
diff --git a/include/polarssl/arc4.h b/include/polarssl/arc4.h
new file mode 100644
index 0000000..f30743b
--- /dev/null
+++ b/include/polarssl/arc4.h
@@ -0,0 +1,51 @@
+/**
+ * \file arc4.h
+ */
+#ifndef XYSSL_ARC4_H
+#define XYSSL_ARC4_H
+
+/**
+ * \brief          ARC4 context structure
+ */
+typedef struct
+{
+    int x;                      /*!< permutation index */
+    int y;                      /*!< permutation index */
+    unsigned char m[256];       /*!< permutation table */
+}
+arc4_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          ARC4 key schedule
+ *
+ * \param ctx      ARC4 context to be initialized
+ * \param key      the secret key
+ * \param keylen   length of the key
+ */
+void arc4_setup( arc4_context *ctx, unsigned char *key, int keylen );
+
+/**
+ * \brief          ARC4 cipher function
+ *
+ * \param ctx      ARC4 context
+ * \param buf      buffer to be processed
+ * \param buflen   amount of data in buf
+ */
+void arc4_crypt( arc4_context *ctx, unsigned char *buf, int buflen );
+
+/*
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int arc4_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* arc4.h */
diff --git a/include/polarssl/base64.h b/include/polarssl/base64.h
new file mode 100644
index 0000000..0cad863
--- /dev/null
+++ b/include/polarssl/base64.h
@@ -0,0 +1,62 @@
+/**
+ * \file base64.h
+ */
+#ifndef XYSSL_BASE64_H
+#define XYSSL_BASE64_H
+
+#define XYSSL_ERR_BASE64_BUFFER_TOO_SMALL               -0x0010
+#define XYSSL_ERR_BASE64_INVALID_CHARACTER              -0x0012
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Encode a buffer into base64 format
+ *
+ * \param dst      destination buffer
+ * \param dlen     size of the buffer
+ * \param src      source buffer
+ * \param slen     amount of data to be encoded
+ *
+ * \return         0 if successful, or XYSSL_ERR_BASE64_BUFFER_TOO_SMALL.
+ *                 *dlen is always updated to reflect the amount
+ *                 of data that has (or would have) been written.
+ *
+ * \note           Call this function with *dlen = 0 to obtain the
+ *                 required buffer size in *dlen
+ */
+int base64_encode( unsigned char *dst, int *dlen,
+                   unsigned char *src, int  slen );
+
+/**
+ * \brief          Decode a base64-formatted buffer
+ *
+ * \param dst      destination buffer
+ * \param dlen     size of the buffer
+ * \param src      source buffer
+ * \param slen     amount of data to be decoded
+ *
+ * \return         0 if successful, XYSSL_ERR_BASE64_BUFFER_TOO_SMALL, or
+ *                 XYSSL_ERR_BASE64_INVALID_DATA if the input data is not
+ *                 correct. *dlen is always updated to reflect the amount
+ *                 of data that has (or would have) been written.
+ *
+ * \note           Call this function with *dlen = 0 to obtain the
+ *                 required buffer size in *dlen
+ */
+int base64_decode( unsigned char *dst, int *dlen,
+                   unsigned char *src, int  slen );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int base64_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* base64.h */
diff --git a/include/polarssl/bignum.h b/include/polarssl/bignum.h
new file mode 100644
index 0000000..ec21412
--- /dev/null
+++ b/include/polarssl/bignum.h
@@ -0,0 +1,406 @@
+/**
+ * \file bignum.h
+ */
+#ifndef XYSSL_BIGNUM_H
+#define XYSSL_BIGNUM_H
+
+#include <stdio.h>
+
+#define XYSSL_ERR_MPI_FILE_IO_ERROR                     -0x0002
+#define XYSSL_ERR_MPI_BAD_INPUT_DATA                    -0x0004
+#define XYSSL_ERR_MPI_INVALID_CHARACTER                 -0x0006
+#define XYSSL_ERR_MPI_BUFFER_TOO_SMALL                  -0x0008
+#define XYSSL_ERR_MPI_NEGATIVE_VALUE                    -0x000A
+#define XYSSL_ERR_MPI_DIVISION_BY_ZERO                  -0x000C
+#define XYSSL_ERR_MPI_NOT_ACCEPTABLE                    -0x000E
+
+#define MPI_CHK(f) if( ( ret = f ) != 0 ) goto cleanup
+
+/*
+ * Define the base integer type, architecture-wise
+ */
+#if defined(XYSSL_HAVE_INT8)
+typedef unsigned char  t_int;
+typedef unsigned short t_dbl;
+#else
+#if defined(XYSSL_HAVE_INT16)
+typedef unsigned short t_int;
+typedef unsigned long  t_dbl;
+#else
+  typedef unsigned long t_int;
+  #if defined(_MSC_VER) && defined(_M_IX86)
+  typedef unsigned __int64 t_dbl;
+  #else
+    #if defined(__amd64__) || defined(__x86_64__)    || \
+        defined(__ppc64__) || defined(__powerpc64__) || \
+        defined(__ia64__)  || defined(__alpha__)
+    typedef unsigned int t_dbl __attribute__((mode(TI)));
+    #else
+    typedef unsigned long long t_dbl;
+    #endif
+  #endif
+#endif
+#endif
+
+/**
+ * \brief          MPI structure
+ */
+typedef struct
+{
+    int s;              /*!<  integer sign      */
+    int n;              /*!<  total # of limbs  */
+    t_int *p;           /*!<  pointer to limbs  */
+}
+mpi;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Initialize one or more mpi
+ */
+void mpi_init( mpi *X, ... );
+
+/**
+ * \brief          Unallocate one or more mpi
+ */
+void mpi_free( mpi *X, ... );
+
+/**
+ * \brief          Enlarge to the specified number of limbs
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_grow( mpi *X, int nblimbs );
+
+/**
+ * \brief          Copy the contents of Y into X
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_copy( mpi *X, mpi *Y );
+
+/**
+ * \brief          Swap the contents of X and Y
+ */
+void mpi_swap( mpi *X, mpi *Y );
+
+/**
+ * \brief          Set value from integer
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_lset( mpi *X, int z );
+
+/**
+ * \brief          Return the number of least significant bits
+ */
+int mpi_lsb( mpi *X );
+
+/**
+ * \brief          Return the number of most significant bits
+ */
+int mpi_msb( mpi *X );
+
+/**
+ * \brief          Return the total size in bytes
+ */
+int mpi_size( mpi *X );
+
+/**
+ * \brief          Import from an ASCII string
+ *
+ * \param X        destination mpi
+ * \param radix    input numeric base
+ * \param s        null-terminated string buffer
+ *
+ * \return         0 if successful, or an XYSSL_ERR_MPI_XXX error code
+ */
+int mpi_read_string( mpi *X, int radix, char *s );
+
+/**
+ * \brief          Export into an ASCII string
+ *
+ * \param X        source mpi
+ * \param radix    output numeric base
+ * \param s        string buffer
+ * \param slen     string buffer size
+ *
+ * \return         0 if successful, or an XYSSL_ERR_MPI_XXX error code
+ *
+ * \note           Call this function with *slen = 0 to obtain the
+ *                 minimum required buffer size in *slen.
+ */
+int mpi_write_string( mpi *X, int radix, char *s, int *slen );
+
+/**
+ * \brief          Read X from an opened file
+ *
+ * \param X        destination mpi
+ * \param radix    input numeric base
+ * \param fin      input file handle
+ *
+ * \return         0 if successful, or an XYSSL_ERR_MPI_XXX error code
+ */
+int mpi_read_file( mpi *X, int radix, FILE *fin );
+
+/**
+ * \brief          Write X into an opened file, or stdout
+ *
+ * \param p        prefix, can be NULL
+ * \param X        source mpi
+ * \param radix    output numeric base
+ * \param fout     output file handle
+ *
+ * \return         0 if successful, or an XYSSL_ERR_MPI_XXX error code
+ *
+ * \note           Set fout == NULL to print X on the console.
+ */
+int mpi_write_file( char *p, mpi *X, int radix, FILE *fout );
+
+/**
+ * \brief          Import X from unsigned binary data, big endian
+ *
+ * \param X        destination mpi
+ * \param buf      input buffer
+ * \param buflen   input buffer size
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_read_binary( mpi *X, unsigned char *buf, int buflen );
+
+/**
+ * \brief          Export X into unsigned binary data, big endian
+ *
+ * \param X        source mpi
+ * \param buf      output buffer
+ * \param buflen   output buffer size
+ *
+ * \return         0 if successful,
+ *                 XYSSL_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough
+ *
+ * \note           Call this function with *buflen = 0 to obtain the
+ *                 minimum required buffer size in *buflen.
+ */
+int mpi_write_binary( mpi *X, unsigned char *buf, int buflen );
+
+/**
+ * \brief          Left-shift: X <<= count
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_shift_l( mpi *X, int count );
+
+/**
+ * \brief          Right-shift: X >>= count
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_shift_r( mpi *X, int count );
+
+/**
+ * \brief          Compare unsigned values
+ *
+ * \return         1 if |X| is greater than |Y|,
+ *                -1 if |X| is lesser  than |Y| or
+ *                 0 if |X| is equal to |Y|
+ */
+int mpi_cmp_abs( mpi *X, mpi *Y );
+
+/**
+ * \brief          Compare signed values
+ *
+ * \return         1 if X is greater than Y,
+ *                -1 if X is lesser  than Y or
+ *                 0 if X is equal to Y
+ */
+int mpi_cmp_mpi( mpi *X, mpi *Y );
+
+/**
+ * \brief          Compare signed values
+ *
+ * \return         1 if X is greater than z,
+ *                -1 if X is lesser  than z or
+ *                 0 if X is equal to z
+ */
+int mpi_cmp_int( mpi *X, int z );
+
+/**
+ * \brief          Unsigned addition: X = |A| + |B|
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_add_abs( mpi *X, mpi *A, mpi *B );
+
+/**
+ * \brief          Unsigned substraction: X = |A| - |B|
+ *
+ * \return         0 if successful,
+ *                 XYSSL_ERR_MPI_NEGATIVE_VALUE if B is greater than A
+ */
+int mpi_sub_abs( mpi *X, mpi *A, mpi *B );
+
+/**
+ * \brief          Signed addition: X = A + B
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_add_mpi( mpi *X, mpi *A, mpi *B );
+
+/**
+ * \brief          Signed substraction: X = A - B
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_sub_mpi( mpi *X, mpi *A, mpi *B );
+
+/**
+ * \brief          Signed addition: X = A + b
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_add_int( mpi *X, mpi *A, int b );
+
+/**
+ * \brief          Signed substraction: X = A - b
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_sub_int( mpi *X, mpi *A, int b );
+
+/**
+ * \brief          Baseline multiplication: X = A * B
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_mul_mpi( mpi *X, mpi *A, mpi *B );
+
+/**
+ * \brief          Baseline multiplication: X = A * b
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_mul_int( mpi *X, mpi *A, t_int b );
+
+/**
+ * \brief          Division by mpi: A = Q * B + R
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 XYSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0
+ *
+ * \note           Either Q or R can be NULL.
+ */
+int mpi_div_mpi( mpi *Q, mpi *R, mpi *A, mpi *B );
+
+/**
+ * \brief          Division by int: A = Q * b + R
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 XYSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0
+ *
+ * \note           Either Q or R can be NULL.
+ */
+int mpi_div_int( mpi *Q, mpi *R, mpi *A, int b );
+
+/**
+ * \brief          Modulo: R = A mod B
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 XYSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0
+ */
+int mpi_mod_mpi( mpi *R, mpi *A, mpi *B );
+
+/**
+ * \brief          Modulo: r = A mod b
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 XYSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0
+ */
+int mpi_mod_int( t_int *r, mpi *A, int b );
+
+/**
+ * \brief          Sliding-window exponentiation: X = A^E mod N
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 XYSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or even
+ *
+ * \note           _RR is used to avoid re-computing R*R mod N across
+ *                 multiple calls, which speeds up things a bit. It can
+ *                 be set to NULL if the extra performance is unneeded.
+ */
+int mpi_exp_mod( mpi *X, mpi *A, mpi *E, mpi *N, mpi *_RR );
+
+/**
+ * \brief          Greatest common divisor: G = gcd(A, B)
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_gcd( mpi *G, mpi *A, mpi *B );
+
+/**
+ * \brief          Modular inverse: X = A^-1 mod N
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 XYSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or nil
+ *                 XYSSL_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N
+ */
+int mpi_inv_mod( mpi *X, mpi *A, mpi *N );
+
+/**
+ * \brief          Miller-Rabin primality test
+ *
+ * \return         0 if successful (probably prime),
+ *                 1 if memory allocation failed,
+ *                 XYSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime
+ */
+int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng );
+
+/**
+ * \brief          Prime number generation
+ *
+ * \param X        destination mpi
+ * \param nbits    required size of X in bits
+ * \param dh_flag  if 1, then (X-1)/2 will be prime too
+ * \param f_rng    RNG function
+ * \param p_rng    RNG parameter
+ *
+ * \return         0 if successful (probably prime),
+ *                 1 if memory allocation failed,
+ *                 XYSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3
+ */
+int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
+                   int (*f_rng)(void *), void *p_rng );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int mpi_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* bignum.h */
diff --git a/include/polarssl/bn_mul.h b/include/polarssl/bn_mul.h
new file mode 100644
index 0000000..4213e74
--- /dev/null
+++ b/include/polarssl/bn_mul.h
@@ -0,0 +1,700 @@
+/**
+ * \file bn_mul.h
+ */
+/*
+ *      Multiply source vector [s] with b, add result
+ *       to destination vector [d] and set carry c.
+ *
+ *      Currently supports:
+ *
+ *         . IA-32 (386+)         . AMD64 / EM64T
+ *         . IA-32 (SSE2)         . Motorola 68000
+ *         . PowerPC, 32-bit      . MicroBlaze
+ *         . PowerPC, 64-bit      . TriCore
+ *         . SPARC v8             . ARM v3+
+ *         . Alpha                . MIPS32
+ *         . C, longlong          . C, generic
+ */
+#ifndef XYSSL_BN_MUL_H
+#define XYSSL_BN_MUL_H
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_HAVE_ASM)
+
+#if defined(__GNUC__)
+#if defined(__i386__)
+
+#define MULADDC_INIT                            \
+    asm( "movl   %%ebx, %0      " : "=m" (t));  \
+    asm( "movl   %0, %%esi      " :: "m" (s));  \
+    asm( "movl   %0, %%edi      " :: "m" (d));  \
+    asm( "movl   %0, %%ecx      " :: "m" (c));  \
+    asm( "movl   %0, %%ebx      " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "lodsl                 " );            \
+    asm( "mull   %ebx           " );            \
+    asm( "addl   %ecx,   %eax   " );            \
+    asm( "adcl   $0,     %edx   " );            \
+    asm( "addl   (%edi), %eax   " );            \
+    asm( "adcl   $0,     %edx   " );            \
+    asm( "movl   %edx,   %ecx   " );            \
+    asm( "stosl                 " );
+
+#if defined(XYSSL_HAVE_SSE2)
+
+#define MULADDC_HUIT                            \
+    asm( "movd     %ecx,     %mm1     " );      \
+    asm( "movd     %ebx,     %mm0     " );      \
+    asm( "movd     (%edi),   %mm3     " );      \
+    asm( "paddq    %mm3,     %mm1     " );      \
+    asm( "movd     (%esi),   %mm2     " );      \
+    asm( "pmuludq  %mm0,     %mm2     " );      \
+    asm( "movd     4(%esi),  %mm4     " );      \
+    asm( "pmuludq  %mm0,     %mm4     " );      \
+    asm( "movd     8(%esi),  %mm6     " );      \
+    asm( "pmuludq  %mm0,     %mm6     " );      \
+    asm( "movd     12(%esi), %mm7     " );      \
+    asm( "pmuludq  %mm0,     %mm7     " );      \
+    asm( "paddq    %mm2,     %mm1     " );      \
+    asm( "movd     4(%edi),  %mm3     " );      \
+    asm( "paddq    %mm4,     %mm3     " );      \
+    asm( "movd     8(%edi),  %mm5     " );      \
+    asm( "paddq    %mm6,     %mm5     " );      \
+    asm( "movd     12(%edi), %mm4     " );      \
+    asm( "paddq    %mm4,     %mm7     " );      \
+    asm( "movd     %mm1,     (%edi)   " );      \
+    asm( "movd     16(%esi), %mm2     " );      \
+    asm( "pmuludq  %mm0,     %mm2     " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "movd     20(%esi), %mm4     " );      \
+    asm( "pmuludq  %mm0,     %mm4     " );      \
+    asm( "paddq    %mm3,     %mm1     " );      \
+    asm( "movd     24(%esi), %mm6     " );      \
+    asm( "pmuludq  %mm0,     %mm6     " );      \
+    asm( "movd     %mm1,     4(%edi)  " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "movd     28(%esi), %mm3     " );      \
+    asm( "pmuludq  %mm0,     %mm3     " );      \
+    asm( "paddq    %mm5,     %mm1     " );      \
+    asm( "movd     16(%edi), %mm5     " );      \
+    asm( "paddq    %mm5,     %mm2     " );      \
+    asm( "movd     %mm1,     8(%edi)  " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "paddq    %mm7,     %mm1     " );      \
+    asm( "movd     20(%edi), %mm5     " );      \
+    asm( "paddq    %mm5,     %mm4     " );      \
+    asm( "movd     %mm1,     12(%edi) " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "paddq    %mm2,     %mm1     " );      \
+    asm( "movd     24(%edi), %mm5     " );      \
+    asm( "paddq    %mm5,     %mm6     " );      \
+    asm( "movd     %mm1,     16(%edi) " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "paddq    %mm4,     %mm1     " );      \
+    asm( "movd     28(%edi), %mm5     " );      \
+    asm( "paddq    %mm5,     %mm3     " );      \
+    asm( "movd     %mm1,     20(%edi) " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "paddq    %mm6,     %mm1     " );      \
+    asm( "movd     %mm1,     24(%edi) " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "paddq    %mm3,     %mm1     " );      \
+    asm( "movd     %mm1,     28(%edi) " );      \
+    asm( "addl     $32,      %edi     " );      \
+    asm( "addl     $32,      %esi     " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "movd     %mm1,     %ecx     " );
+
+#define MULADDC_STOP                            \
+    asm( "emms                        " );      \
+    asm( "movl   %0, %%ebx      " :: "m" (t));  \
+    asm( "movl   %%ecx, %0      " : "=m" (c));  \
+    asm( "movl   %%edi, %0      " : "=m" (d));  \
+    asm( "movl   %%esi, %0      " : "=m" (s) :: \
+    "eax", "ecx", "edx", "esi", "edi" );
+
+#else
+
+#define MULADDC_STOP                            \
+    asm( "movl   %0, %%ebx      " :: "m" (t));  \
+    asm( "movl   %%ecx, %0      " : "=m" (c));  \
+    asm( "movl   %%edi, %0      " : "=m" (d));  \
+    asm( "movl   %%esi, %0      " : "=m" (s) :: \
+    "eax", "ecx", "edx", "esi", "edi" );
+
+#endif /* SSE2 */
+#endif /* i386 */
+
+#if defined(__amd64__) || defined (__x86_64__)
+
+#define MULADDC_INIT                            \
+    asm( "movq   %0, %%rsi      " :: "m" (s));  \
+    asm( "movq   %0, %%rdi      " :: "m" (d));  \
+    asm( "movq   %0, %%rcx      " :: "m" (c));  \
+    asm( "movq   %0, %%rbx      " :: "m" (b));  \
+    asm( "xorq   %r8, %r8       " );
+
+#define MULADDC_CORE                            \
+    asm( "movq  (%rsi),%rax     " );            \
+    asm( "mulq   %rbx           " );            \
+    asm( "addq   $8,   %rsi     " );            \
+    asm( "addq   %rcx, %rax     " );            \
+    asm( "movq   %r8,  %rcx     " );            \
+    asm( "adcq   $0,   %rdx     " );            \
+    asm( "nop                   " );            \
+    asm( "addq   %rax, (%rdi)   " );            \
+    asm( "adcq   %rdx, %rcx     " );            \
+    asm( "addq   $8,   %rdi     " );
+
+#define MULADDC_STOP                            \
+    asm( "movq   %%rcx, %0      " : "=m" (c));  \
+    asm( "movq   %%rdi, %0      " : "=m" (d));  \
+    asm( "movq   %%rsi, %0      " : "=m" (s) :: \
+    "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" );
+
+#endif /* AMD64 */
+
+#if defined(__mc68020__) || defined(__mcpu32__)
+
+#define MULADDC_INIT                            \
+    asm( "movl   %0, %%a2       " :: "m" (s));  \
+    asm( "movl   %0, %%a3       " :: "m" (d));  \
+    asm( "movl   %0, %%d3       " :: "m" (c));  \
+    asm( "movl   %0, %%d2       " :: "m" (b));  \
+    asm( "moveq  #0, %d0        " );
+
+#define MULADDC_CORE                            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addl   %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "moveq  #0,  %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "addxl  %d4, %d3       " );
+
+#define MULADDC_STOP                            \
+    asm( "movl   %%d3, %0       " : "=m" (c));  \
+    asm( "movl   %%a3, %0       " : "=m" (d));  \
+    asm( "movl   %%a2, %0       " : "=m" (s) :: \
+    "d0", "d1", "d2", "d3", "d4", "a2", "a3" );
+
+#define MULADDC_HUIT                            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "addxl  %d0, %d3       " );
+
+#endif /* MC68000 */
+
+#if defined(__powerpc__)   || defined(__ppc__)
+#if defined(__powerpc64__) || defined(__ppc64__)
+
+#if defined(__MACH__) && defined(__APPLE__)
+
+#define MULADDC_INIT                            \
+    asm( "ld     r3, %0         " :: "m" (s));  \
+    asm( "ld     r4, %0         " :: "m" (d));  \
+    asm( "ld     r5, %0         " :: "m" (c));  \
+    asm( "ld     r6, %0         " :: "m" (b));  \
+    asm( "addi   r3, r3, -8     " );            \
+    asm( "addi   r4, r4, -8     " );            \
+    asm( "addic  r5, r5,  0     " );
+
+#define MULADDC_CORE                            \
+    asm( "ldu    r7, 8(r3)      " );            \
+    asm( "mulld  r8, r7, r6     " );            \
+    asm( "mulhdu r9, r7, r6     " );            \
+    asm( "adde   r8, r8, r5     " );            \
+    asm( "ld     r7, 8(r4)      " );            \
+    asm( "addze  r5, r9         " );            \
+    asm( "addc   r8, r8, r7     " );            \
+    asm( "stdu   r8, 8(r4)      " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  r5, r5         " );            \
+    asm( "addi   r4, r4, 8      " );            \
+    asm( "addi   r3, r3, 8      " );            \
+    asm( "std    r5, %0         " : "=m" (c));  \
+    asm( "std    r4, %0         " : "=m" (d));  \
+    asm( "std    r3, %0         " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#else
+
+#define MULADDC_INIT                            \
+    asm( "ld     %%r3, %0       " :: "m" (s));  \
+    asm( "ld     %%r4, %0       " :: "m" (d));  \
+    asm( "ld     %%r5, %0       " :: "m" (c));  \
+    asm( "ld     %%r6, %0       " :: "m" (b));  \
+    asm( "addi   %r3, %r3, -8   " );            \
+    asm( "addi   %r4, %r4, -8   " );            \
+    asm( "addic  %r5, %r5,  0   " );
+
+#define MULADDC_CORE                            \
+    asm( "ldu    %r7, 8(%r3)    " );            \
+    asm( "mulld  %r8, %r7, %r6  " );            \
+    asm( "mulhdu %r9, %r7, %r6  " );            \
+    asm( "adde   %r8, %r8, %r5  " );            \
+    asm( "ld     %r7, 8(%r4)    " );            \
+    asm( "addze  %r5, %r9       " );            \
+    asm( "addc   %r8, %r8, %r7  " );            \
+    asm( "stdu   %r8, 8(%r4)    " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  %r5, %r5       " );            \
+    asm( "addi   %r4, %r4, 8    " );            \
+    asm( "addi   %r3, %r3, 8    " );            \
+    asm( "std    %%r5, %0       " : "=m" (c));  \
+    asm( "std    %%r4, %0       " : "=m" (d));  \
+    asm( "std    %%r3, %0       " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#endif
+
+#else /* PPC32 */
+
+#if defined(__MACH__) && defined(__APPLE__)
+
+#define MULADDC_INIT                            \
+    asm( "lwz    r3, %0         " :: "m" (s));  \
+    asm( "lwz    r4, %0         " :: "m" (d));  \
+    asm( "lwz    r5, %0         " :: "m" (c));  \
+    asm( "lwz    r6, %0         " :: "m" (b));  \
+    asm( "addi   r3, r3, -4     " );            \
+    asm( "addi   r4, r4, -4     " );            \
+    asm( "addic  r5, r5,  0     " );
+
+#define MULADDC_CORE                            \
+    asm( "lwzu   r7, 4(r3)      " );            \
+    asm( "mullw  r8, r7, r6     " );            \
+    asm( "mulhwu r9, r7, r6     " );            \
+    asm( "adde   r8, r8, r5     " );            \
+    asm( "lwz    r7, 4(r4)      " );            \
+    asm( "addze  r5, r9         " );            \
+    asm( "addc   r8, r8, r7     " );            \
+    asm( "stwu   r8, 4(r4)      " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  r5, r5         " );            \
+    asm( "addi   r4, r4, 4      " );            \
+    asm( "addi   r3, r3, 4      " );            \
+    asm( "stw    r5, %0         " : "=m" (c));  \
+    asm( "stw    r4, %0         " : "=m" (d));  \
+    asm( "stw    r3, %0         " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#else
+
+#define MULADDC_INIT                            \
+    asm( "lwz    %%r3, %0       " :: "m" (s));  \
+    asm( "lwz    %%r4, %0       " :: "m" (d));  \
+    asm( "lwz    %%r5, %0       " :: "m" (c));  \
+    asm( "lwz    %%r6, %0       " :: "m" (b));  \
+    asm( "addi   %r3, %r3, -4   " );            \
+    asm( "addi   %r4, %r4, -4   " );            \
+    asm( "addic  %r5, %r5,  0   " );
+
+#define MULADDC_CORE                            \
+    asm( "lwzu   %r7, 4(%r3)    " );            \
+    asm( "mullw  %r8, %r7, %r6  " );            \
+    asm( "mulhwu %r9, %r7, %r6  " );            \
+    asm( "adde   %r8, %r8, %r5  " );            \
+    asm( "lwz    %r7, 4(%r4)    " );            \
+    asm( "addze  %r5, %r9       " );            \
+    asm( "addc   %r8, %r8, %r7  " );            \
+    asm( "stwu   %r8, 4(%r4)    " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  %r5, %r5       " );            \
+    asm( "addi   %r4, %r4, 4    " );            \
+    asm( "addi   %r3, %r3, 4    " );            \
+    asm( "stw    %%r5, %0       " : "=m" (c));  \
+    asm( "stw    %%r4, %0       " : "=m" (d));  \
+    asm( "stw    %%r3, %0       " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#endif
+
+#endif /* PPC32 */
+#endif /* PPC64 */
+
+#if defined(__sparc__)
+
+#define MULADDC_INIT                            \
+    asm( "ld     %0, %%o0       " :: "m" (s));  \
+    asm( "ld     %0, %%o1       " :: "m" (d));  \
+    asm( "ld     %0, %%o2       " :: "m" (c));  \
+    asm( "ld     %0, %%o3       " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "ld    [%o0], %o4      " );            \
+    asm( "inc      4,  %o0      " );            \
+    asm( "ld    [%o1], %o5      " );            \
+    asm( "umul   %o3,  %o4, %o4 " );            \
+    asm( "addcc  %o4,  %o2, %o4 " );            \
+    asm( "rd      %y,  %g1      " );            \
+    asm( "addx   %g1,    0, %g1 " );            \
+    asm( "addcc  %o4,  %o5, %o4 " );            \
+    asm( "st     %o4, [%o1]     " );            \
+    asm( "addx   %g1,    0, %o2 " );            \
+    asm( "inc      4,  %o1      " );
+
+#define MULADDC_STOP                            \
+    asm( "st     %%o2, %0       " : "=m" (c));  \
+    asm( "st     %%o1, %0       " : "=m" (d));  \
+    asm( "st     %%o0, %0       " : "=m" (s) :: \
+    "g1", "o0", "o1", "o2", "o3", "o4", "o5" );
+
+#endif /* SPARCv8 */
+
+#if defined(__microblaze__) || defined(microblaze)
+
+#define MULADDC_INIT                            \
+    asm( "lwi   r3,   %0        " :: "m" (s));  \
+    asm( "lwi   r4,   %0        " :: "m" (d));  \
+    asm( "lwi   r5,   %0        " :: "m" (c));  \
+    asm( "lwi   r6,   %0        " :: "m" (b));  \
+    asm( "andi  r7,   r6, 0xffff" );            \
+    asm( "bsrli r6,   r6, 16    " );
+
+#define MULADDC_CORE                            \
+    asm( "lhui  r8,   r3,   0   " );            \
+    asm( "addi  r3,   r3,   2   " );            \
+    asm( "lhui  r9,   r3,   0   " );            \
+    asm( "addi  r3,   r3,   2   " );            \
+    asm( "mul   r10,  r9,  r6   " );            \
+    asm( "mul   r11,  r8,  r7   " );            \
+    asm( "mul   r12,  r9,  r7   " );            \
+    asm( "mul   r13,  r8,  r6   " );            \
+    asm( "bsrli  r8, r10,  16   " );            \
+    asm( "bsrli  r9, r11,  16   " );            \
+    asm( "add   r13, r13,  r8   " );            \
+    asm( "add   r13, r13,  r9   " );            \
+    asm( "bslli r10, r10,  16   " );            \
+    asm( "bslli r11, r11,  16   " );            \
+    asm( "add   r12, r12, r10   " );            \
+    asm( "addc  r13, r13,  r0   " );            \
+    asm( "add   r12, r12, r11   " );            \
+    asm( "addc  r13, r13,  r0   " );            \
+    asm( "lwi   r10,  r4,   0   " );            \
+    asm( "add   r12, r12, r10   " );            \
+    asm( "addc  r13, r13,  r0   " );            \
+    asm( "add   r12, r12,  r5   " );            \
+    asm( "addc   r5, r13,  r0   " );            \
+    asm( "swi   r12,  r4,   0   " );            \
+    asm( "addi   r4,  r4,   4   " );
+
+#define MULADDC_STOP                            \
+    asm( "swi   r5,   %0        " : "=m" (c));  \
+    asm( "swi   r4,   %0        " : "=m" (d));  \
+    asm( "swi   r3,   %0        " : "=m" (s) :: \
+     "r3", "r4" , "r5" , "r6" , "r7" , "r8" ,   \
+     "r9", "r10", "r11", "r12", "r13" );
+
+#endif /* MicroBlaze */
+
+#if defined(__tricore__)
+
+#define MULADDC_INIT                            \
+    asm( "ld.a   %%a2, %0       " :: "m" (s));  \
+    asm( "ld.a   %%a3, %0       " :: "m" (d));  \
+    asm( "ld.w   %%d4, %0       " :: "m" (c));  \
+    asm( "ld.w   %%d1, %0       " :: "m" (b));  \
+    asm( "xor    %d5, %d5       " );
+
+#define MULADDC_CORE                            \
+    asm( "ld.w   %d0,   [%a2+]      " );        \
+    asm( "madd.u %e2, %e4, %d0, %d1 " );        \
+    asm( "ld.w   %d0,   [%a3]       " );        \
+    asm( "addx   %d2,    %d2,  %d0  " );        \
+    asm( "addc   %d3,    %d3,    0  " );        \
+    asm( "mov    %d4,    %d3        " );        \
+    asm( "st.w  [%a3+],  %d2        " );
+
+#define MULADDC_STOP                            \
+    asm( "st.w   %0, %%d4       " : "=m" (c));  \
+    asm( "st.a   %0, %%a3       " : "=m" (d));  \
+    asm( "st.a   %0, %%a2       " : "=m" (s) :: \
+    "d0", "d1", "e2", "d4", "a2", "a3" );
+
+#endif /* TriCore */
+
+#if defined(__arm__)
+
+#define MULADDC_INIT                            \
+    asm( "ldr    r0, %0         " :: "m" (s));  \
+    asm( "ldr    r1, %0         " :: "m" (d));  \
+    asm( "ldr    r2, %0         " :: "m" (c));  \
+    asm( "ldr    r3, %0         " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "ldr    r4, [r0], #4   " );            \
+    asm( "mov    r5, #0         " );            \
+    asm( "ldr    r6, [r1]       " );            \
+    asm( "umlal  r2, r5, r3, r4 " );            \
+    asm( "adds   r7, r6, r2     " );            \
+    asm( "adc    r2, r5, #0     " );            \
+    asm( "str    r7, [r1], #4   " );
+
+#define MULADDC_STOP                            \
+    asm( "str    r2, %0         " : "=m" (c));  \
+    asm( "str    r1, %0         " : "=m" (d));  \
+    asm( "str    r0, %0         " : "=m" (s) :: \
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" );
+
+#endif /* ARMv3 */
+
+#if defined(__alpha__)
+
+#define MULADDC_INIT                            \
+    asm( "ldq    $1, %0         " :: "m" (s));  \
+    asm( "ldq    $2, %0         " :: "m" (d));  \
+    asm( "ldq    $3, %0         " :: "m" (c));  \
+    asm( "ldq    $4, %0         " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "ldq    $6,  0($1)     " );            \
+    asm( "addq   $1,  8, $1     " );            \
+    asm( "mulq   $6, $4, $7     " );            \
+    asm( "umulh  $6, $4, $6     " );            \
+    asm( "addq   $7, $3, $7     " );            \
+    asm( "cmpult $7, $3, $3     " );            \
+    asm( "ldq    $5,  0($2)     " );            \
+    asm( "addq   $7, $5, $7     " );            \
+    asm( "cmpult $7, $5, $5     " );            \
+    asm( "stq    $7,  0($2)     " );            \
+    asm( "addq   $2,  8, $2     " );            \
+    asm( "addq   $6, $3, $3     " );            \
+    asm( "addq   $5, $3, $3     " );
+
+#define MULADDC_STOP                            \
+    asm( "stq    $3, %0         " : "=m" (c));  \
+    asm( "stq    $2, %0         " : "=m" (d));  \
+    asm( "stq    $1, %0         " : "=m" (s) :: \
+    "$1", "$2", "$3", "$4", "$5", "$6", "$7" );
+
+#endif /* Alpha */
+
+#if defined(__mips__)
+
+#define MULADDC_INIT                            \
+    asm( "lw     $10, %0        " :: "m" (s));  \
+    asm( "lw     $11, %0        " :: "m" (d));  \
+    asm( "lw     $12, %0        " :: "m" (c));  \
+    asm( "lw     $13, %0        " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "lw     $14, 0($10)    " );            \
+    asm( "multu  $13, $14       " );            \
+    asm( "addi   $10, $10, 4    " );            \
+    asm( "mflo   $14            " );            \
+    asm( "mfhi   $9             " );            \
+    asm( "addu   $14, $12, $14  " );            \
+    asm( "lw     $15, 0($11)    " );            \
+    asm( "sltu   $12, $14, $12  " );            \
+    asm( "addu   $15, $14, $15  " );            \
+    asm( "sltu   $14, $15, $14  " );            \
+    asm( "addu   $12, $12, $9   " );            \
+    asm( "sw     $15, 0($11)    " );            \
+    asm( "addu   $12, $12, $14  " );            \
+    asm( "addi   $11, $11, 4    " );
+
+#define MULADDC_STOP                            \
+    asm( "sw     $12, %0        " : "=m" (c));  \
+    asm( "sw     $11, %0        " : "=m" (d));  \
+    asm( "sw     $10, %0        " : "=m" (s) :: \
+    "$9", "$10", "$11", "$12", "$13", "$14", "$15" );
+
+#endif /* MIPS */
+#endif /* GNUC */
+
+#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
+
+#define MULADDC_INIT                            \
+    __asm   mov     esi, s                      \
+    __asm   mov     edi, d                      \
+    __asm   mov     ecx, c                      \
+    __asm   mov     ebx, b
+
+#define MULADDC_CORE                            \
+    __asm   lodsd                               \
+    __asm   mul     ebx                         \
+    __asm   add     eax, ecx                    \
+    __asm   adc     edx, 0                      \
+    __asm   add     eax, [edi]                  \
+    __asm   adc     edx, 0                      \
+    __asm   mov     ecx, edx                    \
+    __asm   stosd
+
+#if defined(XYSSL_HAVE_SSE2)
+
+#define EMIT __asm _emit
+
+#define MULADDC_HUIT                            \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0xC9             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0xC3             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x1F             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x16             \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xD0             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x66  EMIT 0x04  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xE0             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x76  EMIT 0x08  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xF0             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x7E  EMIT 0x0C  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xF8             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCA             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x5F  EMIT 0x04  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xDC             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x08  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xEE             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x67  EMIT 0x0C  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xFC             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x0F             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x56  EMIT 0x10  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xD0             \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x66  EMIT 0x14  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xE0             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x76  EMIT 0x18  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xF0             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x04  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x5E  EMIT 0x1C  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xD8             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCD             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x10  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xD5             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x08  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCF             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x14  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xE5             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x0C  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCA             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x18  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xF5             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x10  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCC             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x1C  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xDD             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x14  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCE             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x18  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x1C  \
+    EMIT 0x83  EMIT 0xC7  EMIT 0x20             \
+    EMIT 0x83  EMIT 0xC6  EMIT 0x20             \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0xC9
+
+#define MULADDC_STOP                            \
+    EMIT 0x0F  EMIT 0x77                        \
+    __asm   mov     c, ecx                      \
+    __asm   mov     d, edi                      \
+    __asm   mov     s, esi                      \
+
+#else
+
+#define MULADDC_STOP                            \
+    __asm   mov     c, ecx                      \
+    __asm   mov     d, edi                      \
+    __asm   mov     s, esi                      \
+
+#endif /* SSE2 */
+#endif /* MSVC */
+
+#endif /* XYSSL_HAVE_ASM */
+
+#if !defined(MULADDC_CORE)
+#if defined(XYSSL_HAVE_LONGLONG)
+
+#define MULADDC_INIT                    \
+{                                       \
+    t_dbl r;                            \
+    t_int r0, r1;
+
+#define MULADDC_CORE                    \
+    r   = *(s++) * (t_dbl) b;           \
+    r0  = r;                            \
+    r1  = r >> biL;                     \
+    r0 += c;  r1 += (r0 <  c);          \
+    r0 += *d; r1 += (r0 < *d);          \
+    c = r1; *(d++) = r0;
+
+#define MULADDC_STOP                    \
+}
+
+#else
+#define MULADDC_INIT                    \
+{                                       \
+    t_int s0, s1, b0, b1;               \
+    t_int r0, r1, rx, ry;               \
+    b0 = ( b << biH ) >> biH;           \
+    b1 = ( b >> biH );
+
+#define MULADDC_CORE                    \
+    s0 = ( *s << biH ) >> biH;          \
+    s1 = ( *s >> biH ); s++;            \
+    rx = s0 * b1; r0 = s0 * b0;         \
+    ry = s1 * b0; r1 = s1 * b1;         \
+    r1 += ( rx >> biH );                \
+    r1 += ( ry >> biH );                \
+    rx <<= biH; ry <<= biH;             \
+    r0 += rx; r1 += (r0 < rx);          \
+    r0 += ry; r1 += (r0 < ry);          \
+    r0 +=  c; r1 += (r0 <  c);          \
+    r0 += *d; r1 += (r0 < *d);          \
+    c = r1; *(d++) = r0;
+
+#define MULADDC_STOP                    \
+}
+
+#endif /* C (generic)  */
+#endif /* C (longlong) */
+
+#endif /* bn_mul.h */
diff --git a/include/polarssl/certs.h b/include/polarssl/certs.h
new file mode 100644
index 0000000..7b91baf
--- /dev/null
+++ b/include/polarssl/certs.h
@@ -0,0 +1,24 @@
+/**
+ * \file certs.h
+ */
+#ifndef XYSSL_CERTS_H
+#define XYSSL_CERTS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char test_ca_crt[];
+extern char test_ca_key[];
+extern char test_ca_pwd[];
+extern char test_srv_crt[];
+extern char test_srv_key[];
+extern char test_cli_crt[];
+extern char test_cli_key[];
+extern char xyssl_ca_crt[];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* certs.h */
diff --git a/include/polarssl/config.h b/include/polarssl/config.h
new file mode 100644
index 0000000..f0c7609
--- /dev/null
+++ b/include/polarssl/config.h
@@ -0,0 +1,284 @@
+/**
+ * \file config.h
+ *
+ * This set of compile-time options may be used to enable
+ * or disable features selectively, and reduce the global
+ * memory footprint.
+ */
+#ifndef XYSSL_CONFIG_H
+#define XYSSL_CONFIG_H
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+/*
+ * Uncomment if native integers are 8-bit wide.
+ *
+#define XYSSL_HAVE_INT8
+ */
+
+/*
+ * Uncomment if native integers are 16-bit wide.
+ *
+#define XYSSL_HAVE_INT16
+ */
+
+/*
+ * Uncomment if the compiler supports long long.
+ *
+#define XYSSL_HAVE_LONGLONG
+ */
+
+/*
+ * Uncomment to enable the use of assembly code.
+ */
+#define XYSSL_HAVE_ASM
+
+/*
+ * Uncomment if the CPU supports SSE2 (IA-32 specific).
+ *
+#define XYSSL_HAVE_SSE2
+ */
+
+/*
+ * Enable all SSL/TLS debugging messages.
+ */
+#define XYSSL_DEBUG_MSG
+
+/*
+ * Enable the checkup functions (*_self_test).
+ */
+#define XYSSL_SELF_TEST
+
+/*
+ * Enable the prime-number generation code.
+ */
+#define XYSSL_GENPRIME
+
+/*
+ * Uncomment this macro to store the AES tables in ROM.
+ *
+#define XYSSL_AES_ROM_TABLES
+ */
+
+/*
+ * Module:  library/aes.c
+ * Caller:  library/ssl_tls.c
+ *
+ * This module enables the following ciphersuites:
+ *      SSL_RSA_AES_128_SHA
+ *      SSL_RSA_AES_256_SHA
+ *      SSL_EDH_RSA_AES_256_SHA
+ */
+#define XYSSL_AES_C
+
+/*
+ * Module:  library/arc4.c
+ * Caller:  library/ssl_tls.c
+ *
+ * This module enables the following ciphersuites:
+ *      SSL_RSA_RC4_128_MD5
+ *      SSL_RSA_RC4_128_SHA
+ */
+#define XYSSL_ARC4_C
+
+/*
+ * Module:  library/base64.c
+ * Caller:  library/x509parse.c
+ *
+ * This module is required for X.509 support.
+ */
+#define XYSSL_BASE64_C
+
+/*
+ * Module:  library/bignum.c
+ * Caller:  library/dhm.c
+ *          library/rsa.c
+ *          library/ssl_tls.c
+ *          library/x509parse.c
+ *
+ * This module is required for RSA and DHM support.
+ */
+#define XYSSL_BIGNUM_C
+
+/*
+ * Module:  library/certs.c
+ * Caller:
+ *
+ * This module is used for testing (ssl_client/server).
+ */
+#define XYSSL_CERTS_C
+
+/*
+ * Module:  library/debug.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *
+ * This module provides debugging functions.
+ */
+#define XYSSL_DEBUG_C
+
+/*
+ * Module:  library/des.c
+ * Caller:  library/ssl_tls.c
+ *
+ * This module enables the following ciphersuites:
+ *      SSL_RSA_DES_168_SHA
+ *      SSL_EDH_RSA_DES_168_SHA
+ */
+#define XYSSL_DES_C
+
+/*
+ * Module:  library/dhm.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * This module enables the following ciphersuites:
+ *      SSL_EDH_RSA_DES_168_SHA
+ *      SSL_EDH_RSA_AES_256_SHA
+ */
+#define XYSSL_DHM_C
+
+/*
+ * Module:  library/havege.c
+ * Caller:
+ *
+ * This module enables the HAVEGE random number generator.
+ */
+#define XYSSL_HAVEGE_C
+
+/*
+ * Module:  library/md2.c
+ * Caller:  library/x509parse.c
+ *
+ * Uncomment to enable support for (rare) MD2-signed X.509 certs.
+ *
+#define XYSSL_MD2_C
+ */
+
+/*
+ * Module:  library/md4.c
+ * Caller:  library/x509parse.c
+ *
+ * Uncomment to enable support for (rare) MD4-signed X.509 certs.
+ *
+#define XYSSL_MD4_C
+ */
+
+/*
+ * Module:  library/md5.c
+ * Caller:  library/ssl_tls.c
+ *          library/x509parse.c
+ *
+ * This module is required for SSL/TLS and X.509.
+ */
+#define XYSSL_MD5_C
+
+/*
+ * Module:  library/net.c
+ * Caller:
+ *
+ * This module provides TCP/IP networking routines.
+ */
+#define XYSSL_NET_C
+
+/*
+ * Module:  library/padlock.c
+ * Caller:  library/aes.c
+ *
+ * This modules adds support for the VIA PadLock on x86.
+ */
+#define XYSSL_PADLOCK_C
+
+/*
+ * Module:  library/rsa.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *          library/x509.c
+ *
+ * This module is required for SSL/TLS and MD5-signed certificates.
+ */
+#define XYSSL_RSA_C
+
+/*
+ * Module:  library/sha1.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *          library/x509parse.c
+ *
+ * This module is required for SSL/TLS and SHA1-signed certificates.
+ */
+#define XYSSL_SHA1_C
+
+/*
+ * Module:  library/sha2.c
+ * Caller:
+ *
+ * This module adds support for SHA-224 and SHA-256.
+ */
+#define XYSSL_SHA2_C
+
+/*
+ * Module:  library/sha4.c
+ * Caller:
+ *
+ * This module adds support for SHA-384 and SHA-512.
+ */
+#define XYSSL_SHA4_C
+
+/*
+ * Module:  library/ssl_cli.c
+ * Caller:
+ *
+ * This module is required for SSL/TLS client support.
+ */
+#define XYSSL_SSL_CLI_C
+
+/*
+ * Module:  library/ssl_srv.c
+ * Caller:
+ *
+ * This module is required for SSL/TLS server support.
+ */
+#define XYSSL_SSL_SRV_C
+
+/*
+ * Module:  library/ssl_tls.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * This module is required for SSL/TLS.
+ */
+#define XYSSL_SSL_TLS_C
+
+/*
+ * Module:  library/timing.c
+ * Caller:  library/havege.c
+ *
+ * This module is used by the HAVEGE random number generator.
+ */
+#define XYSSL_TIMING_C
+
+/*
+ * Module:  library/x509parse.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *
+ * This module is required for X.509 certificate parsing.
+ */
+#define XYSSL_X509_PARSE_C
+
+/*
+ * Module:  library/x509_write.c
+ * Caller:
+ *
+ * This module is required for X.509 certificate writing.
+ */
+#define XYSSL_X509_WRITE_C
+
+#endif /* config.h */
diff --git a/include/polarssl/debug.h b/include/polarssl/debug.h
new file mode 100644
index 0000000..1ffb0ec
--- /dev/null
+++ b/include/polarssl/debug.h
@@ -0,0 +1,63 @@
+/**
+ * \file debug.h
+ */
+#ifndef SSL_DEBUG_H
+#define SSL_DEBUG_H
+
+#include "xyssl/config.h"
+#include "xyssl/ssl.h"
+
+#if defined(XYSSL_DEBUG_MSG)
+
+#define SSL_DEBUG_MSG( level, args )                    \
+    debug_print_msg( ssl, level, __FILE__, __LINE__, debug_fmt args );
+
+#define SSL_DEBUG_RET( level, text, ret )                \
+    debug_print_ret( ssl, level, __FILE__, __LINE__, text, ret );
+
+#define SSL_DEBUG_BUF( level, text, buf, len )           \
+    debug_print_buf( ssl, level, __FILE__, __LINE__, text, buf, len );
+
+#define SSL_DEBUG_MPI( level, text, X )                  \
+    debug_print_mpi( ssl, level, __FILE__, __LINE__, text, X );
+
+#define SSL_DEBUG_CRT( level, text, crt )                \
+    debug_print_crt( ssl, level, __FILE__, __LINE__, text, crt );
+
+#else
+
+#define SSL_DEBUG_MSG( level, args )            do { } while( 0 )
+#define SSL_DEBUG_RET( level, text, ret )       do { } while( 0 )
+#define SSL_DEBUG_BUF( level, text, buf, len )  do { } while( 0 )
+#define SSL_DEBUG_MPI( level, text, X )         do { } while( 0 )
+#define SSL_DEBUG_CRT( level, text, crt )       do { } while( 0 )
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char *debug_fmt( const char *format, ... );
+
+void debug_print_msg( ssl_context *ssl, int level,
+                      char *file, int line, char *text );
+
+void debug_print_ret( ssl_context *ssl, int level,
+                      char *file, int line, char *text, int ret );
+
+void debug_print_buf( ssl_context *ssl, int level,
+                      char *file, int line, char *text,
+                      unsigned char *buf, int len );
+
+void debug_print_mpi( ssl_context *ssl, int level,
+                      char *file, int line, char *text, mpi *X );
+
+void debug_print_crt( ssl_context *ssl, int level,
+                      char *file, int line, char *text, x509_cert *crt );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* debug.h */
diff --git a/include/polarssl/des.h b/include/polarssl/des.h
new file mode 100644
index 0000000..f118eac
--- /dev/null
+++ b/include/polarssl/des.h
@@ -0,0 +1,149 @@
+/**
+ * \file des.h
+ */
+#ifndef XYSSL_DES_H
+#define XYSSL_DES_H
+
+#define DES_ENCRYPT     1
+#define DES_DECRYPT     0
+
+/**
+ * \brief          DES context structure
+ */
+typedef struct
+{
+    int mode;                   /*!<  encrypt/decrypt   */
+    unsigned long sk[32];       /*!<  DES subkeys       */
+}
+des_context;
+
+/**
+ * \brief          Triple-DES context structure
+ */
+typedef struct
+{
+    int mode;                   /*!<  encrypt/decrypt   */
+    unsigned long sk[96];       /*!<  3DES subkeys      */
+}
+des3_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          DES key schedule (56-bit, encryption)
+ *
+ * \param ctx      DES context to be initialized
+ * \param key      8-byte secret key
+ */
+void des_setkey_enc( des_context *ctx, unsigned char key[8] );
+
+/**
+ * \brief          DES key schedule (56-bit, decryption)
+ *
+ * \param ctx      DES context to be initialized
+ * \param key      8-byte secret key
+ */
+void des_setkey_dec( des_context *ctx, unsigned char key[8] );
+
+/**
+ * \brief          Triple-DES key schedule (112-bit, encryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      16-byte secret key
+ */
+void des3_set2key_enc( des3_context *ctx, unsigned char key[16] );
+
+/**
+ * \brief          Triple-DES key schedule (112-bit, decryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      16-byte secret key
+ */
+void des3_set2key_dec( des3_context *ctx, unsigned char key[16] );
+
+/**
+ * \brief          Triple-DES key schedule (168-bit, encryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      24-byte secret key
+ */
+void des3_set3key_enc( des3_context *ctx, unsigned char key[24] );
+
+/**
+ * \brief          Triple-DES key schedule (168-bit, decryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      24-byte secret key
+ */
+void des3_set3key_dec( des3_context *ctx, unsigned char key[24] );
+
+/**
+ * \brief          DES-ECB block encryption/decryption
+ *
+ * \param ctx      DES context
+ * \param input    64-bit input block
+ * \param output   64-bit output block
+ */
+void des_crypt_ecb( des_context *ctx,
+                    unsigned char input[8],
+                    unsigned char output[8] );
+
+/**
+ * \brief          DES-CBC buffer encryption/decryption
+ *
+ * \param ctx      DES context
+ * \param mode     DES_ENCRYPT or DES_DECRYPT
+ * \param length   length of the input data
+ * \param iv       initialization vector (updated after use)
+ * \param input    buffer holding the input data
+ * \param output   buffer holding the output data
+ */
+void des_crypt_cbc( des_context *ctx,
+                    int mode,
+                    int length,
+                    unsigned char iv[8],
+                    unsigned char *input,
+                    unsigned char *output );
+
+/**
+ * \brief          3DES-ECB block encryption/decryption
+ *
+ * \param ctx      3DES context
+ * \param input    64-bit input block
+ * \param output   64-bit output block
+ */
+void des3_crypt_ecb( des3_context *ctx,
+                     unsigned char input[8],
+                     unsigned char output[8] );
+
+/**
+ * \brief          3DES-CBC buffer encryption/decryption
+ *
+ * \param ctx      3DES context
+ * \param mode     DES_ENCRYPT or DES_DECRYPT
+ * \param length   length of the input data
+ * \param iv       initialization vector (updated after use)
+ * \param input    buffer holding the input data
+ * \param output   buffer holding the output data
+ */
+void des3_crypt_cbc( des3_context *ctx,
+                     int mode,
+                     int length,
+                     unsigned char iv[8],
+                     unsigned char *input,
+                     unsigned char *output );
+
+/*
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int des_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* des.h */
diff --git a/include/polarssl/dhm.h b/include/polarssl/dhm.h
new file mode 100644
index 0000000..127d626
--- /dev/null
+++ b/include/polarssl/dhm.h
@@ -0,0 +1,122 @@
+/**
+ * \file dhm.h
+ */
+#ifndef XYSSL_DHM_H
+#define XYSSL_DHM_H
+
+#include "xyssl/bignum.h"
+
+#define XYSSL_ERR_DHM_BAD_INPUT_DATA                    -0x0480
+#define XYSSL_ERR_DHM_READ_PARAMS_FAILED                -0x0490
+#define XYSSL_ERR_DHM_MAKE_PARAMS_FAILED                -0x04A0
+#define XYSSL_ERR_DHM_READ_PUBLIC_FAILED                -0x04B0
+#define XYSSL_ERR_DHM_MAKE_PUBLIC_FAILED                -0x04C0
+#define XYSSL_ERR_DHM_CALC_SECRET_FAILED                -0x04D0
+
+typedef struct
+{
+    int len;    /*!<  size(P) in chars  */
+    mpi P;      /*!<  prime modulus     */
+    mpi G;      /*!<  generator         */
+    mpi X;      /*!<  secret value      */
+    mpi GX;     /*!<  self = G^X mod P  */
+    mpi GY;     /*!<  peer = G^Y mod P  */
+    mpi K;      /*!<  key = GY^X mod P  */
+    mpi RP;     /*!<  cached R^2 mod P  */
+}
+dhm_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Parse the ServerKeyExchange parameters
+ *
+ * \param ctx      DHM context
+ * \param p        &(start of input buffer)
+ * \param end      end of buffer
+ *
+ * \return         0 if successful, or an XYSSL_ERR_DHM_XXX error code
+ */
+int dhm_read_params( dhm_context *ctx,
+                     unsigned char **p,
+                     unsigned char *end );
+
+/**
+ * \brief          Setup and write the ServerKeyExchange parameters
+ *
+ * \param ctx      DHM context
+ * \param x_size   private value size in bits
+ * \param output   destination buffer
+ * \param olen     number of chars written
+ * \param f_rng    RNG function
+ * \param p_rng    RNG parameter
+ *
+ * \note           This function assumes that ctx->P and ctx->G
+ *                 have already been properly set (for example
+ *                 using mpi_read_string or mpi_read_binary).
+ *
+ * \return         0 if successful, or an XYSSL_ERR_DHM_XXX error code
+ */
+int dhm_make_params( dhm_context *ctx, int s_size,
+                     unsigned char *output, int *olen,
+                     int (*f_rng)(void *), void *p_rng );
+
+/**
+ * \brief          Import the peer's public value G^Y
+ *
+ * \param ctx      DHM context
+ * \param input    input buffer
+ * \param ilen     size of buffer
+ *
+ * \return         0 if successful, or an XYSSL_ERR_DHM_XXX error code
+ */
+int dhm_read_public( dhm_context *ctx,
+                     unsigned char *input, int ilen );
+
+/**
+ * \brief          Create own private value X and export G^X
+ *
+ * \param ctx      DHM context
+ * \param x_size   private value size in bits
+ * \param output   destination buffer
+ * \param olen     must be equal to ctx->P.len
+ * \param f_rng    RNG function
+ * \param p_rng    RNG parameter
+ *
+ * \return         0 if successful, or an XYSSL_ERR_DHM_XXX error code
+ */
+int dhm_make_public( dhm_context *ctx, int s_size,
+                     unsigned char *output, int olen,
+                     int (*f_rng)(void *), void *p_rng );
+
+/**
+ * \brief          Derive and export the shared secret (G^Y)^X mod P
+ *
+ * \param ctx      DHM context
+ * \param output   destination buffer
+ * \param olen     number of chars written
+ *
+ * \return         0 if successful, or an XYSSL_ERR_DHM_XXX error code
+ */
+int dhm_calc_secret( dhm_context *ctx,
+                     unsigned char *output, int *olen );
+
+/*
+ * \brief          Free the components of a DHM key
+ */
+void dhm_free( dhm_context *ctx );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int dhm_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/polarssl/havege.h b/include/polarssl/havege.h
new file mode 100644
index 0000000..3ad84b4
--- /dev/null
+++ b/include/polarssl/havege.h
@@ -0,0 +1,44 @@
+/**
+ * \file havege.h
+ */
+#ifndef XYSSL_HAVEGE_H
+#define XYSSL_HAVEGE_H
+
+#define COLLECT_SIZE 1024
+
+/**
+ * \brief          HAVEGE state structure
+ */
+typedef struct
+{
+    int PT1, PT2, offset[2];
+    int pool[COLLECT_SIZE];
+    int WALK[8192];
+}
+havege_state;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          HAVEGE initialization
+ *
+ * \param hs       HAVEGE state to be initialized
+ */
+void havege_init( havege_state *hs );
+
+/**
+ * \brief          HAVEGE rand function
+ *
+ * \param rng_st   points to an HAVEGE state
+ *
+ * \return         A random int
+ */
+int havege_rand( void *p_rng );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* havege.h */
diff --git a/include/polarssl/md2.h b/include/polarssl/md2.h
new file mode 100644
index 0000000..c303483
--- /dev/null
+++ b/include/polarssl/md2.h
@@ -0,0 +1,120 @@
+/**
+ * \file md2.h
+ */
+#ifndef XYSSL_MD2_H
+#define XYSSL_MD2_H
+
+/**
+ * \brief          MD2 context structure
+ */
+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 */
+
+    unsigned char ipad[64];     /*!< HMAC: inner padding        */
+    unsigned char opad[64];     /*!< HMAC: outer padding        */
+    int left;                   /*!< amount of data in buffer   */
+}
+md2_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          MD2 context setup
+ *
+ * \param ctx      context to be initialized
+ */
+void md2_starts( md2_context *ctx );
+
+/**
+ * \brief          MD2 process buffer
+ *
+ * \param ctx      MD2 context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void md2_update( md2_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief          MD2 final digest
+ *
+ * \param ctx      MD2 context
+ * \param output   MD2 checksum result
+ */
+void md2_finish( md2_context *ctx, unsigned char output[16] );
+
+/**
+ * \brief          Output = MD2( input buffer )
+ *
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   MD2 checksum result
+ */
+void md2( unsigned char *input, int ilen, unsigned char output[16] );
+
+/**
+ * \brief          Output = MD2( file contents )
+ *
+ * \param path     input file name
+ * \param output   MD2 checksum result
+ *
+ * \return         0 if successful, 1 if fopen failed,
+ *                 or 2 if fread failed
+ */
+int md2_file( char *path, unsigned char output[16] );
+
+/**
+ * \brief          MD2 HMAC context setup
+ *
+ * \param ctx      HMAC context to be initialized
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ */
+void md2_hmac_starts( md2_context *ctx, unsigned char *key, int keylen );
+
+/**
+ * \brief          MD2 HMAC process buffer
+ *
+ * \param ctx      HMAC context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void md2_hmac_update( md2_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief          MD2 HMAC final digest
+ *
+ * \param ctx      HMAC context
+ * \param output   MD2 HMAC checksum result
+ */
+void md2_hmac_finish( md2_context *ctx, unsigned char output[16] );
+
+/**
+ * \brief          Output = HMAC-MD2( hmac key, input buffer )
+ *
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   HMAC-MD2 result
+ */
+void md2_hmac( unsigned char *key, int keylen,
+               unsigned char *input, int ilen,
+               unsigned char output[16] );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int md2_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* md2.h */
diff --git a/include/polarssl/md4.h b/include/polarssl/md4.h
new file mode 100644
index 0000000..f0a7c33
--- /dev/null
+++ b/include/polarssl/md4.h
@@ -0,0 +1,119 @@
+/**
+ * \file md4.h
+ */
+#ifndef XYSSL_MD4_H
+#define XYSSL_MD4_H
+
+/**
+ * \brief          MD4 context structure
+ */
+typedef struct
+{
+    unsigned long total[2];     /*!< number of bytes processed  */
+    unsigned long state[4];     /*!< intermediate digest state  */
+    unsigned char buffer[64];   /*!< data block being processed */
+
+    unsigned char ipad[64];     /*!< HMAC: inner padding        */
+    unsigned char opad[64];     /*!< HMAC: outer padding        */
+}
+md4_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          MD4 context setup
+ *
+ * \param ctx      context to be initialized
+ */
+void md4_starts( md4_context *ctx );
+
+/**
+ * \brief          MD4 process buffer
+ *
+ * \param ctx      MD4 context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void md4_update( md4_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief          MD4 final digest
+ *
+ * \param ctx      MD4 context
+ * \param output   MD4 checksum result
+ */
+void md4_finish( md4_context *ctx, unsigned char output[16] );
+
+/**
+ * \brief          Output = MD4( input buffer )
+ *
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   MD4 checksum result
+ */
+void md4( unsigned char *input, int ilen, unsigned char output[16] );
+
+/**
+ * \brief          Output = MD4( file contents )
+ *
+ * \param path     input file name
+ * \param output   MD4 checksum result
+ *
+ * \return         0 if successful, 1 if fopen failed,
+ *                 or 2 if fread failed
+ */
+int md4_file( char *path, unsigned char output[16] );
+
+/**
+ * \brief          MD4 HMAC context setup
+ *
+ * \param ctx      HMAC context to be initialized
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ */
+void md4_hmac_starts( md4_context *ctx, unsigned char *key, int keylen );
+
+/**
+ * \brief          MD4 HMAC process buffer
+ *
+ * \param ctx      HMAC context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void md4_hmac_update( md4_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief          MD4 HMAC final digest
+ *
+ * \param ctx      HMAC context
+ * \param output   MD4 HMAC checksum result
+ */
+void md4_hmac_finish( md4_context *ctx, unsigned char output[16] );
+
+/**
+ * \brief          Output = HMAC-MD4( hmac key, input buffer )
+ *
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   HMAC-MD4 result
+ */
+void md4_hmac( unsigned char *key, int keylen,
+               unsigned char *input, int ilen,
+               unsigned char output[16] );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int md4_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* md4.h */
diff --git a/include/polarssl/md5.h b/include/polarssl/md5.h
new file mode 100644
index 0000000..a772542
--- /dev/null
+++ b/include/polarssl/md5.h
@@ -0,0 +1,119 @@
+/**
+ * \file md5.h
+ */
+#ifndef XYSSL_MD5_H
+#define XYSSL_MD5_H
+
+/**
+ * \brief          MD5 context structure
+ */
+typedef struct
+{
+    unsigned long total[2];     /*!< number of bytes processed  */
+    unsigned long state[4];     /*!< intermediate digest state  */
+    unsigned char buffer[64];   /*!< data block being processed */
+
+    unsigned char ipad[64];     /*!< HMAC: inner padding        */
+    unsigned char opad[64];     /*!< HMAC: outer padding        */
+}
+md5_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          MD5 context setup
+ *
+ * \param ctx      context to be initialized
+ */
+void md5_starts( md5_context *ctx );
+
+/**
+ * \brief          MD5 process buffer
+ *
+ * \param ctx      MD5 context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void md5_update( md5_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief          MD5 final digest
+ *
+ * \param ctx      MD5 context
+ * \param output   MD5 checksum result
+ */
+void md5_finish( md5_context *ctx, unsigned char output[16] );
+
+/**
+ * \brief          Output = MD5( input buffer )
+ *
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   MD5 checksum result
+ */
+void md5( unsigned char *input, int ilen, unsigned char output[16] );
+
+/**
+ * \brief          Output = MD5( file contents )
+ *
+ * \param path     input file name
+ * \param output   MD5 checksum result
+ *
+ * \return         0 if successful, 1 if fopen failed,
+ *                 or 2 if fread failed
+ */
+int md5_file( char *path, unsigned char output[16] );
+
+/**
+ * \brief          MD5 HMAC context setup
+ *
+ * \param ctx      HMAC context to be initialized
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ */
+void md5_hmac_starts( md5_context *ctx, unsigned char *key, int keylen );
+
+/**
+ * \brief          MD5 HMAC process buffer
+ *
+ * \param ctx      HMAC context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void md5_hmac_update( md5_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief          MD5 HMAC final digest
+ *
+ * \param ctx      HMAC context
+ * \param output   MD5 HMAC checksum result
+ */
+void md5_hmac_finish( md5_context *ctx, unsigned char output[16] );
+
+/**
+ * \brief          Output = HMAC-MD5( hmac key, input buffer )
+ *
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   HMAC-MD5 result
+ */
+void md5_hmac( unsigned char *key, int keylen,
+               unsigned char *input, int ilen,
+               unsigned char output[16] );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int md5_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* md5.h */
diff --git a/include/polarssl/net.h b/include/polarssl/net.h
new file mode 100644
index 0000000..1860b3d
--- /dev/null
+++ b/include/polarssl/net.h
@@ -0,0 +1,103 @@
+/**
+ * \file net.h
+ */
+#ifndef XYSSL_NET_H
+#define XYSSL_NET_H
+
+#define XYSSL_ERR_NET_UNKNOWN_HOST                      -0x0F00
+#define XYSSL_ERR_NET_SOCKET_FAILED                     -0x0F10
+#define XYSSL_ERR_NET_CONNECT_FAILED                    -0x0F20
+#define XYSSL_ERR_NET_BIND_FAILED                       -0x0F30
+#define XYSSL_ERR_NET_LISTEN_FAILED                     -0x0F40
+#define XYSSL_ERR_NET_ACCEPT_FAILED                     -0x0F50
+#define XYSSL_ERR_NET_RECV_FAILED                       -0x0F60
+#define XYSSL_ERR_NET_SEND_FAILED                       -0x0F70
+#define XYSSL_ERR_NET_CONN_RESET                        -0x0F80
+#define XYSSL_ERR_NET_TRY_AGAIN                         -0x0F90
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Initiate a TCP connection with host:port
+ *
+ * \return         0 if successful, or one of:
+ *                      XYSSL_ERR_NET_SOCKET_FAILED,
+ *                      XYSSL_ERR_NET_UNKNOWN_HOST,
+ *                      XYSSL_ERR_NET_CONNECT_FAILED
+ */
+int net_connect( int *fd, char *host, int port );
+
+/**
+ * \brief          Create a listening socket on bind_ip:port.
+ *                 If bind_ip == NULL, all interfaces are binded.
+ *
+ * \return         0 if successful, or one of:
+ *                      XYSSL_ERR_NET_SOCKET_FAILED,
+ *                      XYSSL_ERR_NET_BIND_FAILED,
+ *                      XYSSL_ERR_NET_LISTEN_FAILED
+ */
+int net_bind( int *fd, char *bind_ip, int port );
+
+/**
+ * \brief          Accept a connection from a remote client
+ *
+ * \return         0 if successful, XYSSL_ERR_NET_ACCEPT_FAILED, or
+ *                 XYSSL_ERR_NET_WOULD_BLOCK is bind_fd was set to
+ *                 non-blocking and accept() is blocking.
+ */
+int net_accept( int bind_fd, int *client_fd, void *client_ip );
+
+/**
+ * \brief          Set the socket blocking
+ *
+ * \return         0 if successful, or a non-zero error code
+ */
+int net_set_block( int fd );
+
+/**
+ * \brief          Set the socket non-blocking
+ *
+ * \return         0 if successful, or a non-zero error code
+ */
+int net_set_nonblock( int fd );
+
+/**
+ * \brief          Portable usleep helper
+ *
+ * \note           Real amount of time slept will not be less than
+ *                 select()'s timeout granularity (typically, 10ms).
+ */
+void net_usleep( unsigned long usec );
+
+/**
+ * \brief          Read at most 'len' characters. len is updated to
+ *                 reflect the actual number of characters read.
+ *
+ * \return         This function returns the number of bytes received,
+ *                 or a negative error code; XYSSL_ERR_NET_TRY_AGAIN
+ *                 indicates read() is blocking.
+ */
+int net_recv( void *ctx, unsigned char *buf, int len );
+
+/**
+ * \brief          Write at most 'len' characters. len is updated to
+ *                 reflect the number of characters _not_ written.
+ *
+ * \return         This function returns the number of bytes sent,
+ *                 or a negative error code; XYSSL_ERR_NET_TRY_AGAIN
+ *                 indicates write() is blocking.
+ */
+int net_send( void *ctx, unsigned char *buf, int len );
+
+/**
+ * \brief          Gracefully shutdown the connection
+ */
+void net_close( int fd );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* net.h */
diff --git a/include/polarssl/openssl.h b/include/polarssl/openssl.h
new file mode 100644
index 0000000..0006754
--- /dev/null
+++ b/include/polarssl/openssl.h
@@ -0,0 +1,113 @@
+/**
+ * \file openssl.h
+ */
+/*
+ * OpenSSL wrapper contributed by David Barett
+ */
+#ifndef XYSSL_OPENSSL_H
+#define XYSSL_OPENSSL_H
+
+#include "xyssl/aes.h"
+#include "xyssl/md5.h"
+#include "xyssl/rsa.h"
+#include "xyssl/sha1.h"
+
+#define AES_SIZE                16
+#define AES_BLOCK_SIZE          16
+#define AES_KEY                 aes_context
+#define MD5_CTX                 md5_context
+#define SHA_CTX                 sha1_context
+
+#define SHA1_Init( CTX ) \
+        sha1_starts( (CTX) )
+#define SHA1_Update(  CTX, BUF, LEN ) \
+        sha1_update( (CTX), (unsigned char *)(BUF), (LEN) )
+#define SHA1_Final( OUT, CTX ) \
+        sha1_finish( (CTX), (OUT) )
+
+#define MD5_Init( CTX ) \
+        md5_starts( (CTX) )
+#define MD5_Update( CTX, BUF, LEN ) \
+        md5_update( (CTX), (unsigned char *)(BUF), (LEN) )
+#define MD5_Final( OUT, CTX ) \
+        md5_finish( (CTX), (OUT) )
+
+#define AES_set_encrypt_key( KEY, KEYSIZE, CTX ) \
+        aes_setkey_enc( (CTX), (KEY), (KEYSIZE) )
+#define AES_set_decrypt_key( KEY, KEYSIZE, CTX ) \
+        aes_setkey_dec( (CTX), (KEY), (KEYSIZE) )
+#define AES_cbc_encrypt( INPUT, OUTPUT, LEN, CTX, IV, MODE ) \
+        aes_crypt_cbc( (CTX), (MODE), (LEN), (IV), (INPUT), (OUTPUT) )
+
+/*
+ * RSA stuff follows. TODO: needs cleanup
+ */
+inline int __RSA_Passthrough( void *output, void *input, int size )
+{
+    memcpy( output, input, size );
+    return size;
+}
+
+inline rsa_context* d2i_RSA_PUBKEY( void *ignore, unsigned char **bufptr,
+                                    int len )
+{
+    unsigned char *buffer = *(unsigned char **) bufptr;
+    rsa_context *rsa;
+    
+    /*
+     * Not a general-purpose parser: only parses public key from *exactly*
+     *   openssl genrsa -out privkey.pem 512 (or 1024)
+     *   openssl rsa -in privkey.pem -out privatekey.der -outform der
+     *   openssl rsa -in privkey.pem -out pubkey.der -outform der -pubout
+     *
+     * TODO: make a general-purpose parse
+     */
+    if( ignore != 0 || ( len != 94 && len != 162 ) )
+        return( 0 );
+
+    rsa = (rsa_context *) malloc( sizeof( rsa_rsa ) );
+    if( rsa == NULL )
+        return( 0 );
+
+    memset( rsa, 0, sizeof( rsa_context ) );
+
+    if( ( len ==  94 && 
+          mpi_read_binary( &rsa->N, &buffer[ 25],  64 ) == 0 &&
+          mpi_read_binary( &rsa->E, &buffer[ 91],   3 ) == 0 ) ||
+        ( len == 162 &&
+          mpi_read_binary( &rsa->N, &buffer[ 29], 128 ) == 0 ) &&
+          mpi_read_binary( &rsa->E, &buffer[159],   3 ) == 0 )
+    {
+        /*
+         * key read successfully
+         */
+        rsa->len = ( mpi_msb( &rsa->N ) + 7 ) >> 3;
+        return( rsa );
+    }
+    else
+    {
+        memset( rsa, 0, sizeof( rsa_context ) );
+        free( rsa );
+        return( 0 );
+    }
+}
+
+#define RSA                     rsa_context
+#define RSA_PKCS1_PADDING       1 /* ignored; always encrypt with this */
+#define RSA_size( CTX )         (CTX)->len
+#define RSA_free( CTX )         rsa_free( CTX )
+#define ERR_get_error( )        "ERR_get_error() not supported"
+#define RSA_blinding_off( IGNORE )
+
+#define d2i_RSAPrivateKey( a, b, c ) new rsa_context /* TODO: C++ bleh */
+
+inline int RSA_public_decrypt ( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { int outsize=size; if( !rsa_pkcs1_decrypt( key, RSA_PUBLIC,  &outsize, input, output ) ) return outsize; else return -1; }
+inline int RSA_private_decrypt( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { int outsize=size; if( !rsa_pkcs1_decrypt( key, RSA_PRIVATE, &outsize, input, output ) ) return outsize; else return -1; }
+inline int RSA_public_encrypt ( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { if( !rsa_pkcs1_encrypt( key, RSA_PUBLIC,  size, input, output ) ) return RSA_size(key); else return -1; }
+inline int RSA_private_encrypt( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { if( !rsa_pkcs1_encrypt( key, RSA_PRIVATE, size, input, output ) ) return RSA_size(key); else return -1; }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* openssl.h */
diff --git a/include/polarssl/padlock.h b/include/polarssl/padlock.h
new file mode 100644
index 0000000..e577de7
--- /dev/null
+++ b/include/polarssl/padlock.h
@@ -0,0 +1,73 @@
+/**
+ * \file padlock.h
+ */
+#ifndef XYSSL_PADLOCK_H
+#define XYSSL_PADLOCK_H
+
+#include "xyssl/aes.h"
+
+#if (defined(__GNUC__) && defined(__i386__))
+
+#ifndef XYSSL_HAVE_X86
+#define XYSSL_HAVE_X86
+#endif
+
+#define PADLOCK_RNG 0x000C
+#define PADLOCK_ACE 0x00C0
+#define PADLOCK_PHE 0x0C00
+#define PADLOCK_PMM 0x3000
+
+#define PADLOCK_ALIGN16(x) (unsigned long *) (16 + ((long) x & ~15))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          PadLock detection routine
+ *
+ * \return         1 if CPU has support for the feature, 0 otherwise
+ */
+int padlock_supports( int feature );
+
+/**
+ * \brief          PadLock AES-ECB block en(de)cryption
+ *
+ * \param ctx      AES context
+ * \param mode     AES_ENCRYPT or AES_DECRYPT
+ * \param input    16-byte input block
+ * \param output   16-byte output block
+ *
+ * \return         0 if success, 1 if operation failed
+ */
+int padlock_xcryptecb( aes_context *ctx,
+                       int mode,
+                       unsigned char input[16],
+                       unsigned char output[16] );
+
+/**
+ * \brief          PadLock AES-CBC buffer en(de)cryption
+ *
+ * \param ctx      AES context
+ * \param mode     AES_ENCRYPT or AES_DECRYPT
+ * \param length   length of the input data
+ * \param iv       initialization vector (updated after use)
+ * \param input    buffer holding the input data
+ * \param output   buffer holding the output data
+ *
+ * \return         0 if success, 1 if operation failed
+ */
+int padlock_xcryptcbc( aes_context *ctx,
+                       int mode,
+                       int length,
+                       unsigned char iv[16],
+                       unsigned char *input,
+                       unsigned char *output );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAVE_X86  */
+
+#endif /* padlock.h */
diff --git a/include/polarssl/rsa.h b/include/polarssl/rsa.h
new file mode 100644
index 0000000..9a8a5dc
--- /dev/null
+++ b/include/polarssl/rsa.h
@@ -0,0 +1,274 @@
+/**
+ * \file rsa.h
+ */
+#ifndef XYSSL_RSA_H
+#define XYSSL_RSA_H
+
+#include "xyssl/bignum.h"
+
+#define XYSSL_ERR_RSA_BAD_INPUT_DATA                    -0x0400
+#define XYSSL_ERR_RSA_INVALID_PADDING                   -0x0410
+#define XYSSL_ERR_RSA_KEY_GEN_FAILED                    -0x0420
+#define XYSSL_ERR_RSA_KEY_CHECK_FAILED                  -0x0430
+#define XYSSL_ERR_RSA_PUBLIC_FAILED                     -0x0440
+#define XYSSL_ERR_RSA_PRIVATE_FAILED                    -0x0450
+#define XYSSL_ERR_RSA_VERIFY_FAILED                     -0x0460
+
+/*
+ * PKCS#1 constants
+ */
+#define RSA_RAW         0
+#define RSA_MD2         2
+#define RSA_MD4         3
+#define RSA_MD5         4
+#define RSA_SHA1        5
+#define RSA_SHA256      6
+
+#define RSA_PUBLIC      0
+#define RSA_PRIVATE     1
+
+#define RSA_PKCS_V15    0
+#define RSA_PKCS_V21    1
+
+#define RSA_SIGN        1
+#define RSA_CRYPT       2
+
+/*
+ * DigestInfo ::= SEQUENCE {
+ *   digestAlgorithm DigestAlgorithmIdentifier,
+ *   digest Digest }
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * Digest ::= OCTET STRING
+ */
+#define ASN1_HASH_MDX                       \
+    "\x30\x20\x30\x0C\x06\x08\x2A\x86\x48"  \
+    "\x86\xF7\x0D\x02\x00\x05\x00\x04\x10"
+
+#define ASN1_HASH_SHA1                      \
+    "\x30\x21\x30\x09\x06\x05\x2B\x0E\x03"  \
+    "\x02\x1A\x05\x00\x04\x14"
+
+/**
+ * \brief          RSA context structure
+ */
+typedef struct
+{
+    int ver;                    /*!<  always 0          */
+    int len;                    /*!<  size(N) in chars  */
+
+    mpi N;                      /*!<  public modulus    */
+    mpi E;                      /*!<  public exponent   */
+
+    mpi D;                      /*!<  private exponent  */
+    mpi P;                      /*!<  1st prime factor  */
+    mpi Q;                      /*!<  2nd prime factor  */
+    mpi DP;                     /*!<  D % (P - 1)       */
+    mpi DQ;                     /*!<  D % (Q - 1)       */
+    mpi QP;                     /*!<  1 / (Q % P)       */
+
+    mpi RN;                     /*!<  cached R^2 mod N  */
+    mpi RP;                     /*!<  cached R^2 mod P  */
+    mpi RQ;                     /*!<  cached R^2 mod Q  */
+
+    int padding;                /*!<  1.5 or OAEP/PSS   */
+    int hash_id;                /*!<  hash identifier   */
+    int (*f_rng)(void *);       /*!<  RNG function      */
+    void *p_rng;                /*!<  RNG parameter     */
+}
+rsa_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Initialize an RSA context
+ *
+ * \param ctx      RSA context to be initialized
+ * \param padding  RSA_PKCS_V15 or RSA_PKCS_V21
+ * \param hash_id  RSA_PKCS_V21 hash identifier
+ * \param f_rng    RNG function
+ * \param p_rng    RNG parameter
+ *
+ * \note           The hash_id parameter is actually ignored
+ *                 when using RSA_PKCS_V15 padding.
+ *
+ * \note           Currently (xyssl-0.8), RSA_PKCS_V21 padding
+ *                 is not supported.
+ */
+void rsa_init( rsa_context *ctx,
+               int padding,
+               int hash_id,
+               int (*f_rng)(void *),
+               void *p_rng );
+
+/**
+ * \brief          Generate an RSA keypair
+ *
+ * \param ctx      RSA context that will hold the key
+ * \param nbits    size of the public key in bits
+ * \param exponent public exponent (e.g., 65537)
+ *
+ * \note           rsa_init() must be called beforehand to setup
+ *                 the RSA context (especially f_rng and p_rng).
+ *
+ * \return         0 if successful, or an XYSSL_ERR_RSA_XXX error code
+ */
+int rsa_gen_key( rsa_context *ctx, int nbits, int exponent );
+
+/**
+ * \brief          Check a public RSA key
+ *
+ * \param ctx      RSA context to be checked
+ *
+ * \return         0 if successful, or an XYSSL_ERR_RSA_XXX error code
+ */
+int rsa_check_pubkey( rsa_context *ctx );
+
+/**
+ * \brief          Check a private RSA key
+ *
+ * \param ctx      RSA context to be checked
+ *
+ * \return         0 if successful, or an XYSSL_ERR_RSA_XXX error code
+ */
+int rsa_check_privkey( rsa_context *ctx );
+
+/**
+ * \brief          Do an RSA public key operation
+ *
+ * \param ctx      RSA context
+ * \param input    input buffer
+ * \param output   output buffer
+ *
+ * \return         0 if successful, or an XYSSL_ERR_RSA_XXX error code
+ *
+ * \note           This function does NOT take care of message
+ *                 padding. Also, be sure to set input[0] = 0.
+ *
+ * \note           The input and output buffers must be large
+ *                 enough (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_public( rsa_context *ctx,
+                unsigned char *input,
+                unsigned char *output );
+
+/**
+ * \brief          Do an RSA private key operation
+ *
+ * \param ctx      RSA context
+ * \param input    input buffer
+ * \param output   output buffer
+ *
+ * \return         0 if successful, or an XYSSL_ERR_RSA_XXX error code
+ *
+ * \note           The input and output buffers must be large
+ *                 enough (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_private( rsa_context *ctx,
+                 unsigned char *input,
+                 unsigned char *output );
+
+/**
+ * \brief          Add the message padding, then do an RSA operation
+ *
+ * \param ctx      RSA context
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param ilen     contains the the plaintext length
+ * \param input    buffer holding the data to be encrypted
+ * \param output   buffer that will hold the ciphertext
+ *
+ * \return         0 if successful, or an XYSSL_ERR_RSA_XXX error code
+ *
+ * \note           The output buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_pkcs1_encrypt( rsa_context *ctx,
+                       int mode, int  ilen,
+                       unsigned char *input,
+                       unsigned char *output );
+
+/**
+ * \brief          Do an RSA operation, then remove the message padding
+ *
+ * \param ctx      RSA context
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param input    buffer holding the encrypted data
+ * \param output   buffer that will hold the plaintext
+ * \param olen     will contain the plaintext length
+ *
+ * \return         0 if successful, or an XYSSL_ERR_RSA_XXX error code
+ *
+ * \note           The output buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_pkcs1_decrypt( rsa_context *ctx,
+                       int mode, int *olen,
+                       unsigned char *input,
+                       unsigned char *output );
+
+/**
+ * \brief          Do a private RSA to sign a message digest
+ *
+ * \param ctx      RSA context
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param hash_id  RSA_RAW, RSA_MD{2,4,5} or RSA_SHA{1,256}
+ * \param hashlen  message digest length (for RSA_RAW only)
+ * \param hash     buffer holding the message digest
+ * \param sig      buffer that will hold the ciphertext
+ *
+ * \return         0 if the signing operation was successful,
+ *                 or an XYSSL_ERR_RSA_XXX error code
+ *
+ * \note           The "sig" buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_pkcs1_sign( rsa_context *ctx,
+                    int mode,
+                    int hash_id,
+                    int hashlen,
+                    unsigned char *hash,
+                    unsigned char *sig );
+
+/**
+ * \brief          Do a public RSA and check the message digest
+ *
+ * \param ctx      points to an RSA public key
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param hash_id  RSA_RAW, RSA_MD{2,4,5} or RSA_SHA{1,256}
+ * \param hashlen  message digest length (for RSA_RAW only)
+ * \param hash     buffer holding the message digest
+ * \param sig      buffer holding the ciphertext
+ *
+ * \return         0 if the verify operation was successful,
+ *                 or an XYSSL_ERR_RSA_XXX error code
+ *
+ * \note           The "sig" buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_pkcs1_verify( rsa_context *ctx,
+                      int mode,
+                      int hash_id,
+                      int hashlen,
+                      unsigned char *hash,
+                      unsigned char *sig );
+
+/**
+ * \brief          Free the components of an RSA key
+ */
+void rsa_free( rsa_context *ctx );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int rsa_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* rsa.h */
diff --git a/include/polarssl/sha1.h b/include/polarssl/sha1.h
new file mode 100644
index 0000000..7d44c67
--- /dev/null
+++ b/include/polarssl/sha1.h
@@ -0,0 +1,119 @@
+/**
+ * \file sha1.h
+ */
+#ifndef XYSSL_SHA1_H
+#define XYSSL_SHA1_H
+
+/**
+ * \brief          SHA-1 context structure
+ */
+typedef struct
+{
+    unsigned long total[2];     /*!< number of bytes processed  */
+    unsigned long state[5];     /*!< intermediate digest state  */
+    unsigned char buffer[64];   /*!< data block being processed */
+
+    unsigned char ipad[64];     /*!< HMAC: inner padding        */
+    unsigned char opad[64];     /*!< HMAC: outer padding        */
+}
+sha1_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          SHA-1 context setup
+ *
+ * \param ctx      context to be initialized
+ */
+void sha1_starts( sha1_context *ctx );
+
+/**
+ * \brief          SHA-1 process buffer
+ *
+ * \param ctx      SHA-1 context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void sha1_update( sha1_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief          SHA-1 final digest
+ *
+ * \param ctx      SHA-1 context
+ * \param output   SHA-1 checksum result
+ */
+void sha1_finish( sha1_context *ctx, unsigned char output[20] );
+
+/**
+ * \brief          Output = SHA-1( input buffer )
+ *
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   SHA-1 checksum result
+ */
+void sha1( unsigned char *input, int ilen, unsigned char output[20] );
+
+/**
+ * \brief          Output = SHA-1( file contents )
+ *
+ * \param path     input file name
+ * \param output   SHA-1 checksum result
+ *
+ * \return         0 if successful, 1 if fopen failed,
+ *                 or 2 if fread failed
+ */
+int sha1_file( char *path, unsigned char output[20] );
+
+/**
+ * \brief          SHA-1 HMAC context setup
+ *
+ * \param ctx      HMAC context to be initialized
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ */
+void sha1_hmac_starts( sha1_context *ctx, unsigned char *key, int keylen );
+
+/**
+ * \brief          SHA-1 HMAC process buffer
+ *
+ * \param ctx      HMAC context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void sha1_hmac_update( sha1_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief          SHA-1 HMAC final digest
+ *
+ * \param ctx      HMAC context
+ * \param output   SHA-1 HMAC checksum result
+ */
+void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] );
+
+/**
+ * \brief          Output = HMAC-SHA-1( hmac key, input buffer )
+ *
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   HMAC-SHA-1 result
+ */
+void sha1_hmac( unsigned char *key, int keylen,
+                unsigned char *input, int ilen,
+                unsigned char output[20] );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int sha1_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* sha1.h */
diff --git a/include/polarssl/sha2.h b/include/polarssl/sha2.h
new file mode 100644
index 0000000..ad2d37b
--- /dev/null
+++ b/include/polarssl/sha2.h
@@ -0,0 +1,127 @@
+/**
+ * \file sha2.h
+ */
+#ifndef XYSSL_SHA2_H
+#define XYSSL_SHA2_H
+
+/**
+ * \brief          SHA-256 context structure
+ */
+typedef struct
+{
+    unsigned long total[2];     /*!< number of bytes processed  */
+    unsigned long state[8];     /*!< intermediate digest state  */
+    unsigned char buffer[64];   /*!< data block being processed */
+
+    unsigned char ipad[64];     /*!< HMAC: inner padding        */
+    unsigned char opad[64];     /*!< HMAC: outer padding        */
+    int is224;                  /*!< 0 => SHA-256, else SHA-224 */
+}
+sha2_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          SHA-256 context setup
+ *
+ * \param ctx      context to be initialized
+ * \param is224    0 = use SHA256, 1 = use SHA224
+ */
+void sha2_starts( sha2_context *ctx, int is224 );
+
+/**
+ * \brief          SHA-256 process buffer
+ *
+ * \param ctx      SHA-256 context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void sha2_update( sha2_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief          SHA-256 final digest
+ *
+ * \param ctx      SHA-256 context
+ * \param output   SHA-224/256 checksum result
+ */
+void sha2_finish( sha2_context *ctx, unsigned char output[32] );
+
+/**
+ * \brief          Output = SHA-256( input buffer )
+ *
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   SHA-224/256 checksum result
+ * \param is224    0 = use SHA256, 1 = use SHA224
+ */
+void sha2( unsigned char *input, int ilen,
+           unsigned char output[32], int is224 );
+
+/**
+ * \brief          Output = SHA-256( file contents )
+ *
+ * \param path     input file name
+ * \param output   SHA-224/256 checksum result
+ * \param is224    0 = use SHA256, 1 = use SHA224
+ *
+ * \return         0 if successful, 1 if fopen failed,
+ *                 or 2 if fread failed
+ */
+int sha2_file( char *path, unsigned char output[32], int is224 );
+
+/**
+ * \brief          SHA-256 HMAC context setup
+ *
+ * \param ctx      HMAC context to be initialized
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ * \param is224    0 = use SHA256, 1 = use SHA224
+ */
+void sha2_hmac_starts( sha2_context *ctx, unsigned char *key, int keylen,
+                       int is224 );
+
+/**
+ * \brief          SHA-256 HMAC process buffer
+ *
+ * \param ctx      HMAC context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void sha2_hmac_update( sha2_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief          SHA-256 HMAC final digest
+ *
+ * \param ctx      HMAC context
+ * \param output   SHA-224/256 HMAC checksum result
+ */
+void sha2_hmac_finish( sha2_context *ctx, unsigned char output[32] );
+
+/**
+ * \brief          Output = HMAC-SHA-256( hmac key, input buffer )
+ *
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   HMAC-SHA-224/256 result
+ * \param is224    0 = use SHA256, 1 = use SHA224
+ */
+void sha2_hmac( unsigned char *key, int keylen,
+                unsigned char *input, int ilen,
+                unsigned char output[32], int is224 );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int sha2_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* sha2.h */
diff --git a/include/polarssl/sha4.h b/include/polarssl/sha4.h
new file mode 100644
index 0000000..6c80085
--- /dev/null
+++ b/include/polarssl/sha4.h
@@ -0,0 +1,135 @@
+/**
+ * \file sha4.h
+ */
+#ifndef XYSSL_SHA4_H
+#define XYSSL_SHA4_H
+
+#if defined(_MSC_VER) || defined(__WATCOMC__)
+  #define UL64(x) x##ui64
+  #define int64 __int64
+#else
+  #define UL64(x) x##ULL
+  #define int64 long long
+#endif
+
+/**
+ * \brief          SHA-512 context structure
+ */
+typedef struct
+{
+    unsigned int64 total[2];    /*!< number of bytes processed  */
+    unsigned int64 state[8];    /*!< intermediate digest state  */
+    unsigned char buffer[128];  /*!< data block being processed */
+
+    unsigned char ipad[128];    /*!< HMAC: inner padding        */
+    unsigned char opad[128];    /*!< HMAC: outer padding        */
+    int is384;                  /*!< 0 => SHA-512, else SHA-384 */
+}
+sha4_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          SHA-512 context setup
+ *
+ * \param ctx      context to be initialized
+ * \param is384    0 = use SHA512, 1 = use SHA384
+ */
+void sha4_starts( sha4_context *ctx, int is384 );
+
+/**
+ * \brief          SHA-512 process buffer
+ *
+ * \param ctx      SHA-512 context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void sha4_update( sha4_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief          SHA-512 final digest
+ *
+ * \param ctx      SHA-512 context
+ * \param output   SHA-384/512 checksum result
+ */
+void sha4_finish( sha4_context *ctx, unsigned char output[64] );
+
+/**
+ * \brief          Output = SHA-512( input buffer )
+ *
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   SHA-384/512 checksum result
+ * \param is384    0 = use SHA512, 1 = use SHA384
+ */
+void sha4( unsigned char *input, int ilen,
+           unsigned char output[64], int is384 );
+
+/**
+ * \brief          Output = SHA-512( file contents )
+ *
+ * \param path     input file name
+ * \param output   SHA-384/512 checksum result
+ * \param is384    0 = use SHA512, 1 = use SHA384
+ *
+ * \return         0 if successful, 1 if fopen failed,
+ *                 or 2 if fread failed
+ */
+int sha4_file( char *path, unsigned char output[64], int is384 );
+
+/**
+ * \brief          SHA-512 HMAC context setup
+ *
+ * \param ctx      HMAC context to be initialized
+ * \param is384    0 = use SHA512, 1 = use SHA384
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ */
+void sha4_hmac_starts( sha4_context *ctx, unsigned char *key, int keylen,
+                       int is384 );
+
+/**
+ * \brief          SHA-512 HMAC process buffer
+ *
+ * \param ctx      HMAC context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void sha4_hmac_update( sha4_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief          SHA-512 HMAC final digest
+ *
+ * \param ctx      HMAC context
+ * \param output   SHA-384/512 HMAC checksum result
+ */
+void sha4_hmac_finish( sha4_context *ctx, unsigned char output[64] );
+
+/**
+ * \brief          Output = HMAC-SHA-512( hmac key, input buffer )
+ *
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   HMAC-SHA-384/512 result
+ * \param is384    0 = use SHA512, 1 = use SHA384
+ */
+void sha4_hmac( unsigned char *key, int keylen,
+                unsigned char *input, int ilen,
+                unsigned char output[64], int is384 );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int sha4_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* sha4.h */
diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h
new file mode 100644
index 0000000..d6bd0da
--- /dev/null
+++ b/include/polarssl/ssl.h
@@ -0,0 +1,517 @@
+/**
+ * \file ssl.h
+ */
+#ifndef XYSSL_SSL_H
+#define XYSSL_SSL_H
+
+#include <time.h>
+
+#include "xyssl/net.h"
+#include "xyssl/dhm.h"
+#include "xyssl/rsa.h"
+#include "xyssl/md5.h"
+#include "xyssl/sha1.h"
+#include "xyssl/x509.h"
+
+#define XYSSL_ERR_SSL_FEATURE_UNAVAILABLE               -0x1000
+#define XYSSL_ERR_SSL_BAD_INPUT_DATA                    -0x1800
+#define XYSSL_ERR_SSL_INVALID_MAC                       -0x2000
+#define XYSSL_ERR_SSL_INVALID_RECORD                    -0x2800
+#define XYSSL_ERR_SSL_INVALID_MODULUS_SIZE              -0x3000
+#define XYSSL_ERR_SSL_UNKNOWN_CIPHER                    -0x3800
+#define XYSSL_ERR_SSL_NO_CIPHER_CHOSEN                  -0x4000
+#define XYSSL_ERR_SSL_NO_SESSION_FOUND                  -0x4800
+#define XYSSL_ERR_SSL_NO_CLIENT_CERTIFICATE             -0x5000
+#define XYSSL_ERR_SSL_CERTIFICATE_TOO_LARGE             -0x5800
+#define XYSSL_ERR_SSL_CERTIFICATE_REQUIRED              -0x6000
+#define XYSSL_ERR_SSL_PRIVATE_KEY_REQUIRED              -0x6800
+#define XYSSL_ERR_SSL_CA_CHAIN_REQUIRED                 -0x7000
+#define XYSSL_ERR_SSL_UNEXPECTED_MESSAGE                -0x7800
+#define XYSSL_ERR_SSL_FATAL_ALERT_MESSAGE               -0x8000
+#define XYSSL_ERR_SSL_PEER_VERIFY_FAILED                -0x8800
+#define XYSSL_ERR_SSL_PEER_CLOSE_NOTIFY                 -0x9000
+#define XYSSL_ERR_SSL_BAD_HS_CLIENT_HELLO               -0x9800
+#define XYSSL_ERR_SSL_BAD_HS_SERVER_HELLO               -0xA000
+#define XYSSL_ERR_SSL_BAD_HS_CERTIFICATE                -0xA800
+#define XYSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST        -0xB000
+#define XYSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE        -0xB800
+#define XYSSL_ERR_SSL_BAD_HS_SERVER_HELLO_DONE          -0xC000
+#define XYSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE        -0xC800
+#define XYSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY         -0xD000
+#define XYSSL_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC         -0xD800
+#define XYSSL_ERR_SSL_BAD_HS_FINISHED                   -0xE000
+
+/*
+ * Various constants
+ */
+#define SSL_MAJOR_VERSION_3             3
+#define SSL_MINOR_VERSION_0             0   /*!< SSL v3.0 */
+#define SSL_MINOR_VERSION_1             1   /*!< TLS v1.0 */
+#define SSL_MINOR_VERSION_2             2   /*!< TLS v1.1 */
+
+#define SSL_IS_CLIENT                   0
+#define SSL_IS_SERVER                   1
+#define SSL_COMPRESS_NULL               0
+
+#define SSL_VERIFY_NONE                 0
+#define SSL_VERIFY_OPTIONAL             1
+#define SSL_VERIFY_REQUIRED             2
+
+#define SSL_MAX_CONTENT_LEN         16384
+
+/*
+ * Allow an extra 512 bytes for the record header
+ * and encryption overhead (counter + MAC + padding).
+ */
+#define SSL_BUFFER_LEN (SSL_MAX_CONTENT_LEN + 512)
+
+/*
+ * Supported ciphersuites
+ */
+#define SSL_RSA_RC4_128_MD5              4
+#define SSL_RSA_RC4_128_SHA              5
+#define SSL_RSA_DES_168_SHA             10
+#define SSL_EDH_RSA_DES_168_SHA         22
+#define SSL_RSA_AES_128_SHA             47
+#define SSL_RSA_AES_256_SHA             53
+#define SSL_EDH_RSA_AES_256_SHA         57
+
+/*
+ * Message, alert and handshake types
+ */
+#define SSL_MSG_CHANGE_CIPHER_SPEC     20
+#define SSL_MSG_ALERT                  21
+#define SSL_MSG_HANDSHAKE              22
+#define SSL_MSG_APPLICATION_DATA       23
+
+#define SSL_ALERT_CLOSE_NOTIFY          0
+#define SSL_ALERT_WARNING               1
+#define SSL_ALERT_FATAL                 2
+#define SSL_ALERT_NO_CERTIFICATE       41
+
+#define SSL_HS_HELLO_REQUEST            0
+#define SSL_HS_CLIENT_HELLO             1
+#define SSL_HS_SERVER_HELLO             2
+#define SSL_HS_CERTIFICATE             11
+#define SSL_HS_SERVER_KEY_EXCHANGE     12
+#define SSL_HS_CERTIFICATE_REQUEST     13
+#define SSL_HS_SERVER_HELLO_DONE       14
+#define SSL_HS_CERTIFICATE_VERIFY      15
+#define SSL_HS_CLIENT_KEY_EXCHANGE     16
+#define SSL_HS_FINISHED                20
+
+/*
+ * TLS extensions
+ */
+#define TLS_EXT_SERVERNAME              0
+#define TLS_EXT_SERVERNAME_HOSTNAME     0
+
+/*
+ * SSL state machine
+ */
+typedef enum
+{
+    SSL_HELLO_REQUEST,
+    SSL_CLIENT_HELLO,
+    SSL_SERVER_HELLO,
+    SSL_SERVER_CERTIFICATE,
+    SSL_SERVER_KEY_EXCHANGE,
+    SSL_CERTIFICATE_REQUEST,
+    SSL_SERVER_HELLO_DONE,
+    SSL_CLIENT_CERTIFICATE,
+    SSL_CLIENT_KEY_EXCHANGE,
+    SSL_CERTIFICATE_VERIFY,
+    SSL_CLIENT_CHANGE_CIPHER_SPEC,
+    SSL_CLIENT_FINISHED,
+    SSL_SERVER_CHANGE_CIPHER_SPEC,
+    SSL_SERVER_FINISHED,
+    SSL_FLUSH_BUFFERS,
+    SSL_HANDSHAKE_OVER
+}
+ssl_states;
+
+typedef struct _ssl_session ssl_session;
+typedef struct _ssl_context ssl_context;
+
+/*
+ * This structure is used for session resuming.
+ */
+struct _ssl_session
+{
+    time_t start;               /*!< starting time      */
+    int cipher;                 /*!< chosen cipher      */
+    int length;                 /*!< session id length  */
+    unsigned char id[32];       /*!< session identifier */
+    unsigned char master[48];   /*!< the master secret  */
+    ssl_session *next;          /*!< next session entry */
+};
+
+struct _ssl_context
+{
+    /*
+     * Miscellaneous
+     */
+    int state;                  /*!< SSL handshake: current state     */
+
+    int major_ver;              /*!< equal to  SSL_MAJOR_VERSION_3    */
+    int minor_ver;              /*!< either 0 (SSL3) or 1 (TLS1.0)    */
+
+    int max_major_ver;          /*!< max. major version from client   */
+    int max_minor_ver;          /*!< max. minor version from client   */
+
+    /*
+     * Callbacks (RNG, debug, I/O)
+     */
+    int  (*f_rng)(void *);
+    void (*f_dbg)(void *, int, char *);
+    int (*f_recv)(void *, unsigned char *, int);
+    int (*f_send)(void *, unsigned char *, int);
+
+    void *p_rng;                /*!< context for the RNG function     */
+    void *p_dbg;                /*!< context for the debug function   */
+    void *p_recv;               /*!< context for reading operations   */
+    void *p_send;               /*!< context for writing operations   */
+
+    /*
+     * Session layer
+     */
+    int resume;                         /*!<  session resuming flag   */
+    int timeout;                        /*!<  sess. expiration time   */
+    ssl_session *session;               /*!<  current session data    */
+    int (*s_get)(ssl_context *);        /*!<  (server) get callback   */
+    int (*s_set)(ssl_context *);        /*!<  (server) set callback   */
+
+    /*
+     * Record layer (incoming data)
+     */
+    unsigned char *in_ctr;      /*!< 64-bit incoming message counter  */
+    unsigned char *in_hdr;      /*!< 5-byte record header (in_ctr+8)  */
+    unsigned char *in_msg;      /*!< the message contents (in_hdr+5)  */
+    unsigned char *in_offt;     /*!< read offset in application data  */
+
+    int in_msgtype;             /*!< record header: message type      */
+    int in_msglen;              /*!< record header: message length    */
+    int in_left;                /*!< amount of data read so far       */
+
+    int in_hslen;               /*!< current handshake message length */
+    int nb_zero;                /*!< # of 0-length encrypted messages */
+
+    /*
+     * Record layer (outgoing data)
+     */
+    unsigned char *out_ctr;     /*!< 64-bit outgoing message counter  */
+    unsigned char *out_hdr;     /*!< 5-byte record header (out_ctr+8) */
+    unsigned char *out_msg;     /*!< the message contents (out_hdr+5) */
+
+    int out_msgtype;            /*!< record header: message type      */
+    int out_msglen;             /*!< record header: message length    */
+    int out_left;               /*!< amount of data not yet written   */
+
+    /*
+     * PKI layer
+     */
+    rsa_context *rsa_key;               /*!<  own RSA private key     */
+    x509_cert *own_cert;                /*!<  own X.509 certificate   */
+    x509_cert *ca_chain;                /*!<  own trusted CA chain    */
+    x509_cert *peer_cert;               /*!<  peer X.509 cert chain   */
+    char *peer_cn;                      /*!<  expected peer CN        */
+
+    int endpoint;                       /*!<  0: client, 1: server    */
+    int authmode;                       /*!<  verification mode       */
+    int client_auth;                    /*!<  flag for client auth.   */
+    int verify_result;                  /*!<  verification result     */
+
+    /*
+     * Crypto layer
+     */
+     dhm_context dhm_ctx;               /*!<  DHM key exchange        */
+     md5_context fin_md5;               /*!<  Finished MD5 checksum   */
+    sha1_context fin_sha1;              /*!<  Finished SHA-1 checksum */
+
+    int do_crypt;                       /*!<  en(de)cryption flag     */
+    int *ciphers;                       /*!<  allowed ciphersuites    */
+    int pmslen;                         /*!<  premaster length        */
+    int keylen;                         /*!<  symmetric key length    */
+    int minlen;                         /*!<  min. ciphertext length  */
+    int ivlen;                          /*!<  IV length               */
+    int maclen;                         /*!<  MAC length              */
+
+    unsigned char randbytes[64];        /*!<  random bytes            */
+    unsigned char premaster[256];       /*!<  premaster secret        */
+
+    unsigned char iv_enc[16];           /*!<  IV (encryption)         */
+    unsigned char iv_dec[16];           /*!<  IV (decryption)         */
+
+    unsigned char mac_enc[32];          /*!<  MAC (encryption)        */
+    unsigned char mac_dec[32];          /*!<  MAC (decryption)        */
+
+    unsigned long ctx_enc[128];         /*!<  encryption context      */
+    unsigned long ctx_dec[128];         /*!<  decryption context      */
+
+    /*
+     * TLS extensions
+     */
+    unsigned char *hostname;
+    unsigned long  hostname_len;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int ssl_default_ciphers[];
+
+/**
+ * \brief          Initialize an SSL context
+ *
+ * \param ssl      SSL context
+ *
+ * \return         0 if successful, or 1 if memory allocation failed
+ */
+int ssl_init( ssl_context *ssl );
+
+/**
+ * \brief          Set the current endpoint type
+ *
+ * \param ssl      SSL context
+ * \param endpoint must be SSL_IS_CLIENT or SSL_IS_SERVER
+ */
+void ssl_set_endpoint( ssl_context *ssl, int endpoint );
+
+/**
+ * \brief          Set the certificate verification mode
+ *
+ * \param ssl      SSL context
+ * \param mode     can be:
+ *
+ *  SSL_VERIFY_NONE:      peer certificate is not checked (default),
+ *                        this is insecure and SHOULD be avoided.
+ *
+ *  SSL_VERIFY_OPTIONAL:  peer certificate is checked, however the
+ *                        handshake continues even if verification failed;
+ *                        ssl_get_verify_result() can be called after the
+ *                        handshake is complete.
+ *
+ *  SSL_VERIFY_REQUIRED:  peer *must* present a valid certificate,
+ *                        handshake is aborted if verification failed.
+ */
+void ssl_set_authmode( ssl_context *ssl, int authmode );
+
+/**
+ * \brief          Set the random number generator callback
+ *
+ * \param ssl      SSL context
+ * \param f_rng    RNG function
+ * \param p_rng    RNG parameter
+ */
+void ssl_set_rng( ssl_context *ssl,
+                  int (*f_rng)(void *),
+                  void *p_rng );
+
+/**
+ * \brief          Set the debug callback
+ *
+ * \param ssl      SSL context
+ * \param f_dbg    debug function
+ * \param p_dbg    debug parameter
+ */
+void ssl_set_dbg( ssl_context *ssl,
+                  void (*f_dbg)(void *, int, char *),
+                  void  *p_dbg );
+
+/**
+ * \brief          Set the underlying BIO read and write callbacks
+ *
+ * \param ssl      SSL context
+ * \param f_recv   read callback
+ * \param p_recv   read parameter
+ * \param f_send   write callback
+ * \param p_send   write parameter
+ */
+void ssl_set_bio( ssl_context *ssl,
+        int (*f_recv)(void *, unsigned char *, int), void *p_recv,
+        int (*f_send)(void *, unsigned char *, int), void *p_send );
+
+/**
+ * \brief          Set the session callbacks (server-side only)
+ *
+ * \param ssl      SSL context
+ * \param s_get    session get callback
+ * \param s_set    session set callback
+ */
+void ssl_set_scb( ssl_context *ssl,
+                  int (*s_get)(ssl_context *),
+                  int (*s_set)(ssl_context *) );
+
+/**
+ * \brief          Set the session resuming flag, timeout and data
+ *
+ * \param ssl      SSL context
+ * \param resume   if 0 (default), the session will not be resumed
+ * \param timeout  session timeout in seconds, or 0 (no timeout)
+ * \param session  session context
+ */
+void ssl_set_session( ssl_context *ssl, int resume, int timeout,
+                      ssl_session *session );
+
+/**
+ * \brief          Set the list of allowed ciphersuites
+ *
+ * \param ssl      SSL context
+ * \param ciphers  0-terminated list of allowed ciphers
+ */
+void ssl_set_ciphers( ssl_context *ssl, int *ciphers );
+
+/**
+ * \brief          Set the data required to verify peer certificate
+ *
+ * \param ssl      SSL context
+ * \param ca_chain trusted CA chain
+ * \param peer_cn  expected peer CommonName (or NULL)
+ *
+ * \note           TODO: add two more parameters: depth and crl
+ */
+void ssl_set_ca_chain( ssl_context *ssl, x509_cert *ca_chain,
+                       char *peer_cn );
+
+/**
+ * \brief          Set own certificate and private key
+ *
+ * \param ssl      SSL context
+ * \param own_cert own public certificate
+ * \param rsa_key  own private RSA key
+ */
+void ssl_set_own_cert( ssl_context *ssl, x509_cert *own_cert,
+                       rsa_context *rsa_key );
+
+/**
+ * \brief          Set the Diffie-Hellman public P and G values,
+ *                 read as hexadecimal strings (server-side only)
+ *
+ * \param ssl      SSL context
+ * \param dhm_P    Diffie-Hellman-Merkle modulus
+ * \param dhm_G    Diffie-Hellman-Merkle generator
+ *
+ * \return         0 if successful
+ */
+int ssl_set_dh_param( ssl_context *ssl, char *dhm_P, char *dhm_G );
+
+/**
+ * \brief          Set hostname for ServerName TLS Extension
+ *                 
+ *
+ * \param ssl      SSL context
+ * \param hostname the server hostname
+ *
+ * \return         0 if successful
+ */
+int ssl_set_hostname( ssl_context *ssl, char *hostname );
+
+/**
+ * \brief          Return the number of data bytes available to read
+ *
+ * \param ssl      SSL context
+ *
+ * \return         how many bytes are available in the read buffer
+ */
+int ssl_get_bytes_avail( ssl_context *ssl );
+
+/**
+ * \brief          Return the result of the certificate verification
+ *
+ * \param ssl      SSL context
+ *
+ * \return         0 if successful, or a combination of:
+ *                      BADCERT_EXPIRED
+ *                      BADCERT_REVOKED
+ *                      BADCERT_CN_MISMATCH
+ *                      BADCERT_NOT_TRUSTED
+ */
+int ssl_get_verify_result( ssl_context *ssl );
+
+/**
+ * \brief          Return the name of the current cipher
+ *
+ * \param ssl      SSL context
+ *
+ * \return         a string containing the cipher name
+ */
+char *ssl_get_cipher( ssl_context *ssl );
+
+/**
+ * \brief          Perform the SSL handshake
+ *
+ * \param ssl      SSL context
+ *
+ * \return         0 if successful, XYSSL_ERR_NET_TRY_AGAIN,
+ *                 or a specific SSL error code.
+ */
+int ssl_handshake( ssl_context *ssl );
+
+/**
+ * \brief          Read at most 'len' application data bytes
+ *
+ * \param ssl      SSL context
+ * \param buf      buffer that will hold the data
+ * \param len      how many bytes must be read
+ *
+ * \return         This function returns the number of bytes read,
+ *                 or a negative error code.
+ */
+int ssl_read( ssl_context *ssl, unsigned char *buf, int len );
+
+/**
+ * \brief          Write exactly 'len' application data bytes
+ *
+ * \param ssl      SSL context
+ * \param buf      buffer holding the data
+ * \param len      how many bytes must be written
+ *
+ * \return         This function returns the number of bytes written,
+ *                 or a negative error code.
+ *
+ * \note           When this function returns XYSSL_ERR_NET_TRY_AGAIN,
+ *                 it must be called later with the *same* arguments,
+ *                 until it returns a positive value.
+ */
+int ssl_write( ssl_context *ssl, unsigned char *buf, int len );
+
+/**
+ * \brief          Notify the peer that the connection is being closed
+ */
+int ssl_close_notify( ssl_context *ssl );
+
+/**
+ * \brief          Free an SSL context
+ */
+void ssl_free( ssl_context *ssl );
+
+/*
+ * Internal functions (do not call directly)
+ */
+int ssl_handshake_client( ssl_context *ssl );
+int ssl_handshake_server( ssl_context *ssl );
+
+int ssl_derive_keys( ssl_context *ssl );
+void ssl_calc_verify( ssl_context *ssl, unsigned char hash[36] );
+
+int ssl_read_record( ssl_context *ssl );
+int ssl_fetch_input( ssl_context *ssl, int nb_want );
+
+int ssl_write_record( ssl_context *ssl );
+int ssl_flush_output( ssl_context *ssl );
+
+int ssl_parse_certificate( ssl_context *ssl );
+int ssl_write_certificate( ssl_context *ssl );
+
+int ssl_parse_change_cipher_spec( ssl_context *ssl );
+int ssl_write_change_cipher_spec( ssl_context *ssl );
+
+int ssl_parse_finished( ssl_context *ssl );
+int ssl_write_finished( ssl_context *ssl );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ssl.h */
diff --git a/include/polarssl/timing.h b/include/polarssl/timing.h
new file mode 100644
index 0000000..32e53e8
--- /dev/null
+++ b/include/polarssl/timing.h
@@ -0,0 +1,50 @@
+/**
+ * \file timing.h
+ */
+#ifndef XYSSL_TIMING_H
+#define XYSSL_TIMING_H
+
+/**
+ * \brief          timer structure
+ */
+struct hr_time
+{
+    unsigned char opaque[32];
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int alarmed;
+
+/**
+ * \brief          Return the CPU cycle counter value
+ */
+unsigned long hardclock( void );
+
+/**
+ * \brief          Return the elapsed time in milliseconds
+ *
+ * \param val      points to a timer structure
+ * \param reset    if set to 1, the timer is restarted
+ */
+unsigned long get_timer( struct hr_time *val, int reset );
+
+/**
+ * \brief          Setup an alarm clock
+ *
+ * \param seconds  delay before the "alarmed" flag is set
+ */
+void set_alarm( int seconds );
+
+/**
+ * \brief          Sleep for a certain amount of time
+ */
+void m_sleep( int milliseconds );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* timing.h */
diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h
new file mode 100644
index 0000000..0ada355
--- /dev/null
+++ b/include/polarssl/x509.h
@@ -0,0 +1,295 @@
+/**
+ * \file x509.h
+ */
+#ifndef XYSSL_X509_H
+#define XYSSL_X509_H
+
+#include "xyssl/rsa.h"
+
+#define XYSSL_ERR_ASN1_OUT_OF_DATA                      -0x0014
+#define XYSSL_ERR_ASN1_UNEXPECTED_TAG                   -0x0016
+#define XYSSL_ERR_ASN1_INVALID_LENGTH                   -0x0018
+#define XYSSL_ERR_ASN1_LENGTH_MISMATCH                  -0x001A
+#define XYSSL_ERR_ASN1_INVALID_DATA                     -0x001C
+
+#define XYSSL_ERR_X509_FEATURE_UNAVAILABLE              -0x0020
+#define XYSSL_ERR_X509_CERT_INVALID_PEM                 -0x0040
+#define XYSSL_ERR_X509_CERT_INVALID_FORMAT              -0x0060
+#define XYSSL_ERR_X509_CERT_INVALID_VERSION             -0x0080
+#define XYSSL_ERR_X509_CERT_INVALID_SERIAL              -0x00A0
+#define XYSSL_ERR_X509_CERT_INVALID_ALG                 -0x00C0
+#define XYSSL_ERR_X509_CERT_INVALID_NAME                -0x00E0
+#define XYSSL_ERR_X509_CERT_INVALID_DATE                -0x0100
+#define XYSSL_ERR_X509_CERT_INVALID_PUBKEY              -0x0120
+#define XYSSL_ERR_X509_CERT_INVALID_SIGNATURE           -0x0140
+#define XYSSL_ERR_X509_CERT_INVALID_EXTENSIONS          -0x0160
+#define XYSSL_ERR_X509_CERT_UNKNOWN_VERSION             -0x0180
+#define XYSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG             -0x01A0
+#define XYSSL_ERR_X509_CERT_UNKNOWN_PK_ALG              -0x01C0
+#define XYSSL_ERR_X509_CERT_SIG_MISMATCH                -0x01E0
+#define XYSSL_ERR_X509_CERT_VERIFY_FAILED               -0x0200
+#define XYSSL_ERR_X509_KEY_INVALID_PEM                  -0x0220
+#define XYSSL_ERR_X509_KEY_INVALID_VERSION              -0x0240
+#define XYSSL_ERR_X509_KEY_INVALID_FORMAT               -0x0260
+#define XYSSL_ERR_X509_KEY_INVALID_ENC_IV               -0x0280
+#define XYSSL_ERR_X509_KEY_UNKNOWN_ENC_ALG              -0x02A0
+#define XYSSL_ERR_X509_KEY_PASSWORD_REQUIRED            -0x02C0
+#define XYSSL_ERR_X509_KEY_PASSWORD_MISMATCH            -0x02E0
+#define XYSSL_ERR_X509_POINT_ERROR                      -0x0300
+#define XYSSL_ERR_X509_VALUE_TO_LENGTH                  -0x0320
+
+#define BADCERT_EXPIRED                 1
+#define BADCERT_REVOKED                 2
+#define BADCERT_CN_MISMATCH             4
+#define BADCERT_NOT_TRUSTED             8
+
+/*
+ * DER constants
+ */
+#define ASN1_BOOLEAN                 0x01
+#define ASN1_INTEGER                 0x02
+#define ASN1_BIT_STRING              0x03
+#define ASN1_OCTET_STRING            0x04
+#define ASN1_NULL                    0x05
+#define ASN1_OID                     0x06
+#define ASN1_UTF8_STRING             0x0C
+#define ASN1_SEQUENCE                0x10
+#define ASN1_SET                     0x11
+#define ASN1_PRINTABLE_STRING        0x13
+#define ASN1_T61_STRING              0x14
+#define ASN1_IA5_STRING              0x16
+#define ASN1_UTC_TIME                0x17
+#define ASN1_UNIVERSAL_STRING        0x1C
+#define ASN1_BMP_STRING              0x1E
+#define ASN1_PRIMITIVE               0x00
+#define ASN1_CONSTRUCTED             0x20
+#define ASN1_CONTEXT_SPECIFIC        0x80
+
+/*
+ * various object identifiers
+ */
+#define X520_COMMON_NAME                3
+#define X520_COUNTRY                    6
+#define X520_LOCALITY                   7
+#define X520_STATE                      8
+#define X520_ORGANIZATION              10
+#define X520_ORG_UNIT                  11
+#define PKCS9_EMAIL                     1
+
+#define X509_OUTPUT_DER              0x01
+#define X509_OUTPUT_PEM              0x02
+#define PEM_LINE_LENGTH                72
+#define X509_ISSUER                  0x01
+#define X509_SUBJECT                 0x02
+
+#define OID_X520                "\x55\x04"
+#define OID_CN                  "\x55\x04\x03"
+#define OID_PKCS1               "\x2A\x86\x48\x86\xF7\x0D\x01\x01"
+#define OID_PKCS1_RSA           "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01"
+#define OID_PKCS1_RSA_SHA       "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05"
+#define OID_PKCS9               "\x2A\x86\x48\x86\xF7\x0D\x01\x09"
+#define OID_PKCS9_EMAIL         "\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01"
+
+/*
+ * Structures for parsing X.509 certificates
+ */
+typedef struct _x509_buf
+{
+    int tag;
+    int len;
+    unsigned char *p;
+}
+x509_buf;
+
+typedef struct _x509_name
+{
+    x509_buf oid;
+    x509_buf val;
+    struct _x509_name *next;
+}
+x509_name;
+
+typedef struct _x509_time
+{
+    int year, mon, day;
+    int hour, min, sec;
+}
+x509_time;
+
+typedef struct _x509_cert
+{
+    x509_buf raw;
+    x509_buf tbs;
+
+    int version;
+    x509_buf serial;
+    x509_buf sig_oid1;
+
+    x509_buf issuer_raw;
+    x509_buf subject_raw;
+
+    x509_name issuer;
+    x509_name subject;
+
+    x509_time valid_from;
+    x509_time valid_to;
+
+    x509_buf pk_oid;
+    rsa_context rsa;
+
+    x509_buf issuer_id;
+    x509_buf subject_id;
+    x509_buf v3_ext;
+
+    int ca_istrue;
+    int max_pathlen;
+
+    x509_buf sig_oid2;
+    x509_buf sig;
+
+    struct _x509_cert *next; 
+}
+x509_cert;
+
+/*
+ * Structures for writing X.509 certificates
+ */
+typedef struct _x509_node
+{
+    unsigned char *data;
+    unsigned char *p;
+    unsigned char *end;
+
+    size_t len;
+}
+x509_node;
+
+typedef struct _x509_raw
+{
+    x509_node raw;
+    x509_node tbs;
+
+    x509_node version;
+    x509_node serial;
+    x509_node tbs_signalg;
+    x509_node issuer;
+    x509_node validity;
+    x509_node subject;
+    x509_node subpubkey;
+
+    x509_node signalg;
+    x509_node sign;
+}
+x509_raw;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Parse one or more certificates and add them
+ *                 to the chained list
+ *
+ * \param chain    points to the start of the chain
+ * \param buf      buffer holding the certificate data
+ * \param buflen   size of the buffer
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509parse_crt( x509_cert *crt, unsigned char *buf, int buflen );
+
+/**
+ * \brief          Load one or more certificates and add them
+ *                 to the chained list
+ *
+ * \param chain    points to the start of the chain
+ * \param path     filename to read the certificates from
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509parse_crtfile( x509_cert *crt, char *path );
+
+/**
+ * \brief          Parse a private RSA key
+ *
+ * \param rsa      RSA context to be initialized
+ * \param buf      input buffer
+ * \param buflen   size of the buffer
+ * \param pwd      password for decryption (optional)
+ * \param pwdlen   size of the password
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509parse_key( rsa_context *rsa,
+                   unsigned char *buf, int buflen,
+                   unsigned char *pwd, int pwdlen );
+
+/**
+ * \brief          Load and parse a private RSA key
+ *
+ * \param rsa      RSA context to be initialized
+ * \param path     filename to read the private key from
+ * \param pwd      password to decrypt the file (can be NULL)
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509parse_keyfile( rsa_context *rsa, char *path, char *password );
+
+/**
+ * \brief          Store the certificate DN in printable form into buf;
+ *                 no more than (end - buf) characters will be written.
+ */
+int x509parse_dn_gets( char *buf, char *end, x509_name *dn );
+
+/**
+ * \brief          Returns an informational string about the
+ *                 certificate.
+ */
+char *x509parse_cert_info( char *prefix, x509_cert *crt );
+
+/**
+ * \brief          Return 0 if the certificate is still valid,
+ *                 or BADCERT_EXPIRED
+ */
+int x509parse_expired( x509_cert *crt );
+
+/**
+ * \brief          Verify the certificate signature
+ *
+ * \param crt      a certificate to be verified
+ * \param trust_ca the trusted CA chain
+ * \param cn       expected Common Name (can be set to
+ *                 NULL if the CN must not be verified)
+ * \param flags    result of the verification
+ *
+ * \return         0 if successful or XYSSL_ERR_X509_SIG_VERIFY_FAILED,
+ *                 in which case *flags will have one or more of
+ *                 the following values set:
+ *                      BADCERT_EXPIRED --
+ *                      BADCERT_REVOKED --
+ *                      BADCERT_CN_MISMATCH --
+ *                      BADCERT_NOT_TRUSTED
+ *
+ * \note           TODO: add two arguments, depth and crl
+ */
+int x509parse_verify( x509_cert *crt,
+                      x509_cert *trust_ca,
+                      char *cn, int *flags );
+
+/**
+ * \brief          Unallocate all certificate data
+ */
+void x509_free( x509_cert *crt );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int x509_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* x509.h */
diff --git a/library/Makefile b/library/Makefile
new file mode 100644
index 0000000..aef615d
--- /dev/null
+++ b/library/Makefile
@@ -0,0 +1,57 @@
+
+# Also see "include/xyssl/config.h"
+
+CFLAGS	= -I../include -D_FILE_OFFSET_BITS=64
+OFLAGS	= -O
+
+# MicroBlaze specific options:
+# CFLAGS += -mno-xl-soft-mul -mxl-barrel-shift
+
+# To compile on Plan9:
+# CFLAGS += -D_BSD_EXTENSION
+
+# To compile as a shared library:
+# CFLAGS += -fPIC
+
+DLEXT=so
+# OSX shared library extension:
+# DLEXT=dylib
+
+OBJS=	aes.o		arc4.o		base64.o	\
+	bignum.o	certs.o		debug.o		\
+	des.o		dhm.o		havege.o	\
+	md2.o		md4.o		md5.o		\
+	net.o		padlock.o	rsa.o		\
+	sha1.o		sha2.o		sha4.o		\
+	ssl_cli.o	ssl_srv.o	ssl_tls.o	\
+	timing.o	x509parse.o
+
+.SILENT:
+
+all: static
+
+static: libxyssl.a
+
+shared: libxyssl.$(DLEXT)
+
+libxyssl.a: $(OBJS)
+	echo "  AR    $@"
+	ar r $@ $(OBJS)
+	echo "  RL    $@"
+	ranlib $@
+
+libxyssl.so: libxyssl.a
+	echo "  LD    $@"
+	$(CC) -shared -Wl,-soname,$@ -o $@ $(OBJS)
+
+libxyssl.dylib: libxyssl.a
+	echo "  LD    $@"
+	$(CC) -dynamiclib -o $@ $(OBJS)
+
+.c.o:
+	echo "  CC    $<"
+	$(CC) $(CFLAGS) $(OFLAGS) -c $<
+
+clean:
+	rm -f *.o libxyssl.*
+
diff --git a/library/aes.c b/library/aes.c
new file mode 100644
index 0000000..84fb037
--- /dev/null
+++ b/library/aes.c
@@ -0,0 +1,1134 @@
+/*
+ *  FIPS-197 compliant AES implementation
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  The AES block cipher was designed by Vincent Rijmen and Joan Daemen.
+ *
+ *  http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf
+ *  http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_AES_C)
+
+#include "xyssl/aes.h"
+#include "xyssl/padlock.h"
+
+#include <string.h>
+
+/*
+ * 32-bit integer manipulation macros (little endian)
+ */
+#ifndef GET_ULONG_LE
+#define GET_ULONG_LE(n,b,i)                             \
+{                                                       \
+    (n) = ( (unsigned long) (b)[(i)    ]       )        \
+        | ( (unsigned long) (b)[(i) + 1] <<  8 )        \
+        | ( (unsigned long) (b)[(i) + 2] << 16 )        \
+        | ( (unsigned long) (b)[(i) + 3] << 24 );       \
+}
+#endif
+
+#ifndef PUT_ULONG_LE
+#define PUT_ULONG_LE(n,b,i)                             \
+{                                                       \
+    (b)[(i)    ] = (unsigned char) ( (n)       );       \
+    (b)[(i) + 1] = (unsigned char) ( (n) >>  8 );       \
+    (b)[(i) + 2] = (unsigned char) ( (n) >> 16 );       \
+    (b)[(i) + 3] = (unsigned char) ( (n) >> 24 );       \
+}
+#endif
+
+#if defined(XYSSL_AES_ROM_TABLES)
+/*
+ * Forward S-box
+ */
+static const unsigned char FSb[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
+};
+
+/*
+ * Forward tables
+ */
+#define FT \
+\
+    V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \
+    V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \
+    V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \
+    V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \
+    V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \
+    V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \
+    V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \
+    V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \
+    V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \
+    V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \
+    V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \
+    V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \
+    V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \
+    V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \
+    V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \
+    V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \
+    V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \
+    V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \
+    V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \
+    V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \
+    V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \
+    V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \
+    V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \
+    V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \
+    V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \
+    V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \
+    V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \
+    V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \
+    V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \
+    V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \
+    V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \
+    V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \
+    V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \
+    V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \
+    V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \
+    V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \
+    V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \
+    V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \
+    V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \
+    V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \
+    V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \
+    V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \
+    V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \
+    V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \
+    V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \
+    V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \
+    V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \
+    V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \
+    V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \
+    V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \
+    V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \
+    V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \
+    V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \
+    V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \
+    V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \
+    V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \
+    V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \
+    V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \
+    V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \
+    V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \
+    V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \
+    V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \
+    V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \
+    V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C)
+
+#define V(a,b,c,d) 0x##a##b##c##d
+static const unsigned long FT0[256] = { FT };
+#undef V
+
+#define V(a,b,c,d) 0x##b##c##d##a
+static const unsigned long FT1[256] = { FT };
+#undef V
+
+#define V(a,b,c,d) 0x##c##d##a##b
+static const unsigned long FT2[256] = { FT };
+#undef V
+
+#define V(a,b,c,d) 0x##d##a##b##c
+static const unsigned long FT3[256] = { FT };
+#undef V
+
+#undef FT
+
+/*
+ * Reverse S-box
+ */
+static const unsigned char RSb[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
+};
+
+/*
+ * Reverse tables
+ */
+#define RT \
+\
+    V(50,A7,F4,51), V(53,65,41,7E), V(C3,A4,17,1A), V(96,5E,27,3A), \
+    V(CB,6B,AB,3B), V(F1,45,9D,1F), V(AB,58,FA,AC), V(93,03,E3,4B), \
+    V(55,FA,30,20), V(F6,6D,76,AD), V(91,76,CC,88), V(25,4C,02,F5), \
+    V(FC,D7,E5,4F), V(D7,CB,2A,C5), V(80,44,35,26), V(8F,A3,62,B5), \
+    V(49,5A,B1,DE), V(67,1B,BA,25), V(98,0E,EA,45), V(E1,C0,FE,5D), \
+    V(02,75,2F,C3), V(12,F0,4C,81), V(A3,97,46,8D), V(C6,F9,D3,6B), \
+    V(E7,5F,8F,03), V(95,9C,92,15), V(EB,7A,6D,BF), V(DA,59,52,95), \
+    V(2D,83,BE,D4), V(D3,21,74,58), V(29,69,E0,49), V(44,C8,C9,8E), \
+    V(6A,89,C2,75), V(78,79,8E,F4), V(6B,3E,58,99), V(DD,71,B9,27), \
+    V(B6,4F,E1,BE), V(17,AD,88,F0), V(66,AC,20,C9), V(B4,3A,CE,7D), \
+    V(18,4A,DF,63), V(82,31,1A,E5), V(60,33,51,97), V(45,7F,53,62), \
+    V(E0,77,64,B1), V(84,AE,6B,BB), V(1C,A0,81,FE), V(94,2B,08,F9), \
+    V(58,68,48,70), V(19,FD,45,8F), V(87,6C,DE,94), V(B7,F8,7B,52), \
+    V(23,D3,73,AB), V(E2,02,4B,72), V(57,8F,1F,E3), V(2A,AB,55,66), \
+    V(07,28,EB,B2), V(03,C2,B5,2F), V(9A,7B,C5,86), V(A5,08,37,D3), \
+    V(F2,87,28,30), V(B2,A5,BF,23), V(BA,6A,03,02), V(5C,82,16,ED), \
+    V(2B,1C,CF,8A), V(92,B4,79,A7), V(F0,F2,07,F3), V(A1,E2,69,4E), \
+    V(CD,F4,DA,65), V(D5,BE,05,06), V(1F,62,34,D1), V(8A,FE,A6,C4), \
+    V(9D,53,2E,34), V(A0,55,F3,A2), V(32,E1,8A,05), V(75,EB,F6,A4), \
+    V(39,EC,83,0B), V(AA,EF,60,40), V(06,9F,71,5E), V(51,10,6E,BD), \
+    V(F9,8A,21,3E), V(3D,06,DD,96), V(AE,05,3E,DD), V(46,BD,E6,4D), \
+    V(B5,8D,54,91), V(05,5D,C4,71), V(6F,D4,06,04), V(FF,15,50,60), \
+    V(24,FB,98,19), V(97,E9,BD,D6), V(CC,43,40,89), V(77,9E,D9,67), \
+    V(BD,42,E8,B0), V(88,8B,89,07), V(38,5B,19,E7), V(DB,EE,C8,79), \
+    V(47,0A,7C,A1), V(E9,0F,42,7C), V(C9,1E,84,F8), V(00,00,00,00), \
+    V(83,86,80,09), V(48,ED,2B,32), V(AC,70,11,1E), V(4E,72,5A,6C), \
+    V(FB,FF,0E,FD), V(56,38,85,0F), V(1E,D5,AE,3D), V(27,39,2D,36), \
+    V(64,D9,0F,0A), V(21,A6,5C,68), V(D1,54,5B,9B), V(3A,2E,36,24), \
+    V(B1,67,0A,0C), V(0F,E7,57,93), V(D2,96,EE,B4), V(9E,91,9B,1B), \
+    V(4F,C5,C0,80), V(A2,20,DC,61), V(69,4B,77,5A), V(16,1A,12,1C), \
+    V(0A,BA,93,E2), V(E5,2A,A0,C0), V(43,E0,22,3C), V(1D,17,1B,12), \
+    V(0B,0D,09,0E), V(AD,C7,8B,F2), V(B9,A8,B6,2D), V(C8,A9,1E,14), \
+    V(85,19,F1,57), V(4C,07,75,AF), V(BB,DD,99,EE), V(FD,60,7F,A3), \
+    V(9F,26,01,F7), V(BC,F5,72,5C), V(C5,3B,66,44), V(34,7E,FB,5B), \
+    V(76,29,43,8B), V(DC,C6,23,CB), V(68,FC,ED,B6), V(63,F1,E4,B8), \
+    V(CA,DC,31,D7), V(10,85,63,42), V(40,22,97,13), V(20,11,C6,84), \
+    V(7D,24,4A,85), V(F8,3D,BB,D2), V(11,32,F9,AE), V(6D,A1,29,C7), \
+    V(4B,2F,9E,1D), V(F3,30,B2,DC), V(EC,52,86,0D), V(D0,E3,C1,77), \
+    V(6C,16,B3,2B), V(99,B9,70,A9), V(FA,48,94,11), V(22,64,E9,47), \
+    V(C4,8C,FC,A8), V(1A,3F,F0,A0), V(D8,2C,7D,56), V(EF,90,33,22), \
+    V(C7,4E,49,87), V(C1,D1,38,D9), V(FE,A2,CA,8C), V(36,0B,D4,98), \
+    V(CF,81,F5,A6), V(28,DE,7A,A5), V(26,8E,B7,DA), V(A4,BF,AD,3F), \
+    V(E4,9D,3A,2C), V(0D,92,78,50), V(9B,CC,5F,6A), V(62,46,7E,54), \
+    V(C2,13,8D,F6), V(E8,B8,D8,90), V(5E,F7,39,2E), V(F5,AF,C3,82), \
+    V(BE,80,5D,9F), V(7C,93,D0,69), V(A9,2D,D5,6F), V(B3,12,25,CF), \
+    V(3B,99,AC,C8), V(A7,7D,18,10), V(6E,63,9C,E8), V(7B,BB,3B,DB), \
+    V(09,78,26,CD), V(F4,18,59,6E), V(01,B7,9A,EC), V(A8,9A,4F,83), \
+    V(65,6E,95,E6), V(7E,E6,FF,AA), V(08,CF,BC,21), V(E6,E8,15,EF), \
+    V(D9,9B,E7,BA), V(CE,36,6F,4A), V(D4,09,9F,EA), V(D6,7C,B0,29), \
+    V(AF,B2,A4,31), V(31,23,3F,2A), V(30,94,A5,C6), V(C0,66,A2,35), \
+    V(37,BC,4E,74), V(A6,CA,82,FC), V(B0,D0,90,E0), V(15,D8,A7,33), \
+    V(4A,98,04,F1), V(F7,DA,EC,41), V(0E,50,CD,7F), V(2F,F6,91,17), \
+    V(8D,D6,4D,76), V(4D,B0,EF,43), V(54,4D,AA,CC), V(DF,04,96,E4), \
+    V(E3,B5,D1,9E), V(1B,88,6A,4C), V(B8,1F,2C,C1), V(7F,51,65,46), \
+    V(04,EA,5E,9D), V(5D,35,8C,01), V(73,74,87,FA), V(2E,41,0B,FB), \
+    V(5A,1D,67,B3), V(52,D2,DB,92), V(33,56,10,E9), V(13,47,D6,6D), \
+    V(8C,61,D7,9A), V(7A,0C,A1,37), V(8E,14,F8,59), V(89,3C,13,EB), \
+    V(EE,27,A9,CE), V(35,C9,61,B7), V(ED,E5,1C,E1), V(3C,B1,47,7A), \
+    V(59,DF,D2,9C), V(3F,73,F2,55), V(79,CE,14,18), V(BF,37,C7,73), \
+    V(EA,CD,F7,53), V(5B,AA,FD,5F), V(14,6F,3D,DF), V(86,DB,44,78), \
+    V(81,F3,AF,CA), V(3E,C4,68,B9), V(2C,34,24,38), V(5F,40,A3,C2), \
+    V(72,C3,1D,16), V(0C,25,E2,BC), V(8B,49,3C,28), V(41,95,0D,FF), \
+    V(71,01,A8,39), V(DE,B3,0C,08), V(9C,E4,B4,D8), V(90,C1,56,64), \
+    V(61,84,CB,7B), V(70,B6,32,D5), V(74,5C,6C,48), V(42,57,B8,D0)
+
+#define V(a,b,c,d) 0x##a##b##c##d
+static const unsigned long RT0[256] = { RT };
+#undef V
+
+#define V(a,b,c,d) 0x##b##c##d##a
+static const unsigned long RT1[256] = { RT };
+#undef V
+
+#define V(a,b,c,d) 0x##c##d##a##b
+static const unsigned long RT2[256] = { RT };
+#undef V
+
+#define V(a,b,c,d) 0x##d##a##b##c
+static const unsigned long RT3[256] = { RT };
+#undef V
+
+#undef RT
+
+/*
+ * Round constants
+ */
+static const unsigned long RCON[10] =
+{
+    0x00000001, 0x00000002, 0x00000004, 0x00000008,
+    0x00000010, 0x00000020, 0x00000040, 0x00000080,
+    0x0000001B, 0x00000036
+};
+
+#else
+
+/*
+ * Forward S-box & tables
+ */
+static unsigned char FSb[256];
+static unsigned long FT0[256]; 
+static unsigned long FT1[256]; 
+static unsigned long FT2[256]; 
+static unsigned long FT3[256]; 
+
+/*
+ * Reverse S-box & tables
+ */
+static unsigned char RSb[256];
+static unsigned long RT0[256];
+static unsigned long RT1[256];
+static unsigned long RT2[256];
+static unsigned long RT3[256];
+
+/*
+ * Round constants
+ */
+static unsigned long RCON[10];
+
+/*
+ * Tables generation code
+ */
+#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 )
+#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) )
+#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 )
+
+static int aes_init_done = 0;
+
+static void aes_gen_tables( void )
+{
+    int i, x, y, z;
+    int pow[256];
+    int log[256];
+
+    /*
+     * compute pow and log tables over GF(2^8)
+     */
+    for( i = 0, x = 1; i < 256; i++ )
+    {
+        pow[i] = x;
+        log[x] = i;
+        x = ( x ^ XTIME( x ) ) & 0xFF;
+    }
+
+    /*
+     * calculate the round constants
+     */
+    for( i = 0, x = 1; i < 10; i++ )
+    {
+        RCON[i] = (unsigned long) x;
+        x = XTIME( x ) & 0xFF;
+    }
+
+    /*
+     * generate the forward and reverse S-boxes
+     */
+    FSb[0x00] = 0x63;
+    RSb[0x63] = 0x00;
+
+    for( i = 1; i < 256; i++ )
+    {
+        x = pow[255 - log[i]];
+
+        y  = x; y = ( (y << 1) | (y >> 7) ) & 0xFF;
+        x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF;
+        x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF;
+        x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF;
+        x ^= y ^ 0x63;
+
+        FSb[i] = (unsigned char) x;
+        RSb[x] = (unsigned char) i;
+    }
+
+    /*
+     * generate the forward and reverse tables
+     */
+    for( i = 0; i < 256; i++ )
+    {
+        x = FSb[i];
+        y = XTIME( x ) & 0xFF;
+        z =  ( y ^ x ) & 0xFF;
+
+        FT0[i] = ( (unsigned long) y       ) ^
+                 ( (unsigned long) x <<  8 ) ^
+                 ( (unsigned long) x << 16 ) ^
+                 ( (unsigned long) z << 24 );
+
+        FT1[i] = ROTL8( FT0[i] );
+        FT2[i] = ROTL8( FT1[i] );
+        FT3[i] = ROTL8( FT2[i] );
+
+        x = RSb[i];
+
+        RT0[i] = ( (unsigned long) MUL( 0x0E, x )       ) ^
+                 ( (unsigned long) MUL( 0x09, x ) <<  8 ) ^
+                 ( (unsigned long) MUL( 0x0D, x ) << 16 ) ^
+                 ( (unsigned long) MUL( 0x0B, x ) << 24 );
+
+        RT1[i] = ROTL8( RT0[i] );
+        RT2[i] = ROTL8( RT1[i] );
+        RT3[i] = ROTL8( RT2[i] );
+    }
+}
+
+#endif
+
+/*
+ * AES key schedule (encryption)
+ */
+void aes_setkey_enc( aes_context *ctx, unsigned char *key, int keysize )
+{
+    int i;
+    unsigned long *RK;
+
+#if !defined(XYSSL_AES_ROM_TABLES)
+    if( aes_init_done == 0 )
+    {
+        aes_gen_tables();
+        aes_init_done = 1;
+    }
+#endif
+
+    switch( keysize )
+    {
+        case 128: ctx->nr = 10; break;
+        case 192: ctx->nr = 12; break;
+        case 256: ctx->nr = 14; break;
+        default : return;
+    }
+
+#if defined(PADLOCK_ALIGN16)
+    ctx->rk = RK = PADLOCK_ALIGN16( ctx->buf );
+#else
+    ctx->rk = RK = ctx->buf;
+#endif
+
+    for( i = 0; i < (keysize >> 5); i++ )
+    {
+        GET_ULONG_LE( RK[i], key, i << 2 );
+    }
+
+    switch( ctx->nr )
+    {
+        case 10:
+
+            for( i = 0; i < 10; i++, RK += 4 )
+            {
+                RK[4]  = RK[0] ^ RCON[i] ^
+                ( (unsigned long) FSb[ ( RK[3] >>  8 ) & 0xFF ]       ) ^
+                ( (unsigned long) FSb[ ( RK[3] >> 16 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) FSb[ ( RK[3]       ) & 0xFF ] << 24 );
+
+                RK[5]  = RK[1] ^ RK[4];
+                RK[6]  = RK[2] ^ RK[5];
+                RK[7]  = RK[3] ^ RK[6];
+            }
+            break;
+
+        case 12:
+
+            for( i = 0; i < 8; i++, RK += 6 )
+            {
+                RK[6]  = RK[0] ^ RCON[i] ^
+                ( (unsigned long) FSb[ ( RK[5] >>  8 ) & 0xFF ]       ) ^
+                ( (unsigned long) FSb[ ( RK[5] >> 16 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) FSb[ ( RK[5]       ) & 0xFF ] << 24 );
+
+                RK[7]  = RK[1] ^ RK[6];
+                RK[8]  = RK[2] ^ RK[7];
+                RK[9]  = RK[3] ^ RK[8];
+                RK[10] = RK[4] ^ RK[9];
+                RK[11] = RK[5] ^ RK[10];
+            }
+            break;
+
+        case 14:
+
+            for( i = 0; i < 7; i++, RK += 8 )
+            {
+                RK[8]  = RK[0] ^ RCON[i] ^
+                ( (unsigned long) FSb[ ( RK[7] >>  8 ) & 0xFF ]       ) ^
+                ( (unsigned long) FSb[ ( RK[7] >> 16 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) FSb[ ( RK[7]       ) & 0xFF ] << 24 );
+
+                RK[9]  = RK[1] ^ RK[8];
+                RK[10] = RK[2] ^ RK[9];
+                RK[11] = RK[3] ^ RK[10];
+
+                RK[12] = RK[4] ^
+                ( (unsigned long) FSb[ ( RK[11]       ) & 0xFF ]       ) ^
+                ( (unsigned long) FSb[ ( RK[11] >>  8 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) FSb[ ( RK[11] >> 24 ) & 0xFF ] << 24 );
+
+                RK[13] = RK[5] ^ RK[12];
+                RK[14] = RK[6] ^ RK[13];
+                RK[15] = RK[7] ^ RK[14];
+            }
+            break;
+
+        default:
+
+            break;
+    }
+}
+
+/*
+ * AES key schedule (decryption)
+ */
+void aes_setkey_dec( aes_context *ctx, unsigned char *key, int keysize )
+{
+    int i, j;
+    aes_context cty;
+    unsigned long *RK;
+    unsigned long *SK;
+
+    switch( keysize )
+    {
+        case 128: ctx->nr = 10; break;
+        case 192: ctx->nr = 12; break;
+        case 256: ctx->nr = 14; break;
+        default : return;
+    }
+
+#if defined(PADLOCK_ALIGN16)
+    ctx->rk = RK = PADLOCK_ALIGN16( ctx->buf );
+#else
+    ctx->rk = RK = ctx->buf;
+#endif
+
+    aes_setkey_enc( &cty, key, keysize );
+    SK = cty.rk + cty.nr * 4;
+
+    *RK++ = *SK++;
+    *RK++ = *SK++;
+    *RK++ = *SK++;
+    *RK++ = *SK++;
+
+    for( i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8 )
+    {
+        for( j = 0; j < 4; j++, SK++ )
+        {
+            *RK++ = RT0[ FSb[ ( *SK       ) & 0xFF ] ] ^
+                    RT1[ FSb[ ( *SK >>  8 ) & 0xFF ] ] ^
+                    RT2[ FSb[ ( *SK >> 16 ) & 0xFF ] ] ^
+                    RT3[ FSb[ ( *SK >> 24 ) & 0xFF ] ];
+        }
+    }
+
+    *RK++ = *SK++;
+    *RK++ = *SK++;
+    *RK++ = *SK++;
+    *RK++ = *SK++;
+
+    memset( &cty, 0, sizeof( aes_context ) );
+}
+
+#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3)     \
+{                                               \
+    X0 = *RK++ ^ FT0[ ( Y0       ) & 0xFF ] ^   \
+                 FT1[ ( Y1 >>  8 ) & 0xFF ] ^   \
+                 FT2[ ( Y2 >> 16 ) & 0xFF ] ^   \
+                 FT3[ ( Y3 >> 24 ) & 0xFF ];    \
+                                                \
+    X1 = *RK++ ^ FT0[ ( Y1       ) & 0xFF ] ^   \
+                 FT1[ ( Y2 >>  8 ) & 0xFF ] ^   \
+                 FT2[ ( Y3 >> 16 ) & 0xFF ] ^   \
+                 FT3[ ( Y0 >> 24 ) & 0xFF ];    \
+                                                \
+    X2 = *RK++ ^ FT0[ ( Y2       ) & 0xFF ] ^   \
+                 FT1[ ( Y3 >>  8 ) & 0xFF ] ^   \
+                 FT2[ ( Y0 >> 16 ) & 0xFF ] ^   \
+                 FT3[ ( Y1 >> 24 ) & 0xFF ];    \
+                                                \
+    X3 = *RK++ ^ FT0[ ( Y3       ) & 0xFF ] ^   \
+                 FT1[ ( Y0 >>  8 ) & 0xFF ] ^   \
+                 FT2[ ( Y1 >> 16 ) & 0xFF ] ^   \
+                 FT3[ ( Y2 >> 24 ) & 0xFF ];    \
+}
+
+#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3)     \
+{                                               \
+    X0 = *RK++ ^ RT0[ ( Y0       ) & 0xFF ] ^   \
+                 RT1[ ( Y3 >>  8 ) & 0xFF ] ^   \
+                 RT2[ ( Y2 >> 16 ) & 0xFF ] ^   \
+                 RT3[ ( Y1 >> 24 ) & 0xFF ];    \
+                                                \
+    X1 = *RK++ ^ RT0[ ( Y1       ) & 0xFF ] ^   \
+                 RT1[ ( Y0 >>  8 ) & 0xFF ] ^   \
+                 RT2[ ( Y3 >> 16 ) & 0xFF ] ^   \
+                 RT3[ ( Y2 >> 24 ) & 0xFF ];    \
+                                                \
+    X2 = *RK++ ^ RT0[ ( Y2       ) & 0xFF ] ^   \
+                 RT1[ ( Y1 >>  8 ) & 0xFF ] ^   \
+                 RT2[ ( Y0 >> 16 ) & 0xFF ] ^   \
+                 RT3[ ( Y3 >> 24 ) & 0xFF ];    \
+                                                \
+    X3 = *RK++ ^ RT0[ ( Y3       ) & 0xFF ] ^   \
+                 RT1[ ( Y2 >>  8 ) & 0xFF ] ^   \
+                 RT2[ ( Y1 >> 16 ) & 0xFF ] ^   \
+                 RT3[ ( Y0 >> 24 ) & 0xFF ];    \
+}
+
+/*
+ * AES-ECB block encryption/decryption
+ */
+void aes_crypt_ecb( aes_context *ctx,
+                    int mode,
+                    unsigned char input[16],
+                    unsigned char output[16] )
+{
+    int i;
+    unsigned long *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3;
+
+#if defined(XYSSL_PADLOCK_C) && defined(XYSSL_HAVE_X86)
+    if( padlock_supports( PADLOCK_ACE ) )
+    {
+        if( padlock_xcryptecb( ctx, mode, input, output ) == 0 )
+            return;
+    }
+#endif
+
+    RK = ctx->rk;
+
+    GET_ULONG_LE( X0, input,  0 ); X0 ^= *RK++;
+    GET_ULONG_LE( X1, input,  4 ); X1 ^= *RK++;
+    GET_ULONG_LE( X2, input,  8 ); X2 ^= *RK++;
+    GET_ULONG_LE( X3, input, 12 ); X3 ^= *RK++;
+
+    if( mode == AES_DECRYPT )
+    {
+        for( i = (ctx->nr >> 1) - 1; i > 0; i-- )
+        {
+            AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
+            AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 );
+        }
+
+        AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
+
+        X0 = *RK++ ^ \
+                ( (unsigned long) RSb[ ( Y0       ) & 0xFF ]       ) ^
+                ( (unsigned long) RSb[ ( Y3 >>  8 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 );
+
+        X1 = *RK++ ^ \
+                ( (unsigned long) RSb[ ( Y1       ) & 0xFF ]       ) ^
+                ( (unsigned long) RSb[ ( Y0 >>  8 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 );
+
+        X2 = *RK++ ^ \
+                ( (unsigned long) RSb[ ( Y2       ) & 0xFF ]       ) ^
+                ( (unsigned long) RSb[ ( Y1 >>  8 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 );
+
+        X3 = *RK++ ^ \
+                ( (unsigned long) RSb[ ( Y3       ) & 0xFF ]       ) ^
+                ( (unsigned long) RSb[ ( Y2 >>  8 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 );
+    }
+    else /* AES_ENCRYPT */
+    {
+        for( i = (ctx->nr >> 1) - 1; i > 0; i-- )
+        {
+            AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
+            AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 );
+        }
+
+        AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
+
+        X0 = *RK++ ^ \
+                ( (unsigned long) FSb[ ( Y0       ) & 0xFF ]       ) ^
+                ( (unsigned long) FSb[ ( Y1 >>  8 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 );
+
+        X1 = *RK++ ^ \
+                ( (unsigned long) FSb[ ( Y1       ) & 0xFF ]       ) ^
+                ( (unsigned long) FSb[ ( Y2 >>  8 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 );
+
+        X2 = *RK++ ^ \
+                ( (unsigned long) FSb[ ( Y2       ) & 0xFF ]       ) ^
+                ( (unsigned long) FSb[ ( Y3 >>  8 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 );
+
+        X3 = *RK++ ^ \
+                ( (unsigned long) FSb[ ( Y3       ) & 0xFF ]       ) ^
+                ( (unsigned long) FSb[ ( Y0 >>  8 ) & 0xFF ] <<  8 ) ^
+                ( (unsigned long) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^
+                ( (unsigned long) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 );
+    }
+
+    PUT_ULONG_LE( X0, output,  0 );
+    PUT_ULONG_LE( X1, output,  4 );
+    PUT_ULONG_LE( X2, output,  8 );
+    PUT_ULONG_LE( X3, output, 12 );
+}
+
+/*
+ * AES-CBC buffer encryption/decryption
+ */
+void aes_crypt_cbc( aes_context *ctx,
+                    int mode,
+                    int length,
+                    unsigned char iv[16],
+                    unsigned char *input,
+                    unsigned char *output )
+{
+    int i;
+    unsigned char temp[16];
+
+#if defined(XYSSL_PADLOCK_C) && defined(XYSSL_HAVE_X86)
+    if( padlock_supports( PADLOCK_ACE ) )
+    {
+        if( padlock_xcryptcbc( ctx, mode, length, iv, input, output ) == 0 )
+            return;
+    }
+#endif
+
+    if( mode == AES_DECRYPT )
+    {
+        while( length > 0 )
+        {
+            memcpy( temp, input, 16 );
+            aes_crypt_ecb( ctx, mode, input, output );
+
+            for( i = 0; i < 16; i++ )
+                output[i] = (unsigned char)( output[i] ^ iv[i] );
+
+            memcpy( iv, temp, 16 );
+
+            input  += 16;
+            output += 16;
+            length -= 16;
+        }
+    }
+    else
+    {
+        while( length > 0 )
+        {
+            for( i = 0; i < 16; i++ )
+                output[i] = (unsigned char)( input[i] ^ iv[i] );
+
+            aes_crypt_ecb( ctx, mode, output, output );
+            memcpy( iv, output, 16 );
+
+            input  += 16;
+            output += 16;
+            length -= 16;
+        }
+    }
+}
+
+/*
+ * AES-CFB128 buffer encryption/decryption
+ */
+void aes_crypt_cfb128( aes_context *ctx,
+                       int mode,
+                       int length,
+                       int *iv_off,
+                       unsigned char iv[16],
+                       unsigned char *input,
+                       unsigned char *output )
+{
+    int c, n = *iv_off;
+
+    if( mode == AES_DECRYPT )
+    {
+        while( length-- )
+        {
+            if( n == 0 )
+                aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv );
+
+            c = *input++;
+            *output++ = (unsigned char)( c ^ iv[n] );
+            iv[n] = (unsigned char) c;
+
+            n = (n + 1) & 0x0F;
+        }
+    }
+    else
+    {
+        while( length-- )
+        {
+            if( n == 0 )
+                aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv );
+
+            iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ );
+
+            n = (n + 1) & 0x0F;
+        }
+    }
+
+    *iv_off = n;
+}
+
+#if defined(XYSSL_SELF_TEST)
+
+#include <stdio.h>
+
+/*
+ * AES test vectors from:
+ *
+ * http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip
+ */
+static const unsigned char aes_test_ecb_dec[3][16] =
+{
+    { 0x44, 0x41, 0x6A, 0xC2, 0xD1, 0xF5, 0x3C, 0x58,
+      0x33, 0x03, 0x91, 0x7E, 0x6B, 0xE9, 0xEB, 0xE0 },
+    { 0x48, 0xE3, 0x1E, 0x9E, 0x25, 0x67, 0x18, 0xF2,
+      0x92, 0x29, 0x31, 0x9C, 0x19, 0xF1, 0x5B, 0xA4 },
+    { 0x05, 0x8C, 0xCF, 0xFD, 0xBB, 0xCB, 0x38, 0x2D,
+      0x1F, 0x6F, 0x56, 0x58, 0x5D, 0x8A, 0x4A, 0xDE }
+};
+
+static const unsigned char aes_test_ecb_enc[3][16] =
+{
+    { 0xC3, 0x4C, 0x05, 0x2C, 0xC0, 0xDA, 0x8D, 0x73,
+      0x45, 0x1A, 0xFE, 0x5F, 0x03, 0xBE, 0x29, 0x7F },
+    { 0xF3, 0xF6, 0x75, 0x2A, 0xE8, 0xD7, 0x83, 0x11,
+      0x38, 0xF0, 0x41, 0x56, 0x06, 0x31, 0xB1, 0x14 },
+    { 0x8B, 0x79, 0xEE, 0xCC, 0x93, 0xA0, 0xEE, 0x5D,
+      0xFF, 0x30, 0xB4, 0xEA, 0x21, 0x63, 0x6D, 0xA4 }
+};
+
+static const unsigned char aes_test_cbc_dec[3][16] =
+{
+    { 0xFA, 0xCA, 0x37, 0xE0, 0xB0, 0xC8, 0x53, 0x73,
+      0xDF, 0x70, 0x6E, 0x73, 0xF7, 0xC9, 0xAF, 0x86 },
+    { 0x5D, 0xF6, 0x78, 0xDD, 0x17, 0xBA, 0x4E, 0x75,
+      0xB6, 0x17, 0x68, 0xC6, 0xAD, 0xEF, 0x7C, 0x7B },
+    { 0x48, 0x04, 0xE1, 0x81, 0x8F, 0xE6, 0x29, 0x75,
+      0x19, 0xA3, 0xE8, 0x8C, 0x57, 0x31, 0x04, 0x13 }
+};
+
+static const unsigned char aes_test_cbc_enc[3][16] =
+{
+    { 0x8A, 0x05, 0xFC, 0x5E, 0x09, 0x5A, 0xF4, 0x84,
+      0x8A, 0x08, 0xD3, 0x28, 0xD3, 0x68, 0x8E, 0x3D },
+    { 0x7B, 0xD9, 0x66, 0xD5, 0x3A, 0xD8, 0xC1, 0xBB,
+      0x85, 0xD2, 0xAD, 0xFA, 0xE8, 0x7B, 0xB1, 0x04 },
+    { 0xFE, 0x3C, 0x53, 0x65, 0x3E, 0x2F, 0x45, 0xB5,
+      0x6F, 0xCD, 0x88, 0xB2, 0xCC, 0x89, 0x8F, 0xF0 }
+};
+
+/*
+ * AES-CFB128 test vectors from:
+ *
+ * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
+ */
+static const unsigned char aes_test_cfb128_key[3][32] =
+{
+    { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
+      0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C },
+    { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52,
+      0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5,
+      0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B },
+    { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE,
+      0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81,
+      0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7,
+      0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 }
+};
+
+static const unsigned char aes_test_cfb128_iv[16] =
+{
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+};
+
+static const unsigned char aes_test_cfb128_pt[64] =
+{
+    0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96,
+    0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A,
+    0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C,
+    0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51,
+    0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11,
+    0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF,
+    0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17,
+    0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10
+};
+
+static const unsigned char aes_test_cfb128_ct[3][64] =
+{
+    { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20,
+      0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A,
+      0xC8, 0xA6, 0x45, 0x37, 0xA0, 0xB3, 0xA9, 0x3F,
+      0xCD, 0xE3, 0xCD, 0xAD, 0x9F, 0x1C, 0xE5, 0x8B,
+      0x26, 0x75, 0x1F, 0x67, 0xA3, 0xCB, 0xB1, 0x40,
+      0xB1, 0x80, 0x8C, 0xF1, 0x87, 0xA4, 0xF4, 0xDF,
+      0xC0, 0x4B, 0x05, 0x35, 0x7C, 0x5D, 0x1C, 0x0E,
+      0xEA, 0xC4, 0xC6, 0x6F, 0x9F, 0xF7, 0xF2, 0xE6 },
+    { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB,
+      0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74,
+      0x67, 0xCE, 0x7F, 0x7F, 0x81, 0x17, 0x36, 0x21,
+      0x96, 0x1A, 0x2B, 0x70, 0x17, 0x1D, 0x3D, 0x7A,
+      0x2E, 0x1E, 0x8A, 0x1D, 0xD5, 0x9B, 0x88, 0xB1,
+      0xC8, 0xE6, 0x0F, 0xED, 0x1E, 0xFA, 0xC4, 0xC9,
+      0xC0, 0x5F, 0x9F, 0x9C, 0xA9, 0x83, 0x4F, 0xA0,
+      0x42, 0xAE, 0x8F, 0xBA, 0x58, 0x4B, 0x09, 0xFF },
+    { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B,
+      0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60,
+      0x39, 0xFF, 0xED, 0x14, 0x3B, 0x28, 0xB1, 0xC8,
+      0x32, 0x11, 0x3C, 0x63, 0x31, 0xE5, 0x40, 0x7B,
+      0xDF, 0x10, 0x13, 0x24, 0x15, 0xE5, 0x4B, 0x92,
+      0xA1, 0x3E, 0xD0, 0xA8, 0x26, 0x7A, 0xE2, 0xF9,
+      0x75, 0xA3, 0x85, 0x74, 0x1A, 0xB9, 0xCE, 0xF8,
+      0x20, 0x31, 0x62, 0x3D, 0x55, 0xB1, 0xE4, 0x71 }
+};
+
+/*
+ * Checkup routine
+ */
+int aes_self_test( int verbose )
+{
+    int i, j, u, v, offset;
+    unsigned char key[32];
+    unsigned char buf[64];
+    unsigned char prv[16];
+    unsigned char iv[16];
+    aes_context ctx;
+
+    memset( key, 0, 32 );
+
+    /*
+     * ECB mode
+     */
+    for( i = 0; i < 6; i++ )
+    {
+        u = i >> 1;
+        v = i  & 1;
+
+        if( verbose != 0 )
+            printf( "  AES-ECB-%3d (%s): ", 128 + u * 64,
+                    ( v == AES_DECRYPT ) ? "dec" : "enc" );
+
+        memset( buf, 0, 16 );
+
+        if( v == AES_DECRYPT )
+        {
+            aes_setkey_dec( &ctx, key, 128 + u * 64 );
+
+            for( j = 0; j < 10000; j++ )
+                aes_crypt_ecb( &ctx, v, buf, buf );
+
+            if( memcmp( buf, aes_test_ecb_dec[u], 16 ) != 0 )
+            {
+                if( verbose != 0 )
+                    printf( "failed\n" );
+
+                return( 1 );
+            }
+        }
+        else
+        {
+            aes_setkey_enc( &ctx, key, 128 + u * 64 );
+
+            for( j = 0; j < 10000; j++ )
+                aes_crypt_ecb( &ctx, v, buf, buf );
+
+            if( memcmp( buf, aes_test_ecb_enc[u], 16 ) != 0 )
+            {
+                if( verbose != 0 )
+                    printf( "failed\n" );
+
+                return( 1 );
+            }
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    /*
+     * CBC mode
+     */
+    for( i = 0; i < 6; i++ )
+    {
+        u = i >> 1;
+        v = i  & 1;
+
+        if( verbose != 0 )
+            printf( "  AES-CBC-%3d (%s): ", 128 + u * 64,
+                    ( v == AES_DECRYPT ) ? "dec" : "enc" );
+
+        memset( iv , 0, 16 );
+        memset( prv, 0, 16 );
+        memset( buf, 0, 16 );
+
+        if( v == AES_DECRYPT )
+        {
+            aes_setkey_dec( &ctx, key, 128 + u * 64 );
+
+            for( j = 0; j < 10000; j++ )
+                aes_crypt_cbc( &ctx, v, 16, iv, buf, buf );
+
+            if( memcmp( buf, aes_test_cbc_dec[u], 16 ) != 0 )
+            {
+                if( verbose != 0 )
+                    printf( "failed\n" );
+
+                return( 1 );
+            }
+        }
+        else
+        {
+            aes_setkey_enc( &ctx, key, 128 + u * 64 );
+
+            for( j = 0; j < 10000; j++ )
+            {
+                unsigned char tmp[16];
+
+                aes_crypt_cbc( &ctx, v, 16, iv, buf, buf );
+
+                memcpy( tmp, prv, 16 );
+                memcpy( prv, buf, 16 );
+                memcpy( buf, tmp, 16 );
+            }
+
+            if( memcmp( prv, aes_test_cbc_enc[u], 16 ) != 0 )
+            {
+                if( verbose != 0 )
+                    printf( "failed\n" );
+
+                return( 1 );
+            }
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    /*
+     * CFB128 mode
+     */
+    for( i = 0; i < 6; i++ )
+    {
+        u = i >> 1;
+        v = i  & 1;
+
+        if( verbose != 0 )
+            printf( "  AES-CFB128-%3d (%s): ", 128 + u * 64,
+                    ( v == AES_DECRYPT ) ? "dec" : "enc" );
+
+        memcpy( iv,  aes_test_cfb128_iv, 16 );
+        memcpy( key, aes_test_cfb128_key[u], 16 + u * 8 );
+
+        offset = 0;
+        aes_setkey_enc( &ctx, key, 128 + u * 64 );
+
+        if( v == AES_DECRYPT )
+        {
+            memcpy( buf, aes_test_cfb128_ct[u], 64 );
+            aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf );
+
+            if( memcmp( buf, aes_test_cfb128_pt, 64 ) != 0 )
+            {
+                if( verbose != 0 )
+                    printf( "failed\n" );
+
+                return( 1 );
+            }
+        }
+        else
+        {
+            memcpy( buf, aes_test_cfb128_pt, 64 );
+            aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf );
+
+            if( memcmp( buf, aes_test_cfb128_ct[u], 64 ) != 0 )
+            {
+                if( verbose != 0 )
+                    printf( "failed\n" );
+
+                return( 1 );
+            }
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/library/arc4.c b/library/arc4.c
new file mode 100644
index 0000000..d226c07
--- /dev/null
+++ b/library/arc4.c
@@ -0,0 +1,158 @@
+/*
+ *  An implementation of the ARCFOUR algorithm
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  The ARCFOUR algorithm was publicly disclosed on 94/09.
+ *
+ *  http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_ARC4_C)
+
+#include "xyssl/arc4.h"
+
+/*
+ * ARC4 key schedule
+ */
+void arc4_setup( arc4_context *ctx, unsigned char *key, int keylen )
+{
+    int i, j, k, a;
+    unsigned char *m;
+
+    ctx->x = 0;
+    ctx->y = 0;
+    m = ctx->m;
+
+    for( i = 0; i < 256; i++ )
+        m[i] = (unsigned char) i;
+
+    j = k = 0;
+
+    for( i = 0; i < 256; i++, k++ )
+    {
+        if( k >= keylen ) k = 0;
+
+        a = m[i];
+        j = ( j + a + key[k] ) & 0xFF;
+        m[i] = m[j];
+        m[j] = (unsigned char) a;
+    }
+}
+
+/*
+ * ARC4 cipher function
+ */
+void arc4_crypt( arc4_context *ctx, unsigned char *buf, int buflen )
+{
+    int i, x, y, a, b;
+    unsigned char *m;
+
+    x = ctx->x;
+    y = ctx->y;
+    m = ctx->m;
+
+    for( i = 0; i < buflen; i++ )
+    {
+        x = ( x + 1 ) & 0xFF; a = m[x];
+        y = ( y + a ) & 0xFF; b = m[y];
+
+        m[x] = (unsigned char) b;
+        m[y] = (unsigned char) a;
+
+        buf[i] = (unsigned char)
+            ( buf[i] ^ m[(unsigned char)( a + b )] );
+    }
+
+    ctx->x = x;
+    ctx->y = y;
+}
+
+#if defined(XYSSL_SELF_TEST)
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * ARC4 tests vectors as posted by Eric Rescorla in sep. 1994:
+ *
+ * http://groups.google.com/group/comp.security.misc/msg/10a300c9d21afca0
+ */
+static const unsigned char arc4_test_key[3][8] =
+{
+    { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF },
+    { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF },
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+};
+
+static const unsigned char arc4_test_pt[3][8] =
+{
+    { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF },
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+};
+
+static const unsigned char arc4_test_ct[3][8] =
+{
+    { 0x75, 0xB7, 0x87, 0x80, 0x99, 0xE0, 0xC5, 0x96 },
+    { 0x74, 0x94, 0xC2, 0xE7, 0x10, 0x4B, 0x08, 0x79 },
+    { 0xDE, 0x18, 0x89, 0x41, 0xA3, 0x37, 0x5D, 0x3A }
+};
+
+/*
+ * Checkup routine
+ */
+int arc4_self_test( int verbose )
+{
+    int i;
+    unsigned char buf[8];
+    arc4_context ctx;
+
+    for( i = 0; i < 3; i++ )
+    {
+        if( verbose != 0 )
+            printf( "  ARC4 test #%d: ", i + 1 );
+
+        memcpy( buf, arc4_test_pt[i], 8 );
+
+        arc4_setup( &ctx, (unsigned char *) arc4_test_key[i], 8 );
+        arc4_crypt( &ctx, buf, 8 );
+
+        if( memcmp( buf, arc4_test_ct[i], 8 ) != 0 )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/library/base64.c b/library/base64.c
new file mode 100644
index 0000000..be6c024
--- /dev/null
+++ b/library/base64.c
@@ -0,0 +1,249 @@
+/*
+ *  RFC 1521 base64 encoding/decoding
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_BASE64_C)
+
+#include "xyssl/base64.h"
+
+static const unsigned char base64_enc_map[64] =
+{
+    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+    'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+    'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
+    'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+    'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
+    'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
+    '8', '9', '+', '/'
+};
+
+static const unsigned char base64_dec_map[128] =
+{
+    127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+    127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+    127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+    127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+    127, 127, 127,  62, 127, 127, 127,  63,  52,  53,
+     54,  55,  56,  57,  58,  59,  60,  61, 127, 127,
+    127,  64, 127, 127, 127,   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, 127, 127, 127, 127, 127, 127,  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, 127, 127, 127, 127, 127
+};
+
+/*
+ * Encode a buffer into base64 format
+ */
+int base64_encode( unsigned char *dst, int *dlen,
+                   unsigned char *src, int  slen )
+{
+    int i, n;
+    int C1, C2, C3;
+    unsigned char *p;
+
+    if( slen == 0 )
+        return( 0 );
+
+    n = (slen << 3) / 6;
+
+    switch( (slen << 3) - (n * 6) )
+    {
+        case  2: n += 3; break;
+        case  4: n += 2; break;
+        default: break;
+    }
+
+    if( *dlen < n + 1 )
+    {
+        *dlen = n + 1;
+        return( XYSSL_ERR_BASE64_BUFFER_TOO_SMALL );
+    }
+
+    n = (slen / 3) * 3;
+
+    for( i = 0, p = dst; i < n; i += 3 )
+    {
+        C1 = *src++;
+        C2 = *src++;
+        C3 = *src++;
+
+        *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
+        *p++ = base64_enc_map[(((C1 &  3) << 4) + (C2 >> 4)) & 0x3F];
+        *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
+        *p++ = base64_enc_map[C3 & 0x3F];
+    }
+
+    if( i < slen )
+    {
+        C1 = *src++;
+        C2 = ((i + 1) < slen) ? *src++ : 0;
+
+        *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
+        *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+
+        if( (i + 1) < slen )
+             *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
+        else *p++ = '=';
+
+        *p++ = '=';
+    }
+
+    *dlen = p - dst;
+    *p = 0;
+
+    return( 0 );
+}
+
+/*
+ * Decode a base64-formatted buffer
+ */
+int base64_decode( unsigned char *dst, int *dlen,
+                   unsigned char *src, int  slen )
+{
+    int i, j, n;
+    unsigned long x;
+    unsigned char *p;
+
+    for( i = j = n = 0; i < slen; i++ )
+    {
+        if( ( slen - i ) >= 2 &&
+            src[i] == '\r' && src[i + 1] == '\n' )
+            continue;
+
+        if( src[i] == '\n' )
+            continue;
+
+        if( src[i] == '=' && ++j > 2 )
+            return( XYSSL_ERR_BASE64_INVALID_CHARACTER );
+
+        if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
+            return( XYSSL_ERR_BASE64_INVALID_CHARACTER );
+
+        if( base64_dec_map[src[i]] < 64 && j != 0 )
+            return( XYSSL_ERR_BASE64_INVALID_CHARACTER );
+
+        n++;
+    }
+
+    if( n == 0 )
+        return( 0 );
+
+    n = ((n * 6) + 7) >> 3;
+
+    if( *dlen < n )
+    {
+        *dlen = n;
+        return( XYSSL_ERR_BASE64_BUFFER_TOO_SMALL );
+    }
+
+   for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
+   {
+        if( *src == '\r' || *src == '\n' )
+            continue;
+
+        j -= ( base64_dec_map[*src] == 64 );
+        x  = (x << 6) | ( base64_dec_map[*src] & 0x3F );
+
+        if( ++n == 4 )
+        {
+            n = 0;
+            if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
+            if( j > 1 ) *p++ = (unsigned char)( x >>  8 );
+            if( j > 2 ) *p++ = (unsigned char)( x       );
+        }
+    }
+
+    *dlen = p - dst;
+
+    return( 0 );
+}
+
+#if defined(XYSSL_SELF_TEST)
+
+#include <string.h>
+#include <stdio.h>
+
+static const unsigned char base64_test_dec[64] =
+{
+    0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
+    0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
+    0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
+    0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
+    0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
+    0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
+    0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
+    0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
+};
+
+static const unsigned char base64_test_enc[] =
+    "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
+    "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
+
+/*
+ * Checkup routine
+ */
+int base64_self_test( int verbose )
+{
+    int len;
+    unsigned char *src, buffer[128];
+
+    if( verbose != 0 )
+        printf( "  Base64 encoding test: " );
+
+    len = sizeof( buffer );
+    src = (unsigned char *) base64_test_dec;
+
+    if( base64_encode( buffer, &len, src, 64 ) != 0 ||
+         memcmp( base64_test_enc, buffer, 88 ) != 0 ) 
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n  Base64 decoding test: " );
+
+    len = sizeof( buffer );
+    src = (unsigned char *) base64_test_enc;
+
+    if( base64_decode( buffer, &len, src, 88 ) != 0 ||
+         memcmp( base64_test_dec, buffer, 64 ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n\n" );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/library/bignum.c b/library/bignum.c
new file mode 100644
index 0000000..f25fc4d
--- /dev/null
+++ b/library/bignum.c
@@ -0,0 +1,1955 @@
+/*
+ *  Multi-precision integer library
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  This MPI implementation is based on:
+ *
+ *  http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
+ *  http://www.stillhq.com/extracted/gnupg-api/mpi/
+ *  http://math.libtomcrypt.com/files/tommath.pdf
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_BIGNUM_C)
+
+#include "xyssl/bignum.h"
+#include "xyssl/bn_mul.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#define ciL    ((int) sizeof(t_int))    /* chars in limb  */
+#define biL    (ciL << 3)               /* bits  in limb  */
+#define biH    (ciL << 2)               /* half limb size */
+
+/*
+ * Convert between bits/chars and number of limbs
+ */
+#define BITS_TO_LIMBS(i)  (((i) + biL - 1) / biL)
+#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL)
+
+/*
+ * Initialize one or more mpi
+ */
+void mpi_init( mpi *X, ... )
+{
+    va_list args;
+
+    va_start( args, X );
+
+    while( X != NULL )
+    {
+        X->s = 1;
+        X->n = 0;
+        X->p = NULL;
+
+        X = va_arg( args, mpi* );
+    }
+
+    va_end( args );
+}
+
+/*
+ * Unallocate one or more mpi
+ */
+void mpi_free( mpi *X, ... )
+{
+    va_list args;
+
+    va_start( args, X );
+
+    while( X != NULL )
+    {
+        if( X->p != NULL )
+        {
+            memset( X->p, 0, X->n * ciL );
+            free( X->p );
+        }
+
+        X->s = 1;
+        X->n = 0;
+        X->p = NULL;
+
+        X = va_arg( args, mpi* );
+    }
+
+    va_end( args );
+}
+
+/*
+ * Enlarge to the specified number of limbs
+ */
+int mpi_grow( mpi *X, int nblimbs )
+{
+    t_int *p;
+
+    if( X->n < nblimbs )
+    {
+        if( ( p = (t_int *) malloc( nblimbs * ciL ) ) == NULL )
+            return( 1 );
+
+        memset( p, 0, nblimbs * ciL );
+
+        if( X->p != NULL )
+        {
+            memcpy( p, X->p, X->n * ciL );
+            memset( X->p, 0, X->n * ciL );
+            free( X->p );
+        }
+
+        X->n = nblimbs;
+        X->p = p;
+    }
+
+    return( 0 );
+}
+
+/*
+ * Copy the contents of Y into X
+ */
+int mpi_copy( mpi *X, mpi *Y )
+{
+    int ret, i;
+
+    if( X == Y )
+        return( 0 );
+
+    for( i = Y->n - 1; i > 0; i-- )
+        if( Y->p[i] != 0 )
+            break;
+    i++;
+
+    X->s = Y->s;
+
+    MPI_CHK( mpi_grow( X, i ) );
+
+    memset( X->p, 0, X->n * ciL );
+    memcpy( X->p, Y->p, i * ciL );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Swap the contents of X and Y
+ */
+void mpi_swap( mpi *X, mpi *Y )
+{
+    mpi T;
+
+    memcpy( &T,  X, sizeof( mpi ) );
+    memcpy(  X,  Y, sizeof( mpi ) );
+    memcpy(  Y, &T, sizeof( mpi ) );
+}
+
+/*
+ * Set value from integer
+ */
+int mpi_lset( mpi *X, int z )
+{
+    int ret;
+
+    MPI_CHK( mpi_grow( X, 1 ) );
+    memset( X->p, 0, X->n * ciL );
+
+    X->p[0] = ( z < 0 ) ? -z : z;
+    X->s    = ( z < 0 ) ? -1 : 1;
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Return the number of least significant bits
+ */
+int mpi_lsb( mpi *X )
+{
+    int i, j, count = 0;
+
+    for( i = 0; i < X->n; i++ )
+        for( j = 0; j < (int) biL; j++, count++ )
+            if( ( ( X->p[i] >> j ) & 1 ) != 0 )
+                return( count );
+
+    return( 0 );
+}
+
+/*
+ * Return the number of most significant bits
+ */
+int mpi_msb( mpi *X )
+{
+    int i, j;
+
+    for( i = X->n - 1; i > 0; i-- )
+        if( X->p[i] != 0 )
+            break;
+
+    for( j = biL - 1; j >= 0; j-- )
+        if( ( ( X->p[i] >> j ) & 1 ) != 0 )
+            break;
+
+    return( ( i * biL ) + j + 1 );
+}
+
+/*
+ * Return the total size in bytes
+ */
+int mpi_size( mpi *X )
+{
+    return( ( mpi_msb( X ) + 7 ) >> 3 );
+}
+
+/*
+ * Convert an ASCII character to digit value
+ */
+static int mpi_get_digit( t_int *d, int radix, char c )
+{
+    *d = 255;
+
+    if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30;
+    if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37;
+    if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57;
+
+    if( *d >= (t_int) radix )
+        return( XYSSL_ERR_MPI_INVALID_CHARACTER );
+
+    return( 0 );
+}
+
+/*
+ * Import from an ASCII string
+ */
+int mpi_read_string( mpi *X, int radix, char *s )
+{
+    int ret, i, j, n;
+    t_int d;
+    mpi T;
+
+    if( radix < 2 || radix > 16 )
+        return( XYSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    mpi_init( &T, NULL );
+
+    if( radix == 16 )
+    {
+        n = BITS_TO_LIMBS( strlen( s ) << 2 );
+
+        MPI_CHK( mpi_grow( X, n ) );
+        MPI_CHK( mpi_lset( X, 0 ) );
+
+        for( i = strlen( s ) - 1, j = 0; i >= 0; i--, j++ )
+        {
+            if( i == 0 && s[i] == '-' )
+            {
+                X->s = -1;
+                break;
+            }
+
+            MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
+            X->p[j / (2 * ciL)] |= d << ( (j % (2 * ciL)) << 2 );
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_lset( X, 0 ) );
+
+        for( i = 0; i < (int) strlen( s ); i++ )
+        {
+            if( i == 0 && s[i] == '-' )
+            {
+                X->s = -1;
+                continue;
+            }
+
+            MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
+            MPI_CHK( mpi_mul_int( &T, X, radix ) );
+            MPI_CHK( mpi_add_int( X, &T, d ) );
+        }
+    }
+
+cleanup:
+
+    mpi_free( &T, NULL );
+
+    return( ret );
+}
+
+/*
+ * Helper to write the digits high-order first
+ */
+static int mpi_write_hlp( mpi *X, int radix, char **p )
+{
+    int ret;
+    t_int r;
+
+    if( radix < 2 || radix > 16 )
+        return( XYSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    MPI_CHK( mpi_mod_int( &r, X, radix ) );
+    MPI_CHK( mpi_div_int( X, NULL, X, radix ) );
+
+    if( mpi_cmp_int( X, 0 ) != 0 )
+        MPI_CHK( mpi_write_hlp( X, radix, p ) );
+
+    if( r < 10 )
+        *(*p)++ = (char)( r + 0x30 );
+    else
+        *(*p)++ = (char)( r + 0x37 );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Export into an ASCII string
+ */
+int mpi_write_string( mpi *X, int radix, char *s, int *slen )
+{
+    int ret = 0, n;
+    char *p;
+    mpi T;
+
+    if( radix < 2 || radix > 16 )
+        return( XYSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    n = mpi_msb( X );
+    if( radix >=  4 ) n >>= 1;
+    if( radix >= 16 ) n >>= 1;
+    n += 3;
+
+    if( *slen < n )
+    {
+        *slen = n;
+        return( XYSSL_ERR_MPI_BUFFER_TOO_SMALL );
+    }
+
+    p = s;
+    mpi_init( &T, NULL );
+
+    if( X->s == -1 )
+        *p++ = '-';
+
+    if( radix == 16 )
+    {
+        int c, i, j, k;
+
+        for( i = X->n - 1, k = 0; i >= 0; i-- )
+        {
+            for( j = ciL - 1; j >= 0; j-- )
+            {
+                c = ( X->p[i] >> (j << 3) ) & 0xFF;
+
+                if( c == 0 && k == 0 && (i + j) != 0 )
+                    continue;
+
+                p += sprintf( p, "%02X", c );
+                k = 1;
+            }
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_copy( &T, X ) );
+        MPI_CHK( mpi_write_hlp( &T, radix, &p ) );
+    }
+
+    *p++ = '\0';
+    *slen = p - s;
+
+cleanup:
+
+    mpi_free( &T, NULL );
+
+    return( ret );
+}
+
+/*
+ * Read X from an opened file
+ */
+int mpi_read_file( mpi *X, int radix, FILE *fin )
+{
+    t_int d;
+    int slen;
+    char *p;
+    char s[1024];
+
+    memset( s, 0, sizeof( s ) );
+    if( fgets( s, sizeof( s ) - 1, fin ) == NULL )
+        return( XYSSL_ERR_MPI_FILE_IO_ERROR );
+
+    slen = strlen( s );
+    if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; }
+    if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; }
+
+    p = s + slen;
+    while( --p >= s )
+        if( mpi_get_digit( &d, radix, *p ) != 0 )
+            break;
+
+    return( mpi_read_string( X, radix, p + 1 ) );
+}
+
+/*
+ * Write X into an opened file (or stdout if fout == NULL)
+ */
+int mpi_write_file( char *p, mpi *X, int radix, FILE *fout )
+{
+    int n, ret;
+    size_t slen;
+    size_t plen;
+    char s[1024];
+
+    n = sizeof( s );
+    memset( s, 0, n );
+    n -= 2;
+
+    MPI_CHK( mpi_write_string( X, radix, s, (int *) &n ) );
+
+    if( p == NULL ) p = "";
+
+    plen = strlen( p );
+    slen = strlen( s );
+    s[slen++] = '\r';
+    s[slen++] = '\n';
+
+    if( fout != NULL )
+    {
+        if( fwrite( p, 1, plen, fout ) != plen ||
+            fwrite( s, 1, slen, fout ) != slen )
+            return( XYSSL_ERR_MPI_FILE_IO_ERROR );
+    }
+    else
+        printf( "%s%s", p, s );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Import X from unsigned binary data, big endian
+ */
+int mpi_read_binary( mpi *X, unsigned char *buf, int buflen )
+{
+    int ret, i, j, n;
+
+    for( n = 0; n < buflen; n++ )
+        if( buf[n] != 0 )
+            break;
+
+    MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) );
+    MPI_CHK( mpi_lset( X, 0 ) );
+
+    for( i = buflen - 1, j = 0; i >= n; i--, j++ )
+        X->p[j / ciL] |= ((t_int) buf[i]) << ((j % ciL) << 3);
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Export X into unsigned binary data, big endian
+ */
+int mpi_write_binary( mpi *X, unsigned char *buf, int buflen )
+{
+    int i, j, n;
+
+    n = mpi_size( X );
+
+    if( buflen < n )
+        return( XYSSL_ERR_MPI_BUFFER_TOO_SMALL );
+
+    memset( buf, 0, buflen );
+
+    for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- )
+        buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) );
+
+    return( 0 );
+}
+
+/*
+ * Left-shift: X <<= count
+ */
+int mpi_shift_l( mpi *X, int count )
+{
+    int ret, i, v0, t1;
+    t_int r0 = 0, r1;
+
+    v0 = count / (biL    );
+    t1 = count & (biL - 1);
+
+    i = mpi_msb( X ) + count;
+
+    if( X->n * (int) biL < i )
+        MPI_CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) );
+
+    ret = 0;
+
+    /*
+     * shift by count / limb_size
+     */
+    if( v0 > 0 )
+    {
+        for( i = X->n - 1; i >= v0; i-- )
+            X->p[i] = X->p[i - v0];
+
+        for( ; i >= 0; i-- )
+            X->p[i] = 0;
+    }
+
+    /*
+     * shift by count % limb_size
+     */
+    if( t1 > 0 )
+    {
+        for( i = v0; i < X->n; i++ )
+        {
+            r1 = X->p[i] >> (biL - t1);
+            X->p[i] <<= t1;
+            X->p[i] |= r0;
+            r0 = r1;
+        }
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Right-shift: X >>= count
+ */
+int mpi_shift_r( mpi *X, int count )
+{
+    int i, v0, v1;
+    t_int r0 = 0, r1;
+
+    v0 = count /  biL;
+    v1 = count & (biL - 1);
+
+    /*
+     * shift by count / limb_size
+     */
+    if( v0 > 0 )
+    {
+        for( i = 0; i < X->n - v0; i++ )
+            X->p[i] = X->p[i + v0];
+
+        for( ; i < X->n; i++ )
+            X->p[i] = 0;
+    }
+
+    /*
+     * shift by count % limb_size
+     */
+    if( v1 > 0 )
+    {
+        for( i = X->n - 1; i >= 0; i-- )
+        {
+            r1 = X->p[i] << (biL - v1);
+            X->p[i] >>= v1;
+            X->p[i] |= r0;
+            r0 = r1;
+        }
+    }
+
+    return( 0 );
+}
+
+/*
+ * Compare unsigned values
+ */
+int mpi_cmp_abs( mpi *X, mpi *Y )
+{
+    int i, j;
+
+    for( i = X->n - 1; i >= 0; i-- )
+        if( X->p[i] != 0 )
+            break;
+
+    for( j = Y->n - 1; j >= 0; j-- )
+        if( Y->p[j] != 0 )
+            break;
+
+    if( i < 0 && j < 0 )
+        return( 0 );
+
+    if( i > j ) return(  1 );
+    if( j > i ) return( -1 );
+
+    for( ; i >= 0; i-- )
+    {
+        if( X->p[i] > Y->p[i] ) return(  1 );
+        if( X->p[i] < Y->p[i] ) return( -1 );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Compare signed values
+ */
+int mpi_cmp_mpi( mpi *X, mpi *Y )
+{
+    int i, j;
+
+    for( i = X->n - 1; i >= 0; i-- )
+        if( X->p[i] != 0 )
+            break;
+
+    for( j = Y->n - 1; j >= 0; j-- )
+        if( Y->p[j] != 0 )
+            break;
+
+    if( i < 0 && j < 0 )
+        return( 0 );
+
+    if( i > j ) return(  X->s );
+    if( j > i ) return( -X->s );
+
+    if( X->s > 0 && Y->s < 0 ) return(  1 );
+    if( Y->s > 0 && X->s < 0 ) return( -1 );
+
+    for( ; i >= 0; i-- )
+    {
+        if( X->p[i] > Y->p[i] ) return(  X->s );
+        if( X->p[i] < Y->p[i] ) return( -X->s );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Compare signed values
+ */
+int mpi_cmp_int( mpi *X, int z )
+{
+    mpi Y;
+    t_int p[1];
+
+    *p  = ( z < 0 ) ? -z : z;
+    Y.s = ( z < 0 ) ? -1 : 1;
+    Y.n = 1;
+    Y.p = p;
+
+    return( mpi_cmp_mpi( X, &Y ) );
+}
+
+/*
+ * Unsigned addition: X = |A| + |B|  (HAC 14.7)
+ */
+int mpi_add_abs( mpi *X, mpi *A, mpi *B )
+{
+    int ret, i, j;
+    t_int *o, *p, c;
+
+    if( X == B )
+    {
+        mpi *T = A; A = X; B = T;
+    }
+
+    if( X != A )
+        MPI_CHK( mpi_copy( X, A ) );
+
+    for( j = B->n - 1; j >= 0; j-- )
+        if( B->p[j] != 0 )
+            break;
+
+    MPI_CHK( mpi_grow( X, j + 1 ) );
+
+    o = B->p; p = X->p; c = 0;
+
+    for( i = 0; i <= j; i++, o++, p++ )
+    {
+        *p +=  c; c  = ( *p <  c );
+        *p += *o; c += ( *p < *o );
+    }
+
+    while( c != 0 )
+    {
+        if( i >= X->n )
+        {
+            MPI_CHK( mpi_grow( X, i + 1 ) );
+            p = X->p + i;
+        }
+
+        *p += c; c = ( *p < c ); i++;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Helper for mpi substraction
+ */
+static void mpi_sub_hlp( int n, t_int *s, t_int *d )
+{
+    int i;
+    t_int c, z;
+
+    for( i = c = 0; i < n; i++, s++, d++ )
+    {
+        z = ( *d <  c );     *d -=  c;
+        c = ( *d < *s ) + z; *d -= *s;
+    }
+
+    while( c != 0 )
+    {
+        z = ( *d < c ); *d -= c;
+        c = z; i++; d++;
+    }
+}
+
+/*
+ * Unsigned substraction: X = |A| - |B|  (HAC 14.9)
+ */
+int mpi_sub_abs( mpi *X, mpi *A, mpi *B )
+{
+    mpi TB;
+    int ret, n;
+
+    if( mpi_cmp_abs( A, B ) < 0 )
+        return( XYSSL_ERR_MPI_NEGATIVE_VALUE );
+
+    mpi_init( &TB, NULL );
+
+    if( X == B )
+    {
+        MPI_CHK( mpi_copy( &TB, B ) );
+        B = &TB;
+    }
+
+    if( X != A )
+        MPI_CHK( mpi_copy( X, A ) );
+
+    ret = 0;
+
+    for( n = B->n - 1; n >= 0; n-- )
+        if( B->p[n] != 0 )
+            break;
+
+    mpi_sub_hlp( n + 1, B->p, X->p );
+
+cleanup:
+
+    mpi_free( &TB, NULL );
+
+    return( ret );
+}
+
+/*
+ * Signed addition: X = A + B
+ */
+int mpi_add_mpi( mpi *X, mpi *A, mpi *B )
+{
+    int ret, s = A->s;
+
+    if( A->s * B->s < 0 )
+    {
+        if( mpi_cmp_abs( A, B ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_abs( X, A, B ) );
+            X->s =  s;
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_abs( X, B, A ) );
+            X->s = -s;
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_add_abs( X, A, B ) );
+        X->s = s;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Signed substraction: X = A - B
+ */
+int mpi_sub_mpi( mpi *X, mpi *A, mpi *B )
+{
+    int ret, s = A->s;
+
+    if( A->s * B->s > 0 )
+    {
+        if( mpi_cmp_abs( A, B ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_abs( X, A, B ) );
+            X->s =  s;
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_abs( X, B, A ) );
+            X->s = -s;
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_add_abs( X, A, B ) );
+        X->s = s;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Signed addition: X = A + b
+ */
+int mpi_add_int( mpi *X, mpi *A, int b )
+{
+    mpi _B;
+    t_int p[1];
+
+    p[0] = ( b < 0 ) ? -b : b;
+    _B.s = ( b < 0 ) ? -1 : 1;
+    _B.n = 1;
+    _B.p = p;
+
+    return( mpi_add_mpi( X, A, &_B ) );
+}
+
+/*
+ * Signed substraction: X = A - b
+ */
+int mpi_sub_int( mpi *X, mpi *A, int b )
+{
+    mpi _B;
+    t_int p[1];
+
+    p[0] = ( b < 0 ) ? -b : b;
+    _B.s = ( b < 0 ) ? -1 : 1;
+    _B.n = 1;
+    _B.p = p;
+
+    return( mpi_sub_mpi( X, A, &_B ) );
+}
+
+/*
+ * Helper for mpi multiplication
+ */ 
+static void mpi_mul_hlp( int i, t_int *s, t_int *d, t_int b )
+{
+    t_int c = 0, t = 0;
+
+#if defined(MULADDC_HUIT)
+    for( ; i >= 8; i -= 8 )
+    {
+        MULADDC_INIT
+        MULADDC_HUIT
+        MULADDC_STOP
+    }
+
+    for( ; i > 0; i-- )
+    {
+        MULADDC_INIT
+        MULADDC_CORE
+        MULADDC_STOP
+    }
+#else
+    for( ; i >= 16; i -= 16 )
+    {
+        MULADDC_INIT
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_STOP
+    }
+
+    for( ; i >= 8; i -= 8 )
+    {
+        MULADDC_INIT
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_STOP
+    }
+
+    for( ; i > 0; i-- )
+    {
+        MULADDC_INIT
+        MULADDC_CORE
+        MULADDC_STOP
+    }
+#endif
+
+    t++;
+
+    do {
+        *d += c; c = ( *d < c ); d++;
+    }
+    while( c != 0 );
+}
+
+/*
+ * Baseline multiplication: X = A * B  (HAC 14.12)
+ */
+int mpi_mul_mpi( mpi *X, mpi *A, mpi *B )
+{
+    int ret, i, j;
+    mpi TA, TB;
+
+    mpi_init( &TA, &TB, NULL );
+
+    if( X == A ) { MPI_CHK( mpi_copy( &TA, A ) ); A = &TA; }
+    if( X == B ) { MPI_CHK( mpi_copy( &TB, B ) ); B = &TB; }
+
+    for( i = A->n - 1; i >= 0; i-- )
+        if( A->p[i] != 0 )
+            break;
+
+    for( j = B->n - 1; j >= 0; j-- )
+        if( B->p[j] != 0 )
+            break;
+
+    MPI_CHK( mpi_grow( X, i + j + 2 ) );
+    MPI_CHK( mpi_lset( X, 0 ) );
+
+    for( i++; j >= 0; j-- )
+        mpi_mul_hlp( i, A->p, X->p + j, B->p[j] );
+
+    X->s = A->s * B->s;
+
+cleanup:
+
+    mpi_free( &TB, &TA, NULL );
+
+    return( ret );
+}
+
+/*
+ * Baseline multiplication: X = A * b
+ */
+int mpi_mul_int( mpi *X, mpi *A, t_int b )
+{
+    mpi _B;
+    t_int p[1];
+
+    _B.s = 1;
+    _B.n = 1;
+    _B.p = p;
+    p[0] = b;
+
+    return( mpi_mul_mpi( X, A, &_B ) );
+}
+
+/*
+ * Division by mpi: A = Q * B + R  (HAC 14.20)
+ */
+int mpi_div_mpi( mpi *Q, mpi *R, mpi *A, mpi *B )
+{
+    int ret, i, n, t, k;
+    mpi X, Y, Z, T1, T2;
+
+    if( mpi_cmp_int( B, 0 ) == 0 )
+        return( XYSSL_ERR_MPI_DIVISION_BY_ZERO );
+
+    mpi_init( &X, &Y, &Z, &T1, &T2, NULL );
+
+    if( mpi_cmp_abs( A, B ) < 0 )
+    {
+        if( Q != NULL ) MPI_CHK( mpi_lset( Q, 0 ) );
+        if( R != NULL ) MPI_CHK( mpi_copy( R, A ) );
+        return( 0 );
+    }
+
+    MPI_CHK( mpi_copy( &X, A ) );
+    MPI_CHK( mpi_copy( &Y, B ) );
+    X.s = Y.s = 1;
+
+    MPI_CHK( mpi_grow( &Z, A->n + 2 ) );
+    MPI_CHK( mpi_lset( &Z,  0 ) );
+    MPI_CHK( mpi_grow( &T1, 2 ) );
+    MPI_CHK( mpi_grow( &T2, 3 ) );
+
+    k = mpi_msb( &Y ) % biL;
+    if( k < (int) biL - 1 )
+    {
+        k = biL - 1 - k;
+        MPI_CHK( mpi_shift_l( &X, k ) );
+        MPI_CHK( mpi_shift_l( &Y, k ) );
+    }
+    else k = 0;
+
+    n = X.n - 1;
+    t = Y.n - 1;
+    mpi_shift_l( &Y, biL * (n - t) );
+
+    while( mpi_cmp_mpi( &X, &Y ) >= 0 )
+    {
+        Z.p[n - t]++;
+        mpi_sub_mpi( &X, &X, &Y );
+    }
+    mpi_shift_r( &Y, biL * (n - t) );
+
+    for( i = n; i > t ; i-- )
+    {
+        if( X.p[i] >= Y.p[t] )
+            Z.p[i - t - 1] = ~0;
+        else
+        {
+#if defined(XYSSL_HAVE_LONGLONG)
+            t_dbl r;
+
+            r  = (t_dbl) X.p[i] << biL;
+            r |= (t_dbl) X.p[i - 1];
+            r /= Y.p[t];
+            if( r > ((t_dbl) 1 << biL) - 1)
+                r = ((t_dbl) 1 << biL) - 1;
+
+            Z.p[i - t - 1] = (t_int) r;
+#else
+            /*
+             * __udiv_qrnnd_c, from gmp/longlong.h
+             */
+            t_int q0, q1, r0, r1;
+            t_int d0, d1, d, m;
+
+            d  = Y.p[t];
+            d0 = ( d << biH ) >> biH;
+            d1 = ( d >> biH );
+
+            q1 = X.p[i] / d1;
+            r1 = X.p[i] - d1 * q1;
+            r1 <<= biH;
+            r1 |= ( X.p[i - 1] >> biH );
+
+            m = q1 * d0;
+            if( r1 < m )
+            {
+                q1--, r1 += d;
+                while( r1 >= d && r1 < m )
+                    q1--, r1 += d;
+            }
+            r1 -= m;
+
+            q0 = r1 / d1;
+            r0 = r1 - d1 * q0;
+            r0 <<= biH;
+            r0 |= ( X.p[i - 1] << biH ) >> biH;
+
+            m = q0 * d0;
+            if( r0 < m )
+            {
+                q0--, r0 += d;
+                while( r0 >= d && r0 < m )
+                    q0--, r0 += d;
+            }
+            r0 -= m;
+
+            Z.p[i - t - 1] = ( q1 << biH ) | q0;
+#endif
+        }
+
+        Z.p[i - t - 1]++;
+        do
+        {
+            Z.p[i - t - 1]--;
+
+            MPI_CHK( mpi_lset( &T1, 0 ) );
+            T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
+            T1.p[1] = Y.p[t];
+            MPI_CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
+
+            MPI_CHK( mpi_lset( &T2, 0 ) );
+            T2.p[0] = (i < 2) ? 0 : X.p[i - 2];
+            T2.p[1] = (i < 1) ? 0 : X.p[i - 1];
+            T2.p[2] = X.p[i];
+        }
+        while( mpi_cmp_mpi( &T1, &T2 ) > 0 );
+
+        MPI_CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
+        MPI_CHK( mpi_shift_l( &T1,  biL * (i - t - 1) ) );
+        MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) );
+
+        if( mpi_cmp_int( &X, 0 ) < 0 )
+        {
+            MPI_CHK( mpi_copy( &T1, &Y ) );
+            MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) );
+            MPI_CHK( mpi_add_mpi( &X, &X, &T1 ) );
+            Z.p[i - t - 1]--;
+        }
+    }
+
+    if( Q != NULL )
+    {
+        mpi_copy( Q, &Z );
+        Q->s = A->s * B->s;
+    }
+
+    if( R != NULL )
+    {
+        mpi_shift_r( &X, k );
+        mpi_copy( R, &X );
+
+        R->s = A->s;
+        if( mpi_cmp_int( R, 0 ) == 0 )
+            R->s = 1;
+    }
+
+cleanup:
+
+    mpi_free( &X, &Y, &Z, &T1, &T2, NULL );
+
+    return( ret );
+}
+
+/*
+ * Division by int: A = Q * b + R
+ *
+ * Returns 0 if successful
+ *         1 if memory allocation failed
+ *         XYSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0
+ */
+int mpi_div_int( mpi *Q, mpi *R, mpi *A, int b )
+{
+    mpi _B;
+    t_int p[1];
+
+    p[0] = ( b < 0 ) ? -b : b;
+    _B.s = ( b < 0 ) ? -1 : 1;
+    _B.n = 1;
+    _B.p = p;
+
+    return( mpi_div_mpi( Q, R, A, &_B ) );
+}
+
+/*
+ * Modulo: R = A mod B
+ */
+int mpi_mod_mpi( mpi *R, mpi *A, mpi *B )
+{
+    int ret;
+
+    MPI_CHK( mpi_div_mpi( NULL, R, A, B ) );
+
+    while( mpi_cmp_int( R, 0 ) < 0 )
+      MPI_CHK( mpi_add_mpi( R, R, B ) );
+
+    while( mpi_cmp_mpi( R, B ) >= 0 )
+      MPI_CHK( mpi_sub_mpi( R, R, B ) );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Modulo: r = A mod b
+ */
+int mpi_mod_int( t_int *r, mpi *A, int b )
+{
+    int i;
+    t_int x, y, z;
+
+    if( b == 0 )
+        return( XYSSL_ERR_MPI_DIVISION_BY_ZERO );
+
+    if( b < 0 )
+        b = -b;
+
+    /*
+     * handle trivial cases
+     */
+    if( b == 1 )
+    {
+        *r = 0;
+        return( 0 );
+    }
+
+    if( b == 2 )
+    {
+        *r = A->p[0] & 1;
+        return( 0 );
+    }
+
+    /*
+     * general case
+     */
+    for( i = A->n - 1, y = 0; i >= 0; i-- )
+    {
+        x  = A->p[i];
+        y  = ( y << biH ) | ( x >> biH );
+        z  = y / b;
+        y -= z * b;
+
+        x <<= biH;
+        y  = ( y << biH ) | ( x >> biH );
+        z  = y / b;
+        y -= z * b;
+    }
+
+    *r = y;
+
+    return( 0 );
+}
+
+/*
+ * Fast Montgomery initialization (thanks to Tom St Denis)
+ */
+static void mpi_montg_init( t_int *mm, mpi *N )
+{
+    t_int x, m0 = N->p[0];
+
+    x  = m0;
+    x += ( ( m0 + 2 ) & 4 ) << 1;
+    x *= ( 2 - ( m0 * x ) );
+
+    if( biL >= 16 ) x *= ( 2 - ( m0 * x ) );
+    if( biL >= 32 ) x *= ( 2 - ( m0 * x ) );
+    if( biL >= 64 ) x *= ( 2 - ( m0 * x ) );
+
+    *mm = ~x + 1;
+}
+
+/*
+ * Montgomery multiplication: A = A * B * R^-1 mod N  (HAC 14.36)
+ */
+static void mpi_montmul( mpi *A, mpi *B, mpi *N, t_int mm, mpi *T )
+{
+    int i, n, m;
+    t_int u0, u1, *d;
+
+    memset( T->p, 0, T->n * ciL );
+
+    d = T->p;
+    n = N->n;
+    m = ( B->n < n ) ? B->n : n;
+
+    for( i = 0; i < n; i++ )
+    {
+        /*
+         * T = (T + u0*B + u1*N) / 2^biL
+         */
+        u0 = A->p[i];
+        u1 = ( d[0] + u0 * B->p[0] ) * mm;
+
+        mpi_mul_hlp( m, B->p, d, u0 );
+        mpi_mul_hlp( n, N->p, d, u1 );
+
+        *d++ = u0; d[n + 1] = 0;
+    }
+
+    memcpy( A->p, d, (n + 1) * ciL );
+
+    if( mpi_cmp_abs( A, N ) >= 0 )
+        mpi_sub_hlp( n, N->p, A->p );
+    else
+        /* prevent timing attacks */
+        mpi_sub_hlp( n, A->p, T->p );
+}
+
+/*
+ * Montgomery reduction: A = A * R^-1 mod N
+ */
+static void mpi_montred( mpi *A, mpi *N, t_int mm, mpi *T )
+{
+    t_int z = 1;
+    mpi U;
+
+    U.n = U.s = z;
+    U.p = &z;
+
+    mpi_montmul( A, &U, N, mm, T );
+}
+
+/*
+ * Sliding-window exponentiation: X = A^E mod N  (HAC 14.85)
+ */
+int mpi_exp_mod( mpi *X, mpi *A, mpi *E, mpi *N, mpi *_RR )
+{
+    int ret, i, j, wsize, wbits;
+    int bufsize, nblimbs, nbits;
+    t_int ei, mm, state;
+    mpi RR, T, W[64];
+
+    if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 )
+        return( XYSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    /*
+     * Init temps and window size
+     */
+    mpi_montg_init( &mm, N );
+    mpi_init( &RR, &T, NULL );
+    memset( W, 0, sizeof( W ) );
+
+    i = mpi_msb( E );
+
+    wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
+            ( i >  79 ) ? 4 : ( i >  23 ) ? 3 : 1;
+
+    j = N->n + 1;
+    MPI_CHK( mpi_grow( X, j ) );
+    MPI_CHK( mpi_grow( &W[1],  j ) );
+    MPI_CHK( mpi_grow( &T, j * 2 ) );
+
+    /*
+     * If 1st call, pre-compute R^2 mod N
+     */
+    if( _RR == NULL || _RR->p == NULL )
+    {
+        MPI_CHK( mpi_lset( &RR, 1 ) );
+        MPI_CHK( mpi_shift_l( &RR, N->n * 2 * biL ) );
+        MPI_CHK( mpi_mod_mpi( &RR, &RR, N ) );
+
+        if( _RR != NULL )
+            memcpy( _RR, &RR, sizeof( mpi ) );
+    }
+    else
+        memcpy( &RR, _RR, sizeof( mpi ) );
+
+    /*
+     * W[1] = A * R^2 * R^-1 mod N = A * R mod N
+     */
+    if( mpi_cmp_mpi( A, N ) >= 0 )
+        mpi_mod_mpi( &W[1], A, N );
+    else   mpi_copy( &W[1], A );
+
+    mpi_montmul( &W[1], &RR, N, mm, &T );
+
+    /*
+     * X = R^2 * R^-1 mod N = R mod N
+     */
+    MPI_CHK( mpi_copy( X, &RR ) );
+    mpi_montred( X, N, mm, &T );
+
+    if( wsize > 1 )
+    {
+        /*
+         * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
+         */
+        j =  1 << (wsize - 1);
+
+        MPI_CHK( mpi_grow( &W[j], N->n + 1 ) );
+        MPI_CHK( mpi_copy( &W[j], &W[1]    ) );
+
+        for( i = 0; i < wsize - 1; i++ )
+            mpi_montmul( &W[j], &W[j], N, mm, &T );
+    
+        /*
+         * W[i] = W[i - 1] * W[1]
+         */
+        for( i = j + 1; i < (1 << wsize); i++ )
+        {
+            MPI_CHK( mpi_grow( &W[i], N->n + 1 ) );
+            MPI_CHK( mpi_copy( &W[i], &W[i - 1] ) );
+
+            mpi_montmul( &W[i], &W[1], N, mm, &T );
+        }
+    }
+
+    nblimbs = E->n;
+    bufsize = 0;
+    nbits   = 0;
+    wbits   = 0;
+    state   = 0;
+
+    while( 1 )
+    {
+        if( bufsize == 0 )
+        {
+            if( nblimbs-- == 0 )
+                break;
+
+            bufsize = sizeof( t_int ) << 3;
+        }
+
+        bufsize--;
+
+        ei = (E->p[nblimbs] >> bufsize) & 1;
+
+        /*
+         * skip leading 0s
+         */
+        if( ei == 0 && state == 0 )
+            continue;
+
+        if( ei == 0 && state == 1 )
+        {
+            /*
+             * out of window, square X
+             */
+            mpi_montmul( X, X, N, mm, &T );
+            continue;
+        }
+
+        /*
+         * add ei to current window
+         */
+        state = 2;
+
+        nbits++;
+        wbits |= (ei << (wsize - nbits));
+
+        if( nbits == wsize )
+        {
+            /*
+             * X = X^wsize R^-1 mod N
+             */
+            for( i = 0; i < wsize; i++ )
+                mpi_montmul( X, X, N, mm, &T );
+
+            /*
+             * X = X * W[wbits] R^-1 mod N
+             */
+            mpi_montmul( X, &W[wbits], N, mm, &T );
+
+            state--;
+            nbits = 0;
+            wbits = 0;
+        }
+    }
+
+    /*
+     * process the remaining bits
+     */
+    for( i = 0; i < nbits; i++ )
+    {
+        mpi_montmul( X, X, N, mm, &T );
+
+        wbits <<= 1;
+
+        if( (wbits & (1 << wsize)) != 0 )
+            mpi_montmul( X, &W[1], N, mm, &T );
+    }
+
+    /*
+     * X = A^E * R * R^-1 mod N = A^E mod N
+     */
+    mpi_montred( X, N, mm, &T );
+
+cleanup:
+
+    for( i = (1 << (wsize - 1)); i < (1 << wsize); i++ )
+        mpi_free( &W[i], NULL );
+
+    if( _RR != NULL )
+         mpi_free( &W[1], &T, NULL );
+    else mpi_free( &W[1], &T, &RR, NULL );
+
+    return( ret );
+}
+
+#if defined(XYSSL_GENPRIME)
+
+/*
+ * Greatest common divisor: G = gcd(A, B)  (HAC 14.54)
+ */
+int mpi_gcd( mpi *G, mpi *A, mpi *B )
+{
+    int ret;
+    mpi TG, TA, TB;
+
+    mpi_init( &TG, &TA, &TB, NULL );
+
+    MPI_CHK( mpi_lset( &TG, 1 ) );
+    MPI_CHK( mpi_copy( &TA, A ) );
+    MPI_CHK( mpi_copy( &TB, B ) );
+
+    TA.s = TB.s = 1;
+
+    while( mpi_cmp_int( &TA, 0 ) != 0 )
+    {
+        while( ( TA.p[0] & 1 ) == 0 ) MPI_CHK( mpi_shift_r( &TA, 1 ) );
+        while( ( TB.p[0] & 1 ) == 0 ) MPI_CHK( mpi_shift_r( &TB, 1 ) );
+
+        if( mpi_cmp_mpi( &TA, &TB ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_abs( &TA, &TA, &TB ) );
+            MPI_CHK( mpi_shift_r( &TA, 1 ) );
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_abs( &TB, &TB, &TA ) );
+            MPI_CHK( mpi_shift_r( &TB, 1 ) );
+        }
+    }
+
+    MPI_CHK( mpi_mul_mpi( G, &TG, &TB ) );
+
+cleanup:
+
+    mpi_free( &TB, &TA, &TG, NULL );
+
+    return( ret );
+}
+
+/*
+ * Modular inverse: X = A^-1 mod N  (HAC 14.61 / 14.64)
+ */
+int mpi_inv_mod( mpi *X, mpi *A, mpi *N )
+{
+    int ret;
+    mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
+
+    if( mpi_cmp_int( N, 0 ) <= 0 )
+        return( XYSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    mpi_init( &TA, &TU, &U1, &U2, &G,
+              &TB, &TV, &V1, &V2, NULL );
+
+    MPI_CHK( mpi_gcd( &G, A, N ) );
+
+    if( mpi_cmp_int( &G, 1 ) != 0 )
+    {
+        ret = XYSSL_ERR_MPI_NOT_ACCEPTABLE;
+        goto cleanup;
+    }
+
+    MPI_CHK( mpi_mod_mpi( &TA, A, N ) );
+    MPI_CHK( mpi_copy( &TU, &TA ) );
+    MPI_CHK( mpi_copy( &TB, N ) );
+    MPI_CHK( mpi_copy( &TV, N ) );
+
+    MPI_CHK( mpi_lset( &U1, 1 ) );
+    MPI_CHK( mpi_lset( &U2, 0 ) );
+    MPI_CHK( mpi_lset( &V1, 0 ) );
+    MPI_CHK( mpi_lset( &V2, 1 ) );
+
+    do
+    {
+        while( ( TU.p[0] & 1 ) == 0 )
+        {
+            MPI_CHK( mpi_shift_r( &TU, 1 ) );
+
+            if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 )
+            {
+                MPI_CHK( mpi_add_mpi( &U1, &U1, &TB ) );
+                MPI_CHK( mpi_sub_mpi( &U2, &U2, &TA ) );
+            }
+
+            MPI_CHK( mpi_shift_r( &U1, 1 ) );
+            MPI_CHK( mpi_shift_r( &U2, 1 ) );
+        }
+
+        while( ( TV.p[0] & 1 ) == 0 )
+        {
+            MPI_CHK( mpi_shift_r( &TV, 1 ) );
+
+            if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 )
+            {
+                MPI_CHK( mpi_add_mpi( &V1, &V1, &TB ) );
+                MPI_CHK( mpi_sub_mpi( &V2, &V2, &TA ) );
+            }
+
+            MPI_CHK( mpi_shift_r( &V1, 1 ) );
+            MPI_CHK( mpi_shift_r( &V2, 1 ) );
+        }
+
+        if( mpi_cmp_mpi( &TU, &TV ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_mpi( &TU, &TU, &TV ) );
+            MPI_CHK( mpi_sub_mpi( &U1, &U1, &V1 ) );
+            MPI_CHK( mpi_sub_mpi( &U2, &U2, &V2 ) );
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_mpi( &TV, &TV, &TU ) );
+            MPI_CHK( mpi_sub_mpi( &V1, &V1, &U1 ) );
+            MPI_CHK( mpi_sub_mpi( &V2, &V2, &U2 ) );
+        }
+    }
+    while( mpi_cmp_int( &TU, 0 ) != 0 );
+
+    while( mpi_cmp_int( &V1, 0 ) < 0 )
+        MPI_CHK( mpi_add_mpi( &V1, &V1, N ) );
+
+    while( mpi_cmp_mpi( &V1, N ) >= 0 )
+        MPI_CHK( mpi_sub_mpi( &V1, &V1, N ) );
+
+    MPI_CHK( mpi_copy( X, &V1 ) );
+
+cleanup:
+
+    mpi_free( &V2, &V1, &TV, &TB, &G,
+              &U2, &U1, &TU, &TA, NULL );
+
+    return( ret );
+}
+
+static const int small_prime[] =
+{
+        3,    5,    7,   11,   13,   17,   19,   23,
+       29,   31,   37,   41,   43,   47,   53,   59,
+       61,   67,   71,   73,   79,   83,   89,   97,
+      101,  103,  107,  109,  113,  127,  131,  137,
+      139,  149,  151,  157,  163,  167,  173,  179,
+      181,  191,  193,  197,  199,  211,  223,  227,
+      229,  233,  239,  241,  251,  257,  263,  269,
+      271,  277,  281,  283,  293,  307,  311,  313,
+      317,  331,  337,  347,  349,  353,  359,  367,
+      373,  379,  383,  389,  397,  401,  409,  419,
+      421,  431,  433,  439,  443,  449,  457,  461,
+      463,  467,  479,  487,  491,  499,  503,  509,
+      521,  523,  541,  547,  557,  563,  569,  571,
+      577,  587,  593,  599,  601,  607,  613,  617,
+      619,  631,  641,  643,  647,  653,  659,  661,
+      673,  677,  683,  691,  701,  709,  719,  727,
+      733,  739,  743,  751,  757,  761,  769,  773,
+      787,  797,  809,  811,  821,  823,  827,  829,
+      839,  853,  857,  859,  863,  877,  881,  883,
+      887,  907,  911,  919,  929,  937,  941,  947,
+      953,  967,  971,  977,  983,  991,  997, -103
+};
+
+/*
+ * Miller-Rabin primality test  (HAC 4.24)
+ */
+int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng )
+{
+    int ret, i, j, n, s, xs;
+    mpi W, R, T, A, RR;
+    unsigned char *p;
+
+    if( mpi_cmp_int( X, 0 ) == 0 )
+        return( 0 );
+
+    mpi_init( &W, &R, &T, &A, &RR, NULL );
+
+    xs = X->s; X->s = 1;
+
+    /*
+     * test trivial factors first
+     */
+    if( ( X->p[0] & 1 ) == 0 )
+        return( XYSSL_ERR_MPI_NOT_ACCEPTABLE );
+
+    for( i = 0; small_prime[i] > 0; i++ )
+    {
+        t_int r;
+
+        if( mpi_cmp_int( X, small_prime[i] ) <= 0 )
+            return( 0 );
+
+        MPI_CHK( mpi_mod_int( &r, X, small_prime[i] ) );
+
+        if( r == 0 )
+            return( XYSSL_ERR_MPI_NOT_ACCEPTABLE );
+    }
+
+    /*
+     * W = |X| - 1
+     * R = W >> lsb( W )
+     */
+    s = mpi_lsb( &W );
+    MPI_CHK( mpi_sub_int( &W, X, 1 ) );
+    MPI_CHK( mpi_copy( &R, &W ) );
+    MPI_CHK( mpi_shift_r( &R, s ) );
+
+    i = mpi_msb( X );
+    /*
+     * HAC, table 4.4
+     */
+    n = ( ( i >= 1300 ) ?  2 : ( i >=  850 ) ?  3 :
+          ( i >=  650 ) ?  4 : ( i >=  350 ) ?  8 :
+          ( i >=  250 ) ? 12 : ( i >=  150 ) ? 18 : 27 );
+
+    for( i = 0; i < n; i++ )
+    {
+        /*
+         * pick a random A, 1 < A < |X| - 1
+         */
+        MPI_CHK( mpi_grow( &A, X->n ) );
+
+        p = (unsigned char *) A.p;
+        for( j = 0; j < A.n * ciL; j++ )
+            *p++ = (unsigned char) f_rng( p_rng );
+
+        j = mpi_msb( &A ) - mpi_msb( &W );
+        MPI_CHK( mpi_shift_r( &A, j + 1 ) );
+        A.p[0] |= 3;
+
+        /*
+         * A = A^R mod |X|
+         */
+        MPI_CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) );
+
+        if( mpi_cmp_mpi( &A, &W ) == 0 ||
+            mpi_cmp_int( &A,  1 ) == 0 )
+            continue;
+
+        j = 1;
+        while( j < s && mpi_cmp_mpi( &A, &W ) != 0 )
+        {
+            /*
+             * A = A * A mod |X|
+             */
+            MPI_CHK( mpi_mul_mpi( &T, &A, &A ) );
+            MPI_CHK( mpi_mod_mpi( &A, &T, X  ) );
+
+            if( mpi_cmp_int( &A, 1 ) == 0 )
+                break;
+
+            j++;
+        }
+
+        /*
+         * not prime if A != |X| - 1 or A == 1
+         */
+        if( mpi_cmp_mpi( &A, &W ) != 0 ||
+            mpi_cmp_int( &A,  1 ) == 0 )
+        {
+            ret = XYSSL_ERR_MPI_NOT_ACCEPTABLE;
+            break;
+        }
+    }
+
+cleanup:
+
+    X->s = xs;
+
+    mpi_free( &RR, &A, &T, &R, &W, NULL );
+
+    return( ret );
+}
+
+/*
+ * Prime number generation
+ */
+int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
+                   int (*f_rng)(void *), void *p_rng )
+{
+    int ret, k, n;
+    unsigned char *p;
+    mpi Y;
+
+    if( nbits < 3 )
+        return( XYSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    mpi_init( &Y, NULL );
+
+    n = BITS_TO_LIMBS( nbits );
+
+    MPI_CHK( mpi_grow( X, n ) );
+    MPI_CHK( mpi_lset( X, 0 ) );
+
+    p = (unsigned char *) X->p;
+    for( k = 0; k < X->n * ciL; k++ )
+        *p++ = (unsigned char) f_rng( p_rng );
+
+    k = mpi_msb( X );
+    if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) );
+    if( k > nbits ) MPI_CHK( mpi_shift_r( X, k - nbits ) );
+
+    X->p[0] |= 3;
+
+    if( dh_flag == 0 )
+    {
+        while( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) != 0 )
+        {
+            if( ret != XYSSL_ERR_MPI_NOT_ACCEPTABLE )
+                goto cleanup;
+
+            MPI_CHK( mpi_add_int( X, X, 2 ) );
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_sub_int( &Y, X, 1 ) );
+        MPI_CHK( mpi_shift_r( &Y, 1 ) );
+
+        while( 1 )
+        {
+            if( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) == 0 )
+            {
+                if( ( ret = mpi_is_prime( &Y, f_rng, p_rng ) ) == 0 )
+                    break;
+
+                if( ret != XYSSL_ERR_MPI_NOT_ACCEPTABLE )
+                    goto cleanup;
+            }
+
+            if( ret != XYSSL_ERR_MPI_NOT_ACCEPTABLE )
+                goto cleanup;
+
+            MPI_CHK( mpi_add_int( &Y, X, 1 ) );
+            MPI_CHK( mpi_add_int(  X, X, 2 ) );
+            MPI_CHK( mpi_shift_r( &Y, 1 ) );
+        }
+    }
+
+cleanup:
+
+    mpi_free( &Y, NULL );
+
+    return( ret );
+}
+
+#endif
+
+#if defined(XYSSL_SELF_TEST)
+
+/*
+ * Checkup routine
+ */
+int mpi_self_test( int verbose )
+{
+    int ret;
+    mpi A, E, N, X, Y, U, V;
+
+    mpi_init( &A, &E, &N, &X, &Y, &U, &V, NULL );
+
+    MPI_CHK( mpi_read_string( &A, 16,
+        "EFE021C2645FD1DC586E69184AF4A31E" \
+        "D5F53E93B5F123FA41680867BA110131" \
+        "944FE7952E2517337780CB0DB80E61AA" \
+        "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) );
+
+    MPI_CHK( mpi_read_string( &E, 16,
+        "B2E7EFD37075B9F03FF989C7C5051C20" \
+        "34D2A323810251127E7BF8625A4F49A5" \
+        "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
+        "5B5C25763222FEFCCFC38B832366C29E" ) );
+
+    MPI_CHK( mpi_read_string( &N, 16,
+        "0066A198186C18C10B2F5ED9B522752A" \
+        "9830B69916E535C8F047518A889A43A5" \
+        "94B6BED27A168D31D4A52F88925AA8F5" ) );
+
+    MPI_CHK( mpi_mul_mpi( &X, &A, &N ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "602AB7ECA597A3D6B56FF9829A5E8B85" \
+        "9E857EA95A03512E2BAE7391688D264A" \
+        "A5663B0341DB9CCFD2C4C5F421FEC814" \
+        "8001B72E848A38CAE1C65F78E56ABDEF" \
+        "E12D3C039B8A02D6BE593F0BBBDA56F1" \
+        "ECF677152EF804370C1A305CAF3B5BF1" \
+        "30879B56C61DE584A0F53A2447A51E" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #1 (mul_mpi): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+    MPI_CHK( mpi_div_mpi( &X, &Y, &A, &N ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "256567336059E52CAE22925474705F39A94" ) );
+
+    MPI_CHK( mpi_read_string( &V, 16,
+        "6613F26162223DF488E9CD48CC132C7A" \
+        "0AC93C701B001B092E4E5B9F73BCD27B" \
+        "9EE50D0657C77F374E903CDFA4C642" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #2 (div_mpi): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 ||
+        mpi_cmp_mpi( &Y, &V ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+    MPI_CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "36E139AEA55215609D2816998ED020BB" \
+        "BD96C37890F65171D948E9BC7CBAA4D9" \
+        "325D24D6A3C12710F10A09FA08AB87" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #3 (exp_mod): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+    MPI_CHK( mpi_inv_mod( &X, &A, &N ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
+        "C3DBA76456363A10869622EAC2DD84EC" \
+        "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #4 (inv_mod): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+cleanup:
+
+    if( ret != 0 && verbose != 0 )
+        printf( "Unexpected error, return code = %08X\n", ret );
+
+    mpi_free( &V, &U, &Y, &X, &N, &E, &A, NULL );
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    return( ret );
+}
+
+#endif
+
+#endif
diff --git a/library/certs.c b/library/certs.c
new file mode 100644
index 0000000..8d0abb6
--- /dev/null
+++ b/library/certs.c
@@ -0,0 +1,211 @@
+/*
+ *  X.509 test certificates
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_CERTS_C)
+
+char test_ca_crt[] =
+"-----BEGIN CERTIFICATE-----\r\n"
+"MIIDpTCCAo2gAwIBAgIBADANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJGUjEO\r\n"
+"MAwGA1UEBxMFUGFyaXMxDjAMBgNVBAoTBVh5U1NMMRYwFAYDVQQDEw1YeVNTTCBU\r\n"
+"ZXN0IENBMB4XDTA3MDcwNzA1MDAxOFoXDTE3MDcwNzA1MDAxOFowRTELMAkGA1UE\r\n"
+"BhMCRlIxDjAMBgNVBAcTBVBhcmlzMQ4wDAYDVQQKEwVYeVNTTDEWMBQGA1UEAxMN\r\n"
+"WHlTU0wgVGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM+k\r\n"
+"gt70fIPiYqmvXr+9uPmWoN405eoSzxdiRLLCHqL4V/Ts0E/H+JNfHS4DHlAgxrJu\r\n"
+"+ZIadvSJuHkI6e1iMkAh5SU1DqaF3jrrFdJCooM6a077M4CRkE1tdAeZDf+BYp0q\r\n"
+"BeMU9Y2+j7ibsQaPAizunbXLf4QdteExCwhYRJ8OVXSEaSNt339gJzTD6kOhES3b\r\n"
+"lEN3qbx6lqFaJ5MLHTix5uNVc2rvbOizV5oLhJNqm52AKOp11tv6WTiI8loagvAc\r\n"
+"jlhEZRNb9el5SL6Jai/uFcqXKzfXNKW3FYPQHFGobmiMfGt1lUSBJ3F2mrqEC7gC\r\n"
+"wHy/FDvAI64/k5LZAFkCAwEAAaOBnzCBnDAMBgNVHRMEBTADAQH/MB0GA1UdDgQW\r\n"
+"BBS87h+Y6Porg+SkfV7DdXKTMdkyZzBtBgNVHSMEZjBkgBS87h+Y6Porg+SkfV7D\r\n"
+"dXKTMdkyZ6FJpEcwRTELMAkGA1UEBhMCRlIxDjAMBgNVBAcTBVBhcmlzMQ4wDAYD\r\n"
+"VQQKEwVYeVNTTDEWMBQGA1UEAxMNWHlTU0wgVGVzdCBDQYIBADANBgkqhkiG9w0B\r\n"
+"AQUFAAOCAQEAIHdoh0NCg6KAAhwDSmfEgSbKUI8/Zr/d56uw42HO0sj/uKPQzUco\r\n"
+"3Mx2BYE1m1itg7q5OhrkB7J4ZB78EtNZM84nV+y6od3YpR0Z9VUxCx7948MozYRy\r\n"
+"TKF5x/lKHRx1PJKfEO4clKdWTFAtWtGhewXrHJQ8C+ENh2Up2wTVh3Z+pEzuZNv3\r\n"
+"u/JYu1H+vkt3l1WCy/9mxUnu+anW1DzxPWnjy4lx6Mi0BD2qfKBWLjVS+7v6ALcj\r\n"
+"S2oRWWr4LUvXT7z9BBAvw2eJQD+a4uAya6EURG7AsAvr5MnWn/r0wLWmBJ6fB1Yp\r\n"
+"F1kOmamOFvstLMf74rLX+LGKeJ/nwuI5FQ==\r\n"
+"-----END CERTIFICATE-----\r\n";
+
+char test_ca_key[] =
+"-----BEGIN RSA PRIVATE KEY-----\r\n"
+"Proc-Type: 4,ENCRYPTED\r\n"
+"DEK-Info: DES-EDE3-CBC,7BDC280BA4C2F45C\r\n"
+"\r\n"
+"KI6rmwY0ChjF/0/Q7d1vE2jojZQTuF8j0wJUOf02PUUD4en8/FCLj69Pf3/lvOlu\r\n"
+"F8hU4IuBHxN2+feuXp6xTmGd/VyKdWh4+NGtKr2V1gXfk2wqHk3/P/YuF7QhOQjZ\r\n"
+"BlNF7n5o76Nufr3iwBbtIABCGQfNRUwGzrvmFXLIrSqns8ppv83qaD5jHVQQj5MM\r\n"
+"cGIoidwmNORdVmBCVZ17dQ+lMPfqjhN27GBhzXbp9a2EP3w+IqrXOvcl4DqSY+DU\r\n"
+"PIhS6KuQZ4iek4dI93wmw2D8Q67omcKYOX/BjCkZ/v6oq481qOej6MicIY/L9LxH\r\n"
+"r91jqIYLJC+1w20YavB3kIkSe5zys30RzhPTOtG60j8kgiQ4Fh+L/nKBP5noOXGE\r\n"
+"uzDBa051HCEYfufOVkXr6wBCFo9boqM1p/GI0Ze5gCsYY+Vzyu96gu+OGv55Jtyo\r\n"
+"fY2yEwVKhfqNy+xJ+8dwf8dcc5vQLatXebDynuSPI2jbaos6MJT6n0LoY2TpAz47\r\n"
+"vNE7UtEEdgZPPVwE4xO+dVa0kCqJxuG8b+ZZTHZidlQ6MBiebL4vXbeIFieQRzUM\r\n"
+"06IQ7YqsiBVLYxicMlApdFpJ4QM2fFKlZRo+fHg8EN9HEbRpgxIf4IwAAFjOgsiO\r\n"
+"ll7OmyzSF12NUIrRsIo02E4Y8X6xSFeYnOIiqZqdxG4xz/DZKoX6Js8WdYbtzrDv\r\n"
+"7gYYEZy1cuR9PJzMDKXoLz/mjBqDsh11Vgm1nAHbhBqFaWSuueH/LV2rgRijUBKh\r\n"
+"yMTnGXrz56DeJ85bYLjVEOM3xhvjsz6Fq5xLqXRTAzyQn7QuqRg2szLtCnN8olCh\r\n"
+"rdS1Gd7EV5g24WnF9gTzYJ4lwO9oxOsPKKCD1Z77B+lbZLoxTu7+rakTtqLikWMv\r\n"
+"7OILfR4iaIu1nKxhhXpwnze3u+1OWcuk0UnBjSnF519tlrgV3dmA0P2LHd6h6xru\r\n"
+"vIgUFHbigCV0i55peEPxtcy9JGLGJ3WvHA3NGSsqkkB/ymdfEaMmEH7403UKqQqq\r\n"
+"+K9Z1cYmeZlfoXClmdSjsxkYeN5raB0kOOSV/MEOySG+lztyLUGB4n46AZG2PgXN\r\n"
+"A9g9tv2gqc51Vl+55qwTg5429DigjiByRkcmBU3A1aF8yzD1QerwobPmqeNZ0mWv\r\n"
+"SllAvgVs2uy2Wf9/5gEWm+HjnJwS9VPNTocG/r+4BnDK8XG0Jy4oI+jSPxj/Y8Jt\r\n"
+"0ejFPM5A7HGngiaPFYHxcwPwo4Aa4HZnk+keFrA+vF9eDd1IOj195a9TESL+IGt1\r\n"
+"nuNmmuYjyJqM9Uvi1Mutv0UQ6Fl6yv4XxaUtMZKl4LtrAaMdW1T0PEgUG0tjSIxX\r\n"
+"hBd1W+Ob4nmK29aa4iuXaOxeAA3QK7KCZo18CJFgnp1w97qohwlKf+4FuNXHL64Q\r\n"
+"FgmpycV9nfP8G9aUYKAxs1+xutNv/B6opHmfLNL6d0cwi8dvGsrDdGlcyi8Dk/PF\r\n"
+"GKSqlQTF5V7l4UOanefB51tuziEBY+LWcXP4XgqNGPQknPF90NnbH1EglQG2paqb\r\n"
+"5bLyT8G6kfCSY4uHxs9lPuvfOjk9ptjy2FwfyBb3Sl4K+IFEE8XTNuNErh83AKh2\r\n"
+"-----END RSA PRIVATE KEY-----\r\n";
+
+char test_ca_pwd[] = "test";
+
+char test_srv_crt[] =
+"-----BEGIN CERTIFICATE-----\r\n"
+"MIIDPjCCAiagAwIBAgIBAjANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJGUjEO\r\n"
+"MAwGA1UEBxMFUGFyaXMxDjAMBgNVBAoTBVh5U1NMMRYwFAYDVQQDEw1YeVNTTCBU\r\n"
+"ZXN0IENBMB4XDTA3MDcwNzA1MDEyOVoXDTA4MDcwNjA1MDEyOVowMTELMAkGA1UE\r\n"
+"BhMCRlIxDjAMBgNVBAoTBVh5U1NMMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0G\r\n"
+"CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC40PDcGTgmHkt6noXDfkjVuymjiNYB\r\n"
+"gjtiL7uA1Ke3tXStacEecQek/OJxYqYr7ffcWalS29LL6HbKpi0xLZKBbD9ACkDh\r\n"
+"1Z/SvHlyQPILJdYb9DMw+kzZds5myXUjzn7Aem1YjoxMZUAMyc34i2900X2pL0v2\r\n"
+"SfCeJ9Ym4MOnZxYl217+dX9ZbkgIgrT6uY2IYK4boDwxbTcyT8i/NPsVsiMwtWPM\r\n"
+"rnQMr+XbgS98sUzcZE70Pe1TlV9Iy8j/8d2OiFo+qTyMu/6UpM2s3gdkQkMzx+Sm\r\n"
+"4QitRUjzmEXeUePRUjEgHIv7vz069xuVBzrks36w5BXiVAhLke/OTKVPAgMBAAGj\r\n"
+"TTBLMAkGA1UdEwQCMAAwHQYDVR0OBBYEFNkOyCTx64SDdPySGWl/tzD7/WMSMB8G\r\n"
+"A1UdIwQYMBaAFLzuH5jo+iuD5KR9XsN1cpMx2TJnMA0GCSqGSIb3DQEBBQUAA4IB\r\n"
+"AQBelJv5t+suaqy5Lo5bjNeHjNZfgg8EigDQ7NqaosvlQZAsh2N34Gg5YdkGyVdg\r\n"
+"s32I/K5aaywyUbG9qVXQxCM2T95qBqyK56h9yJoZKWQD9H//+zB8kCK/16WvRfv3\r\n"
+"VA7eSR19qOFWlHe+1qGh2YhxeDUfyi+fm4D36dGxqC2A34tZjo0QPHKtIeqM0kJy\r\n"
+"zzL65TlbJQKkyTuRHofFv0jW9ZFG2wkGysVgCY5fjuLI1do/sWUaXd2987iNFa+K\r\n"
+"FrHsTi6urSfZuGlZNxDXDHEE7Q2snAvvev+KR7DD9X4DJGcPX9gA4CGJj+9ZzyAA\r\n"
+"ZTGpOzk1hIH44RFs2lJMZRlE\r\n"
+"-----END CERTIFICATE-----\r\n";
+
+char test_srv_key[] =
+"-----BEGIN RSA PRIVATE KEY-----\r\n"
+"MIIEowIBAAKCAQEAuNDw3Bk4Jh5Lep6Fw35I1bspo4jWAYI7Yi+7gNSnt7V0rWnB\r\n"
+"HnEHpPzicWKmK+333FmpUtvSy+h2yqYtMS2SgWw/QApA4dWf0rx5ckDyCyXWG/Qz\r\n"
+"MPpM2XbOZsl1I85+wHptWI6MTGVADMnN+ItvdNF9qS9L9knwnifWJuDDp2cWJdte\r\n"
+"/nV/WW5ICIK0+rmNiGCuG6A8MW03Mk/IvzT7FbIjMLVjzK50DK/l24EvfLFM3GRO\r\n"
+"9D3tU5VfSMvI//HdjohaPqk8jLv+lKTNrN4HZEJDM8fkpuEIrUVI85hF3lHj0VIx\r\n"
+"IByL+789OvcblQc65LN+sOQV4lQIS5HvzkylTwIDAQABAoIBABeah8h0aBlmMRmd\r\n"
+"+VN4Y3D4kF7UcRCMQ21Mz1Oq1Si/QgGLyiBLK0DFE16LzNE7eTZpNRjh/lAQhmtn\r\n"
+"QcpQGa/x1TomlRbCo8DUVWZkKQWHdYroa0lMDliPtdimzhEepE2M1T5EJmLzY3S+\r\n"
+"qVGe7UMsJjJfWgJAezyXteANQK+2YSt+CjPIqIHch1KexUnvdN9++1oEx6AbuZ8T\r\n"
+"4avhFYZQP15tZNGsk2LfQlYS/NfbowkCsd0/TVubJBmDGUML/E5MbxjxLzlaNB2M\r\n"
+"V59cBNgsgA35CODAUF4xOyoSfZGqG1Rb9qQrv1E6Jz56dG8SsKF3HqnDjxiPOVBN\r\n"
+"FBnVJ+ECgYEA29MhAsKMm4XqBUKp6pIMFTgm/s1E5vxig70vqIiL+guvBhhQ7zs1\r\n"
+"8UMTNXZoMELNoB/ev9fN0Cjc1Vr46b/x/yDw7wMb96i+vzENOzu4RHWi3OWpCPbp\r\n"
+"qBKEi3hzN8M+BulPX8CDQx3aLRrfxw51J5EuA0NeybngbItgxTi0u6kCgYEA1zr0\r\n"
+"6P5YdOhYHtSWDlkeD49MApcVuzaHnsHZVAhUqu3Rwiy9LRaJLZfr7fQDb9DYJbZp\r\n"
+"sxTRLG6LSAcsR7mw+m+GvNqGt/9pSqbtW+L/VwVWSyF+YYklxZUD3UAAyrDVcDEC\r\n"
+"a5S+jad4Csi/lVHt5ulWIckWL1fJvadn5ubKNDcCgYA+71xVGPP+lsFgTiytfrC8\r\n"
+"5n2rl4MxinJ9+w0I+EbzCKNMYGvTgiU4dJasSMEdiBKs1FMGo7dF8F0BLHF1IsIa\r\n"
+"5Ah2tXItXn9154o9OiTQXMmK6qmRaneM6fhOoeaCwYAhpGxYIpqx/Xr4TOhiag46\r\n"
+"jMMaphAeOvw4t1K2RDziOQKBgQCyPCCU0gxuw/o1jda2CxbZy9EmU/erEX09+0n+\r\n"
+"TOfQpSEPq/z9WaxAFY9LfsdZ0ZktoeHma1bNdL3i6A3DWAM3YSQzQMRPmzOWnqXx\r\n"
+"cgoCBmlvzkzaeLjO5phMoLQHJmmafvuCG6uxov3F8Hi3LyHUF2c8k0nL6ucmJ3vj\r\n"
+"uzu4AQKBgBSASMAJS63M9UJB1Eazy2v2NWw04CmzNxUfWrHuKpd/C2ik4QKu0sRO\r\n"
+"r9KnkDgxxEhjDm7lXhlW12PU42yORst5I3Eaa1Cfi4KPFn/ozt+iNBYrzd8Tyvnb\r\n"
+"qkdECl0+G2Fo/ER4NRCv7a24WNEsOMGzGRqw5cnSJrjbZLYMaIyK\r\n"
+"-----END RSA PRIVATE KEY-----\r\n";
+
+char test_cli_crt[] =
+"-----BEGIN CERTIFICATE-----\r\n"
+"MIIDPTCCAiWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJGUjEO\r\n"
+"MAwGA1UEBxMFUGFyaXMxDjAMBgNVBAoTBVh5U1NMMRYwFAYDVQQDEw1YeVNTTCBU\r\n"
+"ZXN0IENBMB4XDTA3MDcwNzA1MDEyMFoXDTA4MDcwNjA1MDEyMFowMDELMAkGA1UE\r\n"
+"BhMCRlIxDjAMBgNVBAoTBVh5U1NMMREwDwYDVQQDEwhKb2UgVXNlcjCCASIwDQYJ\r\n"
+"KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKZkg8ANl6kGmLGqKc6KUHb9IsZwb2+K\r\n"
+"jBw83Qb0KuvPVnu3MzEcXFvOZ83g0PL/z8ob5PKr8HP6bVYzhsD65imcCDEEVPk2\r\n"
+"9r0XGTggGjB601Fd8aTShUWE4NLrKw6YNXTXgTNdvhHNxXwqmdNVLkmZjj3ZwYUc\r\n"
+"cEE8eE5jHs8cMDXJLMCwgKIM7Sax22OhSHQHKwifVO4/Fdw5G+Suys8PhMX2jDXM\r\n"
+"ICFwq8ld+bZGoNUtgp48FWhAMfJyTEaHh9LC46KkqGSDRIzx7/4cPB6QqrpzJN0o\r\n"
+"Kr8kH7vdRDTFDmO23D4C5l0Bw/2aC76DhEJpB2bGA4iIszJs+F/PIL8CAwEAAaNN\r\n"
+"MEswCQYDVR0TBAIwADAdBgNVHQ4EFgQUiWX1IvjRdYGt0zz5Sq16x01k0o4wHwYD\r\n"
+"VR0jBBgwFoAUvO4fmOj6K4PkpH1ew3VykzHZMmcwDQYJKoZIhvcNAQEFBQADggEB\r\n"
+"AGdqD7VThJmC+oeeMUHk2TQX2wZNU+GsC+RLjtlenckny95KnljGvMtCznyLkS5D\r\n"
+"fAjLKfR1No8pk5gRdscqgyIuQx5WnHNv4QBZmMsmvDICxzRQaxuPFHbS4aLXldeL\r\n"
+"yOWm5Z4qkMHpCKvA86blYsEkksGDV47fF9ZkOQ8nkh7Z4eY4/5TwqTY72ww5g4NL\r\n"
+"6DZtWpcpGbX99NRaNVzcq9D+ElxkgHnH4YWafOKBclSgqrutbRLi2uZx/QpvuF+i\r\n"
+"sUbe+HFPMWwU5lBv/oOhQkz0VD+HusYtXWS2lG88cT40aNly2CkYUugdTR/b9Uea\r\n"
+"p/i862sL/lO40qlQ0xV5N7U=\r\n"
+"-----END CERTIFICATE-----\r\n";
+
+char test_cli_key[] =
+"-----BEGIN RSA PRIVATE KEY-----\r\n"
+"MIIEowIBAAKCAQEApmSDwA2XqQaYsaopzopQdv0ixnBvb4qMHDzdBvQq689We7cz\r\n"
+"MRxcW85nzeDQ8v/Pyhvk8qvwc/ptVjOGwPrmKZwIMQRU+Tb2vRcZOCAaMHrTUV3x\r\n"
+"pNKFRYTg0usrDpg1dNeBM12+Ec3FfCqZ01UuSZmOPdnBhRxwQTx4TmMezxwwNcks\r\n"
+"wLCAogztJrHbY6FIdAcrCJ9U7j8V3Dkb5K7Kzw+ExfaMNcwgIXCryV35tkag1S2C\r\n"
+"njwVaEAx8nJMRoeH0sLjoqSoZINEjPHv/hw8HpCqunMk3SgqvyQfu91ENMUOY7bc\r\n"
+"PgLmXQHD/ZoLvoOEQmkHZsYDiIizMmz4X88gvwIDAQABAoIBAE0nBkAjDVN+j4ax\r\n"
+"1DjEwZKqxVkmAUXDBDyDrCjxRoWY2gz7YW1ALUMUbeV0fO5v1zVrwbkUKKZeVBxI\r\n"
+"QA9zRw28H8A6tfvolHgRIcx4dixMh3ePC+DVDJ6zglvKV2ipAwBufKYIrX0r4Io2\r\n"
+"ZqUrNg9CeEYNlkHWceaN12rhYwO82pgHxnB1p5pI42pY7lzyLgSddf5n+M5UBOJI\r\n"
+"gsNCkvbGdv7WQPVFTRDiRgEnCJ3rI8oPSK6MOUWJw3rh2hbkx+ex8NPvEKbzEXiU\r\n"
+"p5j1AlbHIWP5sYBbA1YviFtryAV4fyfLcWPfoqa33Oozofjlwoj0Aixz+6rerLjZ\r\n"
+"cpTSrAECgYEA2oCffUo6HH3Lq9oeWhFCoOyG3YjZmFrJaJwjHnvroX9/pXHqYKog\r\n"
+"TehcjUJBtFZw0klcetYbZCFqT8v9nf0uPlgaiVGCtXf1MSbFXDUFKkYBiFwzdWMT\r\n"
+"Ysmvhff82jMWZ8ecsXTyDRl858SR5WPZ52qEsCc5X2un7QENm6FtVT8CgYEAwvKS\r\n"
+"zQNzuoJETqZX7AalmK3JM8Fdam+Qm5LNMcbvhbKwI8HKMS1VMuqaR0XdAX/iMXAx\r\n"
+"P1VhSsmoSDbsMpxBEZIptpCen/GcqctITxANTakrBHxqb2aQ5EEu7SzgfHZWse3/\r\n"
+"vQEyfcFTBlPIdcZUDzk4/w7WmyivpYtCWoAh1IECgYEA0UYZ+1UJfVpapRj+swMP\r\n"
+"DrQbo7i7t7lUaFYLKNpFX2OPLTWC5txqnlOruTu5VHDqE+5hneDNUUTT3uOg4B2q\r\n"
+"mdmmaNjh2M6wz0e0BVFexhNQynqMaqTe32IOM8DFs3L0xacgg7JfVn6P7CeQGOVe\r\n"
+"wc96kICw6ZxhtJSqpOGipt8CgYBI/0Pw+IXxJK4nNSpe+u4vCYP5mUI9hKEFYCbt\r\n"
+"qKwvyAUknn/zgiIQ+r/iSErFMPmlwXjvWi0gL/qPb+Fp4hCLX8u2zNhY08Px4Gin\r\n"
+"Ej+pANtWxq+kHyfKEI5dyRwV/snfvlqwjy404JsSF3VMhIMdYDPzbb72Qnni5w5l\r\n"
+"jO0eAQKBgBqt9jJMd1JdpemC2dm0BuuDIz2h3/MH+CMjfaDLenVpKykn17B6N92h\r\n"
+"klMesqK3RQzDGwauDw431LQw0R69onn9fCM3wJw2yEC6wC9sF8I8hsNZbt64yZhZ\r\n"
+"4Bi2YRTiHhpEuBqKlhHLDFHneo3SMYh8PU/PDQQcyWGHHUi9z1RE\r\n"
+"-----END RSA PRIVATE KEY-----\r\n";
+
+char xyssl_ca_crt[] =
+"-----BEGIN CERTIFICATE-----\r\n"
+"MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh\r\n"
+"MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE\r\n"
+"YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3\r\n"
+"MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo\r\n"
+"ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg\r\n"
+"MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN\r\n"
+"ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA\r\n"
+"PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w\r\n"
+"wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi\r\n"
+"EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY\r\n"
+"avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+\r\n"
+"YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE\r\n"
+"sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h\r\n"
+"/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5\r\n"
+"IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj\r\n"
+"YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD\r\n"
+"ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy\r\n"
+"OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P\r\n"
+"TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ\r\n"
+"HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER\r\n"
+"dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf\r\n"
+"ReYNnyicsbkqWletNw+vHX/bvZ8=\r\n"
+"-----END CERTIFICATE-----\r\n";
+
+#endif
diff --git a/library/debug.c b/library/debug.c
new file mode 100644
index 0000000..4862fc4
--- /dev/null
+++ b/library/debug.c
@@ -0,0 +1,202 @@
+/*
+ *  Debugging routines
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_DEBUG_C)
+
+#include "xyssl/debug.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#if defined _MSC_VER && !defined  snprintf
+#define  snprintf  _snprintf
+#endif
+
+#if defined _MSC_VER && !defined vsnprintf
+#define vsnprintf _vsnprintf
+#endif
+
+char *debug_fmt( const char *format, ... )
+{
+    va_list argp;
+    static char str[512];
+    int maxlen = sizeof( str ) - 1;
+
+    va_start( argp, format );
+    vsnprintf( str, maxlen, format, argp );
+    va_end( argp );
+
+    str[maxlen] = '\0';
+    return( str );
+}
+
+void debug_print_msg( ssl_context *ssl, int level,
+                      char *file, int line, char *text )
+{
+    char str[512];
+    int maxlen = sizeof( str ) - 1;
+
+    if( ssl->f_dbg == NULL )
+        return;
+
+    snprintf( str, maxlen, "%s(%04d): %s\n", file, line, text );
+    str[maxlen] = '\0';
+    ssl->f_dbg( ssl->p_dbg, level, str );
+}
+
+void debug_print_ret( ssl_context *ssl, int level,
+                      char *file, int line, char *text, int ret )
+{
+    char str[512];
+    int maxlen = sizeof( str ) - 1;
+
+    if( ssl->f_dbg == NULL )
+        return;
+
+    snprintf( str, maxlen, "%s(%04d): %s() returned %d (0x%x)\n",
+              file, line, text, ret, ret );
+
+    str[maxlen] = '\0';
+    ssl->f_dbg( ssl->p_dbg, level, str );
+}
+
+void debug_print_buf( ssl_context *ssl, int level,
+                      char *file, int line, char *text,
+                      unsigned char *buf, int len )
+{
+    char str[512];
+    int i, maxlen = sizeof( str ) - 1;
+
+    if( ssl->f_dbg == NULL || len < 0 )
+        return;
+
+    snprintf( str, maxlen, "%s(%04d): dumping '%s' (%d bytes)\n",
+              file, line, text, len );
+
+    str[maxlen] = '\0';
+    ssl->f_dbg( ssl->p_dbg, level, str );
+
+    for( i = 0; i < len; i++ )
+    {
+        if( i >= 4096 )
+            break;
+
+        if( i % 16 == 0 )
+        {
+            if( i > 0 )
+                ssl->f_dbg( ssl->p_dbg, level, "\n" );
+
+            snprintf( str, maxlen, "%s(%04d): %04x: ", file, line, i );
+
+            str[maxlen] = '\0';
+            ssl->f_dbg( ssl->p_dbg, level, str );
+        }
+
+        snprintf( str, maxlen, " %02x", (unsigned int) buf[i] );
+
+        str[maxlen] = '\0';
+        ssl->f_dbg( ssl->p_dbg, level, str );
+    }
+
+    if( len > 0 )
+        ssl->f_dbg( ssl->p_dbg, level, "\n" );
+}
+
+void debug_print_mpi( ssl_context *ssl, int level,
+                      char *file, int line, char *text, mpi *X )
+{
+    char str[512];
+    int i, j, k, n, maxlen = sizeof( str ) - 1;
+
+    if( ssl->f_dbg == NULL || X == NULL )
+        return;
+
+    for( n = X->n - 1; n >= 0; n-- )
+        if( X->p[n] != 0 )
+            break;
+
+    snprintf( str, maxlen, "%s(%04d): value of '%s' (%d bits) is:\n",
+              file, line, text, ((n + 1) * sizeof( t_int )) << 3 );
+
+    str[maxlen] = '\0';
+    ssl->f_dbg( ssl->p_dbg, level, str );
+
+    for( i = n, j = 0; i >= 0; i--, j++ )
+    {
+        if( j % ( 16 / sizeof( t_int ) ) == 0 )
+        {
+            if( j > 0 )
+                ssl->f_dbg( ssl->p_dbg, level, "\n" );
+
+            snprintf( str, maxlen, "%s(%04d): ", file, line );
+
+            str[maxlen] = '\0';
+            ssl->f_dbg( ssl->p_dbg, level, str );
+        }
+
+        for( k = sizeof( t_int ) - 1; k >= 0; k-- )
+        {
+            snprintf( str, maxlen, " %02x", (unsigned int)
+                      ( X->p[i] >> (k << 3) ) & 0xFF );
+
+            str[maxlen] = '\0';
+            ssl->f_dbg( ssl->p_dbg, level, str );
+        }
+    }
+
+    ssl->f_dbg( ssl->p_dbg, level, "\n" );
+}
+
+void debug_print_crt( ssl_context *ssl, int level,
+                      char *file, int line, char *text, x509_cert *crt )
+{
+    char str[512], prefix[64], *p;
+    int i = 0, maxlen = sizeof( prefix ) - 1;
+
+    if( ssl->f_dbg == NULL || crt == NULL )
+        return;
+
+    snprintf( prefix, maxlen, "%s(%04d): ", file, line );
+    prefix[maxlen] = '\0';
+    maxlen = sizeof( str ) - 1;
+
+    while( crt != NULL && crt->next != NULL )
+    {
+        p = x509parse_cert_info( prefix, crt );
+
+        snprintf( str, maxlen, "%s(%04d): %s #%d:\n%s",
+                  file, line, text, ++i, p );
+
+        str[maxlen] = '\0';
+        ssl->f_dbg( ssl->p_dbg, level, str );
+
+        debug_print_mpi( ssl, level, file, line,
+                         "crt->rsa.N", &crt->rsa.N );
+
+        debug_print_mpi( ssl, level, file, line,
+                         "crt->rsa.E", &crt->rsa.E );
+
+        crt = crt->next;
+    }
+}
+
+#endif
diff --git a/library/des.c b/library/des.c
new file mode 100644
index 0000000..aec027d
--- /dev/null
+++ b/library/des.c
@@ -0,0 +1,876 @@
+/*
+ *  FIPS-46-3 compliant Triple-DES implementation
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  DES, on which TDES is based, was originally designed by Horst Feistel
+ *  at IBM in 1974, and was adopted as a standard by NIST (formerly NBS).
+ *
+ *  http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_DES_C)
+
+#include "xyssl/des.h"
+
+#include <string.h>
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_ULONG_BE
+#define GET_ULONG_BE(n,b,i)                             \
+{                                                       \
+    (n) = ( (unsigned long) (b)[(i)    ] << 24 )        \
+        | ( (unsigned long) (b)[(i) + 1] << 16 )        \
+        | ( (unsigned long) (b)[(i) + 2] <<  8 )        \
+        | ( (unsigned long) (b)[(i) + 3]       );       \
+}
+#endif
+
+#ifndef PUT_ULONG_BE
+#define PUT_ULONG_BE(n,b,i)                             \
+{                                                       \
+    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
+    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
+    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
+    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
+}
+#endif
+
+/*
+ * Expanded DES S-boxes
+ */
+static const unsigned long SB1[64] =
+{
+    0x01010400, 0x00000000, 0x00010000, 0x01010404,
+    0x01010004, 0x00010404, 0x00000004, 0x00010000,
+    0x00000400, 0x01010400, 0x01010404, 0x00000400,
+    0x01000404, 0x01010004, 0x01000000, 0x00000004,
+    0x00000404, 0x01000400, 0x01000400, 0x00010400,
+    0x00010400, 0x01010000, 0x01010000, 0x01000404,
+    0x00010004, 0x01000004, 0x01000004, 0x00010004,
+    0x00000000, 0x00000404, 0x00010404, 0x01000000,
+    0x00010000, 0x01010404, 0x00000004, 0x01010000,
+    0x01010400, 0x01000000, 0x01000000, 0x00000400,
+    0x01010004, 0x00010000, 0x00010400, 0x01000004,
+    0x00000400, 0x00000004, 0x01000404, 0x00010404,
+    0x01010404, 0x00010004, 0x01010000, 0x01000404,
+    0x01000004, 0x00000404, 0x00010404, 0x01010400,
+    0x00000404, 0x01000400, 0x01000400, 0x00000000,
+    0x00010004, 0x00010400, 0x00000000, 0x01010004
+};
+
+static const unsigned long SB2[64] =
+{
+    0x80108020, 0x80008000, 0x00008000, 0x00108020,
+    0x00100000, 0x00000020, 0x80100020, 0x80008020,
+    0x80000020, 0x80108020, 0x80108000, 0x80000000,
+    0x80008000, 0x00100000, 0x00000020, 0x80100020,
+    0x00108000, 0x00100020, 0x80008020, 0x00000000,
+    0x80000000, 0x00008000, 0x00108020, 0x80100000,
+    0x00100020, 0x80000020, 0x00000000, 0x00108000,
+    0x00008020, 0x80108000, 0x80100000, 0x00008020,
+    0x00000000, 0x00108020, 0x80100020, 0x00100000,
+    0x80008020, 0x80100000, 0x80108000, 0x00008000,
+    0x80100000, 0x80008000, 0x00000020, 0x80108020,
+    0x00108020, 0x00000020, 0x00008000, 0x80000000,
+    0x00008020, 0x80108000, 0x00100000, 0x80000020,
+    0x00100020, 0x80008020, 0x80000020, 0x00100020,
+    0x00108000, 0x00000000, 0x80008000, 0x00008020,
+    0x80000000, 0x80100020, 0x80108020, 0x00108000
+};
+
+static const unsigned long SB3[64] =
+{
+    0x00000208, 0x08020200, 0x00000000, 0x08020008,
+    0x08000200, 0x00000000, 0x00020208, 0x08000200,
+    0x00020008, 0x08000008, 0x08000008, 0x00020000,
+    0x08020208, 0x00020008, 0x08020000, 0x00000208,
+    0x08000000, 0x00000008, 0x08020200, 0x00000200,
+    0x00020200, 0x08020000, 0x08020008, 0x00020208,
+    0x08000208, 0x00020200, 0x00020000, 0x08000208,
+    0x00000008, 0x08020208, 0x00000200, 0x08000000,
+    0x08020200, 0x08000000, 0x00020008, 0x00000208,
+    0x00020000, 0x08020200, 0x08000200, 0x00000000,
+    0x00000200, 0x00020008, 0x08020208, 0x08000200,
+    0x08000008, 0x00000200, 0x00000000, 0x08020008,
+    0x08000208, 0x00020000, 0x08000000, 0x08020208,
+    0x00000008, 0x00020208, 0x00020200, 0x08000008,
+    0x08020000, 0x08000208, 0x00000208, 0x08020000,
+    0x00020208, 0x00000008, 0x08020008, 0x00020200
+};
+
+static const unsigned long SB4[64] =
+{
+    0x00802001, 0x00002081, 0x00002081, 0x00000080,
+    0x00802080, 0x00800081, 0x00800001, 0x00002001,
+    0x00000000, 0x00802000, 0x00802000, 0x00802081,
+    0x00000081, 0x00000000, 0x00800080, 0x00800001,
+    0x00000001, 0x00002000, 0x00800000, 0x00802001,
+    0x00000080, 0x00800000, 0x00002001, 0x00002080,
+    0x00800081, 0x00000001, 0x00002080, 0x00800080,
+    0x00002000, 0x00802080, 0x00802081, 0x00000081,
+    0x00800080, 0x00800001, 0x00802000, 0x00802081,
+    0x00000081, 0x00000000, 0x00000000, 0x00802000,
+    0x00002080, 0x00800080, 0x00800081, 0x00000001,
+    0x00802001, 0x00002081, 0x00002081, 0x00000080,
+    0x00802081, 0x00000081, 0x00000001, 0x00002000,
+    0x00800001, 0x00002001, 0x00802080, 0x00800081,
+    0x00002001, 0x00002080, 0x00800000, 0x00802001,
+    0x00000080, 0x00800000, 0x00002000, 0x00802080
+};
+
+static const unsigned long SB5[64] =
+{
+    0x00000100, 0x02080100, 0x02080000, 0x42000100,
+    0x00080000, 0x00000100, 0x40000000, 0x02080000,
+    0x40080100, 0x00080000, 0x02000100, 0x40080100,
+    0x42000100, 0x42080000, 0x00080100, 0x40000000,
+    0x02000000, 0x40080000, 0x40080000, 0x00000000,
+    0x40000100, 0x42080100, 0x42080100, 0x02000100,
+    0x42080000, 0x40000100, 0x00000000, 0x42000000,
+    0x02080100, 0x02000000, 0x42000000, 0x00080100,
+    0x00080000, 0x42000100, 0x00000100, 0x02000000,
+    0x40000000, 0x02080000, 0x42000100, 0x40080100,
+    0x02000100, 0x40000000, 0x42080000, 0x02080100,
+    0x40080100, 0x00000100, 0x02000000, 0x42080000,
+    0x42080100, 0x00080100, 0x42000000, 0x42080100,
+    0x02080000, 0x00000000, 0x40080000, 0x42000000,
+    0x00080100, 0x02000100, 0x40000100, 0x00080000,
+    0x00000000, 0x40080000, 0x02080100, 0x40000100
+};
+
+static const unsigned long SB6[64] =
+{
+    0x20000010, 0x20400000, 0x00004000, 0x20404010,
+    0x20400000, 0x00000010, 0x20404010, 0x00400000,
+    0x20004000, 0x00404010, 0x00400000, 0x20000010,
+    0x00400010, 0x20004000, 0x20000000, 0x00004010,
+    0x00000000, 0x00400010, 0x20004010, 0x00004000,
+    0x00404000, 0x20004010, 0x00000010, 0x20400010,
+    0x20400010, 0x00000000, 0x00404010, 0x20404000,
+    0x00004010, 0x00404000, 0x20404000, 0x20000000,
+    0x20004000, 0x00000010, 0x20400010, 0x00404000,
+    0x20404010, 0x00400000, 0x00004010, 0x20000010,
+    0x00400000, 0x20004000, 0x20000000, 0x00004010,
+    0x20000010, 0x20404010, 0x00404000, 0x20400000,
+    0x00404010, 0x20404000, 0x00000000, 0x20400010,
+    0x00000010, 0x00004000, 0x20400000, 0x00404010,
+    0x00004000, 0x00400010, 0x20004010, 0x00000000,
+    0x20404000, 0x20000000, 0x00400010, 0x20004010
+};
+
+static const unsigned long SB7[64] =
+{
+    0x00200000, 0x04200002, 0x04000802, 0x00000000,
+    0x00000800, 0x04000802, 0x00200802, 0x04200800,
+    0x04200802, 0x00200000, 0x00000000, 0x04000002,
+    0x00000002, 0x04000000, 0x04200002, 0x00000802,
+    0x04000800, 0x00200802, 0x00200002, 0x04000800,
+    0x04000002, 0x04200000, 0x04200800, 0x00200002,
+    0x04200000, 0x00000800, 0x00000802, 0x04200802,
+    0x00200800, 0x00000002, 0x04000000, 0x00200800,
+    0x04000000, 0x00200800, 0x00200000, 0x04000802,
+    0x04000802, 0x04200002, 0x04200002, 0x00000002,
+    0x00200002, 0x04000000, 0x04000800, 0x00200000,
+    0x04200800, 0x00000802, 0x00200802, 0x04200800,
+    0x00000802, 0x04000002, 0x04200802, 0x04200000,
+    0x00200800, 0x00000000, 0x00000002, 0x04200802,
+    0x00000000, 0x00200802, 0x04200000, 0x00000800,
+    0x04000002, 0x04000800, 0x00000800, 0x00200002
+};
+
+static const unsigned long SB8[64] =
+{
+    0x10001040, 0x00001000, 0x00040000, 0x10041040,
+    0x10000000, 0x10001040, 0x00000040, 0x10000000,
+    0x00040040, 0x10040000, 0x10041040, 0x00041000,
+    0x10041000, 0x00041040, 0x00001000, 0x00000040,
+    0x10040000, 0x10000040, 0x10001000, 0x00001040,
+    0x00041000, 0x00040040, 0x10040040, 0x10041000,
+    0x00001040, 0x00000000, 0x00000000, 0x10040040,
+    0x10000040, 0x10001000, 0x00041040, 0x00040000,
+    0x00041040, 0x00040000, 0x10041000, 0x00001000,
+    0x00000040, 0x10040040, 0x00001000, 0x00041040,
+    0x10001000, 0x00000040, 0x10000040, 0x10040000,
+    0x10040040, 0x10000000, 0x00040000, 0x10001040,
+    0x00000000, 0x10041040, 0x00040040, 0x10000040,
+    0x10040000, 0x10001000, 0x10001040, 0x00000000,
+    0x10041040, 0x00041000, 0x00041000, 0x00001040,
+    0x00001040, 0x00040040, 0x10000000, 0x10041000
+};
+
+/*
+ * PC1: left and right halves bit-swap
+ */
+static const unsigned long LHs[16] =
+{
+    0x00000000, 0x00000001, 0x00000100, 0x00000101,
+    0x00010000, 0x00010001, 0x00010100, 0x00010101,
+    0x01000000, 0x01000001, 0x01000100, 0x01000101,
+    0x01010000, 0x01010001, 0x01010100, 0x01010101
+};
+
+static const unsigned long RHs[16] =
+{
+    0x00000000, 0x01000000, 0x00010000, 0x01010000,
+    0x00000100, 0x01000100, 0x00010100, 0x01010100,
+    0x00000001, 0x01000001, 0x00010001, 0x01010001,
+    0x00000101, 0x01000101, 0x00010101, 0x01010101,
+};
+
+/*
+ * Initial Permutation macro
+ */
+#define DES_IP(X,Y)                                             \
+{                                                               \
+    T = ((X >>  4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T <<  4);   \
+    T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16);   \
+    T = ((Y >>  2) ^ X) & 0x33333333; X ^= T; Y ^= (T <<  2);   \
+    T = ((Y >>  8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T <<  8);   \
+    Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF;                    \
+    T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T;                   \
+    X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF;                    \
+}
+
+/*
+ * Final Permutation macro
+ */
+#define DES_FP(X,Y)                                             \
+{                                                               \
+    X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF;                    \
+    T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T;                   \
+    Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF;                    \
+    T = ((Y >>  8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T <<  8);   \
+    T = ((Y >>  2) ^ X) & 0x33333333; X ^= T; Y ^= (T <<  2);   \
+    T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16);   \
+    T = ((X >>  4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T <<  4);   \
+}
+
+/*
+ * DES round macro
+ */
+#define DES_ROUND(X,Y)                          \
+{                                               \
+    T = *SK++ ^ X;                              \
+    Y ^= SB8[ (T      ) & 0x3F ] ^              \
+         SB6[ (T >>  8) & 0x3F ] ^              \
+         SB4[ (T >> 16) & 0x3F ] ^              \
+         SB2[ (T >> 24) & 0x3F ];               \
+                                                \
+    T = *SK++ ^ ((X << 28) | (X >> 4));         \
+    Y ^= SB7[ (T      ) & 0x3F ] ^              \
+         SB5[ (T >>  8) & 0x3F ] ^              \
+         SB3[ (T >> 16) & 0x3F ] ^              \
+         SB1[ (T >> 24) & 0x3F ];               \
+}
+
+#define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; }
+
+static void des_setkey( unsigned long SK[32], unsigned char key[8] )
+{
+    int i;
+    unsigned long X, Y, T;
+
+    GET_ULONG_BE( X, key, 0 );
+    GET_ULONG_BE( Y, key, 4 );
+
+    /*
+     * Permuted Choice 1
+     */
+    T =  ((Y >>  4) ^ X) & 0x0F0F0F0F;  X ^= T; Y ^= (T <<  4);
+    T =  ((Y      ) ^ X) & 0x10101010;  X ^= T; Y ^= (T      );
+
+    X =   (LHs[ (X      ) & 0xF] << 3) | (LHs[ (X >>  8) & 0xF ] << 2)
+        | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ]     )
+        | (LHs[ (X >>  5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6)
+        | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4);
+
+    Y =   (RHs[ (Y >>  1) & 0xF] << 3) | (RHs[ (Y >>  9) & 0xF ] << 2)
+        | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ]     )
+        | (RHs[ (Y >>  4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6)
+        | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4);
+
+    X &= 0x0FFFFFFF;
+    Y &= 0x0FFFFFFF;
+
+    /*
+     * calculate subkeys
+     */
+    for( i = 0; i < 16; i++ )
+    {
+        if( i < 2 || i == 8 || i == 15 )
+        {
+            X = ((X <<  1) | (X >> 27)) & 0x0FFFFFFF;
+            Y = ((Y <<  1) | (Y >> 27)) & 0x0FFFFFFF;
+        }
+        else
+        {
+            X = ((X <<  2) | (X >> 26)) & 0x0FFFFFFF;
+            Y = ((Y <<  2) | (Y >> 26)) & 0x0FFFFFFF;
+        }
+
+        *SK++ =   ((X <<  4) & 0x24000000) | ((X << 28) & 0x10000000)
+                | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000)
+                | ((X <<  6) & 0x01000000) | ((X <<  9) & 0x00200000)
+                | ((X >>  1) & 0x00100000) | ((X << 10) & 0x00040000)
+                | ((X <<  2) & 0x00020000) | ((X >> 10) & 0x00010000)
+                | ((Y >> 13) & 0x00002000) | ((Y >>  4) & 0x00001000)
+                | ((Y <<  6) & 0x00000800) | ((Y >>  1) & 0x00000400)
+                | ((Y >> 14) & 0x00000200) | ((Y      ) & 0x00000100)
+                | ((Y >>  5) & 0x00000020) | ((Y >> 10) & 0x00000010)
+                | ((Y >>  3) & 0x00000008) | ((Y >> 18) & 0x00000004)
+                | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001);
+
+        *SK++ =   ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000)
+                | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000)
+                | ((X >>  2) & 0x02000000) | ((X <<  1) & 0x01000000)
+                | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000)
+                | ((X <<  3) & 0x00080000) | ((X >>  6) & 0x00040000)
+                | ((X << 15) & 0x00020000) | ((X >>  4) & 0x00010000)
+                | ((Y >>  2) & 0x00002000) | ((Y <<  8) & 0x00001000)
+                | ((Y >> 14) & 0x00000808) | ((Y >>  9) & 0x00000400)
+                | ((Y      ) & 0x00000200) | ((Y <<  7) & 0x00000100)
+                | ((Y >>  7) & 0x00000020) | ((Y >>  3) & 0x00000011)
+                | ((Y <<  2) & 0x00000004) | ((Y >> 21) & 0x00000002);
+    }
+}
+
+/*
+ * DES key schedule (56-bit, encryption)
+ */
+void des_setkey_enc( des_context *ctx, unsigned char key[8] )
+{
+    des_setkey( ctx->sk, key );
+}
+
+/*
+ * DES key schedule (56-bit, decryption)
+ */
+void des_setkey_dec( des_context *ctx, unsigned char key[8] )
+{
+    int i;
+
+    des_setkey( ctx->sk, key );
+
+    for( i = 0; i < 16; i += 2 )
+    {
+        SWAP( ctx->sk[i    ], ctx->sk[30 - i] );
+        SWAP( ctx->sk[i + 1], ctx->sk[31 - i] );
+    }
+}
+
+static void des3_set2key( unsigned long esk[96],
+                          unsigned long dsk[96],
+                          unsigned char key[16] )
+{
+    int i;
+
+    des_setkey( esk, key );
+    des_setkey( dsk + 32, key + 8 );
+
+    for( i = 0; i < 32; i += 2 )
+    {
+        dsk[i     ] = esk[30 - i];
+        dsk[i +  1] = esk[31 - i];
+
+        esk[i + 32] = dsk[62 - i];
+        esk[i + 33] = dsk[63 - i];
+
+        esk[i + 64] = esk[i    ];
+        esk[i + 65] = esk[i + 1];
+
+        dsk[i + 64] = dsk[i    ];
+        dsk[i + 65] = dsk[i + 1];
+    }
+}
+
+/*
+ * Triple-DES key schedule (112-bit, encryption)
+ */
+void des3_set2key_enc( des3_context *ctx, unsigned char key[16] )
+{
+    unsigned long sk[96];
+
+    des3_set2key( ctx->sk, sk, key );
+    memset( sk,  0, sizeof( sk ) );
+}
+
+/*
+ * Triple-DES key schedule (112-bit, decryption)
+ */
+void des3_set2key_dec( des3_context *ctx, unsigned char key[16] )
+{
+    unsigned long sk[96];
+
+    des3_set2key( sk, ctx->sk, key );
+    memset( sk,  0, sizeof( sk ) );
+}
+
+static void des3_set3key( unsigned long esk[96],
+                          unsigned long dsk[96],
+                          unsigned char key[24] )
+{
+    int i;
+
+    des_setkey( esk, key );
+    des_setkey( dsk + 32, key +  8 );
+    des_setkey( esk + 64, key + 16 );
+
+    for( i = 0; i < 32; i += 2 )
+    {
+        dsk[i     ] = esk[94 - i];
+        dsk[i +  1] = esk[95 - i];
+
+        esk[i + 32] = dsk[62 - i];
+        esk[i + 33] = dsk[63 - i];
+
+        dsk[i + 64] = esk[30 - i];
+        dsk[i + 65] = esk[31 - i];
+    }
+}
+
+/*
+ * Triple-DES key schedule (168-bit, encryption)
+ */
+void des3_set3key_enc( des3_context *ctx, unsigned char key[24] )
+{
+    unsigned long sk[96];
+
+    des3_set3key( ctx->sk, sk, key );
+    memset( sk, 0, sizeof( sk ) );
+}
+
+/*
+ * Triple-DES key schedule (168-bit, decryption)
+ */
+void des3_set3key_dec( des3_context *ctx, unsigned char key[24] )
+{
+    unsigned long sk[96];
+
+    des3_set3key( sk, ctx->sk, key );
+    memset( sk, 0, sizeof( sk ) );
+}
+
+/*
+ * DES-ECB block encryption/decryption
+ */
+void des_crypt_ecb( des_context *ctx,
+                    unsigned char input[8],
+                    unsigned char output[8] )
+{
+    int i;
+    unsigned long X, Y, T, *SK;
+
+    SK = ctx->sk;
+
+    GET_ULONG_BE( X, input, 0 );
+    GET_ULONG_BE( Y, input, 4 );
+
+    DES_IP( X, Y );
+
+    for( i = 0; i < 8; i++ )
+    {
+        DES_ROUND( Y, X );
+        DES_ROUND( X, Y );
+    }
+
+    DES_FP( Y, X );
+
+    PUT_ULONG_BE( Y, output, 0 );
+    PUT_ULONG_BE( X, output, 4 );
+}
+
+/*
+ * DES-CBC buffer encryption/decryption
+ */
+void des_crypt_cbc( des_context *ctx,
+                    int mode,
+                    int length,
+                    unsigned char iv[8],
+                    unsigned char *input,
+                    unsigned char *output )
+{
+    int i;
+    unsigned char temp[8];
+
+    if( mode == DES_ENCRYPT )
+    {
+        while( length > 0 )
+        {
+            for( i = 0; i < 8; i++ )
+                output[i] = (unsigned char)( input[i] ^ iv[i] );
+
+            des_crypt_ecb( ctx, output, output );
+            memcpy( iv, output, 8 );
+
+            input  += 8;
+            output += 8;
+            length -= 8;
+        }
+    }
+    else /* DES_DECRYPT */
+    {
+        while( length > 0 )
+        {
+            memcpy( temp, input, 8 );
+            des_crypt_ecb( ctx, input, output );
+
+            for( i = 0; i < 8; i++ )
+                output[i] = (unsigned char)( output[i] ^ iv[i] );
+
+            memcpy( iv, temp, 8 );
+
+            input  += 8;
+            output += 8;
+            length -= 8;
+        }
+    }
+}
+
+/*
+ * 3DES-ECB block encryption/decryption
+ */
+void des3_crypt_ecb( des3_context *ctx,
+                     unsigned char input[8],
+                     unsigned char output[8] )
+{
+    int i;
+    unsigned long X, Y, T, *SK;
+
+    SK = ctx->sk;
+
+    GET_ULONG_BE( X, input, 0 );
+    GET_ULONG_BE( Y, input, 4 );
+
+    DES_IP( X, Y );
+
+    for( i = 0; i < 8; i++ )
+    {
+        DES_ROUND( Y, X );
+        DES_ROUND( X, Y );
+    }
+
+    for( i = 0; i < 8; i++ )
+    {
+        DES_ROUND( X, Y );
+        DES_ROUND( Y, X );
+    }
+
+    for( i = 0; i < 8; i++ )
+    {
+        DES_ROUND( Y, X );
+        DES_ROUND( X, Y );
+    }
+
+    DES_FP( Y, X );
+
+    PUT_ULONG_BE( Y, output, 0 );
+    PUT_ULONG_BE( X, output, 4 );
+}
+
+/*
+ * 3DES-CBC buffer encryption/decryption
+ */
+void des3_crypt_cbc( des3_context *ctx,
+                     int mode,
+                     int length,
+                     unsigned char iv[8],
+                     unsigned char *input,
+                     unsigned char *output )
+{
+    int i;
+    unsigned char temp[8];
+
+    if( mode == DES_ENCRYPT )
+    {
+        while( length > 0 )
+        {
+            for( i = 0; i < 8; i++ )
+                output[i] = (unsigned char)( input[i] ^ iv[i] );
+
+            des3_crypt_ecb( ctx, output, output );
+            memcpy( iv, output, 8 );
+
+            input  += 8;
+            output += 8;
+            length -= 8;
+        }
+    }
+    else /* DES_DECRYPT */
+    {
+        while( length > 0 )
+        {
+            memcpy( temp, input, 8 );
+            des3_crypt_ecb( ctx, input, output );
+
+            for( i = 0; i < 8; i++ )
+                output[i] = (unsigned char)( output[i] ^ iv[i] );
+
+            memcpy( iv, temp, 8 );
+
+            input  += 8;
+            output += 8;
+            length -= 8;
+        }
+    }
+}
+
+#if defined(XYSSL_SELF_TEST)
+
+#include <stdio.h>
+
+/*
+ * DES and 3DES test vectors from:
+ *
+ * http://csrc.nist.gov/groups/STM/cavp/documents/des/tripledes-vectors.zip
+ */
+static const unsigned char des3_test_keys[24] =
+{
+    0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+    0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01,
+    0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23
+};
+
+static const unsigned char des3_test_iv[8] =
+{
+    0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF,
+};
+
+static const unsigned char des3_test_buf[8] =
+{
+    0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74
+};
+
+static const unsigned char des3_test_ecb_dec[3][8] =
+{
+    { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D },
+    { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB },
+    { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A }
+};
+
+static const unsigned char des3_test_ecb_enc[3][8] =
+{
+    { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B },
+    { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 },
+    { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 }
+};
+
+static const unsigned char des3_test_cbc_dec[3][8] =
+{
+    { 0x12, 0x9F, 0x40, 0xB9, 0xD2, 0x00, 0x56, 0xB3 },
+    { 0x47, 0x0E, 0xFC, 0x9A, 0x6B, 0x8E, 0xE3, 0x93 },
+    { 0xC5, 0xCE, 0xCF, 0x63, 0xEC, 0xEC, 0x51, 0x4C }
+};
+
+static const unsigned char des3_test_cbc_enc[3][8] =
+{
+    { 0x54, 0xF1, 0x5A, 0xF6, 0xEB, 0xE3, 0xA4, 0xB4 },
+    { 0x35, 0x76, 0x11, 0x56, 0x5F, 0xA1, 0x8E, 0x4D },
+    { 0xCB, 0x19, 0x1F, 0x85, 0xD1, 0xED, 0x84, 0x39 }
+};
+
+/*
+ * Checkup routine
+ */
+int des_self_test( int verbose )
+{
+    int i, j, u, v;
+    des_context ctx;
+    des3_context ctx3;
+    unsigned char key[24];
+    unsigned char buf[8];
+    unsigned char prv[8];
+    unsigned char iv[8];
+
+    memset( key, 0, 24 );
+
+    /*
+     * ECB mode
+     */
+    for( i = 0; i < 6; i++ )
+    {
+        u = i >> 1;
+        v = i  & 1;
+
+        if( verbose != 0 )
+            printf( "  DES%c-ECB-%3d (%s): ",
+                    ( u == 0 ) ? ' ' : '3', 56 + u * 56,
+                    ( v == DES_DECRYPT ) ? "dec" : "enc" );
+
+        memcpy( buf, des3_test_buf, 8 );
+
+        switch( i )
+        {
+        case 0:
+            des_setkey_dec( &ctx, (unsigned char *) des3_test_keys );
+            break;
+
+        case 1:
+            des_setkey_enc( &ctx, (unsigned char *) des3_test_keys );
+            break;
+
+        case 2:
+            des3_set2key_dec( &ctx3, (unsigned char *) des3_test_keys );
+            break;
+
+        case 3:
+            des3_set2key_enc( &ctx3, (unsigned char *) des3_test_keys );
+            break;
+
+        case 4:
+            des3_set3key_dec( &ctx3, (unsigned char *) des3_test_keys );
+            break;
+
+        case 5:
+            des3_set3key_enc( &ctx3, (unsigned char *) des3_test_keys );
+            break;
+
+        default:
+            return( 1 );
+        }
+
+        for( j = 0; j < 10000; j++ )
+        {
+            if( u == 0 )
+                des_crypt_ecb( &ctx, buf, buf );
+            else
+                des3_crypt_ecb( &ctx3, buf, buf );
+        }
+
+        if( ( v == DES_DECRYPT &&
+                memcmp( buf, des3_test_ecb_dec[u], 8 ) != 0 ) ||
+            ( v != DES_DECRYPT &&
+                memcmp( buf, des3_test_ecb_enc[u], 8 ) != 0 ) )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    /*
+     * CBC mode
+     */
+    for( i = 0; i < 6; i++ )
+    {
+        u = i >> 1;
+        v = i  & 1;
+
+        if( verbose != 0 )
+            printf( "  DES%c-CBC-%3d (%s): ",
+                    ( u == 0 ) ? ' ' : '3', 56 + u * 56,
+                    ( v == DES_DECRYPT ) ? "dec" : "enc" );
+
+        memcpy( iv,  des3_test_iv,  8 );
+        memcpy( prv, des3_test_iv,  8 );
+        memcpy( buf, des3_test_buf, 8 );
+
+        switch( i )
+        {
+        case 0:
+            des_setkey_dec( &ctx, (unsigned char *) des3_test_keys );
+            break;
+
+        case 1:
+            des_setkey_enc( &ctx, (unsigned char *) des3_test_keys );
+            break;
+
+        case 2:
+            des3_set2key_dec( &ctx3, (unsigned char *) des3_test_keys );
+            break;
+
+        case 3:
+            des3_set2key_enc( &ctx3, (unsigned char *) des3_test_keys );
+            break;
+
+        case 4:
+            des3_set3key_dec( &ctx3, (unsigned char *) des3_test_keys );
+            break;
+
+        case 5:
+            des3_set3key_enc( &ctx3, (unsigned char *) des3_test_keys );
+            break;
+
+        default:
+            return( 1 );
+        }
+
+        if( v == DES_DECRYPT )
+        {
+            for( j = 0; j < 10000; j++ )
+            {
+                if( u == 0 )
+                    des_crypt_cbc( &ctx, v, 8, iv, buf, buf );
+                else
+                    des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf );
+            }
+        }
+        else
+        {
+            for( j = 0; j < 10000; j++ )
+            {
+                unsigned char tmp[8];
+
+                if( u == 0 )
+                    des_crypt_cbc( &ctx, v, 8, iv, buf, buf );
+                else
+                    des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf );
+
+                memcpy( tmp, prv, 8 );
+                memcpy( prv, buf, 8 );
+                memcpy( buf, tmp, 8 );
+            }
+
+            memcpy( buf, prv, 8 );
+        }
+
+        if( ( v == DES_DECRYPT &&
+                memcmp( buf, des3_test_cbc_dec[u], 8 ) != 0 ) ||
+            ( v != DES_DECRYPT &&
+                memcmp( buf, des3_test_cbc_enc[u], 8 ) != 0 ) )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/library/dhm.c b/library/dhm.c
new file mode 100644
index 0000000..4fff264
--- /dev/null
+++ b/library/dhm.c
@@ -0,0 +1,253 @@
+/*
+ *  Diffie-Hellman-Merkle key exchange
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  Reference:
+ *
+ *  http://www.cacr.math.uwaterloo.ca/hac/ (chapter 12)
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_DHM_C)
+
+#include "xyssl/dhm.h"
+
+#include <string.h>
+
+/*
+ * helper to validate the mpi size and import it
+ */
+static int dhm_read_bignum( mpi *X,
+                            unsigned char **p,
+                            unsigned char *end )
+{
+    int ret, n;
+
+    if( end - *p < 2 )
+        return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
+
+    n = ( (*p)[0] << 8 ) | (*p)[1];
+    (*p) += 2;
+
+    if( (int)( end - *p ) < n )
+        return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
+
+    if( ( ret = mpi_read_binary( X, *p, n ) ) != 0 )
+        return( XYSSL_ERR_DHM_READ_PARAMS_FAILED | ret );
+
+    (*p) += n;
+
+    return( 0 );
+}
+
+/*
+ * Parse the ServerKeyExchange parameters
+ */
+int dhm_read_params( dhm_context *ctx,
+                     unsigned char **p,
+                     unsigned char *end )
+{
+    int ret, n;
+
+    memset( ctx, 0, sizeof( dhm_context ) );
+
+    if( ( ret = dhm_read_bignum( &ctx->P,  p, end ) ) != 0 ||
+        ( ret = dhm_read_bignum( &ctx->G,  p, end ) ) != 0 ||
+        ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 )
+        return( ret );
+
+    ctx->len = mpi_size( &ctx->P );
+
+    if( end - *p < 2 )
+        return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
+
+    n = ( (*p)[0] << 8 ) | (*p)[1];
+    (*p) += 2;
+
+    if( end != *p + n )
+        return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
+
+    return( 0 );
+}
+
+/*
+ * Setup and write the ServerKeyExchange parameters
+ */
+int dhm_make_params( dhm_context *ctx, int x_size,
+                     unsigned char *output, int *olen,
+                     int (*f_rng)(void *), void *p_rng )
+{
+    int i, ret, n, n1, n2, n3;
+    unsigned char *p;
+
+    /*
+     * generate X and calculate GX = G^X mod P
+     */
+    n = x_size / sizeof( t_int );
+    MPI_CHK( mpi_grow( &ctx->X, n ) );
+    MPI_CHK( mpi_lset( &ctx->X, 0 ) );
+
+    n = x_size >> 3;
+    p = (unsigned char *) ctx->X.p;
+    for( i = 0; i < n; i++ )
+        *p++ = (unsigned char) f_rng( p_rng );
+
+    while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
+           mpi_shift_r( &ctx->X, 1 );
+
+    MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
+                          &ctx->P , &ctx->RP ) );
+
+    /*
+     * export P, G, GX
+     */
+#define DHM_MPI_EXPORT(X,n)                     \
+    MPI_CHK( mpi_write_binary( X, p + 2, n ) ); \
+    *p++ = (unsigned char)( n >> 8 );           \
+    *p++ = (unsigned char)( n      ); p += n;
+
+    n1 = mpi_size( &ctx->P  );
+    n2 = mpi_size( &ctx->G  );
+    n3 = mpi_size( &ctx->GX );
+
+    p = output;
+    DHM_MPI_EXPORT( &ctx->P , n1 );
+    DHM_MPI_EXPORT( &ctx->G , n2 );
+    DHM_MPI_EXPORT( &ctx->GX, n3 );
+
+    *olen  = p - output;
+
+    ctx->len = n1;
+
+cleanup:
+
+    if( ret != 0 )
+        return( ret | XYSSL_ERR_DHM_MAKE_PARAMS_FAILED );
+
+    return( 0 );
+}
+
+/*
+ * Import the peer's public value G^Y
+ */
+int dhm_read_public( dhm_context *ctx,
+                     unsigned char *input, int ilen )
+{
+    int ret;
+
+    if( ctx == NULL || ilen < 1 || ilen > ctx->len )
+        return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
+
+    if( ( ret = mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
+        return( XYSSL_ERR_DHM_READ_PUBLIC_FAILED | ret );
+
+    return( 0 );
+}
+
+/*
+ * Create own private value X and export G^X
+ */
+int dhm_make_public( dhm_context *ctx, int x_size,
+                     unsigned char *output, int olen,
+                     int (*f_rng)(void *), void *p_rng )
+{
+    int ret, i, n;
+    unsigned char *p;
+
+    if( ctx == NULL || olen < 1 || olen > ctx->len )
+        return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
+
+    /*
+     * generate X and calculate GX = G^X mod P
+     */
+    n = x_size / sizeof( t_int );
+    MPI_CHK( mpi_grow( &ctx->X, n ) );
+    MPI_CHK( mpi_lset( &ctx->X, 0 ) );
+
+    n = x_size >> 3;
+    p = (unsigned char *) ctx->X.p;
+    for( i = 0; i < n; i++ )
+        *p++ = (unsigned char) f_rng( p_rng );
+
+    while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
+           mpi_shift_r( &ctx->X, 1 );
+
+    MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
+                          &ctx->P , &ctx->RP ) );
+
+    MPI_CHK( mpi_write_binary( &ctx->GX, output, olen ) );
+
+cleanup:
+
+    if( ret != 0 )
+        return( XYSSL_ERR_DHM_MAKE_PUBLIC_FAILED | ret );
+
+    return( 0 );
+}
+
+/*
+ * Derive and export the shared secret (G^Y)^X mod P
+ */
+int dhm_calc_secret( dhm_context *ctx,
+                     unsigned char *output, int *olen )
+{
+    int ret;
+
+    if( ctx == NULL || *olen < ctx->len )
+        return( XYSSL_ERR_DHM_BAD_INPUT_DATA );
+
+    MPI_CHK( mpi_exp_mod( &ctx->K, &ctx->GY, &ctx->X,
+                          &ctx->P, &ctx->RP ) );
+
+    *olen = mpi_size( &ctx->K );
+
+    MPI_CHK( mpi_write_binary( &ctx->K, output, *olen ) );
+
+cleanup:
+
+    if( ret != 0 )
+        return( XYSSL_ERR_DHM_CALC_SECRET_FAILED | ret );
+
+    return( 0 );
+}
+
+/*
+ * Free the components of a DHM key
+ */
+void dhm_free( dhm_context *ctx )
+{
+    mpi_free( &ctx->RP, &ctx->K, &ctx->GY,
+              &ctx->GX, &ctx->X, &ctx->G,
+              &ctx->P, NULL );    
+}
+
+#if defined(XYSSL_SELF_TEST)
+
+/*
+ * Checkup routine
+ */
+int dhm_self_test( int verbose )
+{
+    return( verbose++ );
+}
+
+#endif
+
+#endif
diff --git a/library/havege.c b/library/havege.c
new file mode 100644
index 0000000..48ae7e6
--- /dev/null
+++ b/library/havege.c
@@ -0,0 +1,261 @@
+/*
+ *  HAVEGE: HArdware Volatile Entropy Gathering and Expansion
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  The HAVEGE RNG was designed by Andre Seznec in 2002.
+ *
+ *  http://www.irisa.fr/caps/projects/hipsor/publi.php
+ *
+ *  Contact: seznec(at)irisa_dot_fr - orocheco(at)irisa_dot_fr
+ */
+
+#include <string.h>
+#include <time.h>
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_HAVEGE_C)
+
+#include "xyssl/havege.h"
+#include "xyssl/timing.h"
+
+/* ------------------------------------------------------------------------
+ * On average, one iteration accesses two 8-word blocks in the havege WALK
+ * table, and generates 16 words in the RES array.
+ *
+ * The data read in the WALK table is updated and permuted after each use.
+ * The result of the hardware clock counter read is used  for this update.
+ *
+ * 25 conditional tests are present.  The conditional tests are grouped in
+ * two nested  groups of 12 conditional tests and 1 test that controls the
+ * permutation; on average, there should be 6 tests executed and 3 of them
+ * should be mispredicted.
+ * ------------------------------------------------------------------------
+ */
+
+#define SWAP(X,Y) { int *T = X; X = Y; Y = T; }
+
+#define TST1_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1;
+#define TST2_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1;
+
+#define TST1_LEAVE U1++; }
+#define TST2_LEAVE U2++; }
+
+#define ONE_ITERATION                                   \
+                                                        \
+    PTEST = PT1 >> 20;                                  \
+                                                        \
+    TST1_ENTER  TST1_ENTER  TST1_ENTER  TST1_ENTER      \
+    TST1_ENTER  TST1_ENTER  TST1_ENTER  TST1_ENTER      \
+    TST1_ENTER  TST1_ENTER  TST1_ENTER  TST1_ENTER      \
+                                                        \
+    TST1_LEAVE  TST1_LEAVE  TST1_LEAVE  TST1_LEAVE      \
+    TST1_LEAVE  TST1_LEAVE  TST1_LEAVE  TST1_LEAVE      \
+    TST1_LEAVE  TST1_LEAVE  TST1_LEAVE  TST1_LEAVE      \
+                                                        \
+    PTX = (PT1 >> 18) & 7;                              \
+    PT1 &= 0x1FFF;                                      \
+    PT2 &= 0x1FFF;                                      \
+    CLK = (int) hardclock();                            \
+                                                        \
+    i = 0;                                              \
+    A = &WALK[PT1    ]; RES[i++] ^= *A;                 \
+    B = &WALK[PT2    ]; RES[i++] ^= *B;                 \
+    C = &WALK[PT1 ^ 1]; RES[i++] ^= *C;                 \
+    D = &WALK[PT2 ^ 4]; RES[i++] ^= *D;                 \
+                                                        \
+    IN = (*A >> (1)) ^ (*A << (31)) ^ CLK;              \
+    *A = (*B >> (2)) ^ (*B << (30)) ^ CLK;              \
+    *B = IN ^ U1;                                       \
+    *C = (*C >> (3)) ^ (*C << (29)) ^ CLK;              \
+    *D = (*D >> (4)) ^ (*D << (28)) ^ CLK;              \
+                                                        \
+    A = &WALK[PT1 ^ 2]; RES[i++] ^= *A;                 \
+    B = &WALK[PT2 ^ 2]; RES[i++] ^= *B;                 \
+    C = &WALK[PT1 ^ 3]; RES[i++] ^= *C;                 \
+    D = &WALK[PT2 ^ 6]; RES[i++] ^= *D;                 \
+                                                        \
+    if( PTEST & 1 ) SWAP( A, C );                       \
+                                                        \
+    IN = (*A >> (5)) ^ (*A << (27)) ^ CLK;              \
+    *A = (*B >> (6)) ^ (*B << (26)) ^ CLK;              \
+    *B = IN; CLK = (int) hardclock();                   \
+    *C = (*C >> (7)) ^ (*C << (25)) ^ CLK;              \
+    *D = (*D >> (8)) ^ (*D << (24)) ^ CLK;              \
+                                                        \
+    A = &WALK[PT1 ^ 4];                                 \
+    B = &WALK[PT2 ^ 1];                                 \
+                                                        \
+    PTEST = PT2 >> 1;                                   \
+                                                        \
+    PT2 = (RES[(i - 8) ^ PTY] ^ WALK[PT2 ^ PTY ^ 7]);   \
+    PT2 = ((PT2 & 0x1FFF) & (~8)) ^ ((PT1 ^ 8) & 0x8);  \
+    PTY = (PT2 >> 10) & 7;                              \
+                                                        \
+    TST2_ENTER  TST2_ENTER  TST2_ENTER  TST2_ENTER      \
+    TST2_ENTER  TST2_ENTER  TST2_ENTER  TST2_ENTER      \
+    TST2_ENTER  TST2_ENTER  TST2_ENTER  TST2_ENTER      \
+                                                        \
+    TST2_LEAVE  TST2_LEAVE  TST2_LEAVE  TST2_LEAVE      \
+    TST2_LEAVE  TST2_LEAVE  TST2_LEAVE  TST2_LEAVE      \
+    TST2_LEAVE  TST2_LEAVE  TST2_LEAVE  TST2_LEAVE      \
+                                                        \
+    C = &WALK[PT1 ^ 5];                                 \
+    D = &WALK[PT2 ^ 5];                                 \
+                                                        \
+    RES[i++] ^= *A;                                     \
+    RES[i++] ^= *B;                                     \
+    RES[i++] ^= *C;                                     \
+    RES[i++] ^= *D;                                     \
+                                                        \
+    IN = (*A >> ( 9)) ^ (*A << (23)) ^ CLK;             \
+    *A = (*B >> (10)) ^ (*B << (22)) ^ CLK;             \
+    *B = IN ^ U2;                                       \
+    *C = (*C >> (11)) ^ (*C << (21)) ^ CLK;             \
+    *D = (*D >> (12)) ^ (*D << (20)) ^ CLK;             \
+                                                        \
+    A = &WALK[PT1 ^ 6]; RES[i++] ^= *A;                 \
+    B = &WALK[PT2 ^ 3]; RES[i++] ^= *B;                 \
+    C = &WALK[PT1 ^ 7]; RES[i++] ^= *C;                 \
+    D = &WALK[PT2 ^ 7]; RES[i++] ^= *D;                 \
+                                                        \
+    IN = (*A >> (13)) ^ (*A << (19)) ^ CLK;             \
+    *A = (*B >> (14)) ^ (*B << (18)) ^ CLK;             \
+    *B = IN;                                            \
+    *C = (*C >> (15)) ^ (*C << (17)) ^ CLK;             \
+    *D = (*D >> (16)) ^ (*D << (16)) ^ CLK;             \
+                                                        \
+    PT1 = ( RES[(i - 8) ^ PTX] ^                        \
+            WALK[PT1 ^ PTX ^ 7] ) & (~1);               \
+    PT1 ^= (PT2 ^ 0x10) & 0x10;                         \
+                                                        \
+    for( n++, i = 0; i < 16; i++ )                      \
+        hs->pool[n % COLLECT_SIZE] ^= RES[i];
+
+/*
+ * Entropy gathering function
+ */
+static void havege_fill( havege_state *hs )
+{
+    int i, n = 0;
+    int  U1,  U2, *A, *B, *C, *D;
+    int PT1, PT2, *WALK, RES[16];
+    int PTX, PTY, CLK, PTEST, IN;
+
+    WALK = hs->WALK;
+    PT1  = hs->PT1;
+    PT2  = hs->PT2;
+
+    PTX  = U1 = 0;
+    PTY  = U2 = 0;
+
+    memset( RES, 0, sizeof( RES ) );
+
+    while( n < COLLECT_SIZE * 4 )
+    {
+        ONE_ITERATION
+        ONE_ITERATION
+        ONE_ITERATION
+        ONE_ITERATION
+    }
+
+    hs->PT1 = PT1;
+    hs->PT2 = PT2;
+
+    hs->offset[0] = 0;
+    hs->offset[1] = COLLECT_SIZE / 2;
+}
+
+/*
+ * HAVEGE initialization
+ */
+void havege_init( havege_state *hs )
+{
+    memset( hs, 0, sizeof( havege_state ) );
+
+    havege_fill( hs );
+}
+
+/*
+ * HAVEGE rand function
+ */
+int havege_rand( void *p_rng )
+{
+    int ret;
+    havege_state *hs = (havege_state *) p_rng;
+
+    if( hs->offset[1] >= COLLECT_SIZE )
+        havege_fill( hs );
+
+    ret  = hs->pool[hs->offset[0]++];
+    ret ^= hs->pool[hs->offset[1]++];
+
+    return( ret );
+}
+
+#if defined(XYSSL_RAND_TEST)
+
+#include <stdio.h>
+
+int main( int argc, char *argv[] )
+{
+    FILE *f;
+    time_t t;
+    int i, j, k;
+    havege_state hs;
+    unsigned char buf[1024];
+
+    if( argc < 2 )
+    {
+        fprintf( stderr, "usage: %s <output filename>\n", argv[0] );
+        return( 1 );
+    }
+
+    if( ( f = fopen( argv[1], "wb+" ) ) == NULL )
+    {
+        printf( "failed to open '%s' for writing.\n", argv[0] );
+        return( 1 );
+    }
+
+    havege_init( &hs );
+
+    t = time( NULL );
+
+    for( i = 0, k = 32768; i < k; i++ )
+    {
+        for( j = 0; j < sizeof( buf ); j++ )
+            buf[j] = havege_rand( &hs );
+
+        fwrite( buf, sizeof( buf ), 1, f );
+
+        printf( "Generating 32Mb of data in file '%s'... %04.1f" \
+                "%% done\r", argv[1], (100 * (float) (i + 1)) / k );
+        fflush( stdout );
+    }
+
+    if( t == time( NULL ) )
+        t--;
+
+    fclose( f );
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/library/md2.c b/library/md2.c
new file mode 100644
index 0000000..9cfce4a
--- /dev/null
+++ b/library/md2.c
@@ -0,0 +1,343 @@
+/*
+ *  RFC 1115/1319 compliant MD2 implementation
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  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 "xyssl/config.h"
+
+#if defined(XYSSL_MD2_C)
+
+#include "xyssl/md2.h"
+
+#include <string.h>
+#include <stdio.h>
+
+static const unsigned char 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
+ */
+void md2_starts( md2_context *ctx )
+{
+    memset( ctx, 0, sizeof( md2_context ) );
+}
+
+static void md2_process( md2_context *ctx )
+{
+    int i, j;
+    unsigned char t = 0;
+
+    for( i = 0; i < 16; i++ )
+    {
+        ctx->state[i + 16] = ctx->buffer[i];
+        ctx->state[i + 32] =
+            (unsigned char)( ctx->buffer[i] ^ ctx->state[i]);
+    }
+
+    for( i = 0; i < 18; i++ )
+    {
+        for( j = 0; j < 48; j++ )
+        {
+            ctx->state[j] = (unsigned char)
+               ( ctx->state[j] ^ PI_SUBST[t] );
+            t  = ctx->state[j];
+        }
+
+        t = (unsigned char)( t + i );
+    }
+
+    t = ctx->cksum[15];
+
+    for( i = 0; i < 16; i++ )
+    {
+        ctx->cksum[i] = (unsigned char)
+           ( ctx->cksum[i] ^ PI_SUBST[ctx->buffer[i] ^ t] );
+        t  = ctx->cksum[i];
+    }
+}
+
+/*
+ * MD2 process buffer
+ */
+void md2_update( md2_context *ctx, unsigned char *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
+ */
+void md2_finish( md2_context *ctx, unsigned char output[16] )
+{
+    int i;
+    unsigned char x;
+
+    x = (unsigned char)( 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 );
+}
+
+/*
+ * output = MD2( input buffer )
+ */
+void md2( unsigned char *input, int ilen, unsigned char output[16] )
+{
+    md2_context ctx;
+
+    md2_starts( &ctx );
+    md2_update( &ctx, input, ilen );
+    md2_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( md2_context ) );
+}
+
+/*
+ * output = MD2( file contents )
+ */
+int md2_file( char *path, unsigned char output[16] )
+{
+    FILE *f;
+    size_t n;
+    md2_context ctx;
+    unsigned char buf[1024];
+
+    if( ( f = fopen( path, "rb" ) ) == NULL )
+        return( 1 );
+
+    md2_starts( &ctx );
+
+    while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+        md2_update( &ctx, buf, (int) n );
+
+    md2_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( md2_context ) );
+
+    if( ferror( f ) != 0 )
+    {
+        fclose( f );
+        return( 2 );
+    }
+
+    fclose( f );
+    return( 0 );
+}
+
+/*
+ * MD2 HMAC context setup
+ */
+void md2_hmac_starts( md2_context *ctx, unsigned char *key, int keylen )
+{
+    int i;
+    unsigned char sum[16];
+
+    if( keylen > 64 )
+    {
+        md2( key, keylen, sum );
+        keylen = 16;
+        key = sum;
+    }
+
+    memset( ctx->ipad, 0x36, 64 );
+    memset( ctx->opad, 0x5C, 64 );
+
+    for( i = 0; i < keylen; i++ )
+    {
+        ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
+        ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
+    }
+
+    md2_starts( ctx );
+    md2_update( ctx, ctx->ipad, 64 );
+
+    memset( sum, 0, sizeof( sum ) );
+}
+
+/*
+ * MD2 HMAC process buffer
+ */
+void md2_hmac_update( md2_context *ctx, unsigned char *input, int ilen )
+{
+    md2_update( ctx, input, ilen );
+}
+
+/*
+ * MD2 HMAC final digest
+ */
+void md2_hmac_finish( md2_context *ctx, unsigned char output[16] )
+{
+    unsigned char tmpbuf[16];
+
+    md2_finish( ctx, tmpbuf );
+    md2_starts( ctx );
+    md2_update( ctx, ctx->opad, 64 );
+    md2_update( ctx, tmpbuf, 16 );
+    md2_finish( ctx, output );
+
+    memset( tmpbuf, 0, sizeof( tmpbuf ) );
+}
+
+/*
+ * output = HMAC-MD2( hmac key, input buffer )
+ */
+void md2_hmac( unsigned char *key, int keylen, unsigned char *input, int ilen,
+               unsigned char output[16] )
+{
+    md2_context ctx;
+
+    md2_hmac_starts( &ctx, key, keylen );
+    md2_hmac_update( &ctx, input, ilen );
+    md2_hmac_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( md2_context ) );
+}
+
+#if defined(XYSSL_SELF_TEST)
+
+/*
+ * RFC 1319 test vectors
+ */
+static const char md2_test_str[7][81] =
+{
+    { "" },
+    { "a" },
+    { "abc" },
+    { "message digest" },
+    { "abcdefghijklmnopqrstuvwxyz" },
+    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
+    { "12345678901234567890123456789012345678901234567890123456789012" \
+      "345678901234567890" }
+};
+
+static const unsigned char md2_test_sum[7][16] =
+{
+    { 0x83, 0x50, 0xE5, 0xA3, 0xE2, 0x4C, 0x15, 0x3D,
+      0xF2, 0x27, 0x5C, 0x9F, 0x80, 0x69, 0x27, 0x73 },
+    { 0x32, 0xEC, 0x01, 0xEC, 0x4A, 0x6D, 0xAC, 0x72,
+      0xC0, 0xAB, 0x96, 0xFB, 0x34, 0xC0, 0xB5, 0xD1 },
+    { 0xDA, 0x85, 0x3B, 0x0D, 0x3F, 0x88, 0xD9, 0x9B,
+      0x30, 0x28, 0x3A, 0x69, 0xE6, 0xDE, 0xD6, 0xBB },
+    { 0xAB, 0x4F, 0x49, 0x6B, 0xFB, 0x2A, 0x53, 0x0B,
+      0x21, 0x9F, 0xF3, 0x30, 0x31, 0xFE, 0x06, 0xB0 },
+    { 0x4E, 0x8D, 0xDF, 0xF3, 0x65, 0x02, 0x92, 0xAB,
+      0x5A, 0x41, 0x08, 0xC3, 0xAA, 0x47, 0x94, 0x0B },
+    { 0xDA, 0x33, 0xDE, 0xF2, 0xA4, 0x2D, 0xF1, 0x39,
+      0x75, 0x35, 0x28, 0x46, 0xC3, 0x03, 0x38, 0xCD },
+    { 0xD5, 0x97, 0x6F, 0x79, 0xD8, 0x3D, 0x3A, 0x0D,
+      0xC9, 0x80, 0x6C, 0x3C, 0x66, 0xF3, 0xEF, 0xD8 }
+};
+
+/*
+ * Checkup routine
+ */
+int md2_self_test( int verbose )
+{
+    int i;
+    unsigned char md2sum[16];
+
+    for( i = 0; i < 7; i++ )
+    {
+        if( verbose != 0 )
+            printf( "  MD2 test #%d: ", i + 1 );
+
+        md2( (unsigned char *) md2_test_str[i],
+             strlen( md2_test_str[i] ), md2sum );
+
+        if( memcmp( md2sum, md2_test_sum[i], 16 ) != 0 )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/library/md4.c b/library/md4.c
new file mode 100644
index 0000000..67fcd99
--- /dev/null
+++ b/library/md4.c
@@ -0,0 +1,442 @@
+/*
+ *  RFC 1186/1320 compliant MD4 implementation
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  The MD4 algorithm was designed by Ron Rivest in 1990.
+ *
+ *  http://www.ietf.org/rfc/rfc1186.txt
+ *  http://www.ietf.org/rfc/rfc1320.txt
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_MD4_C)
+
+#include "xyssl/md4.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * 32-bit integer manipulation macros (little endian)
+ */
+#ifndef GET_ULONG_LE
+#define GET_ULONG_LE(n,b,i)                             \
+{                                                       \
+    (n) = ( (unsigned long) (b)[(i)    ]       )        \
+        | ( (unsigned long) (b)[(i) + 1] <<  8 )        \
+        | ( (unsigned long) (b)[(i) + 2] << 16 )        \
+        | ( (unsigned long) (b)[(i) + 3] << 24 );       \
+}
+#endif
+
+#ifndef PUT_ULONG_LE
+#define PUT_ULONG_LE(n,b,i)                             \
+{                                                       \
+    (b)[(i)    ] = (unsigned char) ( (n)       );       \
+    (b)[(i) + 1] = (unsigned char) ( (n) >>  8 );       \
+    (b)[(i) + 2] = (unsigned char) ( (n) >> 16 );       \
+    (b)[(i) + 3] = (unsigned char) ( (n) >> 24 );       \
+}
+#endif
+
+/*
+ * MD4 context setup
+ */
+void md4_starts( md4_context *ctx )
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+}
+
+static void md4_process( md4_context *ctx, unsigned char data[64] )
+{
+    unsigned long X[16], A, B, C, D;
+
+    GET_ULONG_LE( X[ 0], data,  0 );
+    GET_ULONG_LE( X[ 1], data,  4 );
+    GET_ULONG_LE( X[ 2], data,  8 );
+    GET_ULONG_LE( X[ 3], data, 12 );
+    GET_ULONG_LE( X[ 4], data, 16 );
+    GET_ULONG_LE( X[ 5], data, 20 );
+    GET_ULONG_LE( X[ 6], data, 24 );
+    GET_ULONG_LE( X[ 7], data, 28 );
+    GET_ULONG_LE( X[ 8], data, 32 );
+    GET_ULONG_LE( X[ 9], data, 36 );
+    GET_ULONG_LE( X[10], data, 40 );
+    GET_ULONG_LE( X[11], data, 44 );
+    GET_ULONG_LE( X[12], data, 48 );
+    GET_ULONG_LE( X[13], data, 52 );
+    GET_ULONG_LE( X[14], data, 56 );
+    GET_ULONG_LE( X[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+
+#define F(x, y, z) ((x & y) | ((~x) & z))
+#define P(a,b,c,d,x,s) { a += F(b,c,d) + x; a = S(a,s); }
+
+    P( A, B, C, D, X[ 0],  3 );
+    P( D, A, B, C, X[ 1],  7 );
+    P( C, D, A, B, X[ 2], 11 );
+    P( B, C, D, A, X[ 3], 19 );
+    P( A, B, C, D, X[ 4],  3 );
+    P( D, A, B, C, X[ 5],  7 );
+    P( C, D, A, B, X[ 6], 11 );
+    P( B, C, D, A, X[ 7], 19 );
+    P( A, B, C, D, X[ 8],  3 );
+    P( D, A, B, C, X[ 9],  7 );
+    P( C, D, A, B, X[10], 11 );
+    P( B, C, D, A, X[11], 19 );
+    P( A, B, C, D, X[12],  3 );
+    P( D, A, B, C, X[13],  7 );
+    P( C, D, A, B, X[14], 11 );
+    P( B, C, D, A, X[15], 19 );
+
+#undef P
+#undef F
+
+#define F(x,y,z) ((x & y) | (x & z) | (y & z))
+#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x5A827999; a = S(a,s); }
+
+    P( A, B, C, D, X[ 0],  3 );
+    P( D, A, B, C, X[ 4],  5 );
+    P( C, D, A, B, X[ 8],  9 );
+    P( B, C, D, A, X[12], 13 );
+    P( A, B, C, D, X[ 1],  3 );
+    P( D, A, B, C, X[ 5],  5 );
+    P( C, D, A, B, X[ 9],  9 );
+    P( B, C, D, A, X[13], 13 );
+    P( A, B, C, D, X[ 2],  3 );
+    P( D, A, B, C, X[ 6],  5 );
+    P( C, D, A, B, X[10],  9 );
+    P( B, C, D, A, X[14], 13 );
+    P( A, B, C, D, X[ 3],  3 );
+    P( D, A, B, C, X[ 7],  5 );
+    P( C, D, A, B, X[11],  9 );
+    P( B, C, D, A, X[15], 13 );
+
+#undef P
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x6ED9EBA1; a = S(a,s); }
+
+    P( A, B, C, D, X[ 0],  3 );
+    P( D, A, B, C, X[ 8],  9 );
+    P( C, D, A, B, X[ 4], 11 );
+    P( B, C, D, A, X[12], 15 );
+    P( A, B, C, D, X[ 2],  3 );
+    P( D, A, B, C, X[10],  9 );
+    P( C, D, A, B, X[ 6], 11 );
+    P( B, C, D, A, X[14], 15 );
+    P( A, B, C, D, X[ 1],  3 );
+    P( D, A, B, C, X[ 9],  9 );
+    P( C, D, A, B, X[ 5], 11 );
+    P( B, C, D, A, X[13], 15 );
+    P( A, B, C, D, X[ 3],  3 );
+    P( D, A, B, C, X[11],  9 );
+    P( C, D, A, B, X[ 7], 11 );
+    P( B, C, D, A, X[15], 15 );
+
+#undef F
+#undef P
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+}
+
+/*
+ * MD4 process buffer
+ */
+void md4_update( md4_context *ctx, unsigned char *input, int ilen )
+{
+    int fill;
+    unsigned long left;
+
+    if( ilen <= 0 )
+        return;
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += ilen;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if( ctx->total[0] < (unsigned long) ilen )
+        ctx->total[1]++;
+
+    if( left && ilen >= fill )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, fill );
+        md4_process( ctx, ctx->buffer );
+        input += fill;
+        ilen  -= fill;
+        left = 0;
+    }
+
+    while( ilen >= 64 )
+    {
+        md4_process( ctx, input );
+        input += 64;
+        ilen  -= 64;
+    }
+
+    if( ilen > 0 )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, ilen );
+    }
+}
+
+static const unsigned char md4_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
+};
+
+/*
+ * MD4 final digest
+ */
+void md4_finish( md4_context *ctx, unsigned char output[16] )
+{
+    unsigned long last, padn;
+    unsigned long high, low;
+    unsigned char msglen[8];
+
+    high = ( ctx->total[0] >> 29 )
+         | ( ctx->total[1] <<  3 );
+    low  = ( ctx->total[0] <<  3 );
+
+    PUT_ULONG_LE( low,  msglen, 0 );
+    PUT_ULONG_LE( high, msglen, 4 );
+
+    last = ctx->total[0] & 0x3F;
+    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+    md4_update( ctx, (unsigned char *) md4_padding, padn );
+    md4_update( ctx, msglen, 8 );
+
+    PUT_ULONG_LE( ctx->state[0], output,  0 );
+    PUT_ULONG_LE( ctx->state[1], output,  4 );
+    PUT_ULONG_LE( ctx->state[2], output,  8 );
+    PUT_ULONG_LE( ctx->state[3], output, 12 );
+}
+
+/*
+ * output = MD4( input buffer )
+ */
+void md4( unsigned char *input, int ilen, unsigned char output[16] )
+{
+    md4_context ctx;
+
+    md4_starts( &ctx );
+    md4_update( &ctx, input, ilen );
+    md4_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( md4_context ) );
+}
+
+/*
+ * output = MD4( file contents )
+ */
+int md4_file( char *path, unsigned char output[16] )
+{
+    FILE *f;
+    size_t n;
+    md4_context ctx;
+    unsigned char buf[1024];
+
+    if( ( f = fopen( path, "rb" ) ) == NULL )
+        return( 1 );
+
+    md4_starts( &ctx );
+
+    while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+        md4_update( &ctx, buf, (int) n );
+
+    md4_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( md4_context ) );
+
+    if( ferror( f ) != 0 )
+    {
+        fclose( f );
+        return( 2 );
+    }
+
+    fclose( f );
+    return( 0 );
+}
+
+/*
+ * MD4 HMAC context setup
+ */
+void md4_hmac_starts( md4_context *ctx, unsigned char *key, int keylen )
+{
+    int i;
+    unsigned char sum[16];
+
+    if( keylen > 64 )
+    {
+        md4( key, keylen, sum );
+        keylen = 16;
+        key = sum;
+    }
+
+    memset( ctx->ipad, 0x36, 64 );
+    memset( ctx->opad, 0x5C, 64 );
+
+    for( i = 0; i < keylen; i++ )
+    {
+        ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
+        ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
+    }
+
+    md4_starts( ctx );
+    md4_update( ctx, ctx->ipad, 64 );
+
+    memset( sum, 0, sizeof( sum ) );
+}
+
+/*
+ * MD4 HMAC process buffer
+ */
+void md4_hmac_update( md4_context *ctx, unsigned char *input, int ilen )
+{
+    md4_update( ctx, input, ilen );
+}
+
+/*
+ * MD4 HMAC final digest
+ */
+void md4_hmac_finish( md4_context *ctx, unsigned char output[16] )
+{
+    unsigned char tmpbuf[16];
+
+    md4_finish( ctx, tmpbuf );
+    md4_starts( ctx );
+    md4_update( ctx, ctx->opad, 64 );
+    md4_update( ctx, tmpbuf, 16 );
+    md4_finish( ctx, output );
+
+    memset( tmpbuf, 0, sizeof( tmpbuf ) );
+}
+
+/*
+ * output = HMAC-MD4( hmac key, input buffer )
+ */
+void md4_hmac( unsigned char *key, int keylen, unsigned char *input, int ilen,
+               unsigned char output[16] )
+{
+    md4_context ctx;
+
+    md4_hmac_starts( &ctx, key, keylen );
+    md4_hmac_update( &ctx, input, ilen );
+    md4_hmac_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( md4_context ) );
+}
+
+#if defined(XYSSL_SELF_TEST)
+
+/*
+ * RFC 1320 test vectors
+ */
+static const char md4_test_str[7][81] =
+{
+    { "" }, 
+    { "a" },
+    { "abc" },
+    { "message digest" },
+    { "abcdefghijklmnopqrstuvwxyz" },
+    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
+    { "12345678901234567890123456789012345678901234567890123456789012" \
+      "345678901234567890" }
+};
+
+static const unsigned char md4_test_sum[7][16] =
+{
+    { 0x31, 0xD6, 0xCF, 0xE0, 0xD1, 0x6A, 0xE9, 0x31,
+      0xB7, 0x3C, 0x59, 0xD7, 0xE0, 0xC0, 0x89, 0xC0 },
+    { 0xBD, 0xE5, 0x2C, 0xB3, 0x1D, 0xE3, 0x3E, 0x46,
+      0x24, 0x5E, 0x05, 0xFB, 0xDB, 0xD6, 0xFB, 0x24 },
+    { 0xA4, 0x48, 0x01, 0x7A, 0xAF, 0x21, 0xD8, 0x52,
+      0x5F, 0xC1, 0x0A, 0xE8, 0x7A, 0xA6, 0x72, 0x9D },
+    { 0xD9, 0x13, 0x0A, 0x81, 0x64, 0x54, 0x9F, 0xE8,
+      0x18, 0x87, 0x48, 0x06, 0xE1, 0xC7, 0x01, 0x4B },
+    { 0xD7, 0x9E, 0x1C, 0x30, 0x8A, 0xA5, 0xBB, 0xCD,
+      0xEE, 0xA8, 0xED, 0x63, 0xDF, 0x41, 0x2D, 0xA9 },
+    { 0x04, 0x3F, 0x85, 0x82, 0xF2, 0x41, 0xDB, 0x35,
+      0x1C, 0xE6, 0x27, 0xE1, 0x53, 0xE7, 0xF0, 0xE4 },
+    { 0xE3, 0x3B, 0x4D, 0xDC, 0x9C, 0x38, 0xF2, 0x19,
+      0x9C, 0x3E, 0x7B, 0x16, 0x4F, 0xCC, 0x05, 0x36 }
+};
+
+/*
+ * Checkup routine
+ */
+int md4_self_test( int verbose )
+{
+    int i;
+    unsigned char md4sum[16];
+
+    for( i = 0; i < 7; i++ )
+    {
+        if( verbose != 0 )
+            printf( "  MD4 test #%d: ", i + 1 );
+
+        md4( (unsigned char *) md4_test_str[i],
+             strlen( md4_test_str[i] ), md4sum );
+
+        if( memcmp( md4sum, md4_test_sum[i], 16 ) != 0 )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/library/md5.c b/library/md5.c
new file mode 100644
index 0000000..b52941d
--- /dev/null
+++ b/library/md5.c
@@ -0,0 +1,565 @@
+/*
+ *  RFC 1321 compliant MD5 implementation
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  The MD5 algorithm was designed by Ron Rivest in 1991.
+ *
+ *  http://www.ietf.org/rfc/rfc1321.txt
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_MD5_C)
+
+#include "xyssl/md5.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * 32-bit integer manipulation macros (little endian)
+ */
+#ifndef GET_ULONG_LE
+#define GET_ULONG_LE(n,b,i)                             \
+{                                                       \
+    (n) = ( (unsigned long) (b)[(i)    ]       )        \
+        | ( (unsigned long) (b)[(i) + 1] <<  8 )        \
+        | ( (unsigned long) (b)[(i) + 2] << 16 )        \
+        | ( (unsigned long) (b)[(i) + 3] << 24 );       \
+}
+#endif
+
+#ifndef PUT_ULONG_LE
+#define PUT_ULONG_LE(n,b,i)                             \
+{                                                       \
+    (b)[(i)    ] = (unsigned char) ( (n)       );       \
+    (b)[(i) + 1] = (unsigned char) ( (n) >>  8 );       \
+    (b)[(i) + 2] = (unsigned char) ( (n) >> 16 );       \
+    (b)[(i) + 3] = (unsigned char) ( (n) >> 24 );       \
+}
+#endif
+
+/*
+ * MD5 context setup
+ */
+void md5_starts( md5_context *ctx )
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+}
+
+static void md5_process( md5_context *ctx, unsigned char data[64] )
+{
+    unsigned long X[16], A, B, C, D;
+
+    GET_ULONG_LE( X[ 0], data,  0 );
+    GET_ULONG_LE( X[ 1], data,  4 );
+    GET_ULONG_LE( X[ 2], data,  8 );
+    GET_ULONG_LE( X[ 3], data, 12 );
+    GET_ULONG_LE( X[ 4], data, 16 );
+    GET_ULONG_LE( X[ 5], data, 20 );
+    GET_ULONG_LE( X[ 6], data, 24 );
+    GET_ULONG_LE( X[ 7], data, 28 );
+    GET_ULONG_LE( X[ 8], data, 32 );
+    GET_ULONG_LE( X[ 9], data, 36 );
+    GET_ULONG_LE( X[10], data, 40 );
+    GET_ULONG_LE( X[11], data, 44 );
+    GET_ULONG_LE( X[12], data, 48 );
+    GET_ULONG_LE( X[13], data, 52 );
+    GET_ULONG_LE( X[14], data, 56 );
+    GET_ULONG_LE( X[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define P(a,b,c,d,k,s,t)                                \
+{                                                       \
+    a += F(b,c,d) + X[k] + t; a = S(a,s) + b;           \
+}
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+
+    P( A, B, C, D,  0,  7, 0xD76AA478 );
+    P( D, A, B, C,  1, 12, 0xE8C7B756 );
+    P( C, D, A, B,  2, 17, 0x242070DB );
+    P( B, C, D, A,  3, 22, 0xC1BDCEEE );
+    P( A, B, C, D,  4,  7, 0xF57C0FAF );
+    P( D, A, B, C,  5, 12, 0x4787C62A );
+    P( C, D, A, B,  6, 17, 0xA8304613 );
+    P( B, C, D, A,  7, 22, 0xFD469501 );
+    P( A, B, C, D,  8,  7, 0x698098D8 );
+    P( D, A, B, C,  9, 12, 0x8B44F7AF );
+    P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
+    P( B, C, D, A, 11, 22, 0x895CD7BE );
+    P( A, B, C, D, 12,  7, 0x6B901122 );
+    P( D, A, B, C, 13, 12, 0xFD987193 );
+    P( C, D, A, B, 14, 17, 0xA679438E );
+    P( B, C, D, A, 15, 22, 0x49B40821 );
+
+#undef F
+
+#define F(x,y,z) (y ^ (z & (x ^ y)))
+
+    P( A, B, C, D,  1,  5, 0xF61E2562 );
+    P( D, A, B, C,  6,  9, 0xC040B340 );
+    P( C, D, A, B, 11, 14, 0x265E5A51 );
+    P( B, C, D, A,  0, 20, 0xE9B6C7AA );
+    P( A, B, C, D,  5,  5, 0xD62F105D );
+    P( D, A, B, C, 10,  9, 0x02441453 );
+    P( C, D, A, B, 15, 14, 0xD8A1E681 );
+    P( B, C, D, A,  4, 20, 0xE7D3FBC8 );
+    P( A, B, C, D,  9,  5, 0x21E1CDE6 );
+    P( D, A, B, C, 14,  9, 0xC33707D6 );
+    P( C, D, A, B,  3, 14, 0xF4D50D87 );
+    P( B, C, D, A,  8, 20, 0x455A14ED );
+    P( A, B, C, D, 13,  5, 0xA9E3E905 );
+    P( D, A, B, C,  2,  9, 0xFCEFA3F8 );
+    P( C, D, A, B,  7, 14, 0x676F02D9 );
+    P( B, C, D, A, 12, 20, 0x8D2A4C8A );
+
+#undef F
+    
+#define F(x,y,z) (x ^ y ^ z)
+
+    P( A, B, C, D,  5,  4, 0xFFFA3942 );
+    P( D, A, B, C,  8, 11, 0x8771F681 );
+    P( C, D, A, B, 11, 16, 0x6D9D6122 );
+    P( B, C, D, A, 14, 23, 0xFDE5380C );
+    P( A, B, C, D,  1,  4, 0xA4BEEA44 );
+    P( D, A, B, C,  4, 11, 0x4BDECFA9 );
+    P( C, D, A, B,  7, 16, 0xF6BB4B60 );
+    P( B, C, D, A, 10, 23, 0xBEBFBC70 );
+    P( A, B, C, D, 13,  4, 0x289B7EC6 );
+    P( D, A, B, C,  0, 11, 0xEAA127FA );
+    P( C, D, A, B,  3, 16, 0xD4EF3085 );
+    P( B, C, D, A,  6, 23, 0x04881D05 );
+    P( A, B, C, D,  9,  4, 0xD9D4D039 );
+    P( D, A, B, C, 12, 11, 0xE6DB99E5 );
+    P( C, D, A, B, 15, 16, 0x1FA27CF8 );
+    P( B, C, D, A,  2, 23, 0xC4AC5665 );
+
+#undef F
+
+#define F(x,y,z) (y ^ (x | ~z))
+
+    P( A, B, C, D,  0,  6, 0xF4292244 );
+    P( D, A, B, C,  7, 10, 0x432AFF97 );
+    P( C, D, A, B, 14, 15, 0xAB9423A7 );
+    P( B, C, D, A,  5, 21, 0xFC93A039 );
+    P( A, B, C, D, 12,  6, 0x655B59C3 );
+    P( D, A, B, C,  3, 10, 0x8F0CCC92 );
+    P( C, D, A, B, 10, 15, 0xFFEFF47D );
+    P( B, C, D, A,  1, 21, 0x85845DD1 );
+    P( A, B, C, D,  8,  6, 0x6FA87E4F );
+    P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
+    P( C, D, A, B,  6, 15, 0xA3014314 );
+    P( B, C, D, A, 13, 21, 0x4E0811A1 );
+    P( A, B, C, D,  4,  6, 0xF7537E82 );
+    P( D, A, B, C, 11, 10, 0xBD3AF235 );
+    P( C, D, A, B,  2, 15, 0x2AD7D2BB );
+    P( B, C, D, A,  9, 21, 0xEB86D391 );
+
+#undef F
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+}
+
+/*
+ * MD5 process buffer
+ */
+void md5_update( md5_context *ctx, unsigned char *input, int ilen )
+{
+    int fill;
+    unsigned long left;
+
+    if( ilen <= 0 )
+        return;
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += ilen;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if( ctx->total[0] < (unsigned long) ilen )
+        ctx->total[1]++;
+
+    if( left && ilen >= fill )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, fill );
+        md5_process( ctx, ctx->buffer );
+        input += fill;
+        ilen  -= fill;
+        left = 0;
+    }
+
+    while( ilen >= 64 )
+    {
+        md5_process( ctx, input );
+        input += 64;
+        ilen  -= 64;
+    }
+
+    if( ilen > 0 )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, ilen );
+    }
+}
+
+static const unsigned char md5_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
+};
+
+/*
+ * MD5 final digest
+ */
+void md5_finish( md5_context *ctx, unsigned char output[16] )
+{
+    unsigned long last, padn;
+    unsigned long high, low;
+    unsigned char msglen[8];
+
+    high = ( ctx->total[0] >> 29 )
+         | ( ctx->total[1] <<  3 );
+    low  = ( ctx->total[0] <<  3 );
+
+    PUT_ULONG_LE( low,  msglen, 0 );
+    PUT_ULONG_LE( high, msglen, 4 );
+
+    last = ctx->total[0] & 0x3F;
+    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+    md5_update( ctx, (unsigned char *) md5_padding, padn );
+    md5_update( ctx, msglen, 8 );
+
+    PUT_ULONG_LE( ctx->state[0], output,  0 );
+    PUT_ULONG_LE( ctx->state[1], output,  4 );
+    PUT_ULONG_LE( ctx->state[2], output,  8 );
+    PUT_ULONG_LE( ctx->state[3], output, 12 );
+}
+
+/*
+ * output = MD5( input buffer )
+ */
+void md5( unsigned char *input, int ilen, unsigned char output[16] )
+{
+    md5_context ctx;
+
+    md5_starts( &ctx );
+    md5_update( &ctx, input, ilen );
+    md5_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( md5_context ) );
+}
+
+/*
+ * output = MD5( file contents )
+ */
+int md5_file( char *path, unsigned char output[16] )
+{
+    FILE *f;
+    size_t n;
+    md5_context ctx;
+    unsigned char buf[1024];
+
+    if( ( f = fopen( path, "rb" ) ) == NULL )
+        return( 1 );
+
+    md5_starts( &ctx );
+
+    while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+        md5_update( &ctx, buf, (int) n );
+
+    md5_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( md5_context ) );
+
+    if( ferror( f ) != 0 )
+    {
+        fclose( f );
+        return( 2 );
+    }
+
+    fclose( f );
+    return( 0 );
+}
+
+/*
+ * MD5 HMAC context setup
+ */
+void md5_hmac_starts( md5_context *ctx, unsigned char *key, int keylen )
+{
+    int i;
+    unsigned char sum[16];
+
+    if( keylen > 64 )
+    {
+        md5( key, keylen, sum );
+        keylen = 16;
+        key = sum;
+    }
+
+    memset( ctx->ipad, 0x36, 64 );
+    memset( ctx->opad, 0x5C, 64 );
+
+    for( i = 0; i < keylen; i++ )
+    {
+        ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
+        ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
+    }
+
+    md5_starts( ctx );
+    md5_update( ctx, ctx->ipad, 64 );
+
+    memset( sum, 0, sizeof( sum ) );
+}
+
+/*
+ * MD5 HMAC process buffer
+ */
+void md5_hmac_update( md5_context *ctx, unsigned char *input, int ilen )
+{
+    md5_update( ctx, input, ilen );
+}
+
+/*
+ * MD5 HMAC final digest
+ */
+void md5_hmac_finish( md5_context *ctx, unsigned char output[16] )
+{
+    unsigned char tmpbuf[16];
+
+    md5_finish( ctx, tmpbuf );
+    md5_starts( ctx );
+    md5_update( ctx, ctx->opad, 64 );
+    md5_update( ctx, tmpbuf, 16 );
+    md5_finish( ctx, output );
+
+    memset( tmpbuf, 0, sizeof( tmpbuf ) );
+}
+
+/*
+ * output = HMAC-MD5( hmac key, input buffer )
+ */
+void md5_hmac( unsigned char *key, int keylen, unsigned char *input, int ilen,
+               unsigned char output[16] )
+{
+    md5_context ctx;
+
+    md5_hmac_starts( &ctx, key, keylen );
+    md5_hmac_update( &ctx, input, ilen );
+    md5_hmac_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( md5_context ) );
+}
+
+#if defined(XYSSL_SELF_TEST)
+/*
+ * RFC 1321 test vectors
+ */
+static unsigned char md5_test_buf[7][81] =
+{
+    { "" }, 
+    { "a" },
+    { "abc" },
+    { "message digest" },
+    { "abcdefghijklmnopqrstuvwxyz" },
+    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
+    { "12345678901234567890123456789012345678901234567890123456789012" \
+      "345678901234567890" }
+};
+
+static const int md5_test_buflen[7] =
+{
+    0, 1, 3, 14, 26, 62, 80
+};
+
+static const unsigned char md5_test_sum[7][16] =
+{
+    { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04,
+      0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E },
+    { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8,
+      0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 },
+    { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0,
+      0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 },
+    { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D,
+      0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 },
+    { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00,
+      0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B },
+    { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5,
+      0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F },
+    { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55,
+      0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A }
+};
+
+/*
+ * RFC 2202 test vectors
+ */
+static unsigned char md5_hmac_test_key[7][26] =
+{
+    { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" },
+    { "Jefe" },
+    { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" },
+    { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
+      "\x11\x12\x13\x14\x15\x16\x17\x18\x19" },
+    { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" },
+    { "" }, /* 0xAA 80 times */
+    { "" }
+};
+
+static const int md5_hmac_test_keylen[7] =
+{
+    16, 4, 16, 25, 16, 80, 80
+};
+
+static unsigned char md5_hmac_test_buf[7][74] =
+{
+    { "Hi There" },
+    { "what do ya want for nothing?" },
+    { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" },
+    { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" },
+    { "Test With Truncation" },
+    { "Test Using Larger Than Block-Size Key - Hash Key First" },
+    { "Test Using Larger Than Block-Size Key and Larger"
+      " Than One Block-Size Data" }
+};
+
+static const int md5_hmac_test_buflen[7] =
+{
+    8, 28, 50, 50, 20, 54, 73
+};
+
+static const unsigned char md5_hmac_test_sum[7][16] =
+{
+    { 0x92, 0x94, 0x72, 0x7A, 0x36, 0x38, 0xBB, 0x1C,
+      0x13, 0xF4, 0x8E, 0xF8, 0x15, 0x8B, 0xFC, 0x9D },
+    { 0x75, 0x0C, 0x78, 0x3E, 0x6A, 0xB0, 0xB5, 0x03,
+      0xEA, 0xA8, 0x6E, 0x31, 0x0A, 0x5D, 0xB7, 0x38 },
+    { 0x56, 0xBE, 0x34, 0x52, 0x1D, 0x14, 0x4C, 0x88,
+      0xDB, 0xB8, 0xC7, 0x33, 0xF0, 0xE8, 0xB3, 0xF6 },
+    { 0x69, 0x7E, 0xAF, 0x0A, 0xCA, 0x3A, 0x3A, 0xEA,
+      0x3A, 0x75, 0x16, 0x47, 0x46, 0xFF, 0xAA, 0x79 },
+    { 0x56, 0x46, 0x1E, 0xF2, 0x34, 0x2E, 0xDC, 0x00,
+      0xF9, 0xBA, 0xB9, 0x95 },
+    { 0x6B, 0x1A, 0xB7, 0xFE, 0x4B, 0xD7, 0xBF, 0x8F,
+      0x0B, 0x62, 0xE6, 0xCE, 0x61, 0xB9, 0xD0, 0xCD },
+    { 0x6F, 0x63, 0x0F, 0xAD, 0x67, 0xCD, 0xA0, 0xEE,
+      0x1F, 0xB1, 0xF5, 0x62, 0xDB, 0x3A, 0xA5, 0x3E }
+};
+
+/*
+ * Checkup routine
+ */
+int md5_self_test( int verbose )
+{
+    int i, buflen;
+    unsigned char buf[1024];
+    unsigned char md5sum[16];
+    md5_context ctx;
+
+    for( i = 0; i < 7; i++ )
+    {
+        if( verbose != 0 )
+            printf( "  MD5 test #%d: ", i + 1 );
+
+        md5( md5_test_buf[i], md5_test_buflen[i], md5sum );
+
+        if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    for( i = 0; i < 7; i++ )
+    {
+        if( verbose != 0 )
+            printf( "  HMAC-MD5 test #%d: ", i + 1 );
+
+        if( i == 5 || i == 6 )
+        {
+            memset( buf, '\xAA', buflen = 80 );
+            md5_hmac_starts( &ctx, buf, buflen );
+        }
+        else
+            md5_hmac_starts( &ctx, md5_hmac_test_key[i],
+                                   md5_hmac_test_keylen[i] );
+
+        md5_hmac_update( &ctx, md5_hmac_test_buf[i],
+                               md5_hmac_test_buflen[i] );
+
+        md5_hmac_finish( &ctx, md5sum );
+
+        buflen = ( i == 4 ) ? 12 : 16;
+
+        if( memcmp( md5sum, md5_hmac_test_sum[i], buflen ) != 0 )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/library/net.c b/library/net.c
new file mode 100644
index 0000000..78525c3
--- /dev/null
+++ b/library/net.c
@@ -0,0 +1,346 @@
+/*
+ *  TCP networking functions
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_NET_C)
+
+#include "xyssl/net.h"
+
+#if defined(WIN32) || defined(_WIN32_WCE)
+
+#include <winsock2.h>
+#include <windows.h>
+
+#if defined(_WIN32_WCE)
+#pragma comment( lib, "ws2.lib" )
+#else
+#pragma comment( lib, "ws2_32.lib" )
+#endif
+
+#define read(fd,buf,len)        recv(fd,buf,len,0)
+#define write(fd,buf,len)       send(fd,buf,len,0)
+#define close(fd)               closesocket(fd)
+
+static int wsa_init_done = 0;
+
+#else
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <errno.h>
+
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+/*
+ * htons() is not always available
+ */
+static unsigned short net_htons( int port )
+{
+    unsigned char buf[4];
+
+    buf[0] = (unsigned char)( port >> 8 );
+    buf[1] = (unsigned char)( port      );
+    buf[2] = buf[3] = 0;
+
+    return( *(unsigned short *) buf );
+}
+
+/*
+ * Initiate a TCP connection with host:port
+ */
+int net_connect( int *fd, char *host, int port )
+{
+    struct sockaddr_in server_addr;
+    struct hostent *server_host;
+
+#if defined(WIN32) || defined(_WIN32_WCE)
+    WSADATA wsaData;
+
+    if( wsa_init_done == 0 )
+    {
+        if( WSAStartup( MAKEWORD(2,0), &wsaData ) == SOCKET_ERROR )
+            return( XYSSL_ERR_NET_SOCKET_FAILED );
+
+        wsa_init_done = 1;
+    }
+#else
+    signal( SIGPIPE, SIG_IGN );
+#endif
+
+    if( ( server_host = gethostbyname( host ) ) == NULL )
+        return( XYSSL_ERR_NET_UNKNOWN_HOST );
+
+    if( ( *fd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP ) ) < 0 )
+        return( XYSSL_ERR_NET_SOCKET_FAILED );
+
+    memcpy( (void *) &server_addr.sin_addr,
+            (void *) server_host->h_addr,
+                     server_host->h_length );
+
+    server_addr.sin_family = AF_INET;
+    server_addr.sin_port   = net_htons( port );
+
+    if( connect( *fd, (struct sockaddr *) &server_addr,
+                 sizeof( server_addr ) ) < 0 )
+    {
+        close( *fd );
+        return( XYSSL_ERR_NET_CONNECT_FAILED );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Create a listening socket on bind_ip:port
+ */
+int net_bind( int *fd, char *bind_ip, int port )
+{
+    int n, c[4];
+    struct sockaddr_in server_addr;
+
+#if defined(WIN32) || defined(_WIN32_WCE)
+    WSADATA wsaData;
+
+    if( wsa_init_done == 0 )
+    {
+        if( WSAStartup( MAKEWORD(2,0), &wsaData ) == SOCKET_ERROR )
+            return( XYSSL_ERR_NET_SOCKET_FAILED );
+
+        wsa_init_done = 1;
+    }
+#else
+    signal( SIGPIPE, SIG_IGN );
+#endif
+
+    if( ( *fd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP ) ) < 0 )
+        return( XYSSL_ERR_NET_SOCKET_FAILED );
+
+    n = 1;
+    setsockopt( *fd, SOL_SOCKET, SO_REUSEADDR,
+                (const char *) &n, sizeof( n ) );
+
+    server_addr.sin_addr.s_addr = INADDR_ANY;
+    server_addr.sin_family      = AF_INET;
+    server_addr.sin_port        = net_htons( port );
+
+    if( bind_ip != NULL )
+    {
+        memset( c, 0, sizeof( c ) );
+        sscanf( bind_ip, "%d.%d.%d.%d", &c[0], &c[1], &c[2], &c[3] );
+
+        for( n = 0; n < 4; n++ )
+            if( c[n] < 0 || c[n] > 255 )
+                break;
+
+        if( n == 4 )
+            server_addr.sin_addr.s_addr =
+                ( (unsigned long) c[0] << 24 ) |
+                ( (unsigned long) c[1] << 16 ) |
+                ( (unsigned long) c[2] <<  8 ) |
+                ( (unsigned long) c[3]       );
+    }
+
+    if( bind( *fd, (struct sockaddr *) &server_addr,
+              sizeof( server_addr ) ) < 0 )
+    {
+        close( *fd );
+        return( XYSSL_ERR_NET_BIND_FAILED );
+    }
+
+    if( listen( *fd, 10 ) != 0 )
+    {
+        close( *fd );
+        return( XYSSL_ERR_NET_LISTEN_FAILED );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Check if the current operation is blocking
+ */
+static int net_is_blocking( void )
+{
+#if defined(WIN32) || defined(_WIN32_WCE)
+    return( WSAGetLastError() == WSAEWOULDBLOCK );
+#else
+    switch( errno )
+    {
+#if defined EAGAIN
+        case EAGAIN:
+#endif
+#if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN
+        case EWOULDBLOCK:
+#endif
+            return( 1 );
+    }
+    return( 0 );
+#endif
+}
+
+/*
+ * Accept a connection from a remote client
+ */
+int net_accept( int bind_fd, int *client_fd, void *client_ip )
+{
+    struct sockaddr_in client_addr;
+
+#if defined(__socklen_t_defined)
+    socklen_t n = (socklen_t) sizeof( client_addr );
+#else
+    int n = (int) sizeof( client_addr );
+#endif
+
+    *client_fd = accept( bind_fd, (struct sockaddr *)
+                         &client_addr, &n );
+
+    if( *client_fd < 0 )
+    {
+        if( net_is_blocking() != 0 )
+            return( XYSSL_ERR_NET_TRY_AGAIN );
+
+        return( XYSSL_ERR_NET_ACCEPT_FAILED );
+    }
+
+    if( client_ip != NULL )
+        memcpy( client_ip, &client_addr.sin_addr.s_addr,
+                    sizeof( client_addr.sin_addr.s_addr ) );
+
+    return( 0 );
+}
+
+/*
+ * Set the socket blocking or non-blocking
+ */
+int net_set_block( int fd )
+{
+#if defined(WIN32) || defined(_WIN32_WCE)
+    long n = 0;
+    return( ioctlsocket( fd, FIONBIO, &n ) );
+#else
+    return( fcntl( fd, F_SETFL, fcntl( fd, F_GETFL ) & ~O_NONBLOCK ) );
+#endif
+}
+
+int net_set_nonblock( int fd )
+{
+#if defined(WIN32) || defined(_WIN32_WCE)
+    long n = 1;
+    return( ioctlsocket( fd, FIONBIO, &n ) );
+#else
+    return( fcntl( fd, F_SETFL, fcntl( fd, F_GETFL ) | O_NONBLOCK ) );
+#endif
+}
+
+/*
+ * Portable usleep helper
+ */
+void net_usleep( unsigned long usec )
+{
+    struct timeval tv;
+    tv.tv_sec  = 0;
+    tv.tv_usec = usec;
+    select( 0, NULL, NULL, NULL, &tv );
+}
+
+/*
+ * Read at most 'len' characters
+ */
+int net_recv( void *ctx, unsigned char *buf, int len )
+{ 
+    int ret = read( *((int *) ctx), buf, len );
+
+    if( len > 0 && ret == 0 )
+        return( XYSSL_ERR_NET_CONN_RESET );
+
+    if( ret < 0 )
+    {
+        if( net_is_blocking() != 0 )
+            return( XYSSL_ERR_NET_TRY_AGAIN );
+
+#if defined(WIN32) || defined(_WIN32_WCE)
+        if( WSAGetLastError() == WSAECONNRESET )
+            return( XYSSL_ERR_NET_CONN_RESET );
+#else
+        if( errno == EPIPE || errno == ECONNRESET )
+            return( XYSSL_ERR_NET_CONN_RESET );
+
+        if( errno == EINTR )
+            return( XYSSL_ERR_NET_TRY_AGAIN );
+#endif
+
+        return( XYSSL_ERR_NET_RECV_FAILED );
+    }
+
+    return( ret );
+}
+
+/*
+ * Write at most 'len' characters
+ */
+int net_send( void *ctx, unsigned char *buf, int len )
+{
+    int ret = write( *((int *) ctx), buf, len );
+
+    if( ret < 0 )
+    {
+        if( net_is_blocking() != 0 )
+            return( XYSSL_ERR_NET_TRY_AGAIN );
+
+#if defined(WIN32) || defined(_WIN32_WCE)
+        if( WSAGetLastError() == WSAECONNRESET )
+            return( XYSSL_ERR_NET_CONN_RESET );
+#else
+        if( errno == EPIPE || errno == ECONNRESET )
+            return( XYSSL_ERR_NET_CONN_RESET );
+
+        if( errno == EINTR )
+            return( XYSSL_ERR_NET_TRY_AGAIN );
+#endif
+
+        return( XYSSL_ERR_NET_SEND_FAILED );
+    }
+
+    return( ret );
+}
+
+/*
+ * Gracefully close the connection
+ */
+void net_close( int fd )
+{
+    shutdown( fd, 2 );
+    close( fd );
+}
+
+#endif
diff --git a/library/padlock.c b/library/padlock.c
new file mode 100644
index 0000000..8d761b2
--- /dev/null
+++ b/library/padlock.c
@@ -0,0 +1,159 @@
+/*
+ *  VIA PadLock support functions
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  This implementation is based on the VIA PadLock Programming Guide:
+ *
+ *  http://www.via.com.tw/en/downloads/whitepapers/initiatives/padlock/
+ *  programming_guide.pdf
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_PADLOCK_C)
+
+#include "xyssl/aes.h"
+#include "xyssl/padlock.h"
+
+#if defined(XYSSL_HAVE_X86)
+
+#include <string.h>
+
+/*
+ * PadLock detection routine
+ */
+int padlock_supports( int feature )
+{
+    static int flags = -1;
+    int ebx, edx;
+
+    if( flags == -1 )
+    {
+        asm( "movl  %%ebx, %0           \n"     \
+             "movl  $0xC0000000, %%eax  \n"     \
+             "cpuid                     \n"     \
+             "cmpl  $0xC0000001, %%eax  \n"     \
+             "movl  $0, %%edx           \n"     \
+             "jb    unsupported         \n"     \
+             "movl  $0xC0000001, %%eax  \n"     \
+             "cpuid                     \n"     \
+             "unsupported:              \n"     \
+             "movl  %%edx, %1           \n"     \
+             "movl  %2, %%ebx           \n"
+             : "=m" (ebx), "=m" (edx)
+             :  "m" (ebx)
+             : "eax", "ecx", "edx" );
+
+        flags = edx;
+    }
+
+    return( flags & feature );
+}
+
+/*
+ * PadLock AES-ECB block en(de)cryption
+ */
+int padlock_xcryptecb( aes_context *ctx,
+                       int mode,
+                       unsigned char input[16],
+                       unsigned char output[16] )
+{
+    int ebx;
+    unsigned long *rk;
+    unsigned long *blk;
+    unsigned long *ctrl;
+    unsigned char buf[256];
+
+    rk  = ctx->rk;
+    blk = PADLOCK_ALIGN16( buf );
+    memcpy( blk, input, 16 );
+
+     ctrl = blk + 4;
+    *ctrl = 0x80 | ctx->nr | ( ( ctx->nr + ( mode^1 ) - 10 ) << 9 );
+
+    asm( "pushfl; popfl         \n"     \
+         "movl    %%ebx, %0     \n"     \
+         "movl    $1, %%ecx     \n"     \
+         "movl    %2, %%edx     \n"     \
+         "movl    %3, %%ebx     \n"     \
+         "movl    %4, %%esi     \n"     \
+         "movl    %4, %%edi     \n"     \
+         ".byte  0xf3,0x0f,0xa7,0xc8\n" \
+         "movl    %1, %%ebx     \n"
+         : "=m" (ebx)
+         :  "m" (ebx), "m" (ctrl), "m" (rk), "m" (blk)
+         : "ecx", "edx", "esi", "edi" );
+
+    memcpy( output, blk, 16 );
+
+    return( 0 );
+}
+
+/*
+ * PadLock AES-CBC buffer en(de)cryption
+ */
+int padlock_xcryptcbc( aes_context *ctx,
+                       int mode,
+                       int length,
+                       unsigned char iv[16],
+                       unsigned char *input,
+                       unsigned char *output )
+{
+    int ebx, count;
+    unsigned long *rk;
+    unsigned long *iw;
+    unsigned long *ctrl;
+    unsigned char buf[256];
+
+    if( ( (long) input  & 15 ) != 0 ||
+        ( (long) output & 15 ) != 0 )
+        return( 1 );
+
+    rk = ctx->rk;
+    iw = PADLOCK_ALIGN16( buf );
+    memcpy( iw, iv, 16 );
+
+     ctrl = iw + 4;
+    *ctrl = 0x80 | ctx->nr | ( ( ctx->nr + (mode^1) - 10 ) << 9 );
+
+    count = (length + 15) >> 4;
+
+    asm( "pushfl; popfl         \n"     \
+         "movl    %%ebx, %0     \n"     \
+         "movl    %2, %%ecx     \n"     \
+         "movl    %3, %%edx     \n"     \
+         "movl    %4, %%ebx     \n"     \
+         "movl    %5, %%esi     \n"     \
+         "movl    %6, %%edi     \n"     \
+         "movl    %7, %%eax     \n"     \
+         ".byte  0xf3,0x0f,0xa7,0xd0\n" \
+         "movl    %1, %%ebx     \n"
+         : "=m" (ebx)
+         :  "m" (ebx), "m" (count), "m" (ctrl),
+            "m"  (rk), "m" (input), "m" (output), "m" (iw)
+         : "eax", "ecx", "edx", "esi", "edi" );
+
+    memcpy( iv, iw, 16 );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/library/rsa.c b/library/rsa.c
new file mode 100644
index 0000000..9d54032
--- /dev/null
+++ b/library/rsa.c
@@ -0,0 +1,730 @@
+/*
+ *  The RSA public-key cryptosystem
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  RSA was designed by Ron Rivest, Adi Shamir and Len Adleman.
+ *
+ *  http://theory.lcs.mit.edu/~rivest/rsapaper.pdf
+ *  http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_RSA_C)
+
+#include "xyssl/rsa.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * Initialize an RSA context
+ */
+void rsa_init( rsa_context *ctx,
+               int padding,
+               int hash_id,
+               int (*f_rng)(void *),
+               void *p_rng )
+{
+    memset( ctx, 0, sizeof( rsa_context ) );
+
+    ctx->padding = padding;
+    ctx->hash_id = hash_id;
+
+    ctx->f_rng = f_rng;
+    ctx->p_rng = p_rng;
+}
+
+#if defined(XYSSL_GENPRIME)
+
+/*
+ * Generate an RSA keypair
+ */
+int rsa_gen_key( rsa_context *ctx, int nbits, int exponent )
+{
+    int ret;
+    mpi P1, Q1, H, G;
+
+    if( ctx->f_rng == NULL || nbits < 128 || exponent < 3 )
+        return( XYSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    mpi_init( &P1, &Q1, &H, &G, NULL );
+
+    /*
+     * find primes P and Q with Q < P so that:
+     * GCD( E, (P-1)*(Q-1) ) == 1
+     */
+    MPI_CHK( mpi_lset( &ctx->E, exponent ) );
+
+    do
+    {
+        MPI_CHK( mpi_gen_prime( &ctx->P, ( nbits + 1 ) >> 1, 0, 
+                                ctx->f_rng, ctx->p_rng ) );
+
+        MPI_CHK( mpi_gen_prime( &ctx->Q, ( nbits + 1 ) >> 1, 0,
+                                ctx->f_rng, ctx->p_rng ) );
+
+        if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 )
+            mpi_swap( &ctx->P, &ctx->Q );
+
+        if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 )
+            continue;
+
+        MPI_CHK( mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) );
+        if( mpi_msb( &ctx->N ) != nbits )
+            continue;
+
+        MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
+        MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
+        MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) );
+        MPI_CHK( mpi_gcd( &G, &ctx->E, &H  ) );
+    }
+    while( mpi_cmp_int( &G, 1 ) != 0 );
+
+    /*
+     * D  = E^-1 mod ((P-1)*(Q-1))
+     * DP = D mod (P - 1)
+     * DQ = D mod (Q - 1)
+     * QP = Q^-1 mod P
+     */
+    MPI_CHK( mpi_inv_mod( &ctx->D , &ctx->E, &H  ) );
+    MPI_CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) );
+    MPI_CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) );
+    MPI_CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) );
+
+    ctx->len = ( mpi_msb( &ctx->N ) + 7 ) >> 3;
+
+cleanup:
+
+    mpi_free( &G, &H, &Q1, &P1, NULL );
+
+    if( ret != 0 )
+    {
+        rsa_free( ctx );
+        return( XYSSL_ERR_RSA_KEY_GEN_FAILED | ret );
+    }
+
+    return( 0 );   
+}
+
+#endif
+
+/*
+ * Check a public RSA key
+ */
+int rsa_check_pubkey( rsa_context *ctx )
+{
+    if( ( ctx->N.p[0] & 1 ) == 0 || 
+        ( ctx->E.p[0] & 1 ) == 0 )
+        return( XYSSL_ERR_RSA_KEY_CHECK_FAILED );
+
+    if( mpi_msb( &ctx->N ) < 128 ||
+        mpi_msb( &ctx->N ) > 4096 )
+        return( XYSSL_ERR_RSA_KEY_CHECK_FAILED );
+
+    if( mpi_msb( &ctx->E ) < 2 ||
+        mpi_msb( &ctx->E ) > 64 )
+        return( XYSSL_ERR_RSA_KEY_CHECK_FAILED );
+
+    return( 0 );
+}
+
+/*
+ * Check a private RSA key
+ */
+int rsa_check_privkey( rsa_context *ctx )
+{
+    int ret;
+    mpi PQ, DE, P1, Q1, H, I, G;
+
+    if( ( ret = rsa_check_pubkey( ctx ) ) != 0 )
+        return( ret );
+
+    mpi_init( &PQ, &DE, &P1, &Q1, &H, &I, &G, NULL );
+
+    MPI_CHK( mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) );
+    MPI_CHK( mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) );
+    MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
+    MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
+    MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) );
+    MPI_CHK( mpi_mod_mpi( &I, &DE, &H  ) );
+    MPI_CHK( mpi_gcd( &G, &ctx->E, &H  ) );
+
+    if( mpi_cmp_mpi( &PQ, &ctx->N ) == 0 &&
+        mpi_cmp_int( &I, 1 ) == 0 &&
+        mpi_cmp_int( &G, 1 ) == 0 )
+    {
+        mpi_free( &G, &I, &H, &Q1, &P1, &DE, &PQ, NULL );
+        return( 0 );
+    }
+
+cleanup:
+
+    mpi_free( &G, &I, &H, &Q1, &P1, &DE, &PQ, NULL );
+    return( XYSSL_ERR_RSA_KEY_CHECK_FAILED | ret );
+}
+
+/*
+ * Do an RSA public key operation
+ */
+int rsa_public( rsa_context *ctx,
+                unsigned char *input,
+                unsigned char *output )
+{
+    int ret, olen;
+    mpi T;
+
+    mpi_init( &T, NULL );
+
+    MPI_CHK( mpi_read_binary( &T, input, ctx->len ) );
+
+    if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
+    {
+        mpi_free( &T, NULL );
+        return( XYSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    olen = ctx->len;
+    MPI_CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) );
+    MPI_CHK( mpi_write_binary( &T, output, olen ) );
+
+cleanup:
+
+    mpi_free( &T, NULL );
+
+    if( ret != 0 )
+        return( XYSSL_ERR_RSA_PUBLIC_FAILED | ret );
+
+    return( 0 );
+}
+
+/*
+ * Do an RSA private key operation
+ */
+int rsa_private( rsa_context *ctx,
+                 unsigned char *input,
+                 unsigned char *output )
+{
+    int ret, olen;
+    mpi T, T1, T2;
+
+    mpi_init( &T, &T1, &T2, NULL );
+
+    MPI_CHK( mpi_read_binary( &T, input, ctx->len ) );
+
+    if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
+    {
+        mpi_free( &T, NULL );
+        return( XYSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
+
+#if 0
+    MPI_CHK( mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) );
+#else
+    /*
+     * faster decryption using the CRT
+     *
+     * T1 = input ^ dP mod P
+     * T2 = input ^ dQ mod Q
+     */
+    MPI_CHK( mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) );
+    MPI_CHK( mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) );
+
+    /*
+     * T = (T1 - T2) * (Q^-1 mod P) mod P
+     */
+    MPI_CHK( mpi_sub_mpi( &T, &T1, &T2 ) );
+    MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->QP ) );
+    MPI_CHK( mpi_mod_mpi( &T, &T1, &ctx->P ) );
+
+    /*
+     * output = T2 + T * Q
+     */
+    MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->Q ) );
+    MPI_CHK( mpi_add_mpi( &T, &T2, &T1 ) );
+#endif
+
+    olen = ctx->len;
+    MPI_CHK( mpi_write_binary( &T, output, olen ) );
+
+cleanup:
+
+    mpi_free( &T, &T1, &T2, NULL );
+
+    if( ret != 0 )
+        return( XYSSL_ERR_RSA_PRIVATE_FAILED | ret );
+
+    return( 0 );
+}
+
+/*
+ * Add the message padding, then do an RSA operation
+ */
+int rsa_pkcs1_encrypt( rsa_context *ctx,
+                       int mode, int  ilen,
+                       unsigned char *input,
+                       unsigned char *output )
+{
+    int nb_pad, olen;
+    unsigned char *p = output;
+
+    olen = ctx->len;
+
+    switch( ctx->padding )
+    {
+        case RSA_PKCS_V15:
+
+            if( ilen < 0 || olen < ilen + 11 )
+                return( XYSSL_ERR_RSA_BAD_INPUT_DATA );
+
+            nb_pad = olen - 3 - ilen;
+
+            *p++ = 0;
+            *p++ = RSA_CRYPT;
+
+            while( nb_pad-- > 0 )
+            {
+                do {
+                    *p = (unsigned char) rand();
+                } while( *p == 0 );
+                p++;
+            }
+            *p++ = 0;
+            memcpy( p, input, ilen );
+            break;
+
+        default:
+
+            return( XYSSL_ERR_RSA_INVALID_PADDING );
+    }
+
+    return( ( mode == RSA_PUBLIC )
+            ? rsa_public(  ctx, output, output )
+            : rsa_private( ctx, output, output ) );
+}
+
+/*
+ * Do an RSA operation, then remove the message padding
+ */
+int rsa_pkcs1_decrypt( rsa_context *ctx,
+                       int mode, int *olen,
+                       unsigned char *input,
+                       unsigned char *output )
+{
+    int ret, ilen;
+    unsigned char *p;
+    unsigned char buf[512];
+
+    ilen = ctx->len;
+
+    if( ilen < 16 || ilen > (int) sizeof( buf ) )
+        return( XYSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    ret = ( mode == RSA_PUBLIC )
+          ? rsa_public(  ctx, input, buf )
+          : rsa_private( ctx, input, buf );
+
+    if( ret != 0 )
+        return( ret );
+
+    p = buf;
+
+    switch( ctx->padding )
+    {
+        case RSA_PKCS_V15:
+
+            if( *p++ != 0 || *p++ != RSA_CRYPT )
+                return( XYSSL_ERR_RSA_INVALID_PADDING );
+
+            while( *p != 0 )
+            {
+                if( p >= buf + ilen - 1 )
+                    return( XYSSL_ERR_RSA_INVALID_PADDING );
+                p++;
+            }
+            p++;
+            break;
+
+        default:
+
+            return( XYSSL_ERR_RSA_INVALID_PADDING );
+    }
+
+    *olen = ilen - (int)(p - buf);
+    memcpy( output, p, *olen );
+
+    return( 0 );
+}
+
+/*
+ * Do an RSA operation to sign the message digest
+ */
+int rsa_pkcs1_sign( rsa_context *ctx,
+                    int mode,
+                    int hash_id,
+                    int hashlen,
+                    unsigned char *hash,
+                    unsigned char *sig )
+{
+    int nb_pad, olen;
+    unsigned char *p = sig;
+
+    olen = ctx->len;
+
+    switch( ctx->padding )
+    {
+        case RSA_PKCS_V15:
+
+            switch( hash_id )
+            {
+                case RSA_RAW:
+                    nb_pad = olen - 3 - hashlen;
+                    break;
+
+                case RSA_MD2:
+                case RSA_MD4:
+                case RSA_MD5:
+                    nb_pad = olen - 3 - 34;
+                    break;
+
+                case RSA_SHA1:
+                    nb_pad = olen - 3 - 35;
+                    break;
+
+                default:
+                    return( XYSSL_ERR_RSA_BAD_INPUT_DATA );
+            }
+
+            if( nb_pad < 8 )
+                return( XYSSL_ERR_RSA_BAD_INPUT_DATA );
+
+            *p++ = 0;
+            *p++ = RSA_SIGN;
+            memset( p, 0xFF, nb_pad );
+            p += nb_pad;
+            *p++ = 0;
+            break;
+
+        default:
+
+            return( XYSSL_ERR_RSA_INVALID_PADDING );
+    }
+
+    switch( hash_id )
+    {
+        case RSA_RAW:
+            memcpy( p, hash, hashlen );
+            break;
+
+        case RSA_MD2:
+            memcpy( p, ASN1_HASH_MDX, 18 );
+            memcpy( p + 18, hash, 16 );
+            p[13] = 2; break;
+
+        case RSA_MD4:
+            memcpy( p, ASN1_HASH_MDX, 18 );
+            memcpy( p + 18, hash, 16 );
+            p[13] = 4; break;
+
+        case RSA_MD5:
+            memcpy( p, ASN1_HASH_MDX, 18 );
+            memcpy( p + 18, hash, 16 );
+            p[13] = 5; break;
+
+        case RSA_SHA1:
+            memcpy( p, ASN1_HASH_SHA1, 15 );
+            memcpy( p + 15, hash, 20 );
+            break;
+
+        default:
+            return( XYSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    return( ( mode == RSA_PUBLIC )
+            ? rsa_public(  ctx, sig, sig )
+            : rsa_private( ctx, sig, sig ) );
+}
+
+/*
+ * Do an RSA operation and check the message digest
+ */
+int rsa_pkcs1_verify( rsa_context *ctx,
+                      int mode,
+                      int hash_id,
+                      int hashlen,
+                      unsigned char *hash,
+                      unsigned char *sig )
+{
+    int ret, len, siglen;
+    unsigned char *p, c;
+    unsigned char buf[512];
+
+    siglen = ctx->len;
+
+    if( siglen < 16 || siglen > (int) sizeof( buf ) )
+        return( XYSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    ret = ( mode == RSA_PUBLIC )
+          ? rsa_public(  ctx, sig, buf )
+          : rsa_private( ctx, sig, buf );
+
+    if( ret != 0 )
+        return( ret );
+
+    p = buf;
+
+    switch( ctx->padding )
+    {
+        case RSA_PKCS_V15:
+
+            if( *p++ != 0 || *p++ != RSA_SIGN )
+                return( XYSSL_ERR_RSA_INVALID_PADDING );
+
+            while( *p != 0 )
+            {
+                if( p >= buf + siglen - 1 || *p != 0xFF )
+                    return( XYSSL_ERR_RSA_INVALID_PADDING );
+                p++;
+            }
+            p++;
+            break;
+
+        default:
+
+            return( XYSSL_ERR_RSA_INVALID_PADDING );
+    }
+
+    len = siglen - (int)( p - buf );
+
+    if( len == 34 )
+    {
+        c = p[13];
+        p[13] = 0;
+
+        if( memcmp( p, ASN1_HASH_MDX, 18 ) != 0 )
+            return( XYSSL_ERR_RSA_VERIFY_FAILED );
+
+        if( ( c == 2 && hash_id == RSA_MD2 ) ||
+            ( c == 4 && hash_id == RSA_MD4 ) ||
+            ( c == 5 && hash_id == RSA_MD5 ) )
+        {
+            if( memcmp( p + 18, hash, 16 ) == 0 ) 
+                return( 0 );
+            else
+                return( XYSSL_ERR_RSA_VERIFY_FAILED );
+        }
+    }
+
+    if( len == 35 && hash_id == RSA_SHA1 )
+    {
+        if( memcmp( p, ASN1_HASH_SHA1, 15 ) == 0 &&
+            memcmp( p + 15, hash, 20 ) == 0 )
+            return( 0 );
+        else
+            return( XYSSL_ERR_RSA_VERIFY_FAILED );
+    }
+
+    if( len == hashlen && hash_id == RSA_RAW )
+    {
+        if( memcmp( p, hash, hashlen ) == 0 )
+            return( 0 );
+        else
+            return( XYSSL_ERR_RSA_VERIFY_FAILED );
+    }
+
+    return( XYSSL_ERR_RSA_INVALID_PADDING );
+}
+
+/*
+ * Free the components of an RSA key
+ */
+void rsa_free( rsa_context *ctx )
+{
+    mpi_free( &ctx->RQ, &ctx->RP, &ctx->RN,
+              &ctx->QP, &ctx->DQ, &ctx->DP,
+              &ctx->Q,  &ctx->P,  &ctx->D,
+              &ctx->E,  &ctx->N,  NULL );
+}
+
+#if defined(XYSSL_SELF_TEST)
+
+#include "xyssl/sha1.h"
+
+/*
+ * Example RSA-1024 keypair, for test purposes
+ */
+#define KEY_LEN 128
+
+#define RSA_N   "9292758453063D803DD603D5E777D788" \
+                "8ED1D5BF35786190FA2F23EBC0848AEA" \
+                "DDA92CA6C3D80B32C4D109BE0F36D6AE" \
+                "7130B9CED7ACDF54CFC7555AC14EEBAB" \
+                "93A89813FBF3C4F8066D2D800F7C38A8" \
+                "1AE31942917403FF4946B0A83D3D3E05" \
+                "EE57C6F5F5606FB5D4BC6CD34EE0801A" \
+                "5E94BB77B07507233A0BC7BAC8F90F79"
+
+#define RSA_E   "10001"
+
+#define RSA_D   "24BF6185468786FDD303083D25E64EFC" \
+                "66CA472BC44D253102F8B4A9D3BFA750" \
+                "91386C0077937FE33FA3252D28855837" \
+                "AE1B484A8A9A45F7EE8C0C634F99E8CD" \
+                "DF79C5CE07EE72C7F123142198164234" \
+                "CABB724CF78B8173B9F880FC86322407" \
+                "AF1FEDFDDE2BEB674CA15F3E81A1521E" \
+                "071513A1E85B5DFA031F21ECAE91A34D"
+
+#define RSA_P   "C36D0EB7FCD285223CFB5AABA5BDA3D8" \
+                "2C01CAD19EA484A87EA4377637E75500" \
+                "FCB2005C5C7DD6EC4AC023CDA285D796" \
+                "C3D9E75E1EFC42488BB4F1D13AC30A57"
+
+#define RSA_Q   "C000DF51A7C77AE8D7C7370C1FF55B69" \
+                "E211C2B9E5DB1ED0BF61D0D9899620F4" \
+                "910E4168387E3C30AA1E00C339A79508" \
+                "8452DD96A9A5EA5D9DCA68DA636032AF"
+
+#define RSA_DP  "C1ACF567564274FB07A0BBAD5D26E298" \
+                "3C94D22288ACD763FD8E5600ED4A702D" \
+                "F84198A5F06C2E72236AE490C93F07F8" \
+                "3CC559CD27BC2D1CA488811730BB5725"
+
+#define RSA_DQ  "4959CBF6F8FEF750AEE6977C155579C7" \
+                "D8AAEA56749EA28623272E4F7D0592AF" \
+                "7C1F1313CAC9471B5C523BFE592F517B" \
+                "407A1BD76C164B93DA2D32A383E58357"
+
+#define RSA_QP  "9AE7FBC99546432DF71896FC239EADAE" \
+                "F38D18D2B2F0E2DD275AA977E2BF4411" \
+                "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \
+                "A74206CEC169D74BF5A8C50D6F48EA08"
+
+#define PT_LEN  24
+#define RSA_PT  "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \
+                "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD"
+
+/*
+ * Checkup routine
+ */
+int rsa_self_test( int verbose )
+{
+    int len;
+    rsa_context rsa;
+    unsigned char sha1sum[20];
+    unsigned char rsa_plaintext[PT_LEN];
+    unsigned char rsa_decrypted[PT_LEN];
+    unsigned char rsa_ciphertext[KEY_LEN];
+
+    memset( &rsa, 0, sizeof( rsa_context ) );
+
+    rsa.len = KEY_LEN;
+    mpi_read_string( &rsa.N , 16, RSA_N  );
+    mpi_read_string( &rsa.E , 16, RSA_E  );
+    mpi_read_string( &rsa.D , 16, RSA_D  );
+    mpi_read_string( &rsa.P , 16, RSA_P  );
+    mpi_read_string( &rsa.Q , 16, RSA_Q  );
+    mpi_read_string( &rsa.DP, 16, RSA_DP );
+    mpi_read_string( &rsa.DQ, 16, RSA_DQ );
+    mpi_read_string( &rsa.QP, 16, RSA_QP );
+
+    if( verbose != 0 )
+        printf( "  RSA key validation: " );
+
+    if( rsa_check_pubkey(  &rsa ) != 0 ||
+        rsa_check_privkey( &rsa ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n  PKCS#1 encryption : " );
+
+    memcpy( rsa_plaintext, RSA_PT, PT_LEN );
+
+    if( rsa_pkcs1_encrypt( &rsa, RSA_PUBLIC, PT_LEN,
+                           rsa_plaintext, rsa_ciphertext ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n  PKCS#1 decryption : " );
+
+    if( rsa_pkcs1_decrypt( &rsa, RSA_PRIVATE, &len,
+                           rsa_ciphertext, rsa_decrypted ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n  PKCS#1 data sign  : " );
+
+    sha1( rsa_plaintext, PT_LEN, sha1sum );
+
+    if( rsa_pkcs1_sign( &rsa, RSA_PRIVATE, RSA_SHA1, 20,
+                        sha1sum, rsa_ciphertext ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n  PKCS#1 sig. verify: " );
+
+    if( rsa_pkcs1_verify( &rsa, RSA_PUBLIC, RSA_SHA1, 20,
+                          sha1sum, rsa_ciphertext ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n\n" );
+
+    rsa_free( &rsa );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/library/sha1.c b/library/sha1.c
new file mode 100644
index 0000000..b15a5bf
--- /dev/null
+++ b/library/sha1.c
@@ -0,0 +1,607 @@
+/*
+ *  FIPS-180-1 compliant SHA-1 implementation
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  The SHA-1 standard was published by NIST in 1993.
+ *
+ *  http://www.itl.nist.gov/fipspubs/fip180-1.htm
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_SHA1_C)
+
+#include "xyssl/sha1.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_ULONG_BE
+#define GET_ULONG_BE(n,b,i)                             \
+{                                                       \
+    (n) = ( (unsigned long) (b)[(i)    ] << 24 )        \
+        | ( (unsigned long) (b)[(i) + 1] << 16 )        \
+        | ( (unsigned long) (b)[(i) + 2] <<  8 )        \
+        | ( (unsigned long) (b)[(i) + 3]       );       \
+}
+#endif
+
+#ifndef PUT_ULONG_BE
+#define PUT_ULONG_BE(n,b,i)                             \
+{                                                       \
+    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
+    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
+    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
+    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
+}
+#endif
+
+/*
+ * SHA-1 context setup
+ */
+void sha1_starts( sha1_context *ctx )
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+    ctx->state[4] = 0xC3D2E1F0;
+}
+
+static void sha1_process( sha1_context *ctx, unsigned char data[64] )
+{
+    unsigned long temp, W[16], A, B, C, D, E;
+
+    GET_ULONG_BE( W[ 0], data,  0 );
+    GET_ULONG_BE( W[ 1], data,  4 );
+    GET_ULONG_BE( W[ 2], data,  8 );
+    GET_ULONG_BE( W[ 3], data, 12 );
+    GET_ULONG_BE( W[ 4], data, 16 );
+    GET_ULONG_BE( W[ 5], data, 20 );
+    GET_ULONG_BE( W[ 6], data, 24 );
+    GET_ULONG_BE( W[ 7], data, 28 );
+    GET_ULONG_BE( W[ 8], data, 32 );
+    GET_ULONG_BE( W[ 9], data, 36 );
+    GET_ULONG_BE( W[10], data, 40 );
+    GET_ULONG_BE( W[11], data, 44 );
+    GET_ULONG_BE( W[12], data, 48 );
+    GET_ULONG_BE( W[13], data, 52 );
+    GET_ULONG_BE( W[14], data, 56 );
+    GET_ULONG_BE( W[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define R(t)                                            \
+(                                                       \
+    temp = W[(t -  3) & 0x0F] ^ W[(t - 8) & 0x0F] ^     \
+           W[(t - 14) & 0x0F] ^ W[ t      & 0x0F],      \
+    ( W[t & 0x0F] = S(temp,1) )                         \
+)
+
+#define P(a,b,c,d,e,x)                                  \
+{                                                       \
+    e += S(a,5) + F(b,c,d) + K + x; b = S(b,30);        \
+}
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define K 0x5A827999
+
+    P( A, B, C, D, E, W[0]  );
+    P( E, A, B, C, D, W[1]  );
+    P( D, E, A, B, C, W[2]  );
+    P( C, D, E, A, B, W[3]  );
+    P( B, C, D, E, A, W[4]  );
+    P( A, B, C, D, E, W[5]  );
+    P( E, A, B, C, D, W[6]  );
+    P( D, E, A, B, C, W[7]  );
+    P( C, D, E, A, B, W[8]  );
+    P( B, C, D, E, A, W[9]  );
+    P( A, B, C, D, E, W[10] );
+    P( E, A, B, C, D, W[11] );
+    P( D, E, A, B, C, W[12] );
+    P( C, D, E, A, B, W[13] );
+    P( B, C, D, E, A, W[14] );
+    P( A, B, C, D, E, W[15] );
+    P( E, A, B, C, D, R(16) );
+    P( D, E, A, B, C, R(17) );
+    P( C, D, E, A, B, R(18) );
+    P( B, C, D, E, A, R(19) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0x6ED9EBA1
+
+    P( A, B, C, D, E, R(20) );
+    P( E, A, B, C, D, R(21) );
+    P( D, E, A, B, C, R(22) );
+    P( C, D, E, A, B, R(23) );
+    P( B, C, D, E, A, R(24) );
+    P( A, B, C, D, E, R(25) );
+    P( E, A, B, C, D, R(26) );
+    P( D, E, A, B, C, R(27) );
+    P( C, D, E, A, B, R(28) );
+    P( B, C, D, E, A, R(29) );
+    P( A, B, C, D, E, R(30) );
+    P( E, A, B, C, D, R(31) );
+    P( D, E, A, B, C, R(32) );
+    P( C, D, E, A, B, R(33) );
+    P( B, C, D, E, A, R(34) );
+    P( A, B, C, D, E, R(35) );
+    P( E, A, B, C, D, R(36) );
+    P( D, E, A, B, C, R(37) );
+    P( C, D, E, A, B, R(38) );
+    P( B, C, D, E, A, R(39) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) ((x & y) | (z & (x | y)))
+#define K 0x8F1BBCDC
+
+    P( A, B, C, D, E, R(40) );
+    P( E, A, B, C, D, R(41) );
+    P( D, E, A, B, C, R(42) );
+    P( C, D, E, A, B, R(43) );
+    P( B, C, D, E, A, R(44) );
+    P( A, B, C, D, E, R(45) );
+    P( E, A, B, C, D, R(46) );
+    P( D, E, A, B, C, R(47) );
+    P( C, D, E, A, B, R(48) );
+    P( B, C, D, E, A, R(49) );
+    P( A, B, C, D, E, R(50) );
+    P( E, A, B, C, D, R(51) );
+    P( D, E, A, B, C, R(52) );
+    P( C, D, E, A, B, R(53) );
+    P( B, C, D, E, A, R(54) );
+    P( A, B, C, D, E, R(55) );
+    P( E, A, B, C, D, R(56) );
+    P( D, E, A, B, C, R(57) );
+    P( C, D, E, A, B, R(58) );
+    P( B, C, D, E, A, R(59) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0xCA62C1D6
+
+    P( A, B, C, D, E, R(60) );
+    P( E, A, B, C, D, R(61) );
+    P( D, E, A, B, C, R(62) );
+    P( C, D, E, A, B, R(63) );
+    P( B, C, D, E, A, R(64) );
+    P( A, B, C, D, E, R(65) );
+    P( E, A, B, C, D, R(66) );
+    P( D, E, A, B, C, R(67) );
+    P( C, D, E, A, B, R(68) );
+    P( B, C, D, E, A, R(69) );
+    P( A, B, C, D, E, R(70) );
+    P( E, A, B, C, D, R(71) );
+    P( D, E, A, B, C, R(72) );
+    P( C, D, E, A, B, R(73) );
+    P( B, C, D, E, A, R(74) );
+    P( A, B, C, D, E, R(75) );
+    P( E, A, B, C, D, R(76) );
+    P( D, E, A, B, C, R(77) );
+    P( C, D, E, A, B, R(78) );
+    P( B, C, D, E, A, R(79) );
+
+#undef K
+#undef F
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+/*
+ * SHA-1 process buffer
+ */
+void sha1_update( sha1_context *ctx, unsigned char *input, int ilen )
+{
+    int fill;
+    unsigned long left;
+
+    if( ilen <= 0 )
+        return;
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += ilen;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if( ctx->total[0] < (unsigned long) ilen )
+        ctx->total[1]++;
+
+    if( left && ilen >= fill )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, fill );
+        sha1_process( ctx, ctx->buffer );
+        input += fill;
+        ilen  -= fill;
+        left = 0;
+    }
+
+    while( ilen >= 64 )
+    {
+        sha1_process( ctx, input );
+        input += 64;
+        ilen  -= 64;
+    }
+
+    if( ilen > 0 )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, ilen );
+    }
+}
+
+static const unsigned char sha1_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
+};
+
+/*
+ * SHA-1 final digest
+ */
+void sha1_finish( sha1_context *ctx, unsigned char output[20] )
+{
+    unsigned long last, padn;
+    unsigned long high, low;
+    unsigned char msglen[8];
+
+    high = ( ctx->total[0] >> 29 )
+         | ( ctx->total[1] <<  3 );
+    low  = ( ctx->total[0] <<  3 );
+
+    PUT_ULONG_BE( high, msglen, 0 );
+    PUT_ULONG_BE( low,  msglen, 4 );
+
+    last = ctx->total[0] & 0x3F;
+    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+    sha1_update( ctx, (unsigned char *) sha1_padding, padn );
+    sha1_update( ctx, msglen, 8 );
+
+    PUT_ULONG_BE( ctx->state[0], output,  0 );
+    PUT_ULONG_BE( ctx->state[1], output,  4 );
+    PUT_ULONG_BE( ctx->state[2], output,  8 );
+    PUT_ULONG_BE( ctx->state[3], output, 12 );
+    PUT_ULONG_BE( ctx->state[4], output, 16 );
+}
+
+/*
+ * output = SHA-1( input buffer )
+ */
+void sha1( unsigned char *input, int ilen, unsigned char output[20] )
+{
+    sha1_context ctx;
+
+    sha1_starts( &ctx );
+    sha1_update( &ctx, input, ilen );
+    sha1_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha1_context ) );
+}
+
+/*
+ * output = SHA-1( file contents )
+ */
+int sha1_file( char *path, unsigned char output[20] )
+{
+    FILE *f;
+    size_t n;
+    sha1_context ctx;
+    unsigned char buf[1024];
+
+    if( ( f = fopen( path, "rb" ) ) == NULL )
+        return( 1 );
+
+    sha1_starts( &ctx );
+
+    while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+        sha1_update( &ctx, buf, (int) n );
+
+    sha1_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha1_context ) );
+
+    if( ferror( f ) != 0 )
+    {
+        fclose( f );
+        return( 2 );
+    }
+
+    fclose( f );
+    return( 0 );
+}
+
+/*
+ * SHA-1 HMAC context setup
+ */
+void sha1_hmac_starts( sha1_context *ctx, unsigned char *key, int keylen )
+{
+    int i;
+    unsigned char sum[20];
+
+    if( keylen > 64 )
+    {
+        sha1( key, keylen, sum );
+        keylen = 20;
+        key = sum;
+    }
+
+    memset( ctx->ipad, 0x36, 64 );
+    memset( ctx->opad, 0x5C, 64 );
+
+    for( i = 0; i < keylen; i++ )
+    {
+        ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
+        ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
+    }
+
+    sha1_starts( ctx );
+    sha1_update( ctx, ctx->ipad, 64 );
+
+    memset( sum, 0, sizeof( sum ) );
+}
+
+/*
+ * SHA-1 HMAC process buffer
+ */
+void sha1_hmac_update( sha1_context *ctx, unsigned char *input, int ilen )
+{
+    sha1_update( ctx, input, ilen );
+}
+
+/*
+ * SHA-1 HMAC final digest
+ */
+void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] )
+{
+    unsigned char tmpbuf[20];
+
+    sha1_finish( ctx, tmpbuf );
+    sha1_starts( ctx );
+    sha1_update( ctx, ctx->opad, 64 );
+    sha1_update( ctx, tmpbuf, 20 );
+    sha1_finish( ctx, output );
+
+    memset( tmpbuf, 0, sizeof( tmpbuf ) );
+}
+
+/*
+ * output = HMAC-SHA-1( hmac key, input buffer )
+ */
+void sha1_hmac( unsigned char *key, int keylen,
+                unsigned char *input, int ilen,
+                unsigned char output[20] )
+{
+    sha1_context ctx;
+
+    sha1_hmac_starts( &ctx, key, keylen );
+    sha1_hmac_update( &ctx, input, ilen );
+    sha1_hmac_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha1_context ) );
+}
+
+#if defined(XYSSL_SELF_TEST)
+/*
+ * FIPS-180-1 test vectors
+ */
+static unsigned char sha1_test_buf[3][57] = 
+{
+    { "abc" },
+    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+    { "" }
+};
+
+static const int sha1_test_buflen[3] =
+{
+    3, 56, 1000
+};
+
+static const unsigned char sha1_test_sum[3][20] =
+{
+    { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
+      0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D },
+    { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
+      0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 },
+    { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
+      0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F }
+};
+
+/*
+ * RFC 2202 test vectors
+ */
+static unsigned char sha1_hmac_test_key[7][26] =
+{
+    { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
+      "\x0B\x0B\x0B\x0B" },
+    { "Jefe" },
+    { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+      "\xAA\xAA\xAA\xAA" },
+    { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
+      "\x11\x12\x13\x14\x15\x16\x17\x18\x19" },
+    { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
+      "\x0C\x0C\x0C\x0C" },
+    { "" }, /* 0xAA 80 times */
+    { "" }
+};
+
+static const int sha1_hmac_test_keylen[7] =
+{
+    20, 4, 20, 25, 20, 80, 80
+};
+
+static unsigned char sha1_hmac_test_buf[7][74] =
+{
+    { "Hi There" },
+    { "what do ya want for nothing?" },
+    { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" },
+    { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" },
+    { "Test With Truncation" },
+    { "Test Using Larger Than Block-Size Key - Hash Key First" },
+    { "Test Using Larger Than Block-Size Key and Larger"
+      " Than One Block-Size Data" }
+};
+
+static const int sha1_hmac_test_buflen[7] =
+{
+    8, 28, 50, 50, 20, 54, 73
+};
+
+static const unsigned char sha1_hmac_test_sum[7][20] =
+{
+    { 0xB6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xE2, 0x8B,
+      0xC0, 0xB6, 0xFB, 0x37, 0x8C, 0x8E, 0xF1, 0x46, 0xBE, 0x00 },
+    { 0xEF, 0xFC, 0xDF, 0x6A, 0xE5, 0xEB, 0x2F, 0xA2, 0xD2, 0x74,
+      0x16, 0xD5, 0xF1, 0x84, 0xDF, 0x9C, 0x25, 0x9A, 0x7C, 0x79 },
+    { 0x12, 0x5D, 0x73, 0x42, 0xB9, 0xAC, 0x11, 0xCD, 0x91, 0xA3,
+      0x9A, 0xF4, 0x8A, 0xA1, 0x7B, 0x4F, 0x63, 0xF1, 0x75, 0xD3 },
+    { 0x4C, 0x90, 0x07, 0xF4, 0x02, 0x62, 0x50, 0xC6, 0xBC, 0x84,
+      0x14, 0xF9, 0xBF, 0x50, 0xC8, 0x6C, 0x2D, 0x72, 0x35, 0xDA },
+    { 0x4C, 0x1A, 0x03, 0x42, 0x4B, 0x55, 0xE0, 0x7F, 0xE7, 0xF2,
+      0x7B, 0xE1 },
+    { 0xAA, 0x4A, 0xE5, 0xE1, 0x52, 0x72, 0xD0, 0x0E, 0x95, 0x70,
+      0x56, 0x37, 0xCE, 0x8A, 0x3B, 0x55, 0xED, 0x40, 0x21, 0x12 },
+    { 0xE8, 0xE9, 0x9D, 0x0F, 0x45, 0x23, 0x7D, 0x78, 0x6D, 0x6B,
+      0xBA, 0xA7, 0x96, 0x5C, 0x78, 0x08, 0xBB, 0xFF, 0x1A, 0x91 }
+};
+
+/*
+ * Checkup routine
+ */
+int sha1_self_test( int verbose )
+{
+    int i, j, buflen;
+    unsigned char buf[1024];
+    unsigned char sha1sum[20];
+    sha1_context ctx;
+
+    /*
+     * SHA-1
+     */
+    for( i = 0; i < 3; i++ )
+    {
+        if( verbose != 0 )
+            printf( "  SHA-1 test #%d: ", i + 1 );
+
+        sha1_starts( &ctx );
+
+        if( i == 2 )
+        {
+            memset( buf, 'a', buflen = 1000 );
+
+            for( j = 0; j < 1000; j++ )
+                sha1_update( &ctx, buf, buflen );
+        }
+        else
+            sha1_update( &ctx, sha1_test_buf[i],
+                               sha1_test_buflen[i] );
+
+        sha1_finish( &ctx, sha1sum );
+
+        if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    for( i = 0; i < 7; i++ )
+    {
+        if( verbose != 0 )
+            printf( "  HMAC-SHA-1 test #%d: ", i + 1 );
+
+        if( i == 5 || i == 6 )
+        {
+            memset( buf, '\xAA', buflen = 80 );
+            sha1_hmac_starts( &ctx, buf, buflen );
+        }
+        else
+            sha1_hmac_starts( &ctx, sha1_hmac_test_key[i],
+                                    sha1_hmac_test_keylen[i] );
+
+        sha1_hmac_update( &ctx, sha1_hmac_test_buf[i],
+                                sha1_hmac_test_buflen[i] );
+
+        sha1_hmac_finish( &ctx, sha1sum );
+
+        buflen = ( i == 4 ) ? 12 : 20;
+
+        if( memcmp( sha1sum, sha1_hmac_test_sum[i], buflen ) != 0 )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/library/sha2.c b/library/sha2.c
new file mode 100644
index 0000000..03e5b70
--- /dev/null
+++ b/library/sha2.c
@@ -0,0 +1,688 @@
+/*
+ *  FIPS-180-2 compliant SHA-256 implementation
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  The SHA-256 Secure Hash Standard was published by NIST in 2002.
+ *
+ *  http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_SHA2_C)
+
+#include "xyssl/sha2.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_ULONG_BE
+#define GET_ULONG_BE(n,b,i)                             \
+{                                                       \
+    (n) = ( (unsigned long) (b)[(i)    ] << 24 )        \
+        | ( (unsigned long) (b)[(i) + 1] << 16 )        \
+        | ( (unsigned long) (b)[(i) + 2] <<  8 )        \
+        | ( (unsigned long) (b)[(i) + 3]       );       \
+}
+#endif
+
+#ifndef PUT_ULONG_BE
+#define PUT_ULONG_BE(n,b,i)                             \
+{                                                       \
+    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
+    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
+    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
+    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
+}
+#endif
+
+/*
+ * SHA-256 context setup
+ */
+void sha2_starts( sha2_context *ctx, int is224 )
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    if( is224 == 0 )
+    {
+        /* SHA-256 */
+        ctx->state[0] = 0x6A09E667;
+        ctx->state[1] = 0xBB67AE85;
+        ctx->state[2] = 0x3C6EF372;
+        ctx->state[3] = 0xA54FF53A;
+        ctx->state[4] = 0x510E527F;
+        ctx->state[5] = 0x9B05688C;
+        ctx->state[6] = 0x1F83D9AB;
+        ctx->state[7] = 0x5BE0CD19;
+    }
+    else
+    {
+        /* SHA-224 */
+        ctx->state[0] = 0xC1059ED8;
+        ctx->state[1] = 0x367CD507;
+        ctx->state[2] = 0x3070DD17;
+        ctx->state[3] = 0xF70E5939;
+        ctx->state[4] = 0xFFC00B31;
+        ctx->state[5] = 0x68581511;
+        ctx->state[6] = 0x64F98FA7;
+        ctx->state[7] = 0xBEFA4FA4;
+    }
+
+    ctx->is224 = is224;
+}
+
+static void sha2_process( sha2_context *ctx, unsigned char data[64] )
+{
+    unsigned long temp1, temp2, W[64];
+    unsigned long A, B, C, D, E, F, G, H;
+
+    GET_ULONG_BE( W[ 0], data,  0 );
+    GET_ULONG_BE( W[ 1], data,  4 );
+    GET_ULONG_BE( W[ 2], data,  8 );
+    GET_ULONG_BE( W[ 3], data, 12 );
+    GET_ULONG_BE( W[ 4], data, 16 );
+    GET_ULONG_BE( W[ 5], data, 20 );
+    GET_ULONG_BE( W[ 6], data, 24 );
+    GET_ULONG_BE( W[ 7], data, 28 );
+    GET_ULONG_BE( W[ 8], data, 32 );
+    GET_ULONG_BE( W[ 9], data, 36 );
+    GET_ULONG_BE( W[10], data, 40 );
+    GET_ULONG_BE( W[11], data, 44 );
+    GET_ULONG_BE( W[12], data, 48 );
+    GET_ULONG_BE( W[13], data, 52 );
+    GET_ULONG_BE( W[14], data, 56 );
+    GET_ULONG_BE( W[15], data, 60 );
+
+#define  SHR(x,n) ((x & 0xFFFFFFFF) >> n)
+#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
+
+#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^  SHR(x, 3))
+#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^  SHR(x,10))
+
+#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
+#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
+
+#define F0(x,y,z) ((x & y) | (z & (x | y)))
+#define F1(x,y,z) (z ^ (x & (y ^ z)))
+
+#define R(t)                                    \
+(                                               \
+    W[t] = S1(W[t -  2]) + W[t -  7] +          \
+           S0(W[t - 15]) + W[t - 16]            \
+)
+
+#define P(a,b,c,d,e,f,g,h,x,K)                  \
+{                                               \
+    temp1 = h + S3(e) + F1(e,f,g) + K + x;      \
+    temp2 = S2(a) + F0(a,b,c);                  \
+    d += temp1; h = temp1 + temp2;              \
+}
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+    F = ctx->state[5];
+    G = ctx->state[6];
+    H = ctx->state[7];
+
+    P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 );
+    P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 );
+    P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF );
+    P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 );
+    P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B );
+    P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 );
+    P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 );
+    P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 );
+    P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 );
+    P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 );
+    P( G, H, A, B, C, D, E, F, W[10], 0x243185BE );
+    P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 );
+    P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 );
+    P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE );
+    P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 );
+    P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 );
+    P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 );
+    P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 );
+    P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 );
+    P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC );
+    P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F );
+    P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA );
+    P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC );
+    P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA );
+    P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 );
+    P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D );
+    P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 );
+    P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 );
+    P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 );
+    P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 );
+    P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 );
+    P( B, C, D, E, F, G, H, A, R(31), 0x14292967 );
+    P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 );
+    P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 );
+    P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC );
+    P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 );
+    P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 );
+    P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB );
+    P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E );
+    P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 );
+    P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 );
+    P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B );
+    P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 );
+    P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 );
+    P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 );
+    P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 );
+    P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 );
+    P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 );
+    P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 );
+    P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 );
+    P( G, H, A, B, C, D, E, F, R(50), 0x2748774C );
+    P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 );
+    P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 );
+    P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A );
+    P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F );
+    P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 );
+    P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE );
+    P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F );
+    P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 );
+    P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 );
+    P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA );
+    P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB );
+    P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 );
+    P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 );
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+    ctx->state[5] += F;
+    ctx->state[6] += G;
+    ctx->state[7] += H;
+}
+
+/*
+ * SHA-256 process buffer
+ */
+void sha2_update( sha2_context *ctx, unsigned char *input, int ilen )
+{
+    int fill;
+    unsigned long left;
+
+    if( ilen <= 0 )
+        return;
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += ilen;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if( ctx->total[0] < (unsigned long) ilen )
+        ctx->total[1]++;
+
+    if( left && ilen >= fill )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, fill );
+        sha2_process( ctx, ctx->buffer );
+        input += fill;
+        ilen  -= fill;
+        left = 0;
+    }
+
+    while( ilen >= 64 )
+    {
+        sha2_process( ctx, input );
+        input += 64;
+        ilen  -= 64;
+    }
+
+    if( ilen > 0 )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, ilen );
+    }
+}
+
+static const unsigned char sha2_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
+};
+
+/*
+ * SHA-256 final digest
+ */
+void sha2_finish( sha2_context *ctx, unsigned char output[32] )
+{
+    unsigned long last, padn;
+    unsigned long high, low;
+    unsigned char msglen[8];
+
+    high = ( ctx->total[0] >> 29 )
+         | ( ctx->total[1] <<  3 );
+    low  = ( ctx->total[0] <<  3 );
+
+    PUT_ULONG_BE( high, msglen, 0 );
+    PUT_ULONG_BE( low,  msglen, 4 );
+
+    last = ctx->total[0] & 0x3F;
+    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+    sha2_update( ctx, (unsigned char *) sha2_padding, padn );
+    sha2_update( ctx, msglen, 8 );
+
+    PUT_ULONG_BE( ctx->state[0], output,  0 );
+    PUT_ULONG_BE( ctx->state[1], output,  4 );
+    PUT_ULONG_BE( ctx->state[2], output,  8 );
+    PUT_ULONG_BE( ctx->state[3], output, 12 );
+    PUT_ULONG_BE( ctx->state[4], output, 16 );
+    PUT_ULONG_BE( ctx->state[5], output, 20 );
+    PUT_ULONG_BE( ctx->state[6], output, 24 );
+
+    if( ctx->is224 == 0 )
+        PUT_ULONG_BE( ctx->state[7], output, 28 );
+}
+
+/*
+ * output = SHA-256( input buffer )
+ */
+void sha2( unsigned char *input, int ilen,
+           unsigned char output[32], int is224 )
+{
+    sha2_context ctx;
+
+    sha2_starts( &ctx, is224 );
+    sha2_update( &ctx, input, ilen );
+    sha2_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha2_context ) );
+}
+
+/*
+ * output = SHA-256( file contents )
+ */
+int sha2_file( char *path, unsigned char output[32], int is224 )
+{
+    FILE *f;
+    size_t n;
+    sha2_context ctx;
+    unsigned char buf[1024];
+
+    if( ( f = fopen( path, "rb" ) ) == NULL )
+        return( 1 );
+
+    sha2_starts( &ctx, is224 );
+
+    while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+        sha2_update( &ctx, buf, (int) n );
+
+    sha2_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha2_context ) );
+
+    if( ferror( f ) != 0 )
+    {
+        fclose( f );
+        return( 2 );
+    }
+
+    fclose( f );
+    return( 0 );
+}
+
+/*
+ * SHA-256 HMAC context setup
+ */
+void sha2_hmac_starts( sha2_context *ctx, unsigned char *key, int keylen,
+                       int is224 )
+{
+    int i;
+    unsigned char sum[32];
+
+    if( keylen > 64 )
+    {
+        sha2( key, keylen, sum, is224 );
+        keylen = ( is224 ) ? 28 : 32;
+        key = sum;
+    }
+
+    memset( ctx->ipad, 0x36, 64 );
+    memset( ctx->opad, 0x5C, 64 );
+
+    for( i = 0; i < keylen; i++ )
+    {
+        ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
+        ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
+    }
+
+    sha2_starts( ctx, is224 );
+    sha2_update( ctx, ctx->ipad, 64 );
+
+    memset( sum, 0, sizeof( sum ) );
+}
+
+/*
+ * SHA-256 HMAC process buffer
+ */
+void sha2_hmac_update( sha2_context *ctx, unsigned char *input, int ilen )
+{
+    sha2_update( ctx, input, ilen );
+}
+
+/*
+ * SHA-256 HMAC final digest
+ */
+void sha2_hmac_finish( sha2_context *ctx, unsigned char output[32] )
+{
+    int is224, hlen;
+    unsigned char tmpbuf[32];
+
+    is224 = ctx->is224;
+    hlen = ( is224 == 0 ) ? 32 : 28;
+
+    sha2_finish( ctx, tmpbuf );
+    sha2_starts( ctx, is224 );
+    sha2_update( ctx, ctx->opad, 64 );
+    sha2_update( ctx, tmpbuf, hlen );
+    sha2_finish( ctx, output );
+
+    memset( tmpbuf, 0, sizeof( tmpbuf ) );
+}
+
+/*
+ * output = HMAC-SHA-256( hmac key, input buffer )
+ */
+void sha2_hmac( unsigned char *key, int keylen,
+                unsigned char *input, int ilen,
+                unsigned char output[32], int is224 )
+{
+    sha2_context ctx;
+
+    sha2_hmac_starts( &ctx, key, keylen, is224 );
+    sha2_hmac_update( &ctx, input, ilen );
+    sha2_hmac_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha2_context ) );
+}
+
+#if defined(XYSSL_SELF_TEST)
+/*
+ * FIPS-180-2 test vectors
+ */
+static unsigned char sha2_test_buf[3][57] = 
+{
+    { "abc" },
+    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+    { "" }
+};
+
+static const int sha2_test_buflen[3] =
+{
+    3, 56, 1000
+};
+
+static const unsigned char sha2_test_sum[6][32] =
+{
+    /*
+     * SHA-224 test vectors
+     */
+    { 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22,
+      0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3,
+      0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7,
+      0xE3, 0x6C, 0x9D, 0xA7 },
+    { 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC,
+      0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50,
+      0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19,
+      0x52, 0x52, 0x25, 0x25 },
+    { 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8,
+      0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B,
+      0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE,
+      0x4E, 0xE7, 0xAD, 0x67 },
+
+    /*
+     * SHA-256 test vectors
+     */
+    { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
+      0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
+      0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
+      0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD },
+    { 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
+      0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
+      0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
+      0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 },
+    { 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92,
+      0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67,
+      0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E,
+      0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 }
+};
+
+/*
+ * RFC 4231 test vectors
+ */
+static unsigned char sha2_hmac_test_key[7][26] =
+{
+    { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
+      "\x0B\x0B\x0B\x0B" },
+    { "Jefe" },
+    { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+      "\xAA\xAA\xAA\xAA" },
+    { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
+      "\x11\x12\x13\x14\x15\x16\x17\x18\x19" },
+    { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
+      "\x0C\x0C\x0C\x0C" },
+    { "" }, /* 0xAA 131 times */
+    { "" }
+};
+
+static const int sha2_hmac_test_keylen[7] =
+{
+    20, 4, 20, 25, 20, 131, 131
+};
+
+static unsigned char sha2_hmac_test_buf[7][153] =
+{
+    { "Hi There" },
+    { "what do ya want for nothing?" },
+    { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" },
+    { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" },
+    { "Test With Truncation" },
+    { "Test Using Larger Than Block-Size Key - Hash Key First" },
+    { "This is a test using a larger than block-size key "
+      "and a larger than block-size data. The key needs to "
+      "be hashed before being used by the HMAC algorithm." }
+};
+
+static const int sha2_hmac_test_buflen[7] =
+{
+    8, 28, 50, 50, 20, 54, 152
+};
+
+static const unsigned char sha2_hmac_test_sum[14][32] =
+{
+    /*
+     * HMAC-SHA-224 test vectors
+     */
+    { 0x89, 0x6F, 0xB1, 0x12, 0x8A, 0xBB, 0xDF, 0x19,
+      0x68, 0x32, 0x10, 0x7C, 0xD4, 0x9D, 0xF3, 0x3F,
+      0x47, 0xB4, 0xB1, 0x16, 0x99, 0x12, 0xBA, 0x4F,
+      0x53, 0x68, 0x4B, 0x22 },
+    { 0xA3, 0x0E, 0x01, 0x09, 0x8B, 0xC6, 0xDB, 0xBF,
+      0x45, 0x69, 0x0F, 0x3A, 0x7E, 0x9E, 0x6D, 0x0F,
+      0x8B, 0xBE, 0xA2, 0xA3, 0x9E, 0x61, 0x48, 0x00,
+      0x8F, 0xD0, 0x5E, 0x44 },
+    { 0x7F, 0xB3, 0xCB, 0x35, 0x88, 0xC6, 0xC1, 0xF6,
+      0xFF, 0xA9, 0x69, 0x4D, 0x7D, 0x6A, 0xD2, 0x64,
+      0x93, 0x65, 0xB0, 0xC1, 0xF6, 0x5D, 0x69, 0xD1,
+      0xEC, 0x83, 0x33, 0xEA },
+    { 0x6C, 0x11, 0x50, 0x68, 0x74, 0x01, 0x3C, 0xAC,
+      0x6A, 0x2A, 0xBC, 0x1B, 0xB3, 0x82, 0x62, 0x7C,
+      0xEC, 0x6A, 0x90, 0xD8, 0x6E, 0xFC, 0x01, 0x2D,
+      0xE7, 0xAF, 0xEC, 0x5A },
+    { 0x0E, 0x2A, 0xEA, 0x68, 0xA9, 0x0C, 0x8D, 0x37,
+      0xC9, 0x88, 0xBC, 0xDB, 0x9F, 0xCA, 0x6F, 0xA8 },
+    { 0x95, 0xE9, 0xA0, 0xDB, 0x96, 0x20, 0x95, 0xAD,
+      0xAE, 0xBE, 0x9B, 0x2D, 0x6F, 0x0D, 0xBC, 0xE2,
+      0xD4, 0x99, 0xF1, 0x12, 0xF2, 0xD2, 0xB7, 0x27,
+      0x3F, 0xA6, 0x87, 0x0E },
+    { 0x3A, 0x85, 0x41, 0x66, 0xAC, 0x5D, 0x9F, 0x02,
+      0x3F, 0x54, 0xD5, 0x17, 0xD0, 0xB3, 0x9D, 0xBD,
+      0x94, 0x67, 0x70, 0xDB, 0x9C, 0x2B, 0x95, 0xC9,
+      0xF6, 0xF5, 0x65, 0xD1 },
+
+    /*
+     * HMAC-SHA-256 test vectors
+     */
+    { 0xB0, 0x34, 0x4C, 0x61, 0xD8, 0xDB, 0x38, 0x53,
+      0x5C, 0xA8, 0xAF, 0xCE, 0xAF, 0x0B, 0xF1, 0x2B,
+      0x88, 0x1D, 0xC2, 0x00, 0xC9, 0x83, 0x3D, 0xA7,
+      0x26, 0xE9, 0x37, 0x6C, 0x2E, 0x32, 0xCF, 0xF7 },
+    { 0x5B, 0xDC, 0xC1, 0x46, 0xBF, 0x60, 0x75, 0x4E,
+      0x6A, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xC7,
+      0x5A, 0x00, 0x3F, 0x08, 0x9D, 0x27, 0x39, 0x83,
+      0x9D, 0xEC, 0x58, 0xB9, 0x64, 0xEC, 0x38, 0x43 },
+    { 0x77, 0x3E, 0xA9, 0x1E, 0x36, 0x80, 0x0E, 0x46,
+      0x85, 0x4D, 0xB8, 0xEB, 0xD0, 0x91, 0x81, 0xA7,
+      0x29, 0x59, 0x09, 0x8B, 0x3E, 0xF8, 0xC1, 0x22,
+      0xD9, 0x63, 0x55, 0x14, 0xCE, 0xD5, 0x65, 0xFE },
+    { 0x82, 0x55, 0x8A, 0x38, 0x9A, 0x44, 0x3C, 0x0E,
+      0xA4, 0xCC, 0x81, 0x98, 0x99, 0xF2, 0x08, 0x3A,
+      0x85, 0xF0, 0xFA, 0xA3, 0xE5, 0x78, 0xF8, 0x07,
+      0x7A, 0x2E, 0x3F, 0xF4, 0x67, 0x29, 0x66, 0x5B },
+    { 0xA3, 0xB6, 0x16, 0x74, 0x73, 0x10, 0x0E, 0xE0,
+      0x6E, 0x0C, 0x79, 0x6C, 0x29, 0x55, 0x55, 0x2B },
+    { 0x60, 0xE4, 0x31, 0x59, 0x1E, 0xE0, 0xB6, 0x7F,
+      0x0D, 0x8A, 0x26, 0xAA, 0xCB, 0xF5, 0xB7, 0x7F,
+      0x8E, 0x0B, 0xC6, 0x21, 0x37, 0x28, 0xC5, 0x14,
+      0x05, 0x46, 0x04, 0x0F, 0x0E, 0xE3, 0x7F, 0x54 },
+    { 0x9B, 0x09, 0xFF, 0xA7, 0x1B, 0x94, 0x2F, 0xCB,
+      0x27, 0x63, 0x5F, 0xBC, 0xD5, 0xB0, 0xE9, 0x44,
+      0xBF, 0xDC, 0x63, 0x64, 0x4F, 0x07, 0x13, 0x93,
+      0x8A, 0x7F, 0x51, 0x53, 0x5C, 0x3A, 0x35, 0xE2 }
+};
+
+/*
+ * Checkup routine
+ */
+int sha2_self_test( int verbose )
+{
+    int i, j, k, buflen;
+    unsigned char buf[1024];
+    unsigned char sha2sum[32];
+    sha2_context ctx;
+
+    for( i = 0; i < 6; i++ )
+    {
+        j = i % 3;
+        k = i < 3;
+
+        if( verbose != 0 )
+            printf( "  SHA-%d test #%d: ", 256 - k * 32, j + 1 );
+
+        sha2_starts( &ctx, k );
+
+        if( j == 2 )
+        {
+            memset( buf, 'a', buflen = 1000 );
+
+            for( j = 0; j < 1000; j++ )
+                sha2_update( &ctx, buf, buflen );
+        }
+        else
+            sha2_update( &ctx, sha2_test_buf[j],
+                               sha2_test_buflen[j] );
+
+        sha2_finish( &ctx, sha2sum );
+
+        if( memcmp( sha2sum, sha2_test_sum[i], 32 - k * 4 ) != 0 )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    for( i = 0; i < 14; i++ )
+    {
+        j = i % 7;
+        k = i < 7;
+
+        if( verbose != 0 )
+            printf( "  HMAC-SHA-%d test #%d: ", 256 - k * 32, j + 1 );
+
+        if( j == 5 || j == 6 )
+        {
+            memset( buf, '\xAA', buflen = 131 );
+            sha2_hmac_starts( &ctx, buf, buflen, k );
+        }
+        else
+            sha2_hmac_starts( &ctx, sha2_hmac_test_key[j],
+                                    sha2_hmac_test_keylen[j], k );
+
+        sha2_hmac_update( &ctx, sha2_hmac_test_buf[j],
+                                sha2_hmac_test_buflen[j] );
+
+        sha2_hmac_finish( &ctx, sha2sum );
+
+        buflen = ( j == 4 ) ? 16 : 32 - k * 4;
+
+        if( memcmp( sha2sum, sha2_hmac_test_sum[i], buflen ) != 0 )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/library/sha4.c b/library/sha4.c
new file mode 100644
index 0000000..52422a0
--- /dev/null
+++ b/library/sha4.c
@@ -0,0 +1,743 @@
+/*
+ *  FIPS-180-2 compliant SHA-384/512 implementation
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  The SHA-512 Secure Hash Standard was published by NIST in 2002.
+ *
+ *  http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_SHA4_C)
+
+#include "xyssl/sha4.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * 64-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT64_BE
+#define GET_UINT64_BE(n,b,i)                            \
+{                                                       \
+    (n) = ( (unsigned int64) (b)[(i)    ] << 56 )       \
+        | ( (unsigned int64) (b)[(i) + 1] << 48 )       \
+        | ( (unsigned int64) (b)[(i) + 2] << 40 )       \
+        | ( (unsigned int64) (b)[(i) + 3] << 32 )       \
+        | ( (unsigned int64) (b)[(i) + 4] << 24 )       \
+        | ( (unsigned int64) (b)[(i) + 5] << 16 )       \
+        | ( (unsigned int64) (b)[(i) + 6] <<  8 )       \
+        | ( (unsigned int64) (b)[(i) + 7]       );      \
+}
+#endif
+
+#ifndef PUT_UINT64_BE
+#define PUT_UINT64_BE(n,b,i)                            \
+{                                                       \
+    (b)[(i)    ] = (unsigned char) ( (n) >> 56 );       \
+    (b)[(i) + 1] = (unsigned char) ( (n) >> 48 );       \
+    (b)[(i) + 2] = (unsigned char) ( (n) >> 40 );       \
+    (b)[(i) + 3] = (unsigned char) ( (n) >> 32 );       \
+    (b)[(i) + 4] = (unsigned char) ( (n) >> 24 );       \
+    (b)[(i) + 5] = (unsigned char) ( (n) >> 16 );       \
+    (b)[(i) + 6] = (unsigned char) ( (n) >>  8 );       \
+    (b)[(i) + 7] = (unsigned char) ( (n)       );       \
+}
+#endif
+
+/*
+ * Round constants
+ */
+static const unsigned int64 K[80] =
+{
+    UL64(0x428A2F98D728AE22),  UL64(0x7137449123EF65CD),
+    UL64(0xB5C0FBCFEC4D3B2F),  UL64(0xE9B5DBA58189DBBC),
+    UL64(0x3956C25BF348B538),  UL64(0x59F111F1B605D019),
+    UL64(0x923F82A4AF194F9B),  UL64(0xAB1C5ED5DA6D8118),
+    UL64(0xD807AA98A3030242),  UL64(0x12835B0145706FBE),
+    UL64(0x243185BE4EE4B28C),  UL64(0x550C7DC3D5FFB4E2),
+    UL64(0x72BE5D74F27B896F),  UL64(0x80DEB1FE3B1696B1),
+    UL64(0x9BDC06A725C71235),  UL64(0xC19BF174CF692694),
+    UL64(0xE49B69C19EF14AD2),  UL64(0xEFBE4786384F25E3),
+    UL64(0x0FC19DC68B8CD5B5),  UL64(0x240CA1CC77AC9C65),
+    UL64(0x2DE92C6F592B0275),  UL64(0x4A7484AA6EA6E483),
+    UL64(0x5CB0A9DCBD41FBD4),  UL64(0x76F988DA831153B5),
+    UL64(0x983E5152EE66DFAB),  UL64(0xA831C66D2DB43210),
+    UL64(0xB00327C898FB213F),  UL64(0xBF597FC7BEEF0EE4),
+    UL64(0xC6E00BF33DA88FC2),  UL64(0xD5A79147930AA725),
+    UL64(0x06CA6351E003826F),  UL64(0x142929670A0E6E70),
+    UL64(0x27B70A8546D22FFC),  UL64(0x2E1B21385C26C926),
+    UL64(0x4D2C6DFC5AC42AED),  UL64(0x53380D139D95B3DF),
+    UL64(0x650A73548BAF63DE),  UL64(0x766A0ABB3C77B2A8),
+    UL64(0x81C2C92E47EDAEE6),  UL64(0x92722C851482353B),
+    UL64(0xA2BFE8A14CF10364),  UL64(0xA81A664BBC423001),
+    UL64(0xC24B8B70D0F89791),  UL64(0xC76C51A30654BE30),
+    UL64(0xD192E819D6EF5218),  UL64(0xD69906245565A910),
+    UL64(0xF40E35855771202A),  UL64(0x106AA07032BBD1B8),
+    UL64(0x19A4C116B8D2D0C8),  UL64(0x1E376C085141AB53),
+    UL64(0x2748774CDF8EEB99),  UL64(0x34B0BCB5E19B48A8),
+    UL64(0x391C0CB3C5C95A63),  UL64(0x4ED8AA4AE3418ACB),
+    UL64(0x5B9CCA4F7763E373),  UL64(0x682E6FF3D6B2B8A3),
+    UL64(0x748F82EE5DEFB2FC),  UL64(0x78A5636F43172F60),
+    UL64(0x84C87814A1F0AB72),  UL64(0x8CC702081A6439EC),
+    UL64(0x90BEFFFA23631E28),  UL64(0xA4506CEBDE82BDE9),
+    UL64(0xBEF9A3F7B2C67915),  UL64(0xC67178F2E372532B),
+    UL64(0xCA273ECEEA26619C),  UL64(0xD186B8C721C0C207),
+    UL64(0xEADA7DD6CDE0EB1E),  UL64(0xF57D4F7FEE6ED178),
+    UL64(0x06F067AA72176FBA),  UL64(0x0A637DC5A2C898A6),
+    UL64(0x113F9804BEF90DAE),  UL64(0x1B710B35131C471B),
+    UL64(0x28DB77F523047D84),  UL64(0x32CAAB7B40C72493),
+    UL64(0x3C9EBE0A15C9BEBC),  UL64(0x431D67C49C100D4C),
+    UL64(0x4CC5D4BECB3E42B6),  UL64(0x597F299CFC657E2A),
+    UL64(0x5FCB6FAB3AD6FAEC),  UL64(0x6C44198C4A475817)
+};
+
+/*
+ * SHA-512 context setup
+ */
+void sha4_starts( sha4_context *ctx, int is384 )
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    if( is384 == 0 )
+    {
+        /* SHA-512 */
+        ctx->state[0] = UL64(0x6A09E667F3BCC908);
+        ctx->state[1] = UL64(0xBB67AE8584CAA73B);
+        ctx->state[2] = UL64(0x3C6EF372FE94F82B);
+        ctx->state[3] = UL64(0xA54FF53A5F1D36F1);
+        ctx->state[4] = UL64(0x510E527FADE682D1);
+        ctx->state[5] = UL64(0x9B05688C2B3E6C1F);
+        ctx->state[6] = UL64(0x1F83D9ABFB41BD6B);
+        ctx->state[7] = UL64(0x5BE0CD19137E2179);
+    }
+    else
+    {
+        /* SHA-384 */
+        ctx->state[0] = UL64(0xCBBB9D5DC1059ED8);
+        ctx->state[1] = UL64(0x629A292A367CD507);
+        ctx->state[2] = UL64(0x9159015A3070DD17);
+        ctx->state[3] = UL64(0x152FECD8F70E5939);
+        ctx->state[4] = UL64(0x67332667FFC00B31);
+        ctx->state[5] = UL64(0x8EB44A8768581511);
+        ctx->state[6] = UL64(0xDB0C2E0D64F98FA7);
+        ctx->state[7] = UL64(0x47B5481DBEFA4FA4);
+    }
+
+    ctx->is384 = is384;
+}
+
+static void sha4_process( sha4_context *ctx, unsigned char data[128] )
+{
+    int i;
+    unsigned int64 temp1, temp2, W[80];
+    unsigned int64 A, B, C, D, E, F, G, H;
+
+#define  SHR(x,n) (x >> n)
+#define ROTR(x,n) (SHR(x,n) | (x << (64 - n)))
+
+#define S0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^  SHR(x, 7))
+#define S1(x) (ROTR(x,19) ^ ROTR(x,61) ^  SHR(x, 6))
+
+#define S2(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39))
+#define S3(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41))
+
+#define F0(x,y,z) ((x & y) | (z & (x | y)))
+#define F1(x,y,z) (z ^ (x & (y ^ z)))
+
+#define P(a,b,c,d,e,f,g,h,x,K)                  \
+{                                               \
+    temp1 = h + S3(e) + F1(e,f,g) + K + x;      \
+    temp2 = S2(a) + F0(a,b,c);                  \
+    d += temp1; h = temp1 + temp2;              \
+}
+
+    for( i = 0; i < 16; i++ )
+    {
+        GET_UINT64_BE( W[i], data, i << 3 );
+    }
+
+    for( ; i < 80; i++ )
+    {
+        W[i] = S1(W[i -  2]) + W[i -  7] +
+               S0(W[i - 15]) + W[i - 16];
+    }
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+    F = ctx->state[5];
+    G = ctx->state[6];
+    H = ctx->state[7];
+    i = 0;
+
+    do
+    {
+        P( A, B, C, D, E, F, G, H, W[i], K[i] ); i++;
+        P( H, A, B, C, D, E, F, G, W[i], K[i] ); i++;
+        P( G, H, A, B, C, D, E, F, W[i], K[i] ); i++;
+        P( F, G, H, A, B, C, D, E, W[i], K[i] ); i++;
+        P( E, F, G, H, A, B, C, D, W[i], K[i] ); i++;
+        P( D, E, F, G, H, A, B, C, W[i], K[i] ); i++;
+        P( C, D, E, F, G, H, A, B, W[i], K[i] ); i++;
+        P( B, C, D, E, F, G, H, A, W[i], K[i] ); i++;
+    }
+    while( i < 80 );
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+    ctx->state[5] += F;
+    ctx->state[6] += G;
+    ctx->state[7] += H;
+}
+
+/*
+ * SHA-512 process buffer
+ */
+void sha4_update( sha4_context *ctx, unsigned char *input, int ilen )
+{
+    int fill;
+    unsigned int64 left;
+
+    if( ilen <= 0 )
+        return;
+
+    left = ctx->total[0] & 0x7F;
+    fill = (int)( 128 - left );
+
+    ctx->total[0] += ilen;
+
+    if( ctx->total[0] < (unsigned int64) ilen )
+        ctx->total[1]++;
+
+    if( left && ilen >= fill )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, fill );
+        sha4_process( ctx, ctx->buffer );
+        input += fill;
+        ilen  -= fill;
+        left = 0;
+    }
+
+    while( ilen >= 128 )
+    {
+        sha4_process( ctx, input );
+        input += 128;
+        ilen  -= 128;
+    }
+
+    if( ilen > 0 )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, ilen );
+    }
+}
+
+static const unsigned char sha4_padding[128] =
+{
+ 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,
+    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, 0
+};
+
+/*
+ * SHA-512 final digest
+ */
+void sha4_finish( sha4_context *ctx, unsigned char output[64] )
+{
+    int last, padn;
+    unsigned int64 high, low;
+    unsigned char msglen[16];
+
+    high = ( ctx->total[0] >> 61 )
+         | ( ctx->total[1] <<  3 );
+    low  = ( ctx->total[0] <<  3 );
+
+    PUT_UINT64_BE( high, msglen, 0 );
+    PUT_UINT64_BE( low,  msglen, 8 );
+
+    last = (int)( ctx->total[0] & 0x7F );
+    padn = ( last < 112 ) ? ( 112 - last ) : ( 240 - last );
+
+    sha4_update( ctx, (unsigned char *) sha4_padding, padn );
+    sha4_update( ctx, msglen, 16 );
+
+    PUT_UINT64_BE( ctx->state[0], output,  0 );
+    PUT_UINT64_BE( ctx->state[1], output,  8 );
+    PUT_UINT64_BE( ctx->state[2], output, 16 );
+    PUT_UINT64_BE( ctx->state[3], output, 24 );
+    PUT_UINT64_BE( ctx->state[4], output, 32 );
+    PUT_UINT64_BE( ctx->state[5], output, 40 );
+
+    if( ctx->is384 == 0 )
+    {
+        PUT_UINT64_BE( ctx->state[6], output, 48 );
+        PUT_UINT64_BE( ctx->state[7], output, 56 );
+    }
+}
+
+/*
+ * output = SHA-512( input buffer )
+ */
+void sha4( unsigned char *input, int ilen,
+           unsigned char output[64], int is384 )
+{
+    sha4_context ctx;
+
+    sha4_starts( &ctx, is384 );
+    sha4_update( &ctx, input, ilen );
+    sha4_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha4_context ) );
+}
+
+/*
+ * output = SHA-512( file contents )
+ */
+int sha4_file( char *path, unsigned char output[64], int is384 )
+{
+    FILE *f;
+    size_t n;
+    sha4_context ctx;
+    unsigned char buf[1024];
+
+    if( ( f = fopen( path, "rb" ) ) == NULL )
+        return( 1 );
+
+    sha4_starts( &ctx, is384 );
+
+    while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+        sha4_update( &ctx, buf, (int) n );
+
+    sha4_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha4_context ) );
+
+    if( ferror( f ) != 0 )
+    {
+        fclose( f );
+        return( 2 );
+    }
+
+    fclose( f );
+    return( 0 );
+}
+
+/*
+ * SHA-512 HMAC context setup
+ */
+void sha4_hmac_starts( sha4_context *ctx, unsigned char *key, int keylen,
+                       int is384 )
+{
+    int i;
+    unsigned char sum[64];
+
+    if( keylen > 128 )
+    {
+        sha4( key, keylen, sum, is384 );
+        keylen = ( is384 ) ? 48 : 64;
+        key = sum;
+    }
+
+    memset( ctx->ipad, 0x36, 128 );
+    memset( ctx->opad, 0x5C, 128 );
+
+    for( i = 0; i < keylen; i++ )
+    {
+        ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
+        ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
+    }
+
+    sha4_starts( ctx, is384 );
+    sha4_update( ctx, ctx->ipad, 128 );
+
+    memset( sum, 0, sizeof( sum ) );
+}
+
+/*
+ * SHA-512 HMAC process buffer
+ */
+void sha4_hmac_update( sha4_context  *ctx,
+                       unsigned char *input, int ilen )
+{
+    sha4_update( ctx, input, ilen );
+}
+
+/*
+ * SHA-512 HMAC final digest
+ */
+void sha4_hmac_finish( sha4_context *ctx, unsigned char output[64] )
+{
+    int is384, hlen;
+    unsigned char tmpbuf[64];
+
+    is384 = ctx->is384;
+    hlen = ( is384 == 0 ) ? 64 : 48;
+
+    sha4_finish( ctx, tmpbuf );
+    sha4_starts( ctx, is384 );
+    sha4_update( ctx, ctx->opad, 128 );
+    sha4_update( ctx, tmpbuf, hlen );
+    sha4_finish( ctx, output );
+
+    memset( tmpbuf, 0, sizeof( tmpbuf ) );
+}
+
+/*
+ * output = HMAC-SHA-512( hmac key, input buffer )
+ */
+void sha4_hmac( unsigned char *key, int keylen,
+                unsigned char *input, int ilen,
+                unsigned char output[64], int is384 )
+{
+    sha4_context ctx;
+
+    sha4_hmac_starts( &ctx, key, keylen, is384 );
+    sha4_hmac_update( &ctx, input, ilen );
+    sha4_hmac_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha4_context ) );
+}
+
+#if defined(XYSSL_SELF_TEST)
+
+/*
+ * FIPS-180-2 test vectors
+ */
+static unsigned char sha4_test_buf[3][113] = 
+{
+    { "abc" },
+    { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+      "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" },
+    { "" }
+};
+
+static const int sha4_test_buflen[3] =
+{
+    3, 112, 1000
+};
+
+static const unsigned char sha4_test_sum[6][64] =
+{
+    /*
+     * SHA-384 test vectors
+     */
+    { 0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B,
+      0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07,
+      0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63,
+      0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED,
+      0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23,
+      0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7 },
+    { 0x09, 0x33, 0x0C, 0x33, 0xF7, 0x11, 0x47, 0xE8,
+      0x3D, 0x19, 0x2F, 0xC7, 0x82, 0xCD, 0x1B, 0x47,
+      0x53, 0x11, 0x1B, 0x17, 0x3B, 0x3B, 0x05, 0xD2,
+      0x2F, 0xA0, 0x80, 0x86, 0xE3, 0xB0, 0xF7, 0x12,
+      0xFC, 0xC7, 0xC7, 0x1A, 0x55, 0x7E, 0x2D, 0xB9,
+      0x66, 0xC3, 0xE9, 0xFA, 0x91, 0x74, 0x60, 0x39 },
+    { 0x9D, 0x0E, 0x18, 0x09, 0x71, 0x64, 0x74, 0xCB,
+      0x08, 0x6E, 0x83, 0x4E, 0x31, 0x0A, 0x4A, 0x1C,
+      0xED, 0x14, 0x9E, 0x9C, 0x00, 0xF2, 0x48, 0x52,
+      0x79, 0x72, 0xCE, 0xC5, 0x70, 0x4C, 0x2A, 0x5B,
+      0x07, 0xB8, 0xB3, 0xDC, 0x38, 0xEC, 0xC4, 0xEB,
+      0xAE, 0x97, 0xDD, 0xD8, 0x7F, 0x3D, 0x89, 0x85 },
+
+    /*
+     * SHA-512 test vectors
+     */
+    { 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA,
+      0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31,
+      0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2,
+      0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A,
+      0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8,
+      0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD,
+      0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E,
+      0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F },
+    { 0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA,
+      0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F,
+      0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1,
+      0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18,
+      0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4,
+      0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A,
+      0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54,
+      0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09 },
+    { 0xE7, 0x18, 0x48, 0x3D, 0x0C, 0xE7, 0x69, 0x64,
+      0x4E, 0x2E, 0x42, 0xC7, 0xBC, 0x15, 0xB4, 0x63,
+      0x8E, 0x1F, 0x98, 0xB1, 0x3B, 0x20, 0x44, 0x28,
+      0x56, 0x32, 0xA8, 0x03, 0xAF, 0xA9, 0x73, 0xEB,
+      0xDE, 0x0F, 0xF2, 0x44, 0x87, 0x7E, 0xA6, 0x0A,
+      0x4C, 0xB0, 0x43, 0x2C, 0xE5, 0x77, 0xC3, 0x1B,
+      0xEB, 0x00, 0x9C, 0x5C, 0x2C, 0x49, 0xAA, 0x2E,
+      0x4E, 0xAD, 0xB2, 0x17, 0xAD, 0x8C, 0xC0, 0x9B }
+};
+
+/*
+ * RFC 4231 test vectors
+ */
+static unsigned char sha4_hmac_test_key[7][26] =
+{
+    { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
+      "\x0B\x0B\x0B\x0B" },
+    { "Jefe" },
+    { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+      "\xAA\xAA\xAA\xAA" },
+    { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
+      "\x11\x12\x13\x14\x15\x16\x17\x18\x19" },
+    { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
+      "\x0C\x0C\x0C\x0C" },
+    { "" }, /* 0xAA 131 times */
+    { "" }
+};
+
+static const int sha4_hmac_test_keylen[7] =
+{
+    20, 4, 20, 25, 20, 131, 131
+};
+
+static unsigned char sha4_hmac_test_buf[7][153] =
+{
+    { "Hi There" },
+    { "what do ya want for nothing?" },
+    { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" },
+    { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" },
+    { "Test With Truncation" },
+    { "Test Using Larger Than Block-Size Key - Hash Key First" },
+    { "This is a test using a larger than block-size key "
+      "and a larger than block-size data. The key needs to "
+      "be hashed before being used by the HMAC algorithm." }
+};
+
+static const int sha4_hmac_test_buflen[7] =
+{
+    8, 28, 50, 50, 20, 54, 152
+};
+
+static const unsigned char sha4_hmac_test_sum[14][64] =
+{
+    /*
+     * HMAC-SHA-384 test vectors
+     */
+    { 0xAF, 0xD0, 0x39, 0x44, 0xD8, 0x48, 0x95, 0x62,
+      0x6B, 0x08, 0x25, 0xF4, 0xAB, 0x46, 0x90, 0x7F,
+      0x15, 0xF9, 0xDA, 0xDB, 0xE4, 0x10, 0x1E, 0xC6,
+      0x82, 0xAA, 0x03, 0x4C, 0x7C, 0xEB, 0xC5, 0x9C,
+      0xFA, 0xEA, 0x9E, 0xA9, 0x07, 0x6E, 0xDE, 0x7F,
+      0x4A, 0xF1, 0x52, 0xE8, 0xB2, 0xFA, 0x9C, 0xB6 },
+    { 0xAF, 0x45, 0xD2, 0xE3, 0x76, 0x48, 0x40, 0x31,
+      0x61, 0x7F, 0x78, 0xD2, 0xB5, 0x8A, 0x6B, 0x1B,
+      0x9C, 0x7E, 0xF4, 0x64, 0xF5, 0xA0, 0x1B, 0x47,
+      0xE4, 0x2E, 0xC3, 0x73, 0x63, 0x22, 0x44, 0x5E,
+      0x8E, 0x22, 0x40, 0xCA, 0x5E, 0x69, 0xE2, 0xC7,
+      0x8B, 0x32, 0x39, 0xEC, 0xFA, 0xB2, 0x16, 0x49 },
+    { 0x88, 0x06, 0x26, 0x08, 0xD3, 0xE6, 0xAD, 0x8A,
+      0x0A, 0xA2, 0xAC, 0xE0, 0x14, 0xC8, 0xA8, 0x6F,
+      0x0A, 0xA6, 0x35, 0xD9, 0x47, 0xAC, 0x9F, 0xEB,
+      0xE8, 0x3E, 0xF4, 0xE5, 0x59, 0x66, 0x14, 0x4B,
+      0x2A, 0x5A, 0xB3, 0x9D, 0xC1, 0x38, 0x14, 0xB9,
+      0x4E, 0x3A, 0xB6, 0xE1, 0x01, 0xA3, 0x4F, 0x27 },
+    { 0x3E, 0x8A, 0x69, 0xB7, 0x78, 0x3C, 0x25, 0x85,
+      0x19, 0x33, 0xAB, 0x62, 0x90, 0xAF, 0x6C, 0xA7,
+      0x7A, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9C,
+      0xC5, 0x57, 0x7C, 0x6E, 0x1F, 0x57, 0x3B, 0x4E,
+      0x68, 0x01, 0xDD, 0x23, 0xC4, 0xA7, 0xD6, 0x79,
+      0xCC, 0xF8, 0xA3, 0x86, 0xC6, 0x74, 0xCF, 0xFB },
+    { 0x3A, 0xBF, 0x34, 0xC3, 0x50, 0x3B, 0x2A, 0x23,
+      0xA4, 0x6E, 0xFC, 0x61, 0x9B, 0xAE, 0xF8, 0x97 },
+    { 0x4E, 0xCE, 0x08, 0x44, 0x85, 0x81, 0x3E, 0x90,
+      0x88, 0xD2, 0xC6, 0x3A, 0x04, 0x1B, 0xC5, 0xB4,
+      0x4F, 0x9E, 0xF1, 0x01, 0x2A, 0x2B, 0x58, 0x8F,
+      0x3C, 0xD1, 0x1F, 0x05, 0x03, 0x3A, 0xC4, 0xC6,
+      0x0C, 0x2E, 0xF6, 0xAB, 0x40, 0x30, 0xFE, 0x82,
+      0x96, 0x24, 0x8D, 0xF1, 0x63, 0xF4, 0x49, 0x52 },
+    { 0x66, 0x17, 0x17, 0x8E, 0x94, 0x1F, 0x02, 0x0D,
+      0x35, 0x1E, 0x2F, 0x25, 0x4E, 0x8F, 0xD3, 0x2C,
+      0x60, 0x24, 0x20, 0xFE, 0xB0, 0xB8, 0xFB, 0x9A,
+      0xDC, 0xCE, 0xBB, 0x82, 0x46, 0x1E, 0x99, 0xC5,
+      0xA6, 0x78, 0xCC, 0x31, 0xE7, 0x99, 0x17, 0x6D,
+      0x38, 0x60, 0xE6, 0x11, 0x0C, 0x46, 0x52, 0x3E },
+
+    /*
+     * HMAC-SHA-512 test vectors
+     */
+    { 0x87, 0xAA, 0x7C, 0xDE, 0xA5, 0xEF, 0x61, 0x9D,
+      0x4F, 0xF0, 0xB4, 0x24, 0x1A, 0x1D, 0x6C, 0xB0,
+      0x23, 0x79, 0xF4, 0xE2, 0xCE, 0x4E, 0xC2, 0x78,
+      0x7A, 0xD0, 0xB3, 0x05, 0x45, 0xE1, 0x7C, 0xDE,
+      0xDA, 0xA8, 0x33, 0xB7, 0xD6, 0xB8, 0xA7, 0x02,
+      0x03, 0x8B, 0x27, 0x4E, 0xAE, 0xA3, 0xF4, 0xE4,
+      0xBE, 0x9D, 0x91, 0x4E, 0xEB, 0x61, 0xF1, 0x70,
+      0x2E, 0x69, 0x6C, 0x20, 0x3A, 0x12, 0x68, 0x54 },
+    { 0x16, 0x4B, 0x7A, 0x7B, 0xFC, 0xF8, 0x19, 0xE2,
+      0xE3, 0x95, 0xFB, 0xE7, 0x3B, 0x56, 0xE0, 0xA3,
+      0x87, 0xBD, 0x64, 0x22, 0x2E, 0x83, 0x1F, 0xD6,
+      0x10, 0x27, 0x0C, 0xD7, 0xEA, 0x25, 0x05, 0x54,
+      0x97, 0x58, 0xBF, 0x75, 0xC0, 0x5A, 0x99, 0x4A,
+      0x6D, 0x03, 0x4F, 0x65, 0xF8, 0xF0, 0xE6, 0xFD,
+      0xCA, 0xEA, 0xB1, 0xA3, 0x4D, 0x4A, 0x6B, 0x4B,
+      0x63, 0x6E, 0x07, 0x0A, 0x38, 0xBC, 0xE7, 0x37 },
+    { 0xFA, 0x73, 0xB0, 0x08, 0x9D, 0x56, 0xA2, 0x84,
+      0xEF, 0xB0, 0xF0, 0x75, 0x6C, 0x89, 0x0B, 0xE9,
+      0xB1, 0xB5, 0xDB, 0xDD, 0x8E, 0xE8, 0x1A, 0x36,
+      0x55, 0xF8, 0x3E, 0x33, 0xB2, 0x27, 0x9D, 0x39,
+      0xBF, 0x3E, 0x84, 0x82, 0x79, 0xA7, 0x22, 0xC8,
+      0x06, 0xB4, 0x85, 0xA4, 0x7E, 0x67, 0xC8, 0x07,
+      0xB9, 0x46, 0xA3, 0x37, 0xBE, 0xE8, 0x94, 0x26,
+      0x74, 0x27, 0x88, 0x59, 0xE1, 0x32, 0x92, 0xFB },
+    { 0xB0, 0xBA, 0x46, 0x56, 0x37, 0x45, 0x8C, 0x69,
+      0x90, 0xE5, 0xA8, 0xC5, 0xF6, 0x1D, 0x4A, 0xF7,
+      0xE5, 0x76, 0xD9, 0x7F, 0xF9, 0x4B, 0x87, 0x2D,
+      0xE7, 0x6F, 0x80, 0x50, 0x36, 0x1E, 0xE3, 0xDB,
+      0xA9, 0x1C, 0xA5, 0xC1, 0x1A, 0xA2, 0x5E, 0xB4,
+      0xD6, 0x79, 0x27, 0x5C, 0xC5, 0x78, 0x80, 0x63,
+      0xA5, 0xF1, 0x97, 0x41, 0x12, 0x0C, 0x4F, 0x2D,
+      0xE2, 0xAD, 0xEB, 0xEB, 0x10, 0xA2, 0x98, 0xDD },
+    { 0x41, 0x5F, 0xAD, 0x62, 0x71, 0x58, 0x0A, 0x53,
+      0x1D, 0x41, 0x79, 0xBC, 0x89, 0x1D, 0x87, 0xA6 },
+    { 0x80, 0xB2, 0x42, 0x63, 0xC7, 0xC1, 0xA3, 0xEB,
+      0xB7, 0x14, 0x93, 0xC1, 0xDD, 0x7B, 0xE8, 0xB4,
+      0x9B, 0x46, 0xD1, 0xF4, 0x1B, 0x4A, 0xEE, 0xC1,
+      0x12, 0x1B, 0x01, 0x37, 0x83, 0xF8, 0xF3, 0x52,
+      0x6B, 0x56, 0xD0, 0x37, 0xE0, 0x5F, 0x25, 0x98,
+      0xBD, 0x0F, 0xD2, 0x21, 0x5D, 0x6A, 0x1E, 0x52,
+      0x95, 0xE6, 0x4F, 0x73, 0xF6, 0x3F, 0x0A, 0xEC,
+      0x8B, 0x91, 0x5A, 0x98, 0x5D, 0x78, 0x65, 0x98 },
+    { 0xE3, 0x7B, 0x6A, 0x77, 0x5D, 0xC8, 0x7D, 0xBA,
+      0xA4, 0xDF, 0xA9, 0xF9, 0x6E, 0x5E, 0x3F, 0xFD,
+      0xDE, 0xBD, 0x71, 0xF8, 0x86, 0x72, 0x89, 0x86,
+      0x5D, 0xF5, 0xA3, 0x2D, 0x20, 0xCD, 0xC9, 0x44,
+      0xB6, 0x02, 0x2C, 0xAC, 0x3C, 0x49, 0x82, 0xB1,
+      0x0D, 0x5E, 0xEB, 0x55, 0xC3, 0xE4, 0xDE, 0x15,
+      0x13, 0x46, 0x76, 0xFB, 0x6D, 0xE0, 0x44, 0x60,
+      0x65, 0xC9, 0x74, 0x40, 0xFA, 0x8C, 0x6A, 0x58 }
+};
+
+/*
+ * Checkup routine
+ */
+int sha4_self_test( int verbose )
+{
+    int i, j, k, buflen;
+    unsigned char buf[1024];
+    unsigned char sha4sum[64];
+    sha4_context ctx;
+
+    for( i = 0; i < 6; i++ )
+    {
+        j = i % 3;
+        k = i < 3;
+
+        if( verbose != 0 )
+            printf( "  SHA-%d test #%d: ", 512 - k * 128, j + 1 );
+
+        sha4_starts( &ctx, k );
+
+        if( j == 2 )
+        {
+            memset( buf, 'a', buflen = 1000 );
+
+            for( j = 0; j < 1000; j++ )
+                sha4_update( &ctx, buf, buflen );
+        }
+        else
+            sha4_update( &ctx, sha4_test_buf[j],
+                               sha4_test_buflen[j] );
+
+        sha4_finish( &ctx, sha4sum );
+
+        if( memcmp( sha4sum, sha4_test_sum[i], 64 - k * 16 ) != 0 )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    for( i = 0; i < 14; i++ )
+    {
+        j = i % 7;
+        k = i < 7;
+
+        if( verbose != 0 )
+            printf( "  HMAC-SHA-%d test #%d: ", 512 - k * 128, j + 1 );
+
+        if( j == 5 || j == 6 )
+        {
+            memset( buf, '\xAA', buflen = 131 );
+            sha4_hmac_starts( &ctx, buf, buflen, k );
+        }
+        else
+            sha4_hmac_starts( &ctx, sha4_hmac_test_key[j],
+                                    sha4_hmac_test_keylen[j], k );
+
+        sha4_hmac_update( &ctx, sha4_hmac_test_buf[j],
+                                sha4_hmac_test_buflen[j] );
+
+        sha4_hmac_finish( &ctx, sha4sum );
+
+        buflen = ( j == 4 ) ? 16 : 64 - k * 16;
+
+        if( memcmp( sha4sum, sha4_hmac_test_sum[i], buflen ) != 0 )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
new file mode 100644
index 0000000..ad91b5f
--- /dev/null
+++ b/library/ssl_cli.c
@@ -0,0 +1,768 @@
+/*
+ *  SSLv3/TLSv1 client-side functions
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_SSL_CLI_C)
+
+#include "xyssl/debug.h"
+#include "xyssl/ssl.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+static int ssl_write_client_hello( ssl_context *ssl )
+{
+    int ret, i, n;
+    unsigned char *buf;
+    unsigned char *p;
+    time_t t;
+
+    SSL_DEBUG_MSG( 2, ( "=> write client hello" ) );
+
+    ssl->major_ver = SSL_MAJOR_VERSION_3;
+    ssl->minor_ver = SSL_MINOR_VERSION_0;
+
+    ssl->max_major_ver = SSL_MAJOR_VERSION_3;
+    ssl->max_minor_ver = SSL_MINOR_VERSION_1;
+
+    /*
+     *     0  .   0   handshake type
+     *     1  .   3   handshake length
+     *     4  .   5   highest version supported
+     *     6  .   9   current UNIX time
+     *    10  .  37   random bytes
+     */
+    buf = ssl->out_msg;
+    p = buf + 4;
+
+    *p++ = (unsigned char) ssl->max_major_ver;
+    *p++ = (unsigned char) ssl->max_minor_ver;
+
+    SSL_DEBUG_MSG( 3, ( "client hello, max version: [%d:%d]",
+                   buf[4], buf[5] ) );
+
+    t = time( NULL );
+    *p++ = (unsigned char)( t >> 24 );
+    *p++ = (unsigned char)( t >> 16 );
+    *p++ = (unsigned char)( t >>  8 );
+    *p++ = (unsigned char)( t       );
+
+    SSL_DEBUG_MSG( 3, ( "client hello, current time: %lu", t ) );
+
+    for( i = 28; i > 0; i-- )
+        *p++ = (unsigned char) ssl->f_rng( ssl->p_rng );
+
+    memcpy( ssl->randbytes, buf + 6, 32 );
+
+    SSL_DEBUG_BUF( 3, "client hello, random bytes", buf + 6, 32 );
+
+    /*
+     *    38  .  38   session id length
+     *    39  . 39+n  session id
+     *   40+n . 41+n  cipherlist length
+     *   42+n . ..    cipherlist
+     *   ..   . ..    compression alg. (0)
+     *   ..   . ..    extensions (unused)
+     */
+    n = ssl->session->length;
+
+    if( n < 16 || n > 32 || ssl->resume == 0 ||
+        t - ssl->session->start > ssl->timeout )
+        n = 0;
+
+    *p++ = (unsigned char) n;
+
+    for( i = 0; i < n; i++ )
+        *p++ = ssl->session->id[i];
+
+    SSL_DEBUG_MSG( 3, ( "client hello, session id len.: %d", n ) );
+    SSL_DEBUG_BUF( 3,   "client hello, session id", buf + 39, n );
+
+    for( n = 0; ssl->ciphers[n] != 0; n++ );
+    *p++ = (unsigned char)( n >> 7 );
+    *p++ = (unsigned char)( n << 1 );
+
+    SSL_DEBUG_MSG( 3, ( "client hello, got %d ciphers", n ) );
+
+    for( i = 0; i < n; i++ )
+    {
+        SSL_DEBUG_MSG( 3, ( "client hello, add cipher: %2d",
+                       ssl->ciphers[i] ) );
+
+        *p++ = (unsigned char)( ssl->ciphers[i] >> 8 );
+        *p++ = (unsigned char)( ssl->ciphers[i]      );
+    }
+
+    SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 1 ) );
+    SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d", 0 ) );
+
+    *p++ = 1;
+    *p++ = SSL_COMPRESS_NULL;
+
+    if ( ssl->hostname != NULL )
+    {
+        SSL_DEBUG_MSG( 3, ( "client hello, server name extension: %s",
+                       ssl->hostname ) );
+
+        *p++ = (unsigned char)( ( (ssl->hostname_len + 9) >> 8 ) & 0xFF );
+        *p++ = (unsigned char)( ( (ssl->hostname_len + 9)      ) & 0xFF );
+
+        *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME >> 8 ) & 0xFF );
+        *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME      ) & 0xFF );
+
+        *p++ = (unsigned char)( ( (ssl->hostname_len + 5) >> 8 ) & 0xFF );
+        *p++ = (unsigned char)( ( (ssl->hostname_len + 5)      ) & 0xFF );
+
+        *p++ = (unsigned char)( ( (ssl->hostname_len + 3) >> 8 ) & 0xFF );
+        *p++ = (unsigned char)( ( (ssl->hostname_len + 3)      ) & 0xFF );
+
+        *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME_HOSTNAME ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->hostname_len >> 8 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->hostname_len      ) & 0xFF );
+
+        memcpy( p, ssl->hostname, ssl->hostname_len );
+
+        p += ssl->hostname_len;
+    }
+
+    ssl->out_msglen  = p - buf;
+    ssl->out_msgtype = SSL_MSG_HANDSHAKE;
+    ssl->out_msg[0]  = SSL_HS_CLIENT_HELLO;
+
+    ssl->state++;
+
+    if( ( ret = ssl_write_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_write_record", ret );
+        return( ret );
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= write client hello" ) );
+
+    return( 0 );
+}
+
+static int ssl_parse_server_hello( ssl_context *ssl )
+{
+    time_t t;
+    int ret, i, n;
+    int ext_len;
+    unsigned char *buf;
+
+    SSL_DEBUG_MSG( 2, ( "=> parse server hello" ) );
+
+    /*
+     *     0  .   0   handshake type
+     *     1  .   3   handshake length
+     *     4  .   5   protocol version
+     *     6  .   9   UNIX time()
+     *    10  .  37   random bytes
+     */
+    buf = ssl->in_msg;
+
+    if( ( ret = ssl_read_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_read_record", ret );
+        return( ret );
+    }
+
+    if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
+        return( XYSSL_ERR_SSL_UNEXPECTED_MESSAGE );
+    }
+
+    SSL_DEBUG_MSG( 3, ( "server hello, chosen version: [%d:%d]",
+                   buf[4], buf[5] ) );
+
+    if( ssl->in_hslen < 42 ||
+        buf[0] != SSL_HS_SERVER_HELLO ||
+        buf[4] != SSL_MAJOR_VERSION_3 )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
+    }
+
+    if( buf[5] != SSL_MINOR_VERSION_0 &&
+        buf[5] != SSL_MINOR_VERSION_1 )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
+    }
+
+    ssl->minor_ver = buf[5];
+
+    t = ( (time_t) buf[6] << 24 )
+      | ( (time_t) buf[7] << 16 )
+      | ( (time_t) buf[8] <<  8 )
+      | ( (time_t) buf[9]       );
+
+    memcpy( ssl->randbytes + 32, buf + 6, 32 );
+
+    n = buf[38];
+
+    SSL_DEBUG_MSG( 3, ( "server hello, current time: %lu", t ) );
+    SSL_DEBUG_BUF( 3,   "server hello, random bytes", buf + 6, 32 );
+
+    /*
+     *    38  .  38   session id length
+     *    39  . 38+n  session id
+     *   39+n . 40+n  chosen cipher
+     *   41+n . 41+n  chosen compression alg.
+     *   42+n . 43+n  extensions length
+     *   44+n . 44+n+m extensions
+     */
+    if( n < 0 || n > 32 || ssl->in_hslen > 42 + n )
+    {
+        ext_len = ( ( buf[42 + n] <<  8 )
+                  | ( buf[43 + n]       ) ) + 2;
+    }
+    else
+    {
+        ext_len = 0;
+    }
+
+    if( n < 0 || n > 32 || ssl->in_hslen != 42 + n + ext_len )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
+    }
+
+    i = ( buf[39 + n] << 8 ) | buf[40 + n];
+
+    SSL_DEBUG_MSG( 3, ( "server hello, session id len.: %d", n ) );
+    SSL_DEBUG_BUF( 3,   "server hello, session id", buf + 39, n );
+
+    /*
+     * Check if the session can be resumed
+     */
+    if( ssl->resume == 0 || n == 0 ||
+        ssl->session->cipher  != i ||
+        ssl->session->length  != n ||
+        memcmp( ssl->session->id, buf + 39, n ) != 0 )
+    {
+        ssl->state++;
+        ssl->resume = 0;
+        ssl->session->start = time( NULL );
+        ssl->session->cipher = i;
+        ssl->session->length = n;
+        memcpy( ssl->session->id, buf + 39, n );
+    }
+    else
+    {
+        ssl->state = SSL_SERVER_CHANGE_CIPHER_SPEC;
+        ssl_derive_keys( ssl );
+    }
+
+    SSL_DEBUG_MSG( 3, ( "%s session has been resumed",
+                   ssl->resume ? "a" : "no" ) );
+
+    SSL_DEBUG_MSG( 3, ( "server hello, chosen cipher: %d", i ) );
+    SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: %d", buf[41 + n] ) );
+
+    i = 0;
+    while( 1 )
+    {
+        if( ssl->ciphers[i] == 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
+        }
+
+        if( ssl->ciphers[i++] == ssl->session->cipher )
+            break;
+    }
+
+    if( buf[41 + n] != SSL_COMPRESS_NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
+    }
+
+    /* TODO: Process extensions */
+
+    SSL_DEBUG_MSG( 2, ( "<= parse server hello" ) );
+
+    return( 0 );
+}
+
+static int ssl_parse_server_key_exchange( ssl_context *ssl )
+{
+    int ret, n;
+    unsigned char *p, *end;
+    unsigned char hash[36];
+    md5_context md5;
+    sha1_context sha1;
+
+    SSL_DEBUG_MSG( 2, ( "=> parse server key exchange" ) );
+
+    if( ssl->session->cipher != SSL_EDH_RSA_DES_168_SHA &&
+        ssl->session->cipher != SSL_EDH_RSA_AES_256_SHA )
+    {
+        SSL_DEBUG_MSG( 2, ( "<= skip parse server key exchange" ) );
+        ssl->state++;
+        return( 0 );
+    }
+
+#if !defined(XYSSL_DHM_C)
+    SSL_DEBUG_MSG( 1, ( "support for dhm in not available" ) );
+    return( XYSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+#else
+    if( ( ret = ssl_read_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_read_record", ret );
+        return( ret );
+    }
+
+    if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
+        return( XYSSL_ERR_SSL_UNEXPECTED_MESSAGE );
+    }
+
+    if( ssl->in_msg[0] != SSL_HS_SERVER_KEY_EXCHANGE )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
+    }
+
+    /*
+     * Ephemeral DH parameters:
+     *
+     * struct {
+     *     opaque dh_p<1..2^16-1>;
+     *     opaque dh_g<1..2^16-1>;
+     *     opaque dh_Ys<1..2^16-1>;
+     * } ServerDHParams;
+     */
+    p   = ssl->in_msg + 4;
+    end = ssl->in_msg + ssl->in_hslen;
+
+    if( ( ret = dhm_read_params( &ssl->dhm_ctx, &p, end ) ) != 0 )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
+    }
+
+    if( (int)( end - p ) != ssl->peer_cert->rsa.len )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
+    }
+
+    if( ssl->dhm_ctx.len < 64 || ssl->dhm_ctx.len > 256 )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
+    }
+
+    SSL_DEBUG_MPI( 3, "DHM: P ", &ssl->dhm_ctx.P  );
+    SSL_DEBUG_MPI( 3, "DHM: G ", &ssl->dhm_ctx.G  );
+    SSL_DEBUG_MPI( 3, "DHM: GY", &ssl->dhm_ctx.GY );
+
+    /*
+     * digitally-signed struct {
+     *     opaque md5_hash[16];
+     *     opaque sha_hash[20];
+     * };
+     *
+     * md5_hash
+     *     MD5(ClientHello.random + ServerHello.random
+     *                            + ServerParams);
+     * sha_hash
+     *     SHA(ClientHello.random + ServerHello.random
+     *                            + ServerParams);
+     */
+    n = ssl->in_hslen - ( end - p ) - 6;
+
+    md5_starts( &md5 );
+    md5_update( &md5, ssl->randbytes, 64 );
+    md5_update( &md5, ssl->in_msg + 4, n );
+    md5_finish( &md5, hash );
+
+    sha1_starts( &sha1 );
+    sha1_update( &sha1, ssl->randbytes, 64 );
+    sha1_update( &sha1, ssl->in_msg + 4, n );
+    sha1_finish( &sha1, hash + 16 );
+
+    SSL_DEBUG_BUF( 3, "parameters hash", hash, 36 );
+
+    if( ( ret = rsa_pkcs1_verify( &ssl->peer_cert->rsa, RSA_PUBLIC,
+                                  RSA_RAW, 36, hash, p ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "rsa_pkcs1_verify", ret );
+        return( ret );
+    }
+
+    ssl->state++;
+
+    SSL_DEBUG_MSG( 2, ( "<= parse server key exchange" ) );
+
+    return( 0 );
+#endif
+}
+
+static int ssl_parse_certificate_request( ssl_context *ssl )
+{
+    int ret;
+
+    SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) );
+
+    /*
+     *     0  .   0   handshake type
+     *     1  .   3   handshake length
+     *     4  .   5   SSL version
+     *     6  .   6   cert type count
+     *     7  .. n-1  cert types
+     *     n  .. n+1  length of all DNs
+     *    n+2 .. n+3  length of DN 1
+     *    n+4 .. ...  Distinguished Name #1
+     *    ... .. ...  length of DN 2, etc.
+     */
+    if( ( ret = ssl_read_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_read_record", ret );
+        return( ret );
+    }
+
+    if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
+        return( XYSSL_ERR_SSL_UNEXPECTED_MESSAGE );
+    }
+
+    ssl->client_auth = 0;
+    ssl->state++;
+
+    if( ssl->in_msg[0] == SSL_HS_CERTIFICATE_REQUEST )
+        ssl->client_auth++;
+
+    SSL_DEBUG_MSG( 3, ( "got %s certificate request",
+                        ssl->client_auth ? "a" : "no" ) );
+
+    SSL_DEBUG_MSG( 2, ( "<= parse certificate request" ) );
+
+    return( 0 );
+}
+
+static int ssl_parse_server_hello_done( ssl_context *ssl )
+{
+    int ret;
+
+    SSL_DEBUG_MSG( 2, ( "=> parse server hello done" ) );
+
+    if( ssl->client_auth != 0 )
+    {
+        if( ( ret = ssl_read_record( ssl ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_read_record", ret );
+            return( ret );
+        }
+
+        if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad server hello done message" ) );
+            return( XYSSL_ERR_SSL_UNEXPECTED_MESSAGE );
+        }
+    }
+
+    if( ssl->in_hslen  != 4 ||
+        ssl->in_msg[0] != SSL_HS_SERVER_HELLO_DONE )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad server hello done message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_SERVER_HELLO_DONE );
+    }
+
+    ssl->state++;
+
+    SSL_DEBUG_MSG( 2, ( "<= parse server hello done" ) );
+
+    return( 0 );
+}
+
+static int ssl_write_client_key_exchange( ssl_context *ssl )
+{
+    int ret, i, n;
+
+    SSL_DEBUG_MSG( 2, ( "=> write client key exchange" ) );
+
+    if( ssl->session->cipher == SSL_EDH_RSA_DES_168_SHA ||
+        ssl->session->cipher == SSL_EDH_RSA_AES_256_SHA )
+    {
+#if !defined(XYSSL_DHM_C)
+        SSL_DEBUG_MSG( 1, ( "support for dhm in not available" ) );
+        return( XYSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+#else
+        /*
+         * DHM key exchange -- send G^X mod P
+         */
+        n = ssl->dhm_ctx.len;
+
+        ssl->out_msg[4] = (unsigned char)( n >> 8 );
+        ssl->out_msg[5] = (unsigned char)( n      );
+        i = 6;
+
+        ret = dhm_make_public( &ssl->dhm_ctx, 256,
+                               &ssl->out_msg[i], n,
+                                ssl->f_rng, ssl->p_rng );
+        if( ret != 0 )
+        {
+            SSL_DEBUG_RET( 1, "dhm_make_public", ret );
+            return( ret );
+        }
+
+        SSL_DEBUG_MPI( 3, "DHM: X ", &ssl->dhm_ctx.X  );
+        SSL_DEBUG_MPI( 3, "DHM: GX", &ssl->dhm_ctx.GX );
+
+        ssl->pmslen = ssl->dhm_ctx.len;
+
+        if( ( ret = dhm_calc_secret( &ssl->dhm_ctx,
+                                      ssl->premaster,
+                                     &ssl->pmslen ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "dhm_calc_secret", ret );
+            return( ret );
+        }
+
+        SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->dhm_ctx.K  );
+#endif
+    }
+    else
+    {
+        /*
+         * RSA key exchange -- send rsa_public(pkcs1 v1.5(premaster))
+         */
+        ssl->premaster[0] = (unsigned char) ssl->max_major_ver;
+        ssl->premaster[1] = (unsigned char) ssl->max_minor_ver;
+        ssl->pmslen = 48;
+
+        for( i = 2; i < ssl->pmslen; i++ )
+            ssl->premaster[i] = (unsigned char) ssl->f_rng( ssl->p_rng );
+
+        i = 4;
+        n = ssl->peer_cert->rsa.len;
+
+        if( ssl->minor_ver != SSL_MINOR_VERSION_0 )
+        {
+            i += 2;
+            ssl->out_msg[4] = (unsigned char)( n >> 8 );
+            ssl->out_msg[5] = (unsigned char)( n      );
+        }
+
+        ret = rsa_pkcs1_encrypt( &ssl->peer_cert->rsa, RSA_PUBLIC,
+                                  ssl->pmslen, ssl->premaster,
+                                  ssl->out_msg + i );
+        if( ret != 0 )
+        {
+            SSL_DEBUG_RET( 1, "rsa_pkcs1_encrypt", ret );
+            return( ret );
+        }
+    }
+
+    ssl_derive_keys( ssl );
+
+    ssl->out_msglen  = i + n;
+    ssl->out_msgtype = SSL_MSG_HANDSHAKE;
+    ssl->out_msg[0]  = SSL_HS_CLIENT_KEY_EXCHANGE;
+
+    ssl->state++;
+
+    if( ( ret = ssl_write_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_write_record", ret );
+        return( ret );
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= write client key exchange" ) );
+
+    return( 0 );
+}
+
+static int ssl_write_certificate_verify( ssl_context *ssl )
+{
+    int ret, n;
+    unsigned char hash[36];
+
+    SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) );
+
+    if( ssl->client_auth == 0 )
+    {
+        SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) );
+        ssl->state++;
+        return( 0 );
+    }
+
+    if( ssl->rsa_key == NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "got no private key" ) );
+        return( XYSSL_ERR_SSL_PRIVATE_KEY_REQUIRED );
+    }
+
+    /*
+     * Make an RSA signature of the handshake digests
+     */
+    ssl_calc_verify( ssl, hash );
+
+    n = ssl->rsa_key->len;
+    ssl->out_msg[4] = (unsigned char)( n >> 8 );
+    ssl->out_msg[5] = (unsigned char)( n      );
+
+    if( ( ret = rsa_pkcs1_sign( ssl->rsa_key, RSA_PRIVATE, RSA_RAW,
+                                36, hash, ssl->out_msg + 6 ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "rsa_pkcs1_sign", ret );
+        return( ret );
+    }
+
+    ssl->out_msglen  = 6 + n;
+    ssl->out_msgtype = SSL_MSG_HANDSHAKE;
+    ssl->out_msg[0]  = SSL_HS_CERTIFICATE_VERIFY;
+
+    ssl->state++;
+
+    if( ( ret = ssl_write_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_write_record", ret );
+        return( ret );
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= write certificate verify" ) );
+
+    return( 0 );
+}
+
+/*
+ * SSL handshake -- client side
+ */
+int ssl_handshake_client( ssl_context *ssl )
+{
+    int ret = 0;
+
+    SSL_DEBUG_MSG( 2, ( "=> handshake client" ) );
+
+    while( ssl->state != SSL_HANDSHAKE_OVER )
+    {
+        SSL_DEBUG_MSG( 2, ( "client state: %d", ssl->state ) );
+
+        if( ( ret = ssl_flush_output( ssl ) ) != 0 )
+            break;
+
+        switch( ssl->state )
+        {
+            case SSL_HELLO_REQUEST:
+                ssl->state = SSL_CLIENT_HELLO;
+                break;
+
+            /*
+             *  ==>   ClientHello
+             */
+            case SSL_CLIENT_HELLO:
+                ret = ssl_write_client_hello( ssl );
+                break;
+
+            /*
+             *  <==   ServerHello
+             *        Certificate
+             *      ( ServerKeyExchange  )
+             *      ( CertificateRequest )
+             *        ServerHelloDone
+             */
+            case SSL_SERVER_HELLO:
+                ret = ssl_parse_server_hello( ssl );
+                break;
+
+            case SSL_SERVER_CERTIFICATE:
+                ret = ssl_parse_certificate( ssl );
+                break;
+
+            case SSL_SERVER_KEY_EXCHANGE:
+                ret = ssl_parse_server_key_exchange( ssl );
+                break;
+
+            case SSL_CERTIFICATE_REQUEST:
+                ret = ssl_parse_certificate_request( ssl );
+                break;
+
+            case SSL_SERVER_HELLO_DONE:
+                ret = ssl_parse_server_hello_done( ssl );
+                break;
+
+            /*
+             *  ==> ( Certificate/Alert  )
+             *        ClientKeyExchange
+             *      ( CertificateVerify  )
+             *        ChangeCipherSpec
+             *        Finished
+             */
+            case SSL_CLIENT_CERTIFICATE:
+                ret = ssl_write_certificate( ssl );
+                break;
+
+            case SSL_CLIENT_KEY_EXCHANGE:
+                ret = ssl_write_client_key_exchange( ssl );
+                break;
+
+            case SSL_CERTIFICATE_VERIFY:
+                ret = ssl_write_certificate_verify( ssl );
+                break;
+
+            case SSL_CLIENT_CHANGE_CIPHER_SPEC:
+                ret = ssl_write_change_cipher_spec( ssl );
+                break;
+
+            case SSL_CLIENT_FINISHED:
+                ret = ssl_write_finished( ssl );
+                break;
+
+            /*
+             *  <==   ChangeCipherSpec
+             *        Finished
+             */
+            case SSL_SERVER_CHANGE_CIPHER_SPEC:
+                ret = ssl_parse_change_cipher_spec( ssl );
+                break;
+
+            case SSL_SERVER_FINISHED:
+                ret = ssl_parse_finished( ssl );
+                break;
+
+            case SSL_FLUSH_BUFFERS:
+                SSL_DEBUG_MSG( 2, ( "handshake: done" ) );
+                ssl->state = SSL_HANDSHAKE_OVER;
+                break;
+
+            default:
+                SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) );
+                return( XYSSL_ERR_SSL_BAD_INPUT_DATA );
+        }
+
+        if( ret != 0 )
+            break;
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= handshake client" ) );
+
+    return( ret );
+}
+
+#endif
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
new file mode 100644
index 0000000..b8dd661
--- /dev/null
+++ b/library/ssl_srv.c
@@ -0,0 +1,930 @@
+/*
+ *  SSLv3/TLSv1 server-side functions
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_SSL_SRV_C)
+
+#include "xyssl/debug.h"
+#include "xyssl/ssl.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+static int ssl_parse_client_hello( ssl_context *ssl )
+{
+    int ret, i, j, n;
+    int ciph_len, sess_len;
+    int chal_len, comp_len;
+    unsigned char *buf, *p;
+
+    SSL_DEBUG_MSG( 2, ( "=> parse client hello" ) );
+
+    if( ( ret = ssl_fetch_input( ssl, 5 ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_fetch_input", ret );
+        return( ret );
+    }
+
+    buf = ssl->in_hdr;
+
+    if( ( buf[0] & 0x80 ) != 0 )
+    {
+        SSL_DEBUG_BUF( 4, "record header", buf, 5 );
+
+        SSL_DEBUG_MSG( 3, ( "client hello v2, message type: %d",
+                       buf[2] ) );
+        SSL_DEBUG_MSG( 3, ( "client hello v2, message len.: %d",
+                       ( ( buf[0] & 0x7F ) << 8 ) | buf[1] ) );
+        SSL_DEBUG_MSG( 3, ( "client hello v2, max. version: [%d:%d]",
+                       buf[3], buf[4] ) );
+
+        /*
+         * SSLv2 Client Hello
+         *
+         * Record layer:
+         *     0  .   1   message length
+         *
+         * SSL layer:
+         *     2  .   2   message type
+         *     3  .   4   protocol version
+         */
+        if( buf[2] != SSL_HS_CLIENT_HELLO ||
+            buf[3] != SSL_MAJOR_VERSION_3 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
+
+        n = ( ( buf[0] << 8 ) | buf[1] ) & 0x7FFF;
+
+        if( n < 17 || n > 512 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
+
+        ssl->max_major_ver = buf[3];
+        ssl->max_minor_ver = buf[4];
+
+        ssl->major_ver = SSL_MAJOR_VERSION_3;
+        ssl->minor_ver = ( buf[4] <= SSL_MINOR_VERSION_1 )
+                         ? buf[4]  : SSL_MINOR_VERSION_1;
+
+        if( ( ret = ssl_fetch_input( ssl, 2 + n ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_fetch_input", ret );
+            return( ret );
+        }
+
+         md5_update( &ssl->fin_md5 , buf + 2, n );
+        sha1_update( &ssl->fin_sha1, buf + 2, n );
+
+        buf = ssl->in_msg;
+        n = ssl->in_left - 5;
+
+        /*
+         *    0  .   1   cipherlist length
+         *    2  .   3   session id length
+         *    4  .   5   challenge length
+         *    6  .  ..   cipherlist
+         *   ..  .  ..   session id
+         *   ..  .  ..   challenge
+         */
+        SSL_DEBUG_BUF( 4, "record contents", buf, n );
+
+        ciph_len = ( buf[0] << 8 ) | buf[1];
+        sess_len = ( buf[2] << 8 ) | buf[3];
+        chal_len = ( buf[4] << 8 ) | buf[5];
+
+        SSL_DEBUG_MSG( 3, ( "ciph_len: %d, sess_len: %d, chal_len: %d",
+                       ciph_len, sess_len, chal_len ) );
+
+        /*
+         * Make sure each parameter length is valid
+         */
+        if( ciph_len < 3 || ( ciph_len % 3 ) != 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
+
+        if( sess_len < 0 || sess_len > 32 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
+
+        if( chal_len < 8 || chal_len > 32 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
+
+        if( n != 6 + ciph_len + sess_len + chal_len )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
+
+        SSL_DEBUG_BUF( 3, "client hello, cipherlist",
+                       buf + 6,  ciph_len );
+        SSL_DEBUG_BUF( 3, "client hello, session id",
+                       buf + 6 + ciph_len,  sess_len );
+        SSL_DEBUG_BUF( 3, "client hello, challenge",
+                       buf + 6 + ciph_len + sess_len,  chal_len );
+
+        p = buf + 6 + ciph_len;
+        ssl->session->length = sess_len;
+        memset( ssl->session->id, 0, sizeof( ssl->session->id ) );
+        memcpy( ssl->session->id, p, ssl->session->length );
+
+        p += sess_len;
+        memset( ssl->randbytes, 0, 64 );
+        memcpy( ssl->randbytes + 32 - chal_len, p, chal_len );
+
+        for( i = 0; ssl->ciphers[i] != 0; i++ )
+        {
+            for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 )
+            {
+                if( p[0] == 0 &&
+                    p[1] == 0 &&
+                    p[2] == ssl->ciphers[i] )
+                    goto have_cipher;
+            }
+        }
+    }
+    else
+    {
+        SSL_DEBUG_BUF( 4, "record header", buf, 5 );
+
+        SSL_DEBUG_MSG( 3, ( "client hello v3, message type: %d",
+                       buf[0] ) );
+        SSL_DEBUG_MSG( 3, ( "client hello v3, message len.: %d",
+                       ( buf[3] << 8 ) | buf[4] ) );
+        SSL_DEBUG_MSG( 3, ( "client hello v3, protocol ver: [%d:%d]",
+                       buf[1], buf[2] ) );
+
+        /*
+         * SSLv3 Client Hello
+         *
+         * Record layer:
+         *     0  .   0   message type
+         *     1  .   2   protocol version
+         *     3  .   4   message length
+         */
+        if( buf[0] != SSL_MSG_HANDSHAKE ||
+            buf[1] != SSL_MAJOR_VERSION_3 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
+
+        n = ( buf[3] << 8 ) | buf[4];
+
+        if( n < 45 || n > 512 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
+
+        if( ( ret = ssl_fetch_input( ssl, 5 + n ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_fetch_input", ret );
+            return( ret );
+        }
+
+        buf = ssl->in_msg;
+        n = ssl->in_left - 5;
+
+         md5_update( &ssl->fin_md5 , buf, n );
+        sha1_update( &ssl->fin_sha1, buf, n );
+
+        /*
+         * SSL layer:
+         *     0  .   0   handshake type
+         *     1  .   3   handshake length
+         *     4  .   5   protocol version
+         *     6  .   9   UNIX time()
+         *    10  .  37   random bytes
+         *    38  .  38   session id length
+         *    39  . 38+x  session id
+         *   39+x . 40+x  cipherlist length
+         *   41+x .  ..   cipherlist
+         *    ..  .  ..   compression alg.
+         *    ..  .  ..   extensions
+         */
+        SSL_DEBUG_BUF( 4, "record contents", buf, n );
+
+        SSL_DEBUG_MSG( 3, ( "client hello v3, handshake type: %d",
+                       buf[0] ) );
+        SSL_DEBUG_MSG( 3, ( "client hello v3, handshake len.: %d",
+                       ( buf[1] << 16 ) | ( buf[2] << 8 ) | buf[3] ) );
+        SSL_DEBUG_MSG( 3, ( "client hello v3, max. version: [%d:%d]",
+                       buf[4], buf[5] ) );
+
+        /*
+         * Check the handshake type and protocol version
+         */
+        if( buf[0] != SSL_HS_CLIENT_HELLO ||
+            buf[4] != SSL_MAJOR_VERSION_3 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
+
+        ssl->major_ver = SSL_MAJOR_VERSION_3;
+        ssl->minor_ver = ( buf[5] <= SSL_MINOR_VERSION_1 )
+                         ? buf[5]  : SSL_MINOR_VERSION_1;
+
+        ssl->max_major_ver = buf[4];
+        ssl->max_minor_ver = buf[5];
+
+        memcpy( ssl->randbytes, buf + 6, 32 );
+
+        /*
+         * Check the handshake message length
+         */
+        if( buf[1] != 0 || n != 4 + ( ( buf[2] << 8 ) | buf[3] ) )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
+
+        /*
+         * Check the session length
+         */
+        sess_len = buf[38];
+
+        if( sess_len < 0 || sess_len > 32 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
+
+        ssl->session->length = sess_len;
+        memset( ssl->session->id, 0, sizeof( ssl->session->id ) );
+        memcpy( ssl->session->id, buf + 39 , ssl->session->length );
+
+        /*
+         * Check the cipherlist length
+         */
+        ciph_len = ( buf[39 + sess_len] << 8 )
+                 | ( buf[40 + sess_len]      );
+
+        if( ciph_len < 2 || ciph_len > 256 || ( ciph_len % 2 ) != 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
+
+        /*
+         * Check the compression algorithms length
+         */
+        comp_len = buf[41 + sess_len + ciph_len];
+
+        if( comp_len < 1 || comp_len > 16 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+        }
+
+        SSL_DEBUG_BUF( 3, "client hello, random bytes",
+                       buf +  6,  32 );
+        SSL_DEBUG_BUF( 3, "client hello, session id",
+                       buf + 38,  sess_len );
+        SSL_DEBUG_BUF( 3, "client hello, cipherlist",
+                       buf + 41 + sess_len,  ciph_len );
+        SSL_DEBUG_BUF( 3, "client hello, compression",
+                       buf + 42 + sess_len + ciph_len, comp_len );
+
+        /*
+         * Search for a matching cipher
+         */
+        for( i = 0; ssl->ciphers[i] != 0; i++ )
+        {
+            for( j = 0, p = buf + 41 + sess_len; j < ciph_len;
+                j += 2, p += 2 )
+            {
+                if( p[0] == 0 && p[1] == ssl->ciphers[i] )
+                    goto have_cipher;
+            }
+        }
+    }
+
+    SSL_DEBUG_MSG( 1, ( "got no ciphers in common" ) );
+
+    return( XYSSL_ERR_SSL_NO_CIPHER_CHOSEN );
+
+have_cipher:
+
+    ssl->session->cipher = ssl->ciphers[i];
+    ssl->in_left = 0;
+    ssl->state++;
+
+    SSL_DEBUG_MSG( 2, ( "<= parse client hello" ) );
+
+    return( 0 );
+}
+
+static int ssl_write_server_hello( ssl_context *ssl )
+{
+    time_t t;
+    int ret, i, n;
+    unsigned char *buf, *p;
+
+    SSL_DEBUG_MSG( 2, ( "=> write server hello" ) );
+
+    /*
+     *     0  .   0   handshake type
+     *     1  .   3   handshake length
+     *     4  .   5   protocol version
+     *     6  .   9   UNIX time()
+     *    10  .  37   random bytes
+     */
+    buf = ssl->out_msg;
+    p = buf + 4;
+
+    *p++ = (unsigned char) ssl->major_ver;
+    *p++ = (unsigned char) ssl->minor_ver;
+
+    SSL_DEBUG_MSG( 3, ( "server hello, chosen version: [%d:%d]",
+                   buf[4], buf[5] ) );
+
+    t = time( NULL );
+    *p++ = (unsigned char)( t >> 24 );
+    *p++ = (unsigned char)( t >> 16 );
+    *p++ = (unsigned char)( t >>  8 );
+    *p++ = (unsigned char)( t       );
+
+    SSL_DEBUG_MSG( 3, ( "server hello, current time: %lu", t ) );
+
+    for( i = 28; i > 0; i-- )
+        *p++ = (unsigned char) ssl->f_rng( ssl->p_rng );
+
+    memcpy( ssl->randbytes + 32, buf + 6, 32 );
+
+    SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 6, 32 );
+
+    /*
+     *    38  .  38   session id length
+     *    39  . 38+n  session id
+     *   39+n . 40+n  chosen cipher
+     *   41+n . 41+n  chosen compression alg.
+     */
+    ssl->session->length = n = 32;
+    *p++ = (unsigned char) ssl->session->length;
+
+    if( ssl->s_get == NULL ||
+        ssl->s_get( ssl ) != 0 )
+    {
+        /*
+         * Not found, create a new session id
+         */
+        ssl->resume = 0;
+        ssl->state++;
+
+        for( i = 0; i < n; i++ )
+            ssl->session->id[i] =
+                (unsigned char) ssl->f_rng( ssl->p_rng );
+    }
+    else
+    {
+        /*
+         * Found a matching session, resume it
+         */
+        ssl->resume = 1;
+        ssl->state = SSL_SERVER_CHANGE_CIPHER_SPEC;
+        ssl_derive_keys( ssl );
+    }
+
+    memcpy( p, ssl->session->id, ssl->session->length );
+    p += ssl->session->length;
+
+    SSL_DEBUG_MSG( 3, ( "server hello, session id len.: %d", n ) );
+    SSL_DEBUG_BUF( 3,   "server hello, session id", buf + 39, n );
+    SSL_DEBUG_MSG( 3, ( "%s session has been resumed",
+                   ssl->resume ? "a" : "no" ) );
+
+    *p++ = (unsigned char)( ssl->session->cipher >> 8 );
+    *p++ = (unsigned char)( ssl->session->cipher      );
+    *p++ = SSL_COMPRESS_NULL;
+
+    SSL_DEBUG_MSG( 3, ( "server hello, chosen cipher: %d",
+                   ssl->session->cipher ) );
+    SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: %d", 0 ) );
+
+    ssl->out_msglen  = p - buf;
+    ssl->out_msgtype = SSL_MSG_HANDSHAKE;
+    ssl->out_msg[0]  = SSL_HS_SERVER_HELLO;
+
+    ret = ssl_write_record( ssl );
+
+    SSL_DEBUG_MSG( 2, ( "<= write server hello" ) );
+
+    return( ret );
+}
+
+static int ssl_write_certificate_request( ssl_context *ssl )
+{
+    int ret, n;
+    unsigned char *buf, *p;
+    x509_cert *crt;
+
+    SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) );
+
+    ssl->state++;
+
+    if( ssl->authmode == SSL_VERIFY_NONE )
+    {
+        SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) );
+        return( 0 );
+    }
+
+    /*
+     *     0  .   0   handshake type
+     *     1  .   3   handshake length
+     *     4  .   4   cert type count
+     *     5  .. n-1  cert types
+     *     n  .. n+1  length of all DNs
+     *    n+2 .. n+3  length of DN 1
+     *    n+4 .. ...  Distinguished Name #1
+     *    ... .. ...  length of DN 2, etc.
+     */
+    buf = ssl->out_msg;
+    p = buf + 4;
+
+    /*
+     * At the moment, only RSA certificates are supported
+     */
+    *p++ = 1;
+    *p++ = 1;
+
+    p += 2;
+    crt = ssl->ca_chain;
+
+    while( crt != NULL && crt->next != NULL )
+    {
+        if( p - buf > 4096 )
+            break;
+
+        n = crt->subject_raw.len;
+        *p++ = (unsigned char)( n >> 8 );
+        *p++ = (unsigned char)( n      );
+        memcpy( p, crt->subject_raw.p, n );
+
+        SSL_DEBUG_BUF( 3, "requested DN", p, n );
+        p += n; crt = crt->next;
+    }
+
+    ssl->out_msglen  = n = p - buf;
+    ssl->out_msgtype = SSL_MSG_HANDSHAKE;
+    ssl->out_msg[0]  = SSL_HS_CERTIFICATE_REQUEST;
+    ssl->out_msg[6]  = (unsigned char)( ( n - 8 ) >> 8 );
+    ssl->out_msg[7]  = (unsigned char)( ( n - 8 )      );
+
+    ret = ssl_write_record( ssl );
+
+    SSL_DEBUG_MSG( 2, ( "<= write certificate request" ) );
+
+    return( ret );
+}
+
+static int ssl_write_server_key_exchange( ssl_context *ssl )
+{
+    int ret, n;
+    unsigned char hash[36];
+    md5_context md5;
+    sha1_context sha1;
+
+    SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) );
+
+    if( ssl->session->cipher != SSL_EDH_RSA_DES_168_SHA &&
+        ssl->session->cipher != SSL_EDH_RSA_AES_256_SHA )
+    {
+        SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) );
+        ssl->state++;
+        return( 0 );
+    }
+
+#if !defined(XYSSL_DHM_C)
+    SSL_DEBUG_MSG( 1, ( "support for dhm is not available" ) );
+    return( XYSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+#else
+    /*
+     * Ephemeral DH parameters:
+     *
+     * struct {
+     *     opaque dh_p<1..2^16-1>;
+     *     opaque dh_g<1..2^16-1>;
+     *     opaque dh_Ys<1..2^16-1>;
+     * } ServerDHParams;
+     */
+    if( ( ret = dhm_make_params( &ssl->dhm_ctx, 256, ssl->out_msg + 4,
+                                 &n, ssl->f_rng, ssl->p_rng ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "dhm_make_params", ret );
+        return( ret );
+    }
+
+    SSL_DEBUG_MPI( 3, "DHM: X ", &ssl->dhm_ctx.X  );
+    SSL_DEBUG_MPI( 3, "DHM: P ", &ssl->dhm_ctx.P  );
+    SSL_DEBUG_MPI( 3, "DHM: G ", &ssl->dhm_ctx.G  );
+    SSL_DEBUG_MPI( 3, "DHM: GX", &ssl->dhm_ctx.GX );
+
+    /*
+     * digitally-signed struct {
+     *     opaque md5_hash[16];
+     *     opaque sha_hash[20];
+     * };
+     *
+     * md5_hash
+     *     MD5(ClientHello.random + ServerHello.random
+     *                            + ServerParams);
+     * sha_hash
+     *     SHA(ClientHello.random + ServerHello.random
+     *                            + ServerParams);
+     */
+    md5_starts( &md5 );
+    md5_update( &md5, ssl->randbytes,  64 );
+    md5_update( &md5, ssl->out_msg + 4, n );
+    md5_finish( &md5, hash );
+
+    sha1_starts( &sha1 );
+    sha1_update( &sha1, ssl->randbytes,  64 );
+    sha1_update( &sha1, ssl->out_msg + 4, n );
+    sha1_finish( &sha1, hash + 16 );
+
+    SSL_DEBUG_BUF( 3, "parameters hash", hash, 36 );
+
+    ssl->out_msg[4 + n] = (unsigned char)( ssl->rsa_key->len >> 8 );
+    ssl->out_msg[5 + n] = (unsigned char)( ssl->rsa_key->len      );
+
+    ret = rsa_pkcs1_sign( ssl->rsa_key, RSA_PRIVATE,
+                          RSA_RAW, 36, hash, ssl->out_msg + 6 + n );
+    if( ret != 0 )
+    {
+        SSL_DEBUG_RET( 1, "rsa_pkcs1_sign", ret );
+        return( ret );
+    }
+
+    SSL_DEBUG_BUF( 3, "my RSA sig", ssl->out_msg + 6 + n,
+                                    ssl->rsa_key->len );
+
+    ssl->out_msglen  = 6 + n + ssl->rsa_key->len;
+    ssl->out_msgtype = SSL_MSG_HANDSHAKE;
+    ssl->out_msg[0]  = SSL_HS_SERVER_KEY_EXCHANGE;
+
+    ssl->state++;
+
+    if( ( ret = ssl_write_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_write_record", ret );
+        return( ret );
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= write server key exchange" ) );
+
+    return( 0 );
+#endif
+}
+
+static int ssl_write_server_hello_done( ssl_context *ssl )
+{
+    int ret;
+
+    SSL_DEBUG_MSG( 2, ( "=> write server hello done" ) );
+
+    ssl->out_msglen  = 4;
+    ssl->out_msgtype = SSL_MSG_HANDSHAKE;
+    ssl->out_msg[0]  = SSL_HS_SERVER_HELLO_DONE;
+
+    ssl->state++;
+
+    if( ( ret = ssl_write_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_write_record", ret );
+        return( ret );
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= write server hello done" ) );
+
+    return( 0 );
+}
+
+static int ssl_parse_client_key_exchange( ssl_context *ssl )
+{
+    int ret, i, n;
+
+    SSL_DEBUG_MSG( 2, ( "=> parse client key exchange" ) );
+
+    if( ( ret = ssl_read_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_read_record", ret );
+        return( ret );
+    }
+
+    if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE );
+    }
+
+    if( ssl->in_msg[0] != SSL_HS_CLIENT_KEY_EXCHANGE )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE );
+    }
+
+    if( ssl->session->cipher == SSL_EDH_RSA_DES_168_SHA ||
+        ssl->session->cipher == SSL_EDH_RSA_AES_256_SHA )
+    {
+#if !defined(XYSSL_DHM_C)
+        SSL_DEBUG_MSG( 1, ( "support for dhm is not available" ) );
+        return( XYSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+#else
+        /*
+         * Receive G^Y mod P, premaster = (G^Y)^X mod P
+         */
+        n = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5];
+
+        if( n < 1 || n > ssl->dhm_ctx.len ||
+            n + 6 != ssl->in_hslen )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE );
+        }
+
+        if( ( ret = dhm_read_public( &ssl->dhm_ctx,
+                                      ssl->in_msg + 6, n ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "dhm_read_public", ret );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE | ret );
+        }
+
+        SSL_DEBUG_MPI( 3, "DHM: GY", &ssl->dhm_ctx.GY );
+
+        ssl->pmslen = ssl->dhm_ctx.len;
+
+        if( ( ret = dhm_calc_secret( &ssl->dhm_ctx,
+                     ssl->premaster, &ssl->pmslen ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "dhm_calc_secret", ret );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE | ret );
+        }
+
+        SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->dhm_ctx.K  );
+#endif
+    }
+    else
+    {
+        /*
+         * Decrypt the premaster using own private RSA key
+         */
+        i = 4;
+        n = ssl->rsa_key->len;
+        ssl->pmslen = 48;
+
+        if( ssl->minor_ver != SSL_MINOR_VERSION_0 )
+        {
+            i += 2;
+            if( ssl->in_msg[4] != ( ( n >> 8 ) & 0xFF ) ||
+                ssl->in_msg[5] != ( ( n      ) & 0xFF ) )
+            {
+                SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) );
+                return( XYSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE );
+            }
+        }
+
+        if( ssl->in_hslen != i + n )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE );
+        }
+
+        ret = rsa_pkcs1_decrypt( ssl->rsa_key, RSA_PRIVATE, &ssl->pmslen,
+                                 ssl->in_msg + i, ssl->premaster );
+
+        if( ret != 0 || ssl->pmslen != 48 ||
+            ssl->premaster[0] != ssl->max_major_ver ||
+            ssl->premaster[1] != ssl->max_minor_ver )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) );
+
+            /*
+             * Protection against Bleichenbacher's attack:
+             * invalid PKCS#1 v1.5 padding must not cause
+             * the connection to end immediately; instead,
+             * send a bad_record_mac later in the handshake.
+             */
+            ssl->pmslen = 48;
+
+            for( i = 0; i < ssl->pmslen; i++ )
+                ssl->premaster[i] = (unsigned char) ssl->f_rng( ssl->p_rng );
+        }
+    }
+
+    ssl_derive_keys( ssl );
+
+    if( ssl->s_set != NULL )
+        ssl->s_set( ssl );
+
+    ssl->state++;
+
+    SSL_DEBUG_MSG( 2, ( "<= parse client key exchange" ) );
+
+    return( 0 );
+}
+
+static int ssl_parse_certificate_verify( ssl_context *ssl )
+{
+    int n1, n2, ret;
+    unsigned char hash[36];
+
+    SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) );
+
+    if( ssl->peer_cert == NULL )
+    {
+        SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) );
+        ssl->state++;
+        return( 0 );
+    }
+
+    ssl_calc_verify( ssl, hash );
+
+    if( ( ret = ssl_read_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_read_record", ret );
+        return( ret );
+    }
+
+    ssl->state++;
+
+    if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
+    }
+
+    if( ssl->in_msg[0] != SSL_HS_CERTIFICATE_VERIFY )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
+    }
+
+    n1 = ssl->peer_cert->rsa.len;
+    n2 = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5];
+
+    if( n1 + 6 != ssl->in_hslen || n1 != n2 )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
+    }
+
+    ret = rsa_pkcs1_verify( &ssl->peer_cert->rsa, RSA_PUBLIC,
+                            RSA_RAW, 36, hash, ssl->in_msg + 6 );
+    if( ret != 0 )
+    {
+        SSL_DEBUG_RET( 1, "rsa_pkcs1_verify", ret );
+        return( ret );
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= parse certificate verify" ) );
+
+    return( 0 );
+}
+
+/*
+ * SSL handshake -- server side
+ */
+int ssl_handshake_server( ssl_context *ssl )
+{
+    int ret = 0;
+
+    SSL_DEBUG_MSG( 2, ( "=> handshake server" ) );
+
+    while( ssl->state != SSL_HANDSHAKE_OVER )
+    {
+        SSL_DEBUG_MSG( 2, ( "server state: %d", ssl->state ) );
+
+        if( ( ret = ssl_flush_output( ssl ) ) != 0 )
+            break;
+
+        switch( ssl->state )
+        {
+            case SSL_HELLO_REQUEST:
+                ssl->state = SSL_CLIENT_HELLO;
+                break;
+
+            /*
+             *  <==   ClientHello
+             */
+            case SSL_CLIENT_HELLO:
+                ret = ssl_parse_client_hello( ssl );
+                break;
+
+            /*
+             *  ==>   ServerHello
+             *        Certificate
+             *      ( ServerKeyExchange  )
+             *      ( CertificateRequest )
+             *        ServerHelloDone
+             */
+            case SSL_SERVER_HELLO:
+                ret = ssl_write_server_hello( ssl );
+                break;
+
+            case SSL_SERVER_CERTIFICATE:
+                ret = ssl_write_certificate( ssl );
+                break;
+
+            case SSL_SERVER_KEY_EXCHANGE:
+                ret = ssl_write_server_key_exchange( ssl );
+                break;
+
+            case SSL_CERTIFICATE_REQUEST:
+                ret = ssl_write_certificate_request( ssl );
+                break;
+
+            case SSL_SERVER_HELLO_DONE:
+                ret = ssl_write_server_hello_done( ssl );
+                break;
+
+            /*
+             *  <== ( Certificate/Alert  )
+             *        ClientKeyExchange
+             *      ( CertificateVerify  )
+             *        ChangeCipherSpec
+             *        Finished
+             */
+            case SSL_CLIENT_CERTIFICATE:
+                ret = ssl_parse_certificate( ssl );
+                break;
+
+            case SSL_CLIENT_KEY_EXCHANGE:
+                ret = ssl_parse_client_key_exchange( ssl );
+                break;
+
+            case SSL_CERTIFICATE_VERIFY:
+                ret = ssl_parse_certificate_verify( ssl );
+                break;
+
+            case SSL_CLIENT_CHANGE_CIPHER_SPEC:
+                ret = ssl_parse_change_cipher_spec( ssl );
+                break;
+
+            case SSL_CLIENT_FINISHED:
+                ret = ssl_parse_finished( ssl );
+                break;
+
+            /*
+             *  ==>   ChangeCipherSpec
+             *        Finished
+             */
+            case SSL_SERVER_CHANGE_CIPHER_SPEC:
+                ret = ssl_write_change_cipher_spec( ssl );
+                break;
+
+            case SSL_SERVER_FINISHED:
+                ret = ssl_write_finished( ssl );
+                break;
+
+            case SSL_FLUSH_BUFFERS:
+                SSL_DEBUG_MSG( 2, ( "handshake: done" ) );
+                ssl->state = SSL_HANDSHAKE_OVER;
+                break;
+
+            default:
+                SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) );
+                return( XYSSL_ERR_SSL_BAD_INPUT_DATA );
+        }
+
+        if( ret != 0 )
+            break;
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= handshake server" ) );
+
+    return( ret );
+}
+
+#endif
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
new file mode 100644
index 0000000..72d98b8
--- /dev/null
+++ b/library/ssl_tls.c
@@ -0,0 +1,1977 @@
+/*
+ *  SSLv3/TLSv1 shared functions
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  The SSL 3.0 specification was drafted by Netscape in 1996,
+ *  and became an IETF standard in 1999.
+ *
+ *  http://wp.netscape.com/eng/ssl3/
+ *  http://www.ietf.org/rfc/rfc2246.txt
+ *  http://www.ietf.org/rfc/rfc4346.txt
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_SSL_TLS_C)
+
+#include "xyssl/aes.h"
+#include "xyssl/arc4.h"
+#include "xyssl/des.h"
+#include "xyssl/debug.h"
+#include "xyssl/ssl.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+/*
+ * Key material generation
+ */
+static int tls1_prf( unsigned char *secret, int slen, char *label,
+                     unsigned char *random, int rlen,
+                     unsigned char *dstbuf, int dlen )
+{
+    int nb, hs;
+    int i, j, k;
+    unsigned char *S1, *S2;
+    unsigned char tmp[128];
+    unsigned char h_i[20];
+
+    if( sizeof( tmp ) < 20 + strlen( label ) + rlen )
+        return( XYSSL_ERR_SSL_BAD_INPUT_DATA );
+
+    hs = ( slen + 1 ) / 2;
+    S1 = secret;
+    S2 = secret + slen - hs;
+
+    nb = strlen( label );
+    memcpy( tmp + 20, label, nb );
+    memcpy( tmp + 20 + nb, random, rlen );
+    nb += rlen;
+
+    /*
+     * First compute P_md5(secret,label+random)[0..dlen]
+     */
+    md5_hmac( S1, hs, tmp + 20, nb, 4 + tmp );
+
+    for( i = 0; i < dlen; i += 16 )
+    {
+        md5_hmac( S1, hs, 4 + tmp, 16 + nb, h_i );
+        md5_hmac( S1, hs, 4 + tmp, 16,  4 + tmp );
+
+        k = ( i + 16 > dlen ) ? dlen % 16 : 16;
+
+        for( j = 0; j < k; j++ )
+            dstbuf[i + j]  = h_i[j];
+    }
+
+    /*
+     * XOR out with P_sha1(secret,label+random)[0..dlen]
+     */
+    sha1_hmac( S2, hs, tmp + 20, nb, tmp );
+
+    for( i = 0; i < dlen; i += 20 )
+    {
+        sha1_hmac( S2, hs, tmp, 20 + nb, h_i );
+        sha1_hmac( S2, hs, tmp, 20,      tmp );
+
+        k = ( i + 20 > dlen ) ? dlen % 20 : 20;
+
+        for( j = 0; j < k; j++ )
+            dstbuf[i + j] = (unsigned char)( dstbuf[i + j] ^ h_i[j] );
+    }
+
+    memset( tmp, 0, sizeof( tmp ) );
+    memset( h_i, 0, sizeof( h_i ) );
+
+    return( 0 );
+}
+
+int ssl_derive_keys( ssl_context *ssl )
+{
+    int i;
+    md5_context md5;
+    sha1_context sha1;
+    unsigned char tmp[64];
+    unsigned char padding[16];
+    unsigned char sha1sum[20];
+    unsigned char keyblk[256];
+    unsigned char *key1;
+    unsigned char *key2;
+
+    SSL_DEBUG_MSG( 2, ( "=> derive keys" ) );
+
+    /*
+     * SSLv3:
+     *   master =
+     *     MD5( premaster + SHA1( 'A'   + premaster + randbytes ) ) +
+     *     MD5( premaster + SHA1( 'BB'  + premaster + randbytes ) ) +
+     *     MD5( premaster + SHA1( 'CCC' + premaster + randbytes ) )
+     *
+     * TLSv1:
+     *   master = PRF( premaster, "master secret", randbytes )[0..47]
+     */
+    if( ssl->resume == 0 )
+    {
+        int len = ssl->pmslen;
+
+        SSL_DEBUG_BUF( 3, "premaster secret", ssl->premaster, len );
+
+        if( ssl->minor_ver == SSL_MINOR_VERSION_0 )
+        {
+            for( i = 0; i < 3; i++ )
+            {
+                memset( padding, 'A' + i, 1 + i );
+
+                sha1_starts( &sha1 );
+                sha1_update( &sha1, padding, 1 + i );
+                sha1_update( &sha1, ssl->premaster, len );
+                sha1_update( &sha1, ssl->randbytes,  64 );
+                sha1_finish( &sha1, sha1sum );
+
+                md5_starts( &md5 );
+                md5_update( &md5, ssl->premaster, len );
+                md5_update( &md5, sha1sum, 20 );
+                md5_finish( &md5, ssl->session->master + i * 16 );
+            }
+        }
+        else
+            tls1_prf( ssl->premaster, len, "master secret",
+                      ssl->randbytes, 64, ssl->session->master, 48 );
+
+        memset( ssl->premaster, 0, sizeof( ssl->premaster ) );
+    }
+    else
+        SSL_DEBUG_MSG( 3, ( "no premaster (session resumed)" ) );
+
+    /*
+     * Swap the client and server random values.
+     */
+    memcpy( tmp, ssl->randbytes, 64 );
+    memcpy( ssl->randbytes, tmp + 32, 32 );
+    memcpy( ssl->randbytes + 32, tmp, 32 );
+    memset( tmp, 0, sizeof( tmp ) );
+
+    /*
+     *  SSLv3:
+     *    key block =
+     *      MD5( master + SHA1( 'A'    + master + randbytes ) ) +
+     *      MD5( master + SHA1( 'BB'   + master + randbytes ) ) +
+     *      MD5( master + SHA1( 'CCC'  + master + randbytes ) ) +
+     *      MD5( master + SHA1( 'DDDD' + master + randbytes ) ) +
+     *      ...
+     *
+     *  TLSv1:
+     *    key block = PRF( master, "key expansion", randbytes )
+     */
+    if( ssl->minor_ver == SSL_MINOR_VERSION_0 )
+    {
+        for( i = 0; i < 16; i++ )
+        {
+            memset( padding, 'A' + i, 1 + i );
+
+            sha1_starts( &sha1 );
+            sha1_update( &sha1, padding, 1 + i );
+            sha1_update( &sha1, ssl->session->master, 48 );
+            sha1_update( &sha1, ssl->randbytes, 64 );
+            sha1_finish( &sha1, sha1sum );
+
+            md5_starts( &md5 );
+            md5_update( &md5, ssl->session->master, 48 );
+            md5_update( &md5, sha1sum, 20 );
+            md5_finish( &md5, keyblk + i * 16 );
+        }
+
+        memset( &md5,  0, sizeof( md5  ) );
+        memset( &sha1, 0, sizeof( sha1 ) );
+
+        memset( padding, 0, sizeof( padding ) );
+        memset( sha1sum, 0, sizeof( sha1sum ) );
+    }
+    else
+        tls1_prf( ssl->session->master, 48, "key expansion",
+                  ssl->randbytes, 64, keyblk, 256 );
+
+    SSL_DEBUG_MSG( 3, ( "cipher = %s", ssl_get_cipher( ssl ) ) );
+    SSL_DEBUG_BUF( 3, "master secret", ssl->session->master, 48 );
+    SSL_DEBUG_BUF( 4, "random bytes", ssl->randbytes, 64 );
+    SSL_DEBUG_BUF( 4, "key block", keyblk, 256 );
+
+    memset( ssl->randbytes, 0, sizeof( ssl->randbytes ) );
+
+    /*
+     * Determine the appropriate key, IV and MAC length.
+     */
+    switch( ssl->session->cipher )
+    {
+#if defined(XYSSL_ARC4_C)
+        case SSL_RSA_RC4_128_MD5:
+            ssl->keylen = 16; ssl->minlen = 16;
+            ssl->ivlen  =  0; ssl->maclen = 16;
+            break;
+
+        case SSL_RSA_RC4_128_SHA:
+            ssl->keylen = 16; ssl->minlen = 20;
+            ssl->ivlen  =  0; ssl->maclen = 20;
+            break;
+#endif
+
+#if defined(XYSSL_DES_C)
+        case SSL_RSA_DES_168_SHA:
+        case SSL_EDH_RSA_DES_168_SHA:
+            ssl->keylen = 24; ssl->minlen = 24;
+            ssl->ivlen  =  8; ssl->maclen = 20;
+            break;
+#endif
+
+#if defined(XYSSL_AES_C)
+        case SSL_RSA_AES_128_SHA:
+            ssl->keylen = 16; ssl->minlen = 32;
+            ssl->ivlen  = 16; ssl->maclen = 20;
+            break;
+
+        case SSL_RSA_AES_256_SHA:
+        case SSL_EDH_RSA_AES_256_SHA:
+            ssl->keylen = 32; ssl->minlen = 32;
+            ssl->ivlen  = 16; ssl->maclen = 20;
+            break;
+#endif
+
+        default:
+            SSL_DEBUG_MSG( 1, ( "cipher %s is not available",
+                           ssl_get_cipher( ssl ) ) );
+            return( XYSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+    }
+
+    SSL_DEBUG_MSG( 3, ( "keylen: %d, minlen: %d, ivlen: %d, maclen: %d",
+                   ssl->keylen, ssl->minlen, ssl->ivlen, ssl->maclen ) );
+
+    /*
+     * Finally setup the cipher contexts, IVs and MAC secrets.
+     */
+    if( ssl->endpoint == SSL_IS_CLIENT )
+    {
+        key1 = keyblk + ssl->maclen * 2;
+        key2 = keyblk + ssl->maclen * 2 + ssl->keylen;
+
+        memcpy( ssl->mac_enc, keyblk,  ssl->maclen );
+        memcpy( ssl->mac_dec, keyblk + ssl->maclen, ssl->maclen );
+
+        memcpy( ssl->iv_enc, key2 + ssl->keylen,  ssl->ivlen );
+        memcpy( ssl->iv_dec, key2 + ssl->keylen + ssl->ivlen,
+                ssl->ivlen );
+    }
+    else
+    {
+        key1 = keyblk + ssl->maclen * 2 + ssl->keylen;
+        key2 = keyblk + ssl->maclen * 2;
+
+        memcpy( ssl->mac_dec, keyblk,  ssl->maclen );
+        memcpy( ssl->mac_enc, keyblk + ssl->maclen, ssl->maclen );
+
+        memcpy( ssl->iv_dec, key1 + ssl->keylen,  ssl->ivlen );
+        memcpy( ssl->iv_enc, key1 + ssl->keylen + ssl->ivlen,
+                ssl->ivlen );
+    }
+
+    switch( ssl->session->cipher )
+    {
+#if defined(XYSSL_ARC4_C)
+        case SSL_RSA_RC4_128_MD5:
+        case SSL_RSA_RC4_128_SHA:
+            arc4_setup( (arc4_context *) ssl->ctx_enc, key1, ssl->keylen );
+            arc4_setup( (arc4_context *) ssl->ctx_dec, key2, ssl->keylen );
+            break;
+#endif
+
+#if defined(XYSSL_DES_C)
+        case SSL_RSA_DES_168_SHA:
+        case SSL_EDH_RSA_DES_168_SHA:
+            des3_set3key_enc( (des3_context *) ssl->ctx_enc, key1 );
+            des3_set3key_dec( (des3_context *) ssl->ctx_dec, key2 );
+            break;
+#endif
+
+#if defined(XYSSL_AES_C)
+        case SSL_RSA_AES_128_SHA:
+            aes_setkey_enc( (aes_context *) ssl->ctx_enc, key1, 128 );
+            aes_setkey_dec( (aes_context *) ssl->ctx_dec, key2, 128 );
+            break;
+
+        case SSL_RSA_AES_256_SHA:
+        case SSL_EDH_RSA_AES_256_SHA:
+            aes_setkey_enc( (aes_context *) ssl->ctx_enc, key1, 256 );
+            aes_setkey_dec( (aes_context *) ssl->ctx_dec, key2, 256 );
+            break;
+#endif
+
+        default:
+            return( XYSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+    }
+
+    memset( keyblk, 0, sizeof( keyblk ) );
+
+    SSL_DEBUG_MSG( 2, ( "<= derive keys" ) );
+
+    return( 0 );
+}
+
+void ssl_calc_verify( ssl_context *ssl, unsigned char hash[36] )
+{
+    md5_context md5;
+    sha1_context sha1;
+    unsigned char pad_1[48];
+    unsigned char pad_2[48];
+
+    SSL_DEBUG_MSG( 2, ( "=> calc verify" ) );
+
+    memcpy( &md5 , &ssl->fin_md5 , sizeof(  md5_context ) );
+    memcpy( &sha1, &ssl->fin_sha1, sizeof( sha1_context ) );
+
+    if( ssl->minor_ver == SSL_MINOR_VERSION_0 )
+    {
+        memset( pad_1, 0x36, 48 );
+        memset( pad_2, 0x5C, 48 );
+
+        md5_update( &md5, ssl->session->master, 48 );
+        md5_update( &md5, pad_1, 48 );
+        md5_finish( &md5, hash );
+
+        md5_starts( &md5 );
+        md5_update( &md5, ssl->session->master, 48 );
+        md5_update( &md5, pad_2, 48 );
+        md5_update( &md5, hash,  16 );
+        md5_finish( &md5, hash );
+        
+        sha1_update( &sha1, ssl->session->master, 48 );
+        sha1_update( &sha1, pad_1, 40 );
+        sha1_finish( &sha1, hash + 16 );
+
+        sha1_starts( &sha1 );
+        sha1_update( &sha1, ssl->session->master, 48 );
+        sha1_update( &sha1, pad_2, 40 );
+        sha1_update( &sha1, hash + 16, 20 );
+        sha1_finish( &sha1, hash + 16 );
+    }
+    else /* TLSv1 */
+    {
+         md5_finish( &md5,  hash );
+        sha1_finish( &sha1, hash + 16 );
+    }
+
+    SSL_DEBUG_BUF( 3, "calculated verify result", hash, 36 );
+    SSL_DEBUG_MSG( 2, ( "<= calc verify" ) );
+
+    return;
+}
+
+/*
+ * SSLv3.0 MAC functions
+ */
+static void ssl_mac_md5( unsigned char *secret,
+                         unsigned char *buf, int len,
+                         unsigned char *ctr, int type )
+{
+    unsigned char header[11];
+    unsigned char padding[48];
+    md5_context md5;
+
+    memcpy( header, ctr, 8 );
+    header[ 8] = (unsigned char)  type;
+    header[ 9] = (unsigned char)( len >> 8 );
+    header[10] = (unsigned char)( len      );
+
+    memset( padding, 0x36, 48 );
+    md5_starts( &md5 );
+    md5_update( &md5, secret,  16 );
+    md5_update( &md5, padding, 48 );
+    md5_update( &md5, header,  11 );
+    md5_update( &md5, buf,  len );
+    md5_finish( &md5, buf + len );
+
+    memset( padding, 0x5C, 48 );
+    md5_starts( &md5 );
+    md5_update( &md5, secret,  16 );
+    md5_update( &md5, padding, 48 );
+    md5_update( &md5, buf + len, 16 );
+    md5_finish( &md5, buf + len );
+}
+
+static void ssl_mac_sha1( unsigned char *secret,
+                          unsigned char *buf, int len,
+                          unsigned char *ctr, int type )
+{
+    unsigned char header[11];
+    unsigned char padding[40];
+    sha1_context sha1;
+
+    memcpy( header, ctr, 8 );
+    header[ 8] = (unsigned char)  type;
+    header[ 9] = (unsigned char)( len >> 8 );
+    header[10] = (unsigned char)( len      );
+
+    memset( padding, 0x36, 40 );
+    sha1_starts( &sha1 );
+    sha1_update( &sha1, secret,  20 );
+    sha1_update( &sha1, padding, 40 );
+    sha1_update( &sha1, header,  11 );
+    sha1_update( &sha1, buf,  len );
+    sha1_finish( &sha1, buf + len );
+
+    memset( padding, 0x5C, 40 );
+    sha1_starts( &sha1 );
+    sha1_update( &sha1, secret,  20 );
+    sha1_update( &sha1, padding, 40 );
+    sha1_update( &sha1, buf + len, 20 );
+    sha1_finish( &sha1, buf + len );
+}
+
+/*
+ * Encryption/decryption functions
+ */ 
+static int ssl_encrypt_buf( ssl_context *ssl )
+{
+    int i, padlen;
+
+    SSL_DEBUG_MSG( 2, ( "=> encrypt buf" ) );
+
+    /*
+     * Add MAC then encrypt
+     */
+    if( ssl->minor_ver == SSL_MINOR_VERSION_0 )
+    {
+        if( ssl->maclen == 16 )
+             ssl_mac_md5( ssl->mac_enc,
+                          ssl->out_msg, ssl->out_msglen,
+                          ssl->out_ctr, ssl->out_msgtype );
+
+        if( ssl->maclen == 20 )
+            ssl_mac_sha1( ssl->mac_enc,
+                          ssl->out_msg, ssl->out_msglen,
+                          ssl->out_ctr, ssl->out_msgtype );
+    }
+    else
+    {
+        if( ssl->maclen == 16 )
+             md5_hmac( ssl->mac_enc, 16,
+                       ssl->out_ctr,  ssl->out_msglen + 13,
+                       ssl->out_msg + ssl->out_msglen );
+
+        if( ssl->maclen == 20 )
+            sha1_hmac( ssl->mac_enc, 20,
+                       ssl->out_ctr,  ssl->out_msglen + 13,
+                       ssl->out_msg + ssl->out_msglen );               
+    }
+
+    SSL_DEBUG_BUF( 4, "computed mac",
+                   ssl->out_msg + ssl->out_msglen, ssl->maclen );
+
+    ssl->out_msglen += ssl->maclen;
+
+    for( i = 7; i >= 0; i-- )
+        if( ++ssl->out_ctr[i] != 0 )
+            break;
+
+    if( ssl->ivlen == 0 )
+    {
+#if defined(XYSSL_ARC4_C)
+        padlen = 0;
+
+        SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, "
+                            "including %d bytes of padding",
+                       ssl->out_msglen, 0 ) );
+
+        SSL_DEBUG_BUF( 4, "before encrypt: output payload",
+                       ssl->out_msg, ssl->out_msglen );
+
+        arc4_crypt( (arc4_context *) ssl->ctx_enc,
+                    ssl->out_msg, ssl->out_msglen );
+#else
+        return( XYSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+#endif
+    }
+    else
+    {
+        padlen = ssl->ivlen - ( ssl->out_msglen + 1 ) % ssl->ivlen;
+        if( padlen == ssl->ivlen )
+            padlen = 0;
+
+        for( i = 0; i <= padlen; i++ )
+            ssl->out_msg[ssl->out_msglen + i] = (unsigned char) padlen;
+
+        ssl->out_msglen += padlen + 1;
+
+        SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, "
+                            "including %d bytes of padding",
+                       ssl->out_msglen, padlen + 1 ) );
+
+        SSL_DEBUG_BUF( 4, "before encrypt: output payload",
+                       ssl->out_msg, ssl->out_msglen );
+
+        switch( ssl->ivlen )
+        {
+            case  8:
+#if defined(XYSSL_DES_C)
+                des3_crypt_cbc( (des3_context *) ssl->ctx_enc,
+                    DES_ENCRYPT, ssl->out_msglen,
+                    ssl->iv_enc, ssl->out_msg, ssl->out_msg );
+                break;
+#endif
+
+            case 16:
+#if defined(XYSSL_AES_C)
+                aes_crypt_cbc( (aes_context *) ssl->ctx_enc,
+                    AES_ENCRYPT, ssl->out_msglen,
+                    ssl->iv_enc, ssl->out_msg, ssl->out_msg );
+                break;
+#endif
+
+            default:
+                return( XYSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+        }
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= encrypt buf" ) );
+
+    return( 0 );
+}
+
+static int ssl_decrypt_buf( ssl_context *ssl )
+{
+    int i, padlen;
+    unsigned char tmp[20];
+
+    SSL_DEBUG_MSG( 2, ( "=> decrypt buf" ) );
+
+    if( ssl->in_msglen < ssl->minlen )
+    {
+        SSL_DEBUG_MSG( 1, ( "in_msglen (%d) < minlen (%d)",
+                       ssl->in_msglen, ssl->minlen ) );
+        return( XYSSL_ERR_SSL_INVALID_MAC );
+    }
+
+    if( ssl->ivlen == 0 )
+    {
+#if defined(XYSSL_ARC4_C)
+        padlen = 0;
+        arc4_crypt( (arc4_context *) ssl->ctx_dec,
+                    ssl->in_msg, ssl->in_msglen );
+#else
+        return( XYSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+#endif
+    }
+    else
+    {
+        /*
+         * Decrypt and check the padding
+         */
+        if( ssl->in_msglen % ssl->ivlen != 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "msglen (%d) %% ivlen (%d) != 0",
+                           ssl->in_msglen, ssl->ivlen ) );
+            return( XYSSL_ERR_SSL_INVALID_MAC );
+        }
+
+        switch( ssl->ivlen )
+        {
+#if defined(XYSSL_DES_C)
+            case  8:
+                des3_crypt_cbc( (des3_context *) ssl->ctx_dec,
+                    DES_DECRYPT, ssl->in_msglen,
+                    ssl->iv_dec, ssl->in_msg, ssl->in_msg );
+                break;
+#endif
+
+#if defined(XYSSL_AES_C)
+            case 16:
+                 aes_crypt_cbc( (aes_context *) ssl->ctx_dec,
+                    AES_DECRYPT, ssl->in_msglen,
+                    ssl->iv_dec, ssl->in_msg, ssl->in_msg );
+                 break;
+#endif
+
+            default:
+                return( XYSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+        }
+
+        padlen = 1 + ssl->in_msg[ssl->in_msglen - 1];
+
+        if( ssl->minor_ver == SSL_MINOR_VERSION_0 )
+        {
+            if( padlen > ssl->ivlen )
+            {
+                SSL_DEBUG_MSG( 1, ( "bad padding length: is %d, "
+                                    "should be no more than %d",
+                               padlen, ssl->ivlen ) );
+                padlen = 0;
+            }
+        }
+        else
+        {
+            /*
+             * TLSv1: always check the padding
+             */
+            for( i = 1; i <= padlen; i++ )
+            {
+                if( ssl->in_msg[ssl->in_msglen - i] != padlen - 1 )
+                {
+                    SSL_DEBUG_MSG( 1, ( "bad padding byte: should be "
+                                        "%02x, but is %02x", padlen - 1,
+                                   ssl->in_msg[ssl->in_msglen - i] ) );
+                    padlen = 0;
+                }
+            }
+        }
+    }
+
+    SSL_DEBUG_BUF( 4, "raw buffer after decryption",
+                   ssl->in_msg, ssl->in_msglen );
+
+    /*
+     * Always compute the MAC (RFC4346, CBCTIME).
+     */
+    ssl->in_msglen -= ( ssl->maclen + padlen );
+
+    ssl->in_hdr[3] = (unsigned char)( ssl->in_msglen >> 8 );
+    ssl->in_hdr[4] = (unsigned char)( ssl->in_msglen      );
+
+    memcpy( tmp, ssl->in_msg + ssl->in_msglen, 20 );
+
+    if( ssl->minor_ver == SSL_MINOR_VERSION_0 )
+    {
+        if( ssl->maclen == 16 )
+             ssl_mac_md5( ssl->mac_dec,
+                          ssl->in_msg, ssl->in_msglen,
+                          ssl->in_ctr, ssl->in_msgtype );
+        else
+            ssl_mac_sha1( ssl->mac_dec,
+                          ssl->in_msg, ssl->in_msglen,
+                          ssl->in_ctr, ssl->in_msgtype );
+    }
+    else
+    {
+        if( ssl->maclen == 16 )
+             md5_hmac( ssl->mac_dec, 16,
+                       ssl->in_ctr,  ssl->in_msglen + 13,
+                       ssl->in_msg + ssl->in_msglen );
+        else
+            sha1_hmac( ssl->mac_dec, 20,
+                       ssl->in_ctr,  ssl->in_msglen + 13,
+                       ssl->in_msg + ssl->in_msglen );
+    }
+
+    SSL_DEBUG_BUF( 4, "message  mac", tmp, ssl->maclen );
+    SSL_DEBUG_BUF( 4, "computed mac", ssl->in_msg + ssl->in_msglen,
+                   ssl->maclen );
+
+    if( memcmp( tmp, ssl->in_msg + ssl->in_msglen,
+                     ssl->maclen ) != 0 )
+    {
+        SSL_DEBUG_MSG( 1, ( "message mac does not match" ) );
+        return( XYSSL_ERR_SSL_INVALID_MAC );
+    }
+
+    /*
+     * Finally check the padding length; bad padding
+     * will produce the same error as an invalid MAC.
+     */
+    if( ssl->ivlen != 0 && padlen == 0 )
+        return( XYSSL_ERR_SSL_INVALID_MAC );
+
+    if( ssl->in_msglen == 0 )
+    {
+        ssl->nb_zero++;
+
+        /*
+         * Three or more empty messages may be a DoS attack
+         * (excessive CPU consumption).
+         */
+        if( ssl->nb_zero > 3 )
+        {
+            SSL_DEBUG_MSG( 1, ( "received four consecutive empty "
+                                "messages, possible DoS attack" ) );
+            return( XYSSL_ERR_SSL_INVALID_MAC );
+        }
+    }
+    else
+        ssl->nb_zero = 0;
+            
+    for( i = 7; i >= 0; i-- )
+        if( ++ssl->in_ctr[i] != 0 )
+            break;
+
+    SSL_DEBUG_MSG( 2, ( "<= decrypt buf" ) );
+
+    return( 0 );
+}
+
+/*
+ * Fill the input message buffer
+ */
+int ssl_fetch_input( ssl_context *ssl, int nb_want )
+{
+    int ret, len;
+
+    SSL_DEBUG_MSG( 2, ( "=> fetch input" ) );
+
+    while( ssl->in_left < nb_want )
+    {
+        len = nb_want - ssl->in_left;
+        ret = ssl->f_recv( ssl->p_recv, ssl->in_hdr + ssl->in_left, len );
+
+        SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d",
+                       ssl->in_left, nb_want ) );
+        SSL_DEBUG_RET( 2, "ssl->f_recv", ret );
+
+        if( ret < 0 )
+            return( ret );
+
+        ssl->in_left += ret;
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= fetch input" ) );
+
+    return( 0 );
+}
+
+/*
+ * Flush any data not yet written
+ */
+int ssl_flush_output( ssl_context *ssl )
+{
+    int ret;
+    unsigned char *buf;
+
+    SSL_DEBUG_MSG( 2, ( "=> flush output" ) );
+
+    while( ssl->out_left > 0 )
+    {
+        SSL_DEBUG_MSG( 2, ( "message length: %d, out_left: %d",
+                       5 + ssl->out_msglen, ssl->out_left ) );
+
+        buf = ssl->out_hdr + 5 + ssl->out_msglen - ssl->out_left;
+        ret = ssl->f_send( ssl->p_send, buf, ssl->out_left );
+        SSL_DEBUG_RET( 2, "ssl->f_send", ret );
+
+        if( ret <= 0 )
+            return( ret );
+
+        ssl->out_left -= ret;
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= flush output" ) );
+
+    return( 0 );
+}
+
+/*
+ * Record layer functions
+ */
+int ssl_write_record( ssl_context *ssl )
+{
+    int ret, len = ssl->out_msglen;
+
+    SSL_DEBUG_MSG( 2, ( "=> write record" ) );
+
+    ssl->out_hdr[0] = (unsigned char) ssl->out_msgtype;
+    ssl->out_hdr[1] = (unsigned char) ssl->major_ver;
+    ssl->out_hdr[2] = (unsigned char) ssl->minor_ver;
+    ssl->out_hdr[3] = (unsigned char)( len >> 8 );
+    ssl->out_hdr[4] = (unsigned char)( len      );
+
+    if( ssl->out_msgtype == SSL_MSG_HANDSHAKE )
+    {
+        ssl->out_msg[1] = (unsigned char)( ( len - 4 ) >> 16 );
+        ssl->out_msg[2] = (unsigned char)( ( len - 4 ) >>  8 );
+        ssl->out_msg[3] = (unsigned char)( ( len - 4 )       );
+
+         md5_update( &ssl->fin_md5 , ssl->out_msg, len );
+        sha1_update( &ssl->fin_sha1, ssl->out_msg, len );
+    }
+
+    if( ssl->do_crypt != 0 )
+    {
+        if( ( ret = ssl_encrypt_buf( ssl ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_encrypt_buf", ret );
+            return( ret );
+        }
+
+        len = ssl->out_msglen;
+        ssl->out_hdr[3] = (unsigned char)( len >> 8 );
+        ssl->out_hdr[4] = (unsigned char)( len      );
+    }
+
+    ssl->out_left = 5 + ssl->out_msglen;
+
+    SSL_DEBUG_MSG( 3, ( "output record: msgtype = %d, "
+                        "version = [%d:%d], msglen = %d",
+                   ssl->out_hdr[0], ssl->out_hdr[1], ssl->out_hdr[2],
+                 ( ssl->out_hdr[3] << 8 ) | ssl->out_hdr[4] ) );
+
+    SSL_DEBUG_BUF( 4, "output record sent to network",
+                   ssl->out_hdr, 5 + ssl->out_msglen );
+
+    if( ( ret = ssl_flush_output( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_flush_output", ret );
+        return( ret );
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= write record" ) );
+
+    return( 0 );
+}
+
+int ssl_read_record( ssl_context *ssl )
+{
+    int ret;
+
+    SSL_DEBUG_MSG( 2, ( "=> read record" ) );
+
+    if( ssl->in_hslen != 0 &&
+        ssl->in_hslen < ssl->in_msglen )
+    {
+        /*
+         * Get next Handshake message in the current record
+         */
+        ssl->in_msglen -= ssl->in_hslen;
+
+        memcpy( ssl->in_msg, ssl->in_msg + ssl->in_hslen,
+                ssl->in_msglen );
+
+        ssl->in_hslen  = 4;
+        ssl->in_hslen += ( ssl->in_msg[2] << 8 ) | ssl->in_msg[3];
+
+        SSL_DEBUG_MSG( 3, ( "handshake message: msglen ="
+                            " %d, type = %d, hslen = %d",
+                       ssl->in_msglen, ssl->in_msg[0], ssl->in_hslen ) );
+
+        if( ssl->in_msglen < 4 || ssl->in_msg[1] != 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad handshake length" ) );
+            return( XYSSL_ERR_SSL_INVALID_RECORD );
+        }
+
+        if( ssl->in_msglen < ssl->in_hslen )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad handshake length" ) );
+            return( XYSSL_ERR_SSL_INVALID_RECORD );
+        }
+
+         md5_update( &ssl->fin_md5 , ssl->in_msg, ssl->in_hslen );
+        sha1_update( &ssl->fin_sha1, ssl->in_msg, ssl->in_hslen );
+
+        return( 0 );
+    }
+
+    ssl->in_hslen = 0;
+
+    /*
+     * Read the record header and validate it
+     */
+    if( ( ret = ssl_fetch_input( ssl, 5 ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_fetch_input", ret );
+        return( ret );
+    }
+
+    ssl->in_msgtype =  ssl->in_hdr[0];
+    ssl->in_msglen = ( ssl->in_hdr[3] << 8 ) | ssl->in_hdr[4];
+
+    SSL_DEBUG_MSG( 3, ( "input record: msgtype = %d, "
+                        "version = [%d:%d], msglen = %d",
+                     ssl->in_hdr[0], ssl->in_hdr[1], ssl->in_hdr[2],
+                   ( ssl->in_hdr[3] << 8 ) | ssl->in_hdr[4] ) );
+
+    if( ssl->in_hdr[1] != ssl->major_ver )
+    {
+        SSL_DEBUG_MSG( 1, ( "major version mismatch" ) );
+        return( XYSSL_ERR_SSL_INVALID_RECORD );
+    }
+
+    if( ssl->in_hdr[2] != SSL_MINOR_VERSION_0 &&
+        ssl->in_hdr[2] != SSL_MINOR_VERSION_1 )
+    {
+        SSL_DEBUG_MSG( 1, ( "minor version mismatch" ) );
+        return( XYSSL_ERR_SSL_INVALID_RECORD );
+    }
+
+    /*
+     * Make sure the message length is acceptable
+     */
+    if( ssl->do_crypt == 0 )
+    {
+        if( ssl->in_msglen < 1 ||
+            ssl->in_msglen > SSL_MAX_CONTENT_LEN )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad message length" ) );
+            return( XYSSL_ERR_SSL_INVALID_RECORD );
+        }
+    }
+    else
+    {
+        if( ssl->in_msglen < ssl->minlen )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad message length" ) );
+            return( XYSSL_ERR_SSL_INVALID_RECORD );
+        }
+
+        if( ssl->minor_ver == SSL_MINOR_VERSION_0 &&
+            ssl->in_msglen > ssl->minlen + SSL_MAX_CONTENT_LEN )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad message length" ) );
+            return( XYSSL_ERR_SSL_INVALID_RECORD );
+        }
+
+        /*
+         * TLS encrypted messages can have up to 256 bytes of padding
+         */
+        if( ssl->minor_ver == SSL_MINOR_VERSION_1 &&
+            ssl->in_msglen > ssl->minlen + SSL_MAX_CONTENT_LEN + 256 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad message length" ) );
+            return( XYSSL_ERR_SSL_INVALID_RECORD );
+        }
+    }
+
+    /*
+     * Read and optionally decrypt the message contents
+     */
+    if( ( ret = ssl_fetch_input( ssl, 5 + ssl->in_msglen ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_fetch_input", ret );
+        return( ret );
+    }
+
+    SSL_DEBUG_BUF( 4, "input record from network",
+                   ssl->in_hdr, 5 + ssl->in_msglen );
+
+    if( ssl->do_crypt != 0 )
+    {
+        if( ( ret = ssl_decrypt_buf( ssl ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_decrypt_buf", ret );
+            return( ret );
+        }
+
+        SSL_DEBUG_BUF( 4, "input payload after decrypt",
+                       ssl->in_msg, ssl->in_msglen );
+
+        if( ssl->in_msglen > SSL_MAX_CONTENT_LEN )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad message length" ) );
+            return( XYSSL_ERR_SSL_INVALID_RECORD );
+        }
+    }
+
+    if( ssl->in_msgtype == SSL_MSG_HANDSHAKE )
+    {
+        ssl->in_hslen  = 4;
+        ssl->in_hslen += ( ssl->in_msg[2] << 8 ) | ssl->in_msg[3];
+
+        SSL_DEBUG_MSG( 3, ( "handshake message: msglen ="
+                            " %d, type = %d, hslen = %d",
+                       ssl->in_msglen, ssl->in_msg[0], ssl->in_hslen ) );
+
+        /*
+         * Additional checks to validate the handshake header
+         */
+        if( ssl->in_msglen < 4 || ssl->in_msg[1] != 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad handshake length" ) );
+            return( XYSSL_ERR_SSL_INVALID_RECORD );
+        }
+
+        if( ssl->in_msglen < ssl->in_hslen )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad handshake length" ) );
+            return( XYSSL_ERR_SSL_INVALID_RECORD );
+        }
+
+         md5_update( &ssl->fin_md5 , ssl->in_msg, ssl->in_hslen );
+        sha1_update( &ssl->fin_sha1, ssl->in_msg, ssl->in_hslen );
+    }
+
+    if( ssl->in_msgtype == SSL_MSG_ALERT )
+    {
+        SSL_DEBUG_MSG( 2, ( "got an alert message, type: [%d:%d]",
+                       ssl->in_msg[0], ssl->in_msg[1] ) );
+
+        /*
+         * Ignore non-fatal alerts, except close_notify
+         */
+        if( ssl->in_msg[0] == SSL_ALERT_FATAL )
+        {
+            SSL_DEBUG_MSG( 1, ( "is a fatal alert message" ) );
+            return( XYSSL_ERR_SSL_FATAL_ALERT_MESSAGE | ssl->in_msg[1] );
+        }
+
+        if( ssl->in_msg[0] == SSL_ALERT_WARNING &&
+            ssl->in_msg[1] == SSL_ALERT_CLOSE_NOTIFY )
+        {
+            SSL_DEBUG_MSG( 2, ( "is a close notify message" ) );
+            return( XYSSL_ERR_SSL_PEER_CLOSE_NOTIFY );
+        }
+    }
+
+    ssl->in_left = 0;
+
+    SSL_DEBUG_MSG( 2, ( "<= read record" ) );
+
+    return( 0 );
+}
+
+/*
+ * Handshake functions
+ */
+int ssl_write_certificate( ssl_context *ssl )
+{
+    int ret, i, n;
+    x509_cert *crt;
+
+    SSL_DEBUG_MSG( 2, ( "=> write certificate" ) );
+
+    if( ssl->endpoint == SSL_IS_CLIENT )
+    {
+        if( ssl->client_auth == 0 )
+        {
+            SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) );
+            ssl->state++;
+            return( 0 );
+        }
+
+        /*
+         * If using SSLv3 and got no cert, send an Alert message
+         * (otherwise an empty Certificate message will be sent).
+         */
+        if( ssl->own_cert  == NULL &&
+            ssl->minor_ver == SSL_MINOR_VERSION_0 )
+        {
+            ssl->out_msglen  = 2;
+            ssl->out_msgtype = SSL_MSG_ALERT;
+            ssl->out_msg[0]  = SSL_ALERT_WARNING;
+            ssl->out_msg[1]  = SSL_ALERT_NO_CERTIFICATE;
+
+            SSL_DEBUG_MSG( 2, ( "got no certificate to send" ) );
+            goto write_msg;
+        }
+    }
+    else /* SSL_IS_SERVER */
+    {
+        if( ssl->own_cert == NULL )
+        {
+            SSL_DEBUG_MSG( 1, ( "got no certificate to send" ) );
+            return( XYSSL_ERR_SSL_CERTIFICATE_REQUIRED );
+        }
+    }
+
+    SSL_DEBUG_CRT( 3, "own certificate", ssl->own_cert );
+
+    /*
+     *     0  .  0    handshake type
+     *     1  .  3    handshake length
+     *     4  .  6    length of all certs
+     *     7  .  9    length of cert. 1
+     *    10  . n-1   peer certificate
+     *     n  . n+2   length of cert. 2
+     *    n+3 . ...   upper level cert, etc.
+     */
+    i = 7;
+    crt = ssl->own_cert;
+
+    while( crt != NULL && crt->next != NULL )
+    {
+        n = crt->raw.len;
+        if( i + 3 + n > SSL_MAX_CONTENT_LEN )
+        {
+            SSL_DEBUG_MSG( 1, ( "certificate too large, %d > %d",
+                           i + 3 + n, SSL_MAX_CONTENT_LEN ) );
+            return( XYSSL_ERR_SSL_CERTIFICATE_TOO_LARGE );
+        }
+
+        ssl->out_msg[i    ] = (unsigned char)( n >> 16 );
+        ssl->out_msg[i + 1] = (unsigned char)( n >>  8 );
+        ssl->out_msg[i + 2] = (unsigned char)( n       );
+
+        i += 3; memcpy( ssl->out_msg + i, crt->raw.p, n );
+        i += n; crt = crt->next;
+    }
+
+    ssl->out_msg[4]  = (unsigned char)( ( i - 7 ) >> 16 );
+    ssl->out_msg[5]  = (unsigned char)( ( i - 7 ) >>  8 );
+    ssl->out_msg[6]  = (unsigned char)( ( i - 7 )       );
+
+    ssl->out_msglen  = i;
+    ssl->out_msgtype = SSL_MSG_HANDSHAKE;
+    ssl->out_msg[0]  = SSL_HS_CERTIFICATE;
+
+write_msg:
+
+    ssl->state++;
+
+    if( ( ret = ssl_write_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_write_record", ret );
+        return( ret );
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= write certificate" ) );
+
+    return( 0 );
+}
+
+int ssl_parse_certificate( ssl_context *ssl )
+{
+    int ret, i, n;
+
+    SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) );
+
+    if( ssl->endpoint == SSL_IS_SERVER &&
+        ssl->authmode == SSL_VERIFY_NONE )
+    {
+        SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
+        ssl->state++;
+        return( 0 );
+    }
+
+    if( ( ret = ssl_read_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_read_record", ret );
+        return( ret );
+    }
+
+    ssl->state++;
+
+    /*
+     * Check if the client sent an empty certificate
+     */
+    if( ssl->endpoint  == SSL_IS_SERVER &&
+        ssl->minor_ver == SSL_MINOR_VERSION_0 )
+    {
+        if( ssl->in_msglen  == 2                    &&
+            ssl->in_msgtype == SSL_MSG_ALERT        &&
+            ssl->in_msg[0]  == SSL_ALERT_WARNING    &&
+            ssl->in_msg[1]  == SSL_ALERT_NO_CERTIFICATE )
+        {
+            SSL_DEBUG_MSG( 1, ( "SSLv3 client has no certificate" ) );
+
+            if( ssl->authmode == SSL_VERIFY_OPTIONAL )
+                return( 0 );
+            else
+                return( XYSSL_ERR_SSL_NO_CLIENT_CERTIFICATE );
+        }
+    }
+
+    if( ssl->endpoint  == SSL_IS_SERVER &&
+        ssl->minor_ver != SSL_MINOR_VERSION_0 )
+    {
+        if( ssl->in_hslen   == 7                    &&
+            ssl->in_msgtype == SSL_MSG_HANDSHAKE    &&
+            ssl->in_msg[0]  == SSL_HS_CERTIFICATE   &&
+            memcmp( ssl->in_msg + 4, "\0\0\0", 3 ) == 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "TLSv1 client has no certificate" ) );
+
+            if( ssl->authmode == SSL_VERIFY_REQUIRED )
+                return( XYSSL_ERR_SSL_NO_CLIENT_CERTIFICATE );
+            else
+                return( 0 );
+        }
+    }
+
+    if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
+        return( XYSSL_ERR_SSL_UNEXPECTED_MESSAGE );
+    }
+
+    if( ssl->in_msg[0] != SSL_HS_CERTIFICATE || ssl->in_hslen < 10 )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_CERTIFICATE );
+    }
+
+    /*
+     * Same message structure as in ssl_write_certificate()
+     */
+    n = ( ssl->in_msg[5] << 8 ) | ssl->in_msg[6];
+
+    if( ssl->in_msg[4] != 0 || ssl->in_hslen != 7 + n )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_CERTIFICATE );
+    }
+
+    if( ( ssl->peer_cert = (x509_cert *) malloc(
+                    sizeof( x509_cert ) ) ) == NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "malloc(%d bytes) failed",
+                       sizeof( x509_cert ) ) );
+        return( 1 );
+    }
+
+    memset( ssl->peer_cert, 0, sizeof( x509_cert ) );
+
+    i = 7;
+
+    while( i < ssl->in_hslen )
+    {
+        if( ssl->in_msg[i] != 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CERTIFICATE );
+        }
+
+        n = ( (unsigned int) ssl->in_msg[i + 1] << 8 )
+            | (unsigned int) ssl->in_msg[i + 2];
+        i += 3;
+
+        if( n < 128 || i + n > ssl->in_hslen )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
+            return( XYSSL_ERR_SSL_BAD_HS_CERTIFICATE );
+        }
+
+        ret = x509parse_crt( ssl->peer_cert, ssl->in_msg + i, n );
+        if( ret != 0 )
+        {
+            SSL_DEBUG_RET( 1, " x509parse_crt", ret );
+            return( ret );
+        }
+
+        i += n;
+    }
+
+    SSL_DEBUG_CRT( 3, "peer certificate", ssl->peer_cert );
+
+    if( ssl->authmode != SSL_VERIFY_NONE )
+    {
+        if( ssl->ca_chain == NULL )
+        {
+            SSL_DEBUG_MSG( 1, ( "got no CA chain" ) );
+            return( XYSSL_ERR_SSL_CA_CHAIN_REQUIRED );
+        }
+
+        ret = x509parse_verify( ssl->peer_cert, ssl->ca_chain,
+                                ssl->peer_cn,  &ssl->verify_result );
+
+        if( ret != 0 )
+            SSL_DEBUG_RET( 1, "x509_verify_cert", ret );
+
+        if( ssl->authmode != SSL_VERIFY_REQUIRED )
+            ret = 0;
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) );
+
+    return( ret );
+}
+
+int ssl_write_change_cipher_spec( ssl_context *ssl )
+{
+    int ret;
+
+    SSL_DEBUG_MSG( 2, ( "=> write change cipher spec" ) );
+
+    ssl->out_msgtype = SSL_MSG_CHANGE_CIPHER_SPEC;
+    ssl->out_msglen  = 1;
+    ssl->out_msg[0]  = 1;
+
+    ssl->do_crypt = 0;
+    ssl->state++;
+
+    if( ( ret = ssl_write_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_write_record", ret );
+        return( ret );
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= write change cipher spec" ) );
+
+    return( 0 );
+}
+
+int ssl_parse_change_cipher_spec( ssl_context *ssl )
+{
+    int ret;
+
+    SSL_DEBUG_MSG( 2, ( "=> parse change cipher spec" ) );
+
+    ssl->do_crypt = 0;
+
+    if( ( ret = ssl_read_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_read_record", ret );
+        return( ret );
+    }
+
+    if( ssl->in_msgtype != SSL_MSG_CHANGE_CIPHER_SPEC )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) );
+        return( XYSSL_ERR_SSL_UNEXPECTED_MESSAGE );
+    }
+
+    if( ssl->in_msglen != 1 || ssl->in_msg[0] != 1 )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC );
+    }
+
+    ssl->state++;
+
+    SSL_DEBUG_MSG( 2, ( "<= parse change cipher spec" ) );
+
+    return( 0 );
+}
+
+static void ssl_calc_finished(
+                ssl_context *ssl, unsigned char *buf, int from,
+                md5_context *md5, sha1_context *sha1 )
+{
+    int len = 12;
+    char *sender;
+    unsigned char padbuf[48];
+    unsigned char md5sum[16];
+    unsigned char sha1sum[20];
+
+    SSL_DEBUG_MSG( 2, ( "=> calc  finished" ) );
+
+    /*
+     * SSLv3:
+     *   hash =
+     *      MD5( master + pad2 +
+     *          MD5( handshake + sender + master + pad1 ) )
+     *   + SHA1( master + pad2 +
+     *         SHA1( handshake + sender + master + pad1 ) )
+     *
+     * TLSv1:
+     *   hash = PRF( master, finished_label,
+     *               MD5( handshake ) + SHA1( handshake ) )[0..11]
+     */
+
+    SSL_DEBUG_BUF( 4, "finished  md5 state", (unsigned char *)
+                    md5->state, sizeof(  md5->state ) );
+
+    SSL_DEBUG_BUF( 4, "finished sha1 state", (unsigned char *)
+                   sha1->state, sizeof( sha1->state ) );
+
+    if( ssl->minor_ver == SSL_MINOR_VERSION_0 )
+    {
+        sender = ( from == SSL_IS_CLIENT ) ? (char *) "CLNT"
+                                           : (char *) "SRVR";
+
+        memset( padbuf, 0x36, 48 );
+
+        md5_update( md5, (unsigned char *) sender, 4 );
+        md5_update( md5, ssl->session->master, 48 );
+        md5_update( md5, padbuf, 48 );
+        md5_finish( md5, md5sum );
+
+        sha1_update( sha1, (unsigned char *) sender, 4 );
+        sha1_update( sha1, ssl->session->master, 48 );
+        sha1_update( sha1, padbuf, 40 );
+        sha1_finish( sha1, sha1sum );
+
+        memset( padbuf, 0x5C, 48 );
+
+        md5_starts( md5 );
+        md5_update( md5, ssl->session->master, 48 );
+        md5_update( md5, padbuf, 48 );
+        md5_update( md5, md5sum, 16 );
+        md5_finish( md5, buf );
+
+        sha1_starts( sha1 );
+        sha1_update( sha1, ssl->session->master, 48 );
+        sha1_update( sha1, padbuf , 40 );
+        sha1_update( sha1, sha1sum, 20 );
+        sha1_finish( sha1, buf + 16 );
+
+        len += 24;
+    }
+    else
+    {
+        sender = ( from == SSL_IS_CLIENT )
+                 ? (char *) "client finished"
+                 : (char *) "server finished";
+
+         md5_finish(  md5, padbuf );
+        sha1_finish( sha1, padbuf + 16 );
+
+        tls1_prf( ssl->session->master, 48, sender,
+                  padbuf, 36, buf, len );
+    }
+
+    SSL_DEBUG_BUF( 3, "calc finished result", buf, len );
+
+    memset(  md5, 0, sizeof(  md5_context ) );
+    memset( sha1, 0, sizeof( sha1_context ) );
+
+    memset(  padbuf, 0, sizeof(  padbuf ) );
+    memset(  md5sum, 0, sizeof(  md5sum ) );
+    memset( sha1sum, 0, sizeof( sha1sum ) );
+
+    SSL_DEBUG_MSG( 2, ( "<= calc  finished" ) );
+}
+
+int ssl_write_finished( ssl_context *ssl )
+{
+    int ret, hash_len;
+     md5_context  md5;
+    sha1_context sha1;
+
+    SSL_DEBUG_MSG( 2, ( "=> write finished" ) );
+
+    memcpy( &md5 , &ssl->fin_md5 , sizeof(  md5_context ) );
+    memcpy( &sha1, &ssl->fin_sha1, sizeof( sha1_context ) );
+
+    ssl_calc_finished( ssl, ssl->out_msg + 4,
+                       ssl->endpoint, &md5, &sha1 );
+
+    hash_len = ( ssl->minor_ver == SSL_MINOR_VERSION_0 ) ? 36 : 12;
+
+    ssl->out_msglen  = 4 + hash_len;
+    ssl->out_msgtype = SSL_MSG_HANDSHAKE;
+    ssl->out_msg[0]  = SSL_HS_FINISHED;
+
+    /*
+     * In case of session resuming, invert the client and server
+     * ChangeCipherSpec messages order.
+     */
+    if( ssl->resume != 0 )
+    {
+        if( ssl->endpoint == SSL_IS_CLIENT )
+            ssl->state = SSL_HANDSHAKE_OVER;
+        else
+            ssl->state = SSL_CLIENT_CHANGE_CIPHER_SPEC;
+    }
+    else
+        ssl->state++;
+
+    ssl->do_crypt = 1;
+
+    if( ( ret = ssl_write_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_write_record", ret );
+        return( ret );
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= write finished" ) );
+
+    return( 0 );
+}
+
+int ssl_parse_finished( ssl_context *ssl )
+{
+    int ret, hash_len;
+     md5_context  md5;
+    sha1_context sha1;
+    unsigned char buf[36];
+
+    SSL_DEBUG_MSG( 2, ( "=> parse finished" ) );
+
+    memcpy( &md5 , &ssl->fin_md5 , sizeof(  md5_context ) );
+    memcpy( &sha1, &ssl->fin_sha1, sizeof( sha1_context ) );
+
+    ssl->do_crypt = 1;
+
+    if( ( ret = ssl_read_record( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_read_record", ret );
+        return( ret );
+    }
+
+    if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad finished message" ) );
+        return( XYSSL_ERR_SSL_UNEXPECTED_MESSAGE );
+    }
+
+    hash_len = ( ssl->minor_ver == SSL_MINOR_VERSION_0 ) ? 36 : 12;
+
+    if( ssl->in_msg[0] != SSL_HS_FINISHED ||
+        ssl->in_hslen  != 4 + hash_len )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad finished message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_FINISHED );
+    }
+
+    ssl_calc_finished( ssl, buf, ssl->endpoint ^ 1, &md5, &sha1 );
+
+    if( memcmp( ssl->in_msg + 4, buf, hash_len ) != 0 )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad finished message" ) );
+        return( XYSSL_ERR_SSL_BAD_HS_FINISHED );
+    }
+
+    if( ssl->resume != 0 )
+    {
+        if( ssl->endpoint == SSL_IS_CLIENT )
+            ssl->state = SSL_CLIENT_CHANGE_CIPHER_SPEC;
+
+        if( ssl->endpoint == SSL_IS_SERVER )
+            ssl->state = SSL_HANDSHAKE_OVER;
+    }
+    else
+        ssl->state++;
+
+    SSL_DEBUG_MSG( 2, ( "<= parse finished" ) );
+
+    return( 0 );
+}
+
+/*
+ * Initialize an SSL context
+ */
+int ssl_init( ssl_context *ssl )
+{
+    int len = SSL_BUFFER_LEN;
+
+    memset( ssl, 0, sizeof( ssl_context ) );
+
+    ssl->in_ctr = (unsigned char *) malloc( len );
+    ssl->in_hdr = ssl->in_ctr +  8;
+    ssl->in_msg = ssl->in_ctr + 13;
+
+    if( ssl->in_ctr == NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "malloc(%d bytes) failed", len ) );
+        return( 1 );
+    }
+
+    ssl->out_ctr = (unsigned char *) malloc( len );
+    ssl->out_hdr = ssl->out_ctr +  8;
+    ssl->out_msg = ssl->out_ctr + 13;
+
+    if( ssl->out_ctr == NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "malloc(%d bytes) failed", len ) );
+        free( ssl-> in_ctr );
+        return( 1 );
+    }
+
+    memset( ssl-> in_ctr, 0, SSL_BUFFER_LEN );
+    memset( ssl->out_ctr, 0, SSL_BUFFER_LEN );
+
+    ssl->hostname = NULL;
+    ssl->hostname_len = 0;
+
+     md5_starts( &ssl->fin_md5  );
+    sha1_starts( &ssl->fin_sha1 );
+
+    return( 0 );
+}
+
+/*
+ * SSL set accessors
+ */
+void ssl_set_endpoint( ssl_context *ssl, int endpoint )
+{
+    ssl->endpoint   = endpoint;
+}
+
+void ssl_set_authmode( ssl_context *ssl, int authmode )
+{
+    ssl->authmode   = authmode;
+}
+
+void ssl_set_rng( ssl_context *ssl,
+                  int (*f_rng)(void *),
+                  void *p_rng )
+{
+    ssl->f_rng      = f_rng;
+    ssl->p_rng      = p_rng;
+}
+
+void ssl_set_dbg( ssl_context *ssl,
+                  void (*f_dbg)(void *, int, char *),
+                  void  *p_dbg )
+{
+    ssl->f_dbg      = f_dbg;
+    ssl->p_dbg      = p_dbg;
+}
+
+void ssl_set_bio( ssl_context *ssl,
+            int (*f_recv)(void *, unsigned char *, int), void *p_recv,
+            int (*f_send)(void *, unsigned char *, int), void *p_send )
+{
+    ssl->f_recv     = f_recv;
+    ssl->f_send     = f_send;
+    ssl->p_recv     = p_recv;
+    ssl->p_send     = p_send;
+}
+
+void ssl_set_scb( ssl_context *ssl,
+                  int (*s_get)(ssl_context *),
+                  int (*s_set)(ssl_context *) )
+{
+    ssl->s_get      = s_get;
+    ssl->s_set      = s_set;
+}
+
+void ssl_set_session( ssl_context *ssl, int resume, int timeout,
+                      ssl_session *session )
+{
+    ssl->resume     = resume;
+    ssl->timeout    = timeout;
+    ssl->session    = session;
+}
+
+void ssl_set_ciphers( ssl_context *ssl, int *ciphers )
+{
+    ssl->ciphers    = ciphers;
+}
+
+void ssl_set_ca_chain( ssl_context *ssl, x509_cert *ca_chain,
+                       char *peer_cn )
+{
+    ssl->ca_chain   = ca_chain;
+    ssl->peer_cn    = peer_cn;
+}
+
+void ssl_set_own_cert( ssl_context *ssl, x509_cert *own_cert,
+                       rsa_context *rsa_key )
+{
+    ssl->own_cert   = own_cert;
+    ssl->rsa_key    = rsa_key;
+}
+
+int ssl_set_dh_param( ssl_context *ssl, char *dhm_P, char *dhm_G )
+{
+    int ret;
+
+    if( ( ret = mpi_read_string( &ssl->dhm_ctx.P, 16, dhm_P ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "mpi_read_string", ret );
+        return( ret );
+    }
+
+    if( ( ret = mpi_read_string( &ssl->dhm_ctx.G, 16, dhm_G ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "mpi_read_string", ret );
+        return( ret );
+    }
+
+    return( 0 );
+}
+
+int ssl_set_hostname( ssl_context *ssl, char *hostname )
+{
+    if( hostname == NULL )
+        return( XYSSL_ERR_SSL_BAD_INPUT_DATA );
+
+    ssl->hostname_len = strlen( hostname );
+    ssl->hostname = (unsigned char *) malloc( ssl->hostname_len );
+
+    memcpy( ssl->hostname, (unsigned char *) hostname,
+            ssl->hostname_len );
+
+    return( 0 );
+}
+
+/*
+ * SSL get accessors
+ */
+int ssl_get_bytes_avail( ssl_context *ssl )
+{
+    return( ssl->in_offt == NULL ? 0 : ssl->in_msglen );
+}
+
+int ssl_get_verify_result( ssl_context *ssl )
+{
+    return( ssl->verify_result );
+}
+
+char *ssl_get_cipher( ssl_context *ssl )
+{
+    switch( ssl->session->cipher )
+    {
+#if defined(XYSSL_ARC4_C)
+        case SSL_RSA_RC4_128_MD5:
+            return( "SSL_RSA_RC4_128_MD5" );
+
+        case SSL_RSA_RC4_128_SHA:
+            return( "SSL_RSA_RC4_128_SHA" );
+#endif
+
+#if defined(XYSSL_DES_C)
+        case SSL_RSA_DES_168_SHA:
+            return( "SSL_RSA_DES_168_SHA" );
+
+        case SSL_EDH_RSA_DES_168_SHA:
+            return( "SSL_EDH_RSA_DES_168_SHA" );
+#endif
+
+#if defined(XYSSL_AES_C)
+        case SSL_RSA_AES_128_SHA:
+            return( "SSL_RSA_AES_128_SHA" );
+
+        case SSL_RSA_AES_256_SHA:
+            return( "SSL_RSA_AES_256_SHA" );
+
+        case SSL_EDH_RSA_AES_256_SHA:
+            return( "SSL_EDH_RSA_AES_256_SHA" );
+#endif
+
+    default:
+        break;
+    }
+
+    return( "unknown" );
+}
+
+int ssl_default_ciphers[] =
+{
+#if defined(XYSSL_DHM_C)
+#if defined(XYSSL_AES_C)
+    SSL_EDH_RSA_AES_256_SHA,
+#endif
+#if defined(XYSSL_DES_C)
+    SSL_EDH_RSA_DES_168_SHA,
+#endif
+#endif
+
+#if defined(XYSSL_AES_C)
+    SSL_RSA_AES_128_SHA,
+    SSL_RSA_AES_256_SHA,
+#endif
+#if defined(XYSSL_DES_C)
+    SSL_RSA_DES_168_SHA,
+#endif
+#if defined(XYSSL_ARC4_C)
+    SSL_RSA_RC4_128_SHA,
+    SSL_RSA_RC4_128_MD5,
+#endif
+    0
+};
+
+/*
+ * Perform the SSL handshake
+ */
+int ssl_handshake( ssl_context *ssl )
+{
+    int ret = XYSSL_ERR_SSL_FEATURE_UNAVAILABLE;
+
+    SSL_DEBUG_MSG( 2, ( "=> handshake" ) );
+
+#if defined(XYSSL_SSL_CLI_C)
+    if( ssl->endpoint == SSL_IS_CLIENT )
+        ret = ssl_handshake_client( ssl );
+#endif
+
+#if defined(XYSSL_SSL_SRV_C)
+    if( ssl->endpoint == SSL_IS_SERVER )
+        ret = ssl_handshake_server( ssl );
+#endif
+
+    SSL_DEBUG_MSG( 2, ( "<= handshake" ) );
+
+    return( ret );
+}
+
+/*
+ * Receive application data decrypted from the SSL layer
+ */
+int ssl_read( ssl_context *ssl, unsigned char *buf, int len )
+{
+    int ret, n;
+
+    SSL_DEBUG_MSG( 2, ( "=> read" ) );
+
+    if( ssl->state != SSL_HANDSHAKE_OVER )
+    {
+        if( ( ret = ssl_handshake( ssl ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_handshake", ret );
+            return( ret );
+        }
+    }
+
+    if( ssl->in_offt == NULL )
+    {
+        if( ( ret = ssl_read_record( ssl ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_read_record", ret );
+            return( ret );
+        }
+
+        if( ssl->in_msglen  == 0 &&
+            ssl->in_msgtype == SSL_MSG_APPLICATION_DATA )
+        {
+            /*
+             * OpenSSL sends empty messages to randomize the IV
+             */
+            if( ( ret = ssl_read_record( ssl ) ) != 0 )
+            {
+                SSL_DEBUG_RET( 1, "ssl_read_record", ret );
+                return( ret );
+            }
+        }
+
+        if( ssl->in_msgtype != SSL_MSG_APPLICATION_DATA )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad application data message" ) );
+            return( XYSSL_ERR_SSL_UNEXPECTED_MESSAGE );
+        }
+
+        ssl->in_offt = ssl->in_msg;
+    }
+
+    n = ( len < ssl->in_msglen )
+        ? len : ssl->in_msglen;
+
+    memcpy( buf, ssl->in_offt, n );
+    ssl->in_msglen -= n;
+
+    if( ssl->in_msglen == 0 )
+        /* all bytes consumed  */
+        ssl->in_offt = NULL;
+    else
+        /* more data available */
+        ssl->in_offt += n;
+
+    SSL_DEBUG_MSG( 2, ( "<= read" ) );
+
+    return( n );
+}
+
+/*
+ * Send application data to be encrypted by the SSL layer
+ */
+int ssl_write( ssl_context *ssl, unsigned char *buf, int len )
+{
+    int ret, n;
+
+    SSL_DEBUG_MSG( 2, ( "=> write" ) );
+
+    if( ssl->state != SSL_HANDSHAKE_OVER )
+    {
+        if( ( ret = ssl_handshake( ssl ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_handshake", ret );
+            return( ret );
+        }
+    }
+
+    n = ( len < SSL_MAX_CONTENT_LEN )
+        ? len : SSL_MAX_CONTENT_LEN;
+
+    if( ssl->out_left != 0 )
+    {
+        if( ( ret = ssl_flush_output( ssl ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_flush_output", ret );
+            return( ret );
+        }
+    }
+    else
+    {
+        ssl->out_msglen  = n;
+        ssl->out_msgtype = SSL_MSG_APPLICATION_DATA;
+        memcpy( ssl->out_msg, buf, n );
+
+        if( ( ret = ssl_write_record( ssl ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_write_record", ret );
+            return( ret );
+        }
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= write" ) );
+
+    return( n );
+}
+
+/*
+ * Notify the peer that the connection is being closed
+ */
+int ssl_close_notify( ssl_context *ssl )
+{
+    int ret;
+
+    SSL_DEBUG_MSG( 2, ( "=> write close notify" ) );
+
+    if( ( ret = ssl_flush_output( ssl ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_flush_output", ret );
+        return( ret );
+    }
+
+    if( ssl->state == SSL_HANDSHAKE_OVER )
+    {
+        ssl->out_msgtype = SSL_MSG_ALERT;
+        ssl->out_msglen  = 2;
+        ssl->out_msg[0]  = SSL_ALERT_WARNING;
+        ssl->out_msg[1]  = SSL_ALERT_CLOSE_NOTIFY;
+
+        if( ( ret = ssl_write_record( ssl ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_write_record", ret );
+            return( ret );
+        }
+    }
+
+    SSL_DEBUG_MSG( 2, ( "<= write close notify" ) );
+
+    return( ret );
+}
+
+/*
+ * Free an SSL context
+ */
+void ssl_free( ssl_context *ssl )
+{
+    SSL_DEBUG_MSG( 2, ( "=> free" ) );
+
+    if( ssl->peer_cert != NULL )
+    {
+        x509_free( ssl->peer_cert );
+        memset( ssl->peer_cert, 0, sizeof( x509_cert ) );
+          free( ssl->peer_cert );
+    }
+
+    if( ssl->out_ctr != NULL )
+    {
+        memset( ssl->out_ctr, 0, SSL_BUFFER_LEN );
+          free( ssl->out_ctr );
+    }
+
+    if( ssl->in_ctr != NULL )
+    {
+        memset( ssl->in_ctr, 0, SSL_BUFFER_LEN );
+          free( ssl->in_ctr );
+    }
+
+#if defined(XYSSL_DHM_C)
+    dhm_free( &ssl->dhm_ctx );
+#endif
+
+    if ( ssl->hostname != NULL)
+    {
+        memset( ssl->hostname, 0, ssl->hostname_len );
+        free( ssl->hostname );
+        ssl->hostname_len = 0;
+    }
+
+    memset( ssl, 0, sizeof( ssl_context ) );
+
+    SSL_DEBUG_MSG( 2, ( "<= free" ) );
+}
+
+#endif
diff --git a/library/timing.c b/library/timing.c
new file mode 100644
index 0000000..49fe7f3
--- /dev/null
+++ b/library/timing.c
@@ -0,0 +1,250 @@
+/*
+ *  Portable interface to the CPU cycle counter
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_TIMING_C)
+
+#include "xyssl/timing.h"
+
+#if defined(WIN32)
+
+#include <windows.h>
+#include <winbase.h>
+
+struct _hr_time
+{
+    LARGE_INTEGER start;
+};
+
+#else
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <time.h>
+
+struct _hr_time
+{
+    struct timeval start;
+};
+
+#endif
+
+#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
+
+unsigned long hardclock( void )
+{
+    unsigned long tsc;
+    __asm   rdtsc
+    __asm   mov  [tsc], eax
+    return( tsc );
+}
+
+#else
+#if defined(__GNUC__) && defined(__i386__)
+
+unsigned long hardclock( void )
+{
+    unsigned long tsc;
+    asm( "rdtsc" : "=a" (tsc) );
+    return( tsc );
+}
+
+#else
+#if defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))
+
+unsigned long hardclock( void )
+{
+    unsigned long lo, hi;
+    asm( "rdtsc" : "=a" (lo), "=d" (hi) ); 
+    return( lo | (hi << 32) );
+}
+
+#else
+#if defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
+
+unsigned long hardclock( void )
+{
+    unsigned long tbl, tbu0, tbu1;
+
+    do
+    {
+        asm( "mftbu %0" : "=r" (tbu0) );
+        asm( "mftb  %0" : "=r" (tbl ) );
+        asm( "mftbu %0" : "=r" (tbu1) );
+    }
+    while( tbu0 != tbu1 );
+
+    return( tbl );
+}
+
+#else
+#if defined(__GNUC__) && defined(__sparc__)
+
+unsigned long hardclock( void )
+{
+    unsigned long tick;
+    asm( ".byte 0x83, 0x41, 0x00, 0x00" );
+    asm( "mov   %%g1, %0" : "=r" (tick) );
+    return( tick );
+}
+
+#else
+#if defined(__GNUC__) && defined(__alpha__)
+
+unsigned long hardclock( void )
+{
+    unsigned long cc;
+    asm( "rpcc %0" : "=r" (cc) );
+    return( cc & 0xFFFFFFFF );
+}
+
+#else
+#if defined(__GNUC__) && defined(__ia64__)
+
+unsigned long hardclock( void )
+{
+    unsigned long itc;
+    asm( "mov %0 = ar.itc" : "=r" (itc) );
+    return( itc );
+}
+
+#else
+
+static int hardclock_init = 0;
+static struct timeval tv_init;
+
+unsigned long hardclock( void )
+{
+    struct timeval tv_cur;
+
+    if( hardclock_init == 0 )
+    {
+        gettimeofday( &tv_init, NULL );
+        hardclock_init = 1;
+    }
+
+    gettimeofday( &tv_cur, NULL );
+    return( ( tv_cur.tv_sec  - tv_init.tv_sec  ) * 1000000
+          + ( tv_cur.tv_usec - tv_init.tv_usec ) );
+}
+
+#endif /* generic */
+#endif /* IA-64   */
+#endif /* Alpha   */
+#endif /* SPARC8  */
+#endif /* PowerPC */
+#endif /* AMD64   */
+#endif /* i586+   */
+
+int alarmed = 0;
+
+#if defined(WIN32)
+
+unsigned long get_timer( struct hr_time *val, int reset )
+{
+    unsigned long delta;
+    LARGE_INTEGER offset, hfreq;
+    struct _hr_time *t = (struct _hr_time *) val;
+
+    QueryPerformanceCounter(  &offset );
+    QueryPerformanceFrequency( &hfreq );
+
+    delta = (unsigned long)( ( 1000 *
+        ( offset.QuadPart - t->start.QuadPart ) ) /
+           hfreq.QuadPart );
+
+    if( reset )
+        QueryPerformanceCounter( &t->start );
+
+    return( delta );
+}
+
+DWORD WINAPI TimerProc( LPVOID uElapse )
+{   
+    Sleep( (DWORD) uElapse );
+    alarmed = 1; 
+    return( TRUE );
+}
+
+void set_alarm( int seconds )
+{   
+    DWORD ThreadId;
+
+    alarmed = 0; 
+    CloseHandle( CreateThread( NULL, 0, TimerProc,
+        (LPVOID) ( seconds * 1000 ), 0, &ThreadId ) );
+}
+
+void m_sleep( int milliseconds )
+{
+    Sleep( milliseconds );
+}
+
+#else
+
+unsigned long get_timer( struct hr_time *val, int reset )
+{
+    unsigned long delta;
+    struct timeval offset;
+    struct _hr_time *t = (struct _hr_time *) val;
+
+    gettimeofday( &offset, NULL );
+
+    delta = ( offset.tv_sec  - t->start.tv_sec  ) * 1000
+          + ( offset.tv_usec - t->start.tv_usec ) / 1000;
+
+    if( reset )
+    {
+        t->start.tv_sec  = offset.tv_sec;
+        t->start.tv_usec = offset.tv_usec;
+    }
+
+    return( delta );
+}
+
+static void sighandler( int signum )
+{   
+    alarmed = 1;
+    signal( signum, sighandler );
+}
+
+void set_alarm( int seconds )
+{
+    alarmed = 0;
+    signal( SIGALRM, sighandler );
+    alarm( seconds );
+}
+
+void m_sleep( int milliseconds )
+{
+    struct timeval tv;
+
+    tv.tv_sec  = milliseconds / 1000;
+    tv.tv_usec = milliseconds * 1000;
+
+    select( 0, NULL, NULL, NULL, &tv );
+}
+
+#endif
+
+#endif
diff --git a/library/x509parse.c b/library/x509parse.c
new file mode 100644
index 0000000..5bac80f
--- /dev/null
+++ b/library/x509parse.c
@@ -0,0 +1,1749 @@
+/*
+ *  X.509 certificate and private key decoding
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  The ITU-T X.509 standard defines a certificat format for PKI.
+ *
+ *  http://www.ietf.org/rfc/rfc2459.txt
+ *  http://www.ietf.org/rfc/rfc3279.txt
+ *
+ *  ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
+ *
+ *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
+ *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
+ */
+
+#include "xyssl/config.h"
+
+#if defined(XYSSL_X509_PARSE_C)
+
+#include "xyssl/x509.h"
+#include "xyssl/base64.h"
+#include "xyssl/des.h"
+#include "xyssl/md2.h"
+#include "xyssl/md4.h"
+#include "xyssl/md5.h"
+#include "xyssl/sha1.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+/*
+ * ASN.1 DER decoding routines
+ */
+static int asn1_get_len( unsigned char **p,
+                         unsigned char *end,
+                         int *len )
+{
+    if( ( end - *p ) < 1 )
+        return( XYSSL_ERR_ASN1_OUT_OF_DATA );
+
+    if( ( **p & 0x80 ) == 0 )
+        *len = *(*p)++;
+    else
+    {
+        switch( **p & 0x7F )
+        {
+        case 1:
+            if( ( end - *p ) < 2 )
+                return( XYSSL_ERR_ASN1_OUT_OF_DATA );
+
+            *len = (*p)[1];
+            (*p) += 2;
+            break;
+
+        case 2:
+            if( ( end - *p ) < 3 )
+                return( XYSSL_ERR_ASN1_OUT_OF_DATA );
+
+            *len = ( (*p)[1] << 8 ) | (*p)[2];
+            (*p) += 3;
+            break;
+
+        default:
+            return( XYSSL_ERR_ASN1_INVALID_LENGTH );
+            break;
+        }
+    }
+
+    if( *len > (int) ( end - *p ) )
+        return( XYSSL_ERR_ASN1_OUT_OF_DATA );
+
+    return( 0 );
+}
+
+static int asn1_get_tag( unsigned char **p,
+                         unsigned char *end,
+                         int *len, int tag )
+{
+    if( ( end - *p ) < 1 )
+        return( XYSSL_ERR_ASN1_OUT_OF_DATA );
+
+    if( **p != tag )
+        return( XYSSL_ERR_ASN1_UNEXPECTED_TAG );
+
+    (*p)++;
+
+    return( asn1_get_len( p, end, len ) );
+}
+
+static int asn1_get_bool( unsigned char **p,
+                          unsigned char *end,
+                          int *val )
+{
+    int ret, len;
+
+    if( ( ret = asn1_get_tag( p, end, &len, ASN1_BOOLEAN ) ) != 0 )
+        return( ret );
+
+    if( len != 1 )
+        return( XYSSL_ERR_ASN1_INVALID_LENGTH );
+
+    *val = ( **p != 0 ) ? 1 : 0;
+    (*p)++;
+
+    return( 0 );
+}
+
+static int asn1_get_int( unsigned char **p,
+                         unsigned char *end,
+                         int *val )
+{
+    int ret, len;
+
+    if( ( ret = asn1_get_tag( p, end, &len, ASN1_INTEGER ) ) != 0 )
+        return( ret );
+
+    if( len > (int) sizeof( int ) || ( **p & 0x80 ) != 0 )
+        return( XYSSL_ERR_ASN1_INVALID_LENGTH );
+
+    *val = 0;
+
+    while( len-- > 0 )
+    {
+        *val = ( *val << 8 ) | **p;
+        (*p)++;
+    }
+
+    return( 0 );
+}
+
+static int asn1_get_mpi( unsigned char **p,
+                         unsigned char *end,
+                         mpi *X )
+{
+    int ret, len;
+
+    if( ( ret = asn1_get_tag( p, end, &len, ASN1_INTEGER ) ) != 0 )
+        return( ret );
+
+    ret = mpi_read_binary( X, *p, len );
+
+    *p += len;
+
+    return( ret );
+}
+
+/*
+ *  Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
+ */
+static int x509_get_version( unsigned char **p,
+                             unsigned char *end,
+                             int *ver )
+{
+    int ret, len;
+
+    if( ( ret = asn1_get_tag( p, end, &len,
+            ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) ) != 0 )
+    {
+        if( ret == XYSSL_ERR_ASN1_UNEXPECTED_TAG )
+            return( *ver = 0 );
+
+        return( ret );
+    }
+
+    end = *p + len;
+
+    if( ( ret = asn1_get_int( p, end, ver ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_VERSION | ret );
+
+    if( *p != end )
+        return( XYSSL_ERR_X509_CERT_INVALID_VERSION |
+                XYSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+    return( 0 );
+}
+
+/*
+ *  CertificateSerialNumber  ::=  INTEGER
+ */
+static int x509_get_serial( unsigned char **p,
+                            unsigned char *end,
+                            x509_buf *serial )
+{
+    int ret;
+
+    if( ( end - *p ) < 1 )
+        return( XYSSL_ERR_X509_CERT_INVALID_SERIAL |
+                XYSSL_ERR_ASN1_OUT_OF_DATA );
+
+    if( **p != ( ASN1_CONTEXT_SPECIFIC | ASN1_PRIMITIVE | 2 ) &&
+        **p !=   ASN1_INTEGER )
+        return( XYSSL_ERR_X509_CERT_INVALID_SERIAL |
+                XYSSL_ERR_ASN1_UNEXPECTED_TAG );
+
+    serial->tag = *(*p)++;
+
+    if( ( ret = asn1_get_len( p, end, &serial->len ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_SERIAL | ret );
+
+    serial->p = *p;
+    *p += serial->len;
+
+    return( 0 );
+}
+
+/*
+ *  AlgorithmIdentifier  ::=  SEQUENCE  {
+ *       algorithm               OBJECT IDENTIFIER,
+ *       parameters              ANY DEFINED BY algorithm OPTIONAL  }
+ */
+static int x509_get_alg( unsigned char **p,
+                         unsigned char *end,
+                         x509_buf *alg )
+{
+    int ret, len;
+
+    if( ( ret = asn1_get_tag( p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_ALG | ret );
+
+    end = *p + len;
+    alg->tag = **p;
+
+    if( ( ret = asn1_get_tag( p, end, &alg->len, ASN1_OID ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_ALG | ret );
+
+    alg->p = *p;
+    *p += alg->len;
+
+    if( *p == end )
+        return( 0 );
+
+    /*
+     * assume the algorithm parameters must be NULL
+     */
+    if( ( ret = asn1_get_tag( p, end, &len, ASN1_NULL ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_ALG | ret );
+
+    if( *p != end )
+        return( XYSSL_ERR_X509_CERT_INVALID_ALG |
+                XYSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+    return( 0 );
+}
+
+/*
+ *  RelativeDistinguishedName ::=
+ *    SET OF AttributeTypeAndValue
+ *
+ *  AttributeTypeAndValue ::= SEQUENCE {
+ *    type     AttributeType,
+ *    value    AttributeValue }
+ *
+ *  AttributeType ::= OBJECT IDENTIFIER
+ *
+ *  AttributeValue ::= ANY DEFINED BY AttributeType
+ */
+static int x509_get_name( unsigned char **p,
+                          unsigned char *end,
+                          x509_name *cur )
+{
+    int ret, len;
+    unsigned char *end2;
+    x509_buf *oid;
+    x509_buf *val;
+
+    if( ( ret = asn1_get_tag( p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SET ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_NAME | ret );
+
+    end2 = end;
+    end  = *p + len;
+
+    if( ( ret = asn1_get_tag( p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_NAME | ret );
+
+    if( *p + len != end )
+        return( XYSSL_ERR_X509_CERT_INVALID_NAME |
+                XYSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+    oid = &cur->oid;
+    oid->tag = **p;
+
+    if( ( ret = asn1_get_tag( p, end, &oid->len, ASN1_OID ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_NAME | ret );
+
+    oid->p = *p;
+    *p += oid->len;
+
+    if( ( end - *p ) < 1 )
+        return( XYSSL_ERR_X509_CERT_INVALID_NAME |
+                XYSSL_ERR_ASN1_OUT_OF_DATA );
+
+    if( **p != ASN1_BMP_STRING && **p != ASN1_UTF8_STRING      &&
+        **p != ASN1_T61_STRING && **p != ASN1_PRINTABLE_STRING &&
+        **p != ASN1_IA5_STRING && **p != ASN1_UNIVERSAL_STRING )
+        return( XYSSL_ERR_X509_CERT_INVALID_NAME |
+                XYSSL_ERR_ASN1_UNEXPECTED_TAG );
+
+    val = &cur->val;
+    val->tag = *(*p)++;
+
+    if( ( ret = asn1_get_len( p, end, &val->len ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_NAME | ret );
+
+    val->p = *p;
+    *p += val->len;
+
+    cur->next = NULL;
+
+    if( *p != end )
+        return( XYSSL_ERR_X509_CERT_INVALID_NAME |
+                XYSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+    /*
+     * recurse until end of SEQUENCE is reached
+     */
+    if( *p == end2 )
+        return( 0 );
+
+    cur->next = (x509_name *) malloc(
+         sizeof( x509_name ) );
+
+    if( cur->next == NULL )
+        return( 1 );
+
+    return( x509_get_name( p, end2, cur->next ) );
+}
+
+/*
+ *  Validity ::= SEQUENCE {
+ *       notBefore      Time,
+ *       notAfter       Time }
+ *
+ *  Time ::= CHOICE {
+ *       utcTime        UTCTime,
+ *       generalTime    GeneralizedTime }
+ */
+static int x509_get_dates( unsigned char **p,
+                           unsigned char *end,
+                           x509_time *from,
+                           x509_time *to )
+{
+    int ret, len;
+    char date[64];
+
+    if( ( ret = asn1_get_tag( p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_DATE | ret );
+
+    end = *p + len;
+
+    /*
+     * TODO: also handle GeneralizedTime
+     */
+    if( ( ret = asn1_get_tag( p, end, &len, ASN1_UTC_TIME ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_DATE | ret );
+
+    memset( date,  0, sizeof( date ) );
+    memcpy( date, *p, ( len < (int) sizeof( date ) - 1 ) ?
+                        len : (int) sizeof( date ) - 1 );
+
+    if( sscanf( date, "%2d%2d%2d%2d%2d%2d",
+                &from->year, &from->mon, &from->day,
+                &from->hour, &from->min, &from->sec ) < 5 )
+        return( XYSSL_ERR_X509_CERT_INVALID_DATE );
+
+    from->year +=  100 * ( from->year < 90 );
+    from->year += 1900;
+
+    *p += len;
+
+    if( ( ret = asn1_get_tag( p, end, &len, ASN1_UTC_TIME ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_DATE | ret );
+
+    memset( date,  0, sizeof( date ) );
+    memcpy( date, *p, ( len < (int) sizeof( date ) - 1 ) ?
+                        len : (int) sizeof( date ) - 1 );
+
+    if( sscanf( date, "%2d%2d%2d%2d%2d%2d",
+                &to->year, &to->mon, &to->day,
+                &to->hour, &to->min, &to->sec ) < 5 ) 
+        return( XYSSL_ERR_X509_CERT_INVALID_DATE );
+
+    to->year +=  100 * ( to->year < 90 );
+    to->year += 1900;
+
+    *p += len;
+
+    if( *p != end )
+        return( XYSSL_ERR_X509_CERT_INVALID_DATE |
+                XYSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+    return( 0 );
+}
+
+/*
+ *  SubjectPublicKeyInfo  ::=  SEQUENCE  {
+ *       algorithm            AlgorithmIdentifier,
+ *       subjectPublicKey     BIT STRING }
+ */
+static int x509_get_pubkey( unsigned char **p,
+                            unsigned char *end,
+                            x509_buf *pk_alg_oid,
+                            mpi *N, mpi *E )
+{
+    int ret, len;
+    unsigned char *end2;
+
+    if( ( ret = x509_get_alg( p, end, pk_alg_oid ) ) != 0 )
+        return( ret );
+
+    /*
+     * only RSA public keys handled at this time
+     */
+    if( pk_alg_oid->len != 9 ||
+        memcmp( pk_alg_oid->p, OID_PKCS1_RSA, 9 ) != 0 )
+        return( XYSSL_ERR_X509_CERT_UNKNOWN_PK_ALG );
+
+    if( ( ret = asn1_get_tag( p, end, &len, ASN1_BIT_STRING ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_PUBKEY | ret );
+
+    if( ( end - *p ) < 1 )
+        return( XYSSL_ERR_X509_CERT_INVALID_PUBKEY |
+                XYSSL_ERR_ASN1_OUT_OF_DATA );
+
+    end2 = *p + len;
+
+    if( *(*p)++ != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_PUBKEY );
+
+    /*
+     *  RSAPublicKey ::= SEQUENCE {
+     *      modulus           INTEGER,  -- n
+     *      publicExponent    INTEGER   -- e
+     *  }
+     */
+    if( ( ret = asn1_get_tag( p, end2, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_PUBKEY | ret );
+
+    if( *p + len != end2 )
+        return( XYSSL_ERR_X509_CERT_INVALID_PUBKEY |
+                XYSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+    if( ( ret = asn1_get_mpi( p, end2, N ) ) != 0 ||
+        ( ret = asn1_get_mpi( p, end2, E ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_PUBKEY | ret );
+
+    if( *p != end )
+        return( XYSSL_ERR_X509_CERT_INVALID_PUBKEY |
+                XYSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+    return( 0 );
+}
+
+static int x509_get_sig( unsigned char **p,
+                         unsigned char *end,
+                         x509_buf *sig )
+{
+    int ret, len;
+
+    sig->tag = **p;
+
+    if( ( ret = asn1_get_tag( p, end, &len, ASN1_BIT_STRING ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_SIGNATURE | ret );
+
+    if( --len < 1 || *(*p)++ != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_SIGNATURE );
+
+    sig->len = len;
+    sig->p = *p;
+
+    *p += len;
+
+    return( 0 );
+}
+
+/*
+ * X.509 v2/v3 unique identifier (not parsed)
+ */
+static int x509_get_uid( unsigned char **p,
+                         unsigned char *end,
+                         x509_buf *uid, int n )
+{
+    int ret;
+
+    if( *p == end )
+        return( 0 );
+
+    uid->tag = **p;
+
+    if( ( ret = asn1_get_tag( p, end, &uid->len,
+            ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | n ) ) != 0 )
+    {
+        if( ret == XYSSL_ERR_ASN1_UNEXPECTED_TAG )
+            return( 0 );
+
+        return( ret );
+    }
+
+    uid->p = *p;
+    *p += uid->len;
+
+    return( 0 );
+}
+
+/*
+ * X.509 v3 extensions (only BasicConstraints are parsed)
+ */
+static int x509_get_ext( unsigned char **p,
+                         unsigned char *end,
+                         x509_buf *ext,
+                         int *ca_istrue,
+                         int *max_pathlen )
+{
+    int ret, len;
+    int is_critical = 1;
+    int is_cacert   = 0;
+    unsigned char *end2;
+
+    if( *p == end )
+        return( 0 );
+
+    ext->tag = **p;
+
+    if( ( ret = asn1_get_tag( p, end, &ext->len,
+            ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3 ) ) != 0 )
+    {
+        if( ret == XYSSL_ERR_ASN1_UNEXPECTED_TAG )
+            return( 0 );
+
+        return( ret );
+    }
+
+    ext->p = *p;
+    end = *p + ext->len;
+
+    /*
+     * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
+     *
+     * Extension  ::=  SEQUENCE  {
+     *      extnID      OBJECT IDENTIFIER,
+     *      critical    BOOLEAN DEFAULT FALSE,
+     *      extnValue   OCTET STRING  }
+     */
+    if( ( ret = asn1_get_tag( p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+        return( XYSSL_ERR_X509_CERT_INVALID_EXTENSIONS | ret );
+
+    if( end != *p + len )
+        return( XYSSL_ERR_X509_CERT_INVALID_EXTENSIONS |
+                XYSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+    while( *p < end )
+    {
+        if( ( ret = asn1_get_tag( p, end, &len,
+                ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+            return( XYSSL_ERR_X509_CERT_INVALID_EXTENSIONS | ret );
+
+        if( memcmp( *p, "\x06\x03\x55\x1D\x13", 5 ) != 0 )
+        {
+            *p += len;
+            continue;
+        }
+
+        *p += 5;
+
+        if( ( ret = asn1_get_bool( p, end, &is_critical ) ) != 0 &&
+            ( ret != XYSSL_ERR_ASN1_UNEXPECTED_TAG ) )
+            return( XYSSL_ERR_X509_CERT_INVALID_EXTENSIONS | ret );
+
+        if( ( ret = asn1_get_tag( p, end, &len,
+                ASN1_OCTET_STRING ) ) != 0 )
+            return( XYSSL_ERR_X509_CERT_INVALID_EXTENSIONS | ret );
+
+        /*
+         * BasicConstraints ::= SEQUENCE {
+         *      cA                      BOOLEAN DEFAULT FALSE,
+         *      pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
+         */
+        end2 = *p + len;
+
+        if( ( ret = asn1_get_tag( p, end2, &len,
+                ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+            return( XYSSL_ERR_X509_CERT_INVALID_EXTENSIONS | ret );
+
+        if( *p == end2 )
+            continue;
+
+        if( ( ret = asn1_get_bool( p, end2, &is_cacert ) ) != 0 )
+        {
+            if( ret == XYSSL_ERR_ASN1_UNEXPECTED_TAG )
+                ret = asn1_get_int( p, end2, &is_cacert );
+
+            if( ret != 0 )
+                return( XYSSL_ERR_X509_CERT_INVALID_EXTENSIONS | ret );
+
+            if( is_cacert != 0 )
+                is_cacert  = 1;
+        }
+
+        if( *p == end2 )
+            continue;
+
+        if( ( ret = asn1_get_int( p, end2, max_pathlen ) ) != 0 )
+            return( XYSSL_ERR_X509_CERT_INVALID_EXTENSIONS | ret );
+
+        if( *p != end2 )
+            return( XYSSL_ERR_X509_CERT_INVALID_EXTENSIONS |
+                    XYSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+        max_pathlen++;
+    }
+
+    if( *p != end )
+        return( XYSSL_ERR_X509_CERT_INVALID_EXTENSIONS |
+                XYSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+    *ca_istrue = is_critical & is_cacert;
+
+    return( 0 );
+}
+
+/*
+ * Parse one or more certificates and add them to the chained list
+ */
+int x509parse_crt( x509_cert *chain, unsigned char *buf, int buflen )
+{
+    int ret, len;
+    unsigned char *s1, *s2;
+    unsigned char *p, *end;
+    x509_cert *crt;
+
+    crt = chain;
+
+    while( crt->version != 0 )
+        crt = crt->next;
+
+    /*
+     * check if the certificate is encoded in base64
+     */
+    s1 = (unsigned char *) strstr( (char *) buf,
+        "-----BEGIN CERTIFICATE-----" );
+
+    if( s1 != NULL )
+    {
+        s2 = (unsigned char *) strstr( (char *) buf,
+            "-----END CERTIFICATE-----" );
+
+        if( s2 == NULL || s2 <= s1 )
+            return( XYSSL_ERR_X509_CERT_INVALID_PEM );
+
+        s1 += 27;
+        if( *s1 == '\r' ) s1++;
+        if( *s1 == '\n' ) s1++;
+            else return( XYSSL_ERR_X509_CERT_INVALID_PEM );
+
+        /*
+         * get the DER data length and decode the buffer
+         */
+        len = 0;
+        ret = base64_decode( NULL, &len, s1, s2 - s1 );
+
+        if( ret == XYSSL_ERR_BASE64_INVALID_CHARACTER )
+            return( XYSSL_ERR_X509_CERT_INVALID_PEM | ret );
+
+        if( ( p = (unsigned char *) malloc( len ) ) == NULL )
+            return( 1 );
+            
+        if( ( ret = base64_decode( p, &len, s1, s2 - s1 ) ) != 0 )
+        {
+            free( p );
+            return( XYSSL_ERR_X509_CERT_INVALID_PEM | ret );
+        }
+
+        /*
+         * update the buffer size and offset
+         */
+        s2 += 25;
+        if( *s2 == '\r' ) s2++;
+        if( *s2 == '\n' ) s2++;
+        else
+        {
+            free( p );
+            return( XYSSL_ERR_X509_CERT_INVALID_PEM );
+        }
+
+        buflen -= s2 - buf;
+        buf = s2;
+    }
+    else
+    {
+        /*
+         * nope, copy the raw DER data
+         */
+        p = (unsigned char *) malloc( len = buflen );
+
+        if( p == NULL )
+            return( 1 );
+
+        memcpy( p, buf, buflen );
+
+        buflen = 0;
+    }
+
+    crt->raw.p = p;
+    crt->raw.len = len;
+    end = p + len;
+
+    /*
+     * Certificate  ::=  SEQUENCE  {
+     *      tbsCertificate       TBSCertificate,
+     *      signatureAlgorithm   AlgorithmIdentifier,
+     *      signatureValue       BIT STRING  }
+     */
+    if( ( ret = asn1_get_tag( &p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+          x509_free( crt );
+        return( XYSSL_ERR_X509_CERT_INVALID_FORMAT );
+    }
+
+    if( len != (int) ( end - p ) )
+    {
+          x509_free( crt );
+        return( XYSSL_ERR_X509_CERT_INVALID_FORMAT |
+                XYSSL_ERR_ASN1_LENGTH_MISMATCH );
+    }
+
+    /*
+     * TBSCertificate  ::=  SEQUENCE  {
+     */
+    crt->tbs.p = p;
+
+    if( ( ret = asn1_get_tag( &p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+          x509_free( crt );
+        return( XYSSL_ERR_X509_CERT_INVALID_FORMAT | ret );
+    }
+
+    end = p + len;
+    crt->tbs.len = end - crt->tbs.p;
+
+    /*
+     * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
+     *
+     * CertificateSerialNumber  ::=  INTEGER
+     *
+     * signature            AlgorithmIdentifier
+     */
+    if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 ||
+        ( ret = x509_get_serial(  &p, end, &crt->serial  ) ) != 0 ||
+        ( ret = x509_get_alg(  &p, end, &crt->sig_oid1   ) ) != 0 )
+    {
+          x509_free( crt );
+        return( ret );
+    }
+
+    crt->version++;
+
+    if( crt->version > 3 )
+    {
+          x509_free( crt );
+        return( XYSSL_ERR_X509_CERT_UNKNOWN_VERSION );
+    }
+
+    if( crt->sig_oid1.len != 9 ||
+        memcmp( crt->sig_oid1.p, OID_PKCS1, 8 ) != 0 )
+    {
+          x509_free( crt );
+        return( XYSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG );
+    }
+
+    if( crt->sig_oid1.p[8] < 2 ||
+        crt->sig_oid1.p[8] > 5 )
+    {
+          x509_free( crt );
+        return( XYSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG );
+    }
+
+    /*
+     * issuer               Name
+     */
+    crt->issuer_raw.p = p;
+
+    if( ( ret = asn1_get_tag( &p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+          x509_free( crt );
+        return( XYSSL_ERR_X509_CERT_INVALID_FORMAT | ret );
+    }
+
+    if( ( ret = x509_get_name( &p, p + len, &crt->issuer ) ) != 0 )
+    {
+          x509_free( crt );
+        return( ret );
+    }
+
+    crt->issuer_raw.len = p - crt->issuer_raw.p;
+
+    /*
+     * Validity ::= SEQUENCE {
+     *      notBefore      Time,
+     *      notAfter       Time }
+     *
+     */
+    if( ( ret = x509_get_dates( &p, end, &crt->valid_from,
+                                         &crt->valid_to ) ) != 0 )
+    {
+          x509_free( crt );
+        return( ret );
+    }
+
+    /*
+     * subject              Name
+     */
+    crt->subject_raw.p = p;
+
+    if( ( ret = asn1_get_tag( &p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+          x509_free( crt );
+        return( XYSSL_ERR_X509_CERT_INVALID_FORMAT | ret );
+    }
+
+    if( ( ret = x509_get_name( &p, p + len, &crt->subject ) ) != 0 )
+    {
+          x509_free( crt );
+        return( ret );
+    }
+
+    crt->subject_raw.len = p - crt->subject_raw.p;
+
+    /*
+     * SubjectPublicKeyInfo  ::=  SEQUENCE
+     *      algorithm            AlgorithmIdentifier,
+     *      subjectPublicKey     BIT STRING  }
+     */
+    if( ( ret = asn1_get_tag( &p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+          x509_free( crt );
+        return( XYSSL_ERR_X509_CERT_INVALID_FORMAT | ret );
+    }
+
+    if( ( ret = x509_get_pubkey( &p, p + len, &crt->pk_oid,
+                                 &crt->rsa.N, &crt->rsa.E ) ) != 0 )
+    {
+          x509_free( crt );
+        return( ret );
+    }
+
+    if( ( ret = rsa_check_pubkey( &crt->rsa ) ) != 0 )
+    {
+          x509_free( crt );
+        return( ret );
+    }
+
+    crt->rsa.len = mpi_size( &crt->rsa.N );
+
+    /*
+     *  issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
+     *                       -- If present, version shall be v2 or v3
+     *  subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
+     *                       -- If present, version shall be v2 or v3
+     *  extensions      [3]  EXPLICIT Extensions OPTIONAL
+     *                       -- If present, version shall be v3
+     */
+    if( crt->version == 2 || crt->version == 3 )
+    {
+        ret = x509_get_uid( &p, end, &crt->issuer_id,  1 );
+        if( ret != 0 )
+        {
+              x509_free( crt );
+            return( ret );
+        }
+    }
+
+    if( crt->version == 2 || crt->version == 3 )
+    {
+        ret = x509_get_uid( &p, end, &crt->subject_id,  2 );
+        if( ret != 0 )
+        {
+              x509_free( crt );
+            return( ret );
+        }
+    }
+
+    if( crt->version == 3 )
+    {
+        ret = x509_get_ext( &p, end, &crt->v3_ext,
+                            &crt->ca_istrue, &crt->max_pathlen );
+        if( ret != 0 )
+        {
+              x509_free( crt );
+            return( ret );
+        }
+    }
+
+    if( p != end )
+    {
+          x509_free( crt );
+        return( XYSSL_ERR_X509_CERT_INVALID_FORMAT |
+                XYSSL_ERR_ASN1_LENGTH_MISMATCH );
+    }
+
+    end = crt->raw.p + crt->raw.len;
+
+    /*
+     *  signatureAlgorithm   AlgorithmIdentifier,
+     *  signatureValue       BIT STRING
+     */
+    if( ( ret = x509_get_alg( &p, end, &crt->sig_oid2 ) ) != 0 )
+    {
+          x509_free( crt );
+        return( ret );
+    }
+
+    if( memcmp( crt->sig_oid1.p, crt->sig_oid2.p, 9 ) != 0 )
+    {
+          x509_free( crt );
+        return( XYSSL_ERR_X509_CERT_SIG_MISMATCH );
+    }
+
+    if( ( ret = x509_get_sig( &p, end, &crt->sig ) ) != 0 )
+    {
+          x509_free( crt );
+        return( ret );
+    }
+
+    if( p != end )
+    {
+          x509_free( crt );
+        return( XYSSL_ERR_X509_CERT_INVALID_FORMAT |
+                XYSSL_ERR_ASN1_LENGTH_MISMATCH );
+    }
+
+    crt->next = (x509_cert *) malloc( sizeof( x509_cert ) );
+
+    if( crt->next == NULL )
+    {
+          x509_free( crt );
+        return( 1 );
+    }
+
+    crt = crt->next;
+    memset( crt, 0, sizeof( x509_cert ) );
+
+    if( buflen > 0 )
+        return( x509parse_crt( crt, buf, buflen ) );
+
+    return( 0 );
+}
+
+/*
+ * Load one or more certificates and add them to the chained list
+ */
+int x509parse_crtfile( x509_cert *chain, char *path )
+{
+    int ret;
+    FILE *f;
+    size_t n;
+    unsigned char *buf;
+
+    if( ( f = fopen( path, "rb" ) ) == NULL )
+        return( 1 );
+
+    fseek( f, 0, SEEK_END );
+    n = (size_t) ftell( f );
+    fseek( f, 0, SEEK_SET );
+
+    if( ( buf = (unsigned char *) malloc( n + 1 ) ) == NULL )
+        return( 1 );
+
+    if( fread( buf, 1, n, f ) != n )
+    {
+        fclose( f );
+        free( buf );
+        return( 1 );
+    }
+
+    buf[n] = '\0';
+
+    ret = x509parse_crt( chain, buf, (int) n );
+
+    memset( buf, 0, n + 1 );
+    free( buf );
+    fclose( f );
+
+    return( ret );
+}
+
+#if defined(XYSSL_DES_C)
+/*
+ * Read a 16-byte hex string and convert it to binary
+ */
+static int x509_get_iv( unsigned char *s, unsigned char iv[8] )
+{
+    int i, j, k;
+
+    memset( iv, 0, 8 );
+
+    for( i = 0; i < 16; i++, s++ )
+    {
+        if( *s >= '0' && *s <= '9' ) j = *s - '0'; else
+        if( *s >= 'A' && *s <= 'F' ) j = *s - '7'; else
+        if( *s >= 'a' && *s <= 'f' ) j = *s - 'W'; else
+            return( XYSSL_ERR_X509_KEY_INVALID_ENC_IV );
+
+        k = ( ( i & 1 ) != 0 ) ? j : j << 4;
+
+        iv[i >> 1] = (unsigned char)( iv[i >> 1] | k );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Decrypt with 3DES-CBC, using PBKDF1 for key derivation
+ */
+static void x509_des3_decrypt( unsigned char des3_iv[8],
+                               unsigned char *buf, int buflen,
+                               unsigned char *pwd, int pwdlen )
+{
+    md5_context md5_ctx;
+    des3_context des3_ctx;
+    unsigned char md5sum[16];
+    unsigned char des3_key[24];
+
+    /*
+     * 3DES key[ 0..15] = MD5(pwd || IV)
+     *      key[16..23] = MD5(pwd || IV || 3DES key[ 0..15])
+     */
+    md5_starts( &md5_ctx );
+    md5_update( &md5_ctx, pwd, pwdlen );
+    md5_update( &md5_ctx, des3_iv,  8 );
+    md5_finish( &md5_ctx, md5sum );
+    memcpy( des3_key, md5sum, 16 );
+
+    md5_starts( &md5_ctx );
+    md5_update( &md5_ctx, md5sum,  16 );
+    md5_update( &md5_ctx, pwd, pwdlen );
+    md5_update( &md5_ctx, des3_iv,  8 );
+    md5_finish( &md5_ctx, md5sum );
+    memcpy( des3_key + 16, md5sum, 8 );
+
+    des3_set3key_dec( &des3_ctx, des3_key );
+    des3_crypt_cbc( &des3_ctx, DES_DECRYPT, buflen,
+                     des3_iv, buf, buf );
+
+    memset(  &md5_ctx, 0, sizeof(  md5_ctx ) );
+    memset( &des3_ctx, 0, sizeof( des3_ctx ) );
+    memset( md5sum, 0, 16 );
+    memset( des3_key, 0, 24 );
+}
+#endif
+
+/*
+ * Parse a private RSA key
+ */
+int x509parse_key( rsa_context *rsa, unsigned char *buf, int buflen,
+                                     unsigned char *pwd, int pwdlen )
+{
+    int ret, len, enc;
+    unsigned char *s1, *s2;
+    unsigned char *p, *end;
+    unsigned char des3_iv[8];
+
+    s1 = (unsigned char *) strstr( (char *) buf,
+        "-----BEGIN RSA PRIVATE KEY-----" );
+
+    if( s1 != NULL )
+    {
+        s2 = (unsigned char *) strstr( (char *) buf,
+            "-----END RSA PRIVATE KEY-----" );
+
+        if( s2 == NULL || s2 <= s1 )
+            return( XYSSL_ERR_X509_KEY_INVALID_PEM );
+
+        s1 += 31;
+        if( *s1 == '\r' ) s1++;
+        if( *s1 == '\n' ) s1++;
+            else return( XYSSL_ERR_X509_KEY_INVALID_PEM );
+
+        enc = 0;
+
+        if( memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 )
+        {
+#if defined(XYSSL_DES_C)
+            enc++;
+
+            s1 += 22;
+            if( *s1 == '\r' ) s1++;
+            if( *s1 == '\n' ) s1++;
+                else return( XYSSL_ERR_X509_KEY_INVALID_PEM );
+
+            if( memcmp( s1, "DEK-Info: DES-EDE3-CBC,", 23 ) != 0 )
+                return( XYSSL_ERR_X509_KEY_UNKNOWN_ENC_ALG );
+
+            s1 += 23;
+            if( x509_get_iv( s1, des3_iv ) != 0 )
+                return( XYSSL_ERR_X509_KEY_INVALID_ENC_IV );
+
+            s1 += 16;
+            if( *s1 == '\r' ) s1++;
+            if( *s1 == '\n' ) s1++;
+                else return( XYSSL_ERR_X509_KEY_INVALID_PEM );
+#else
+            return( XYSSL_ERR_X509_FEATURE_UNAVAILABLE );
+#endif
+        }
+
+        len = 0;
+        ret = base64_decode( NULL, &len, s1, s2 - s1 );
+
+        if( ret == XYSSL_ERR_BASE64_INVALID_CHARACTER )
+            return( ret | XYSSL_ERR_X509_KEY_INVALID_PEM );
+
+        if( ( buf = (unsigned char *) malloc( len ) ) == NULL )
+            return( 1 );
+
+        if( ( ret = base64_decode( buf, &len, s1, s2 - s1 ) ) != 0 )
+        {
+            free( buf );
+            return( ret | XYSSL_ERR_X509_KEY_INVALID_PEM );
+        }
+
+        buflen = len;
+
+        if( enc != 0 )
+        {
+#if defined(XYSSL_DES_C)
+            if( pwd == NULL )
+            {
+                free( buf );
+                return( XYSSL_ERR_X509_KEY_PASSWORD_REQUIRED );
+            }
+
+            x509_des3_decrypt( des3_iv, buf, buflen, pwd, pwdlen );
+
+            if( buf[0] != 0x30 || buf[1] != 0x82 ||
+                buf[4] != 0x02 || buf[5] != 0x01 )
+            {
+                free( buf );
+                return( XYSSL_ERR_X509_KEY_PASSWORD_MISMATCH );
+            }
+#else
+            return( XYSSL_ERR_X509_FEATURE_UNAVAILABLE );
+#endif
+        }
+    }
+
+    memset( rsa, 0, sizeof( rsa_context ) );
+
+    p = buf;
+    end = buf + buflen;
+
+    /*
+     *  RSAPrivateKey ::= SEQUENCE {
+     *      version           Version,
+     *      modulus           INTEGER,  -- n
+     *      publicExponent    INTEGER,  -- e
+     *      privateExponent   INTEGER,  -- d
+     *      prime1            INTEGER,  -- p
+     *      prime2            INTEGER,  -- q
+     *      exponent1         INTEGER,  -- d mod (p-1)
+     *      exponent2         INTEGER,  -- d mod (q-1)
+     *      coefficient       INTEGER,  -- (inverse of q) mod p
+     *      otherPrimeInfos   OtherPrimeInfos OPTIONAL
+     *  }
+     */
+    if( ( ret = asn1_get_tag( &p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+        if( s1 != NULL )
+            free( buf );
+
+        rsa_free( rsa );
+        return( XYSSL_ERR_X509_KEY_INVALID_FORMAT | ret );
+    }
+
+    end = p + len;
+
+    if( ( ret = asn1_get_int( &p, end, &rsa->ver ) ) != 0 )
+    {
+        if( s1 != NULL )
+            free( buf );
+
+        rsa_free( rsa );
+        return( XYSSL_ERR_X509_KEY_INVALID_FORMAT | ret );
+    }
+
+    if( rsa->ver != 0 )
+    {
+        if( s1 != NULL )
+            free( buf );
+
+        rsa_free( rsa );
+        return( ret | XYSSL_ERR_X509_KEY_INVALID_VERSION );
+    }
+
+    if( ( ret = asn1_get_mpi( &p, end, &rsa->N  ) ) != 0 ||
+        ( ret = asn1_get_mpi( &p, end, &rsa->E  ) ) != 0 ||
+        ( ret = asn1_get_mpi( &p, end, &rsa->D  ) ) != 0 ||
+        ( ret = asn1_get_mpi( &p, end, &rsa->P  ) ) != 0 ||
+        ( ret = asn1_get_mpi( &p, end, &rsa->Q  ) ) != 0 ||
+        ( ret = asn1_get_mpi( &p, end, &rsa->DP ) ) != 0 ||
+        ( ret = asn1_get_mpi( &p, end, &rsa->DQ ) ) != 0 ||
+        ( ret = asn1_get_mpi( &p, end, &rsa->QP ) ) != 0 )
+    {
+        if( s1 != NULL )
+            free( buf );
+
+        rsa_free( rsa );
+        return( ret | XYSSL_ERR_X509_KEY_INVALID_FORMAT );
+    }
+
+    rsa->len = mpi_size( &rsa->N );
+
+    if( p != end )
+    {
+        if( s1 != NULL )
+            free( buf );
+
+        rsa_free( rsa );
+        return( XYSSL_ERR_X509_KEY_INVALID_FORMAT |
+                XYSSL_ERR_ASN1_LENGTH_MISMATCH );
+    }
+
+    if( ( ret = rsa_check_privkey( rsa ) ) != 0 )
+    {
+        if( s1 != NULL )
+            free( buf );
+
+        rsa_free( rsa );
+        return( ret );
+    }
+
+    if( s1 != NULL )
+        free( buf );
+
+    return( 0 );
+}
+
+/*
+ * Load and parse a private RSA key
+ */
+int x509parse_keyfile( rsa_context *rsa, char *path, char *pwd )
+{
+    int ret;
+    FILE *f;
+    size_t n;
+    unsigned char *buf;
+
+    if( ( f = fopen( path, "rb" ) ) == NULL )
+        return( 1 );
+
+    fseek( f, 0, SEEK_END );
+    n = (size_t) ftell( f );
+    fseek( f, 0, SEEK_SET );
+
+    if( ( buf = (unsigned char *) malloc( n + 1 ) ) == NULL )
+        return( 1 );
+
+    if( fread( buf, 1, n, f ) != n )
+    {
+        fclose( f );
+        free( buf );
+        return( 1 );
+    }
+
+    buf[n] = '\0';
+
+    if( pwd == NULL )
+        ret = x509parse_key( rsa, buf, (int) n, NULL, 0 );
+    else
+        ret = x509parse_key( rsa, buf, (int) n,
+                (unsigned char *) pwd, strlen( pwd ) );
+
+    memset( buf, 0, n + 1 );
+    free( buf );
+    fclose( f );
+
+    return( ret );
+}
+
+#if defined _MSC_VER && !defined snprintf
+#define snprintf _snprintf
+#endif
+
+/*
+ * Store the name in printable form into buf; no more
+ * than (end - buf) characters will be written
+ */
+int x509parse_dn_gets( char *buf, char *end, x509_name *dn )
+{
+    int i;
+    unsigned char c;
+    x509_name *name;
+    char s[128], *p;
+
+    memset( s, 0, sizeof( s ) );
+
+    name = dn;
+    p = buf;
+
+    while( name != NULL )
+    {
+        if( name != dn )
+            p += snprintf( p, end - p, ", " );
+
+        if( memcmp( name->oid.p, OID_X520, 2 ) == 0 )
+        {
+            switch( name->oid.p[2] )
+            {
+            case X520_COMMON_NAME:
+                p += snprintf( p, end - p, "CN=" ); break;
+
+            case X520_COUNTRY:
+                p += snprintf( p, end - p, "C="  ); break;
+
+            case X520_LOCALITY:
+                p += snprintf( p, end - p, "L="  ); break;
+
+            case X520_STATE:
+                p += snprintf( p, end - p, "ST=" ); break;
+
+            case X520_ORGANIZATION:
+                p += snprintf( p, end - p, "O="  ); break;
+
+            case X520_ORG_UNIT:
+                p += snprintf( p, end - p, "OU=" ); break;
+
+            default:
+                p += snprintf( p, end - p, "0x%02X=",
+                               name->oid.p[2] );
+                break;
+            }
+        }
+        else if( memcmp( name->oid.p, OID_PKCS9, 8 ) == 0 )
+        {
+            switch( name->oid.p[8] )
+            {
+            case PKCS9_EMAIL:
+                p += snprintf( p, end - p, "emailAddress=" ); break;
+
+            default:
+                p += snprintf( p, end - p, "0x%02X=",
+                               name->oid.p[8] );
+                break;
+            }
+        }
+        else
+            p += snprintf( p, end - p, "\?\?=" );
+
+        for( i = 0; i < name->val.len; i++ )
+        {
+            if( i >= (int) sizeof( s ) - 1 )
+                break;
+
+            c = name->val.p[i];
+            if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
+                 s[i] = '?';
+            else s[i] = c;
+        }
+        s[i] = '\0';
+        p += snprintf( p, end - p, "%s", s );
+        name = name->next;
+    }
+
+    return( p - buf );
+}
+
+/*
+ * Return an informational string about the
+ * certificate, or NULL if memory allocation failed
+ */
+char *x509parse_cert_info( char *prefix, x509_cert *crt )
+{
+    int i, n;
+    char *p, *end;
+    static char buf[512];
+
+    p = buf;
+    end = buf + sizeof( buf ) - 1;
+
+    p += snprintf( p, end - p, "%scert. version : %d\n",
+                               prefix, crt->version );
+    p += snprintf( p, end - p, "%sserial number : ",
+                               prefix );
+
+    n = ( crt->serial.len <= 32 )
+        ? crt->serial.len  : 32;
+
+    for( i = 0; i < n; i++ )
+        p += snprintf( p, end - p, "%02X%s",
+                crt->serial.p[i], ( i < n - 1 ) ? ":" : "" );
+
+    p += snprintf( p, end - p, "\n%sissuer  name  : ", prefix );
+    p += x509parse_dn_gets( p, end, &crt->issuer  );
+
+    p += snprintf( p, end - p, "\n%ssubject name  : ", prefix );
+    p += x509parse_dn_gets( p, end, &crt->subject );
+
+    p += snprintf( p, end - p, "\n%sissued  on    : " \
+                   "%04d-%02d-%02d %02d:%02d:%02d", prefix,
+                   crt->valid_from.year, crt->valid_from.mon,
+                   crt->valid_from.day,  crt->valid_from.hour,
+                   crt->valid_from.min,  crt->valid_from.sec );
+
+    p += snprintf( p, end - p, "\n%sexpires on    : " \
+                   "%04d-%02d-%02d %02d:%02d:%02d", prefix,
+                   crt->valid_to.year, crt->valid_to.mon,
+                   crt->valid_to.day,  crt->valid_to.hour,
+                   crt->valid_to.min,  crt->valid_to.sec );
+
+    p += snprintf( p, end - p, "\n%ssigned using  : RSA+", prefix );
+
+    switch( crt->sig_oid1.p[8] )
+    {
+        case RSA_MD2 : p += snprintf( p, end - p, "MD2"  ); break;
+        case RSA_MD4 : p += snprintf( p, end - p, "MD4"  ); break;
+        case RSA_MD5 : p += snprintf( p, end - p, "MD5"  ); break;
+        case RSA_SHA1: p += snprintf( p, end - p, "SHA1" ); break;
+        default: p += snprintf( p, end - p, "???"  ); break;
+    }
+
+    p += snprintf( p, end - p, "\n%sRSA key size  : %d bits\n", prefix,
+                   crt->rsa.N.n * (int) sizeof( unsigned long ) * 8 );
+
+    return( buf );
+}
+
+/*
+ * Return 0 if the certificate is still valid, or BADCERT_EXPIRED
+ */
+int x509parse_expired( x509_cert *crt )
+{
+    struct tm *lt;
+    time_t tt;
+
+    tt = time( NULL );
+    lt = localtime( &tt );
+
+    if( lt->tm_year  > crt->valid_to.year - 1900 )
+        return( BADCERT_EXPIRED );
+
+    if( lt->tm_year == crt->valid_to.year - 1900 &&
+        lt->tm_mon   > crt->valid_to.mon  - 1 )
+        return( BADCERT_EXPIRED );
+
+    if( lt->tm_year == crt->valid_to.year - 1900 &&
+        lt->tm_mon  == crt->valid_to.mon  - 1    &&
+        lt->tm_mday  > crt->valid_to.day )
+        return( BADCERT_EXPIRED );
+
+    return( 0 );
+}
+
+static void x509_hash( unsigned char *in, int len, int alg,
+                       unsigned char *out )
+{
+    switch( alg )
+    {
+#if defined(XYSSL_MD2_C)
+        case RSA_MD2  :  md2( in, len, out ); break;
+#endif
+#if defined(XYSSL_MD4_C)
+        case RSA_MD4  :  md4( in, len, out ); break;
+#endif
+        case RSA_MD5  :  md5( in, len, out ); break;
+        case RSA_SHA1 : sha1( in, len, out ); break;
+        default:
+            memset( out, '\xFF', len );
+            break;
+    }
+}
+
+/*
+ * Verify the certificate validity
+ */
+int x509parse_verify( x509_cert *crt,
+                      x509_cert *trust_ca,
+                      char *cn, int *flags )
+{
+    int cn_len;
+    int hash_id;
+    int pathlen;
+    x509_cert *cur;
+    x509_name *name;
+    unsigned char hash[20];
+
+    *flags = x509parse_expired( crt );
+
+    if( cn != NULL )
+    {
+        name = &crt->subject;
+        cn_len = strlen( cn );
+
+        while( name != NULL )
+        {
+            if( memcmp( name->oid.p, OID_CN,  3 ) == 0 &&
+                memcmp( name->val.p, cn, cn_len ) == 0 &&
+                name->val.len == cn_len )
+                break;
+
+            name = name->next;
+        }
+
+        if( name == NULL )
+            *flags |= BADCERT_CN_MISMATCH;
+    }
+
+    *flags |= BADCERT_NOT_TRUSTED;
+
+    /*
+     * Iterate upwards in the given cert chain,
+     * ignoring any upper cert with CA != TRUE.
+     */
+    cur = crt->next;
+
+    pathlen = 1;
+
+    while( cur->version != 0 )
+    {
+        if( cur->ca_istrue == 0 ||
+            crt->issuer_raw.len != cur->subject_raw.len ||
+            memcmp( crt->issuer_raw.p, cur->subject_raw.p,
+                    crt->issuer_raw.len ) != 0 )
+        {
+            cur = cur->next;
+            continue;
+        }
+
+        hash_id = crt->sig_oid1.p[8];
+
+        x509_hash( crt->tbs.p, crt->tbs.len, hash_id, hash );
+
+        if( rsa_pkcs1_verify( &cur->rsa, RSA_PUBLIC, hash_id,
+                              0, hash, crt->sig.p ) != 0 )
+            return( XYSSL_ERR_X509_CERT_VERIFY_FAILED );
+
+        pathlen++;
+
+        crt = cur;
+        cur = crt->next;
+    }
+
+    /*
+     * Atempt to validate topmost cert with our CA chain.
+     */
+    while( trust_ca->version != 0 )
+    {
+        if( crt->issuer_raw.len != trust_ca->subject_raw.len ||
+            memcmp( crt->issuer_raw.p, trust_ca->subject_raw.p,
+                    crt->issuer_raw.len ) != 0 )
+        {
+            trust_ca = trust_ca->next;
+            continue;
+        }
+
+        if( trust_ca->max_pathlen > 0 &&
+            trust_ca->max_pathlen < pathlen )
+            break;
+
+        hash_id = crt->sig_oid1.p[8];
+
+        x509_hash( crt->tbs.p, crt->tbs.len, hash_id, hash );
+
+        if( rsa_pkcs1_verify( &trust_ca->rsa, RSA_PUBLIC, hash_id,
+                              0, hash, crt->sig.p ) == 0 )
+        {
+            /*
+             * cert. is signed by a trusted CA
+             */
+            *flags &= ~BADCERT_NOT_TRUSTED;
+            break;
+        }
+
+        trust_ca = trust_ca->next;
+    }
+
+    if( *flags != 0 )
+        return( XYSSL_ERR_X509_CERT_VERIFY_FAILED );
+
+    return( 0 );
+}
+
+/*
+ * Unallocate all certificate data
+ */
+void x509_free( x509_cert *crt )
+{
+    x509_cert *cert_cur = crt;
+    x509_cert *cert_prv;
+    x509_name *name_cur;
+    x509_name *name_prv;
+
+    if( crt == NULL )
+        return;
+
+    do
+    {
+        rsa_free( &cert_cur->rsa );
+
+        name_cur = cert_cur->issuer.next;
+        while( name_cur != NULL )
+        {
+            name_prv = name_cur;
+            name_cur = name_cur->next;
+            memset( name_prv, 0, sizeof( x509_name ) );
+            free( name_prv );
+        }
+
+        name_cur = cert_cur->subject.next;
+        while( name_cur != NULL )
+        {
+            name_prv = name_cur;
+            name_cur = name_cur->next;
+            memset( name_prv, 0, sizeof( x509_name ) );
+            free( name_prv );
+        }
+
+        if( cert_cur->raw.p != NULL )
+        {
+            memset( cert_cur->raw.p, 0, cert_cur->raw.len );
+            free( cert_cur->raw.p );
+        }
+
+        cert_cur = cert_cur->next;
+    }
+    while( cert_cur != NULL );
+
+    cert_cur = crt;
+    do
+    {
+        cert_prv = cert_cur;
+        cert_cur = cert_cur->next;
+
+        memset( cert_prv, 0, sizeof( x509_cert ) );
+        if( cert_prv != crt )
+            free( cert_prv );
+    }
+    while( cert_cur != NULL );
+}
+
+#if defined(XYSSL_SELF_TEST)
+
+#include "xyssl/certs.h"
+
+/*
+ * Checkup routine
+ */
+int x509_self_test( int verbose )
+{
+    int ret, i, j;
+    x509_cert cacert;
+    x509_cert clicert;
+    rsa_context rsa;
+
+    if( verbose != 0 )
+        printf( "  X.509 certificate load: " );
+
+    memset( &clicert, 0, sizeof( x509_cert ) );
+
+    ret = x509parse_crt( &clicert, (unsigned char *) test_cli_crt,
+                         strlen( test_cli_crt ) );
+    if( ret != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( ret );
+    }
+
+    memset( &cacert, 0, sizeof( x509_cert ) );
+
+    ret = x509parse_crt( &cacert, (unsigned char *) test_ca_crt,
+                         strlen( test_ca_crt ) );
+    if( ret != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( ret );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n  X.509 private key load: " );
+
+    i = strlen( test_ca_key );
+    j = strlen( test_ca_pwd );
+
+    if( ( ret = x509parse_key( &rsa,
+                    (unsigned char *) test_ca_key, i,
+                    (unsigned char *) test_ca_pwd, j ) ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( ret );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n  X.509 signature verify: ");
+
+    ret = x509parse_verify( &clicert, &cacert, "Joe User", &i );
+    if( ret != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( ret );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n\n" );
+
+    x509_free( &cacert  );
+    x509_free( &clicert );
+    rsa_free( &rsa );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/programs/Makefile b/programs/Makefile
new file mode 100644
index 0000000..5771a57
--- /dev/null
+++ b/programs/Makefile
@@ -0,0 +1,97 @@
+
+# To compile on SunOS: add "-lsocket -lnsl" to LDFLAGS
+# To compile on MinGW: add "-lws2_32" to LDFLAGS
+
+CFLAGS	= -I../include -D_FILE_OFFSET_BITS=64
+OFLAGS	= -O
+LDFLAGS	= -L../library -lxyssl
+
+APPS =	aes/aescrypt2		hash/hello		\
+	hash/md5sum		hash/sha1sum		\
+	hash/sha2sum		pkey/dh_client		\
+	pkey/dh_genprime	pkey/dh_server		\
+	pkey/mpi_demo		pkey/rsa_genkey		\
+	pkey/rsa_sign		pkey/rsa_verify		\
+	ssl/ssl_client1		ssl/ssl_client2		\
+	ssl/ssl_server		test/benchmark		\
+	test/selftest		test/ssl_test
+
+.SILENT:
+
+all: $(APPS)
+
+aes/aescrypt2: aes/aescrypt2.c ../library/libxyssl.a
+	echo   "  CC    aes/aescrypt2.c"
+	$(CC) $(CFLAGS) $(OFLAGS) aes/aescrypt2.c    $(LDFLAGS) -o $@
+
+hash/hello: hash/hello.c ../library/libxyssl.a
+	echo   "  CC    hash/hello.c"
+	$(CC) $(CFLAGS) $(OFLAGS) hash/hello.c       $(LDFLAGS) -o $@
+
+hash/md5sum: hash/md5sum.c ../library/libxyssl.a
+	echo   "  CC    hash/md5sum.c"
+	$(CC) $(CFLAGS) $(OFLAGS) hash/md5sum.c      $(LDFLAGS) -o $@
+
+hash/sha1sum: hash/sha1sum.c ../library/libxyssl.a
+	echo   "  CC    hash/sha1sum.c"
+	$(CC) $(CFLAGS) $(OFLAGS) hash/sha1sum.c     $(LDFLAGS) -o $@
+
+hash/sha2sum: hash/sha2sum.c ../library/libxyssl.a
+	echo   "  CC    hash/sha2sum.c"
+	$(CC) $(CFLAGS) $(OFLAGS) hash/sha2sum.c     $(LDFLAGS) -o $@
+
+pkey/dh_client: pkey/dh_client.c ../library/libxyssl.a
+	echo   "  CC    pkey/dh_client.c"
+	$(CC) $(CFLAGS) $(OFLAGS) pkey/dh_client.c   $(LDFLAGS) -o $@
+
+pkey/dh_genprime: pkey/dh_genprime.c ../library/libxyssl.a
+	echo   "  CC    pkey/dh_genprime.c"
+	$(CC) $(CFLAGS) $(OFLAGS) pkey/dh_genprime.c $(LDFLAGS) -o $@
+
+pkey/dh_server: pkey/dh_server.c ../library/libxyssl.a
+	echo   "  CC    pkey/dh_server.c"
+	$(CC) $(CFLAGS) $(OFLAGS) pkey/dh_server.c   $(LDFLAGS) -o $@
+
+pkey/mpi_demo: pkey/mpi_demo.c ../library/libxyssl.a
+	echo   "  CC    pkey/mpi_demo.c"
+	$(CC) $(CFLAGS) $(OFLAGS) pkey/mpi_demo.c    $(LDFLAGS) -o $@
+
+pkey/rsa_genkey: pkey/rsa_genkey.c ../library/libxyssl.a
+	echo   "  CC    pkey/rsa_genkey.c"
+	$(CC) $(CFLAGS) $(OFLAGS) pkey/rsa_genkey.c  $(LDFLAGS) -o $@
+
+pkey/rsa_sign: pkey/rsa_sign.c ../library/libxyssl.a
+	echo   "  CC    pkey/rsa_sign.c"
+	$(CC) $(CFLAGS) $(OFLAGS) pkey/rsa_sign.c    $(LDFLAGS) -o $@
+
+pkey/rsa_verify: pkey/rsa_verify.c ../library/libxyssl.a
+	echo   "  CC    pkey/rsa_verify.c"
+	$(CC) $(CFLAGS) $(OFLAGS) pkey/rsa_verify.c  $(LDFLAGS) -o $@
+
+ssl/ssl_client1: ssl/ssl_client1.c ../library/libxyssl.a
+	echo   "  CC    ssl/ssl_client1.c"
+	$(CC) $(CFLAGS) $(OFLAGS) ssl/ssl_client1.c  $(LDFLAGS) -o $@
+
+ssl/ssl_client2: ssl/ssl_client2.c ../library/libxyssl.a
+	echo   "  CC    ssl/ssl_client2.c"
+	$(CC) $(CFLAGS) $(OFLAGS) ssl/ssl_client2.c  $(LDFLAGS) -o $@
+
+ssl/ssl_server: ssl/ssl_server.c ../library/libxyssl.a
+	echo   "  CC    ssl/ssl_server.c"
+	$(CC) $(CFLAGS) $(OFLAGS) ssl/ssl_server.c   $(LDFLAGS) -o $@
+
+test/benchmark: test/benchmark.c ../library/libxyssl.a
+	echo   "  CC    test/benchmark.c"
+	$(CC) $(CFLAGS) $(OFLAGS) test/benchmark.c   $(LDFLAGS) -o $@
+
+test/selftest: test/selftest.c ../library/libxyssl.a
+	echo   "  CC    test/selftest.c"
+	$(CC) $(CFLAGS) $(OFLAGS) test/selftest.c    $(LDFLAGS) -o $@
+
+test/ssl_test: test/ssl_test.c ../library/libxyssl.a
+	echo   "  CC    test/ssl_test.c"
+	$(CC) $(CFLAGS) $(OFLAGS) test/ssl_test.c    $(LDFLAGS) -o $@
+
+clean:
+	rm -f $(APPS)
+
diff --git a/programs/aes/aescrypt2.c b/programs/aes/aescrypt2.c
new file mode 100644
index 0000000..3d9c06d
--- /dev/null
+++ b/programs/aes/aescrypt2.c
@@ -0,0 +1,396 @@
+/*
+ *  AES-256 file encryption program
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#if defined(WIN32)
+#include <windows.h>
+#include <io.h>
+#else
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "xyssl/aes.h"
+#include "xyssl/sha2.h"
+
+#define MODE_ENCRYPT    0
+#define MODE_DECRYPT    1
+
+#define USAGE   \
+    "\n  aescrypt2 <mode> <input filename> <output filename> <key>\n" \
+    "\n   <mode>: 0 = encrypt, 1 = decrypt\n" \
+    "\n  example: aescrypt2 0 file file.aes hex:E76B2413958B00E193\n" \
+    "\n"
+
+int main( int argc, char *argv[] )
+{
+    int ret = 1, i, n;
+    int keylen, mode, lastn;
+    FILE *fkey, *fin, *fout;
+
+    char *p;
+    unsigned char IV[16];
+    unsigned char key[512];
+    unsigned char digest[32];
+    unsigned char buffer[1024];
+
+    aes_context aes_ctx;
+    sha2_context sha_ctx;
+
+#if defined(WIN32)
+       LARGE_INTEGER li_size;
+    __int64 filesize, offset;
+#else
+      off_t filesize, offset;
+#endif
+
+    /*
+     * Parse the command-line arguments.
+     */
+    if( argc != 5 )
+    {
+        printf( USAGE );
+
+#if defined(WIN32)
+        printf( "\n  Press Enter to exit this program.\n" );
+        fflush( stdout ); getchar();
+#endif
+
+        goto exit;
+    }
+
+    mode = atoi( argv[1] );
+
+    if( mode != MODE_ENCRYPT && mode != MODE_DECRYPT )
+    {
+        fprintf( stderr, "invalide operation mode\n" );
+        goto exit;
+    }
+
+    if( strcmp( argv[2], argv[3] ) == 0 )
+    {
+        fprintf( stderr, "input and output filenames must differ\n" );
+        goto exit;
+    }
+
+    if( ( fin = fopen( argv[2], "rb" ) ) == NULL )
+    {
+        fprintf( stderr, "fopen(%s,rb) failed\n", argv[2] );
+        goto exit;
+    }
+
+    if( ( fout = fopen( argv[3], "wb+" ) ) == NULL )
+    {
+        fprintf( stderr, "fopen(%s,wb+) failed\n", argv[3] );
+        goto exit;
+    }
+
+    /*
+     * Read the secret key and clean the command line.
+     */
+    if( ( fkey = fopen( argv[4], "rb" ) ) != NULL )
+    {
+        keylen = fread( key, 1, sizeof( key ), fkey );
+        fclose( fkey );
+    }
+    else
+    {
+        if( memcmp( argv[4], "hex:", 4 ) == 0 )
+        {
+            p = &argv[4][4];
+            keylen = 0;
+
+            while( sscanf( p, "%02X", &n ) > 0 &&
+                   keylen < (int) sizeof( key ) )
+            {
+                key[keylen++] = (unsigned char) n;
+                p += 2;
+            }
+        }
+        else
+        {
+            keylen = strlen( argv[4] );
+
+            if( keylen > (int) sizeof( key ) )
+                keylen = (int) sizeof( key );
+
+            memcpy( key, argv[4], keylen );
+        }
+    }
+
+    memset( argv[4], 0, strlen( argv[4] ) );
+
+#if defined(WIN32)
+    /*
+     * Support large files (> 2Gb) on Win32
+     */
+    li_size.QuadPart = 0;
+    li_size.LowPart  =
+        SetFilePointer( (HANDLE) _get_osfhandle( _fileno( fin ) ),
+                        li_size.LowPart, &li_size.HighPart, FILE_END );
+
+    if( li_size.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR )
+    {
+        fprintf( stderr, "SetFilePointer(0,FILE_END) failed\n" );
+        goto exit;
+    }
+
+    filesize = li_size.QuadPart;
+#else
+    if( ( filesize = lseek( fileno( fin ), 0, SEEK_END ) ) < 0 )
+    {
+        perror( "lseek" );
+        goto exit;
+    }
+#endif
+
+    if( fseek( fin, 0, SEEK_SET ) < 0 )
+    {
+        fprintf( stderr, "fseek(0,SEEK_SET) failed\n" );
+        goto exit;
+    }
+
+    if( mode == MODE_ENCRYPT )
+    {
+        /*
+         * Generate the initialization vector as:
+         * IV = SHA-256( filesize || filename )[0..15]
+         */
+        for( i = 0; i < 8; i++ )
+            buffer[i] = (unsigned char)( filesize >> ( i << 3 ) );
+
+        p = argv[2];
+
+        sha2_starts( &sha_ctx, 0 );
+        sha2_update( &sha_ctx, buffer, 8 );
+        sha2_update( &sha_ctx, (unsigned char *) p, strlen( p ) );
+        sha2_finish( &sha_ctx, digest );
+
+        memcpy( IV, digest, 16 );
+
+        /*
+         * The last four bits in the IV are actually used
+         * to store the file size modulo the AES block size.
+         */
+        lastn = (int)( filesize & 0x0F );
+
+        IV[15] = (unsigned char)
+            ( ( IV[15] & 0xF0 ) | lastn );
+
+        /*
+         * Append the IV at the beginning of the output.
+         */
+        if( fwrite( IV, 1, 16, fout ) != 16 )
+        {
+            fprintf( stderr, "fwrite(%d bytes) failed\n", 16 );
+            goto exit;
+        }
+
+        /*
+         * Hash the IV and the secret key together 8192 times
+         * using the result to setup the AES context and HMAC.
+         */
+        memset( digest, 0,  32 );
+        memcpy( digest, IV, 16 );
+
+        for( i = 0; i < 8192; i++ )
+        {
+            sha2_starts( &sha_ctx, 0 );
+            sha2_update( &sha_ctx, digest, 32 );
+            sha2_update( &sha_ctx, key, keylen );
+            sha2_finish( &sha_ctx, digest );
+        }
+
+        memset( key, 0, sizeof( key ) );
+          aes_setkey_enc( &aes_ctx, digest, 256 );
+        sha2_hmac_starts( &sha_ctx, digest, 32, 0 );
+
+        /*
+         * Encrypt and write the ciphertext.
+         */
+        for( offset = 0; offset < filesize; offset += 16 )
+        {
+            n = ( filesize - offset > 16 ) ? 16 : (int)
+                ( filesize - offset );
+
+            if( fread( buffer, 1, n, fin ) != (size_t) n )
+            {
+                fprintf( stderr, "fread(%d bytes) failed\n", n );
+                goto exit;
+            }
+
+            for( i = 0; i < 16; i++ )
+                buffer[i] = (unsigned char)( buffer[i] ^ IV[i] );
+
+            aes_crypt_ecb( &aes_ctx, AES_ENCRYPT, buffer, buffer );
+            sha2_hmac_update( &sha_ctx, buffer, 16 );
+
+            if( fwrite( buffer, 1, 16, fout ) != 16 )
+            {
+                fprintf( stderr, "fwrite(%d bytes) failed\n", 16 );
+                goto exit;
+            }
+
+            memcpy( IV, buffer, 16 );
+        }
+
+        /*
+         * Finally write the HMAC.
+         */
+        sha2_hmac_finish( &sha_ctx, digest );
+
+        if( fwrite( digest, 1, 32, fout ) != 32 )
+        {
+            fprintf( stderr, "fwrite(%d bytes) failed\n", 16 );
+            goto exit;
+        }
+    }
+
+    if( mode == MODE_DECRYPT )
+    {
+        unsigned char tmp[16];
+
+        /*
+         *  The encrypted file must be structured as follows:
+         *
+         *        00 .. 15              Initialization Vector
+         *        16 .. 31              AES Encrypted Block #1
+         *           ..
+         *      N*16 .. (N+1)*16 - 1    AES Encrypted Block #N
+         *  (N+1)*16 .. (N+1)*16 + 32   HMAC-SHA-256(ciphertext)
+         */
+        if( filesize < 48 )
+        {
+            fprintf( stderr, "File too short to be encrypted.\n" );
+            goto exit;
+        }
+
+        if( ( filesize & 0x0F ) != 0 )
+        {
+            fprintf( stderr, "File size not a multiple of 16.\n" );
+            goto exit;
+        }
+
+        /*
+         * Substract the IV + HMAC length.
+         */
+        filesize -= ( 16 + 32 );
+
+        /*
+         * Read the IV and original filesize modulo 16.
+         */
+        if( fread( buffer, 1, 16, fin ) != 16 )
+        {
+            fprintf( stderr, "fread(%d bytes) failed\n", 16 );
+            goto exit;
+        }
+
+        memcpy( IV, buffer, 16 );
+        lastn = IV[15] & 0x0F;
+
+        /*
+         * Hash the IV and the secret key together 8192 times
+         * using the result to setup the AES context and HMAC.
+         */
+        memset( digest, 0,  32 );
+        memcpy( digest, IV, 16 );
+
+        for( i = 0; i < 8192; i++ )
+        {
+            sha2_starts( &sha_ctx, 0 );
+            sha2_update( &sha_ctx, digest, 32 );
+            sha2_update( &sha_ctx, key, keylen );
+            sha2_finish( &sha_ctx, digest );
+        }
+
+        memset( key, 0, sizeof( key ) );
+          aes_setkey_dec( &aes_ctx, digest, 256 );
+        sha2_hmac_starts( &sha_ctx, digest, 32, 0 );
+
+        /*
+         * Decrypt and write the plaintext.
+         */
+        for( offset = 0; offset < filesize; offset += 16 )
+        {
+            if( fread( buffer, 1, 16, fin ) != 16 )
+            {
+                fprintf( stderr, "fread(%d bytes) failed\n", 16 );
+                goto exit;
+            }
+
+            memcpy( tmp, buffer, 16 );
+ 
+            sha2_hmac_update( &sha_ctx, buffer, 16 );
+            aes_crypt_ecb( &aes_ctx, AES_DECRYPT, buffer, buffer );
+   
+            for( i = 0; i < 16; i++ )
+                buffer[i] = (unsigned char)( buffer[i] ^ IV[i] );
+
+            memcpy( IV, tmp, 16 );
+
+            n = ( lastn > 0 && offset == filesize - 16 )
+                ? lastn : 16;
+
+            if( fwrite( buffer, 1, n, fout ) != (size_t) n )
+            {
+                fprintf( stderr, "fwrite(%d bytes) failed\n", n );
+                goto exit;
+            }
+        }
+
+        /*
+         * Verify the message authentication code.
+         */
+        sha2_hmac_finish( &sha_ctx, digest );
+
+        if( fread( buffer, 1, 32, fin ) != 32 )
+        {
+            fprintf( stderr, "fread(%d bytes) failed\n", 32 );
+            goto exit;
+        }
+
+        if( memcmp( digest, buffer, 32 ) != 0 )
+        {
+            fprintf( stderr, "HMAC check failed: wrong key, "
+                             "or file corrupted.\n" );
+            goto exit;
+        }
+    }
+
+    ret = 0;
+
+exit:
+
+    memset( buffer, 0, sizeof( buffer ) );
+    memset( digest, 0, sizeof( digest ) );
+
+    memset( &aes_ctx, 0, sizeof(  aes_context ) );
+    memset( &sha_ctx, 0, sizeof( sha2_context ) );
+
+    return( ret );
+}
diff --git a/programs/hash/hello.c b/programs/hash/hello.c
new file mode 100644
index 0000000..12e0167
--- /dev/null
+++ b/programs/hash/hello.c
@@ -0,0 +1,50 @@
+/*
+ *  Classic "Hello, world" demonstration program
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <stdio.h>
+
+#include "xyssl/md5.h"
+
+int main( void )
+{
+    int i;
+    unsigned char digest[16];
+    char str[] = "Hello, world!";
+
+    printf( "\n  MD5('%s') = ", str );
+
+    md5( (unsigned char *) str, 13, digest );
+
+    for( i = 0; i < 16; i++ )
+        printf( "%02x", digest[i] );
+
+    printf( "\n\n" );
+
+#ifdef WIN32
+    printf( "  Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( 0 );
+}
diff --git a/programs/hash/md5sum.c b/programs/hash/md5sum.c
new file mode 100644
index 0000000..10e9a71
--- /dev/null
+++ b/programs/hash/md5sum.c
@@ -0,0 +1,156 @@
+/*
+ *  md5sum demonstration program
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "xyssl/md5.h"
+
+static int md5_wrapper( char *filename, unsigned char *sum )
+{
+    int ret = md5_file( filename, sum );
+
+    if( ret == 1 )
+        fprintf( stderr, "failed to open: %s\n", filename );
+
+    if( ret == 2 )
+        fprintf( stderr, "failed to read: %s\n", filename );
+
+    return( ret );
+}
+
+static int md5_print( char *filename )
+{
+    int i;
+    unsigned char sum[16];
+
+    if( md5_wrapper( filename, sum ) != 0 )
+        return( 1 );
+
+    for( i = 0; i < 16; i++ )
+        printf( "%02x", sum[i] );
+
+    printf( "  %s\n", filename );
+    return( 0 );
+}
+
+static int md5_check( char *filename )
+{
+    int i;
+    size_t n;
+    FILE *f;
+    int nb_err1, nb_err2;
+    int nb_tot1, nb_tot2;
+    unsigned char sum[16];
+    char buf[33], line[1024];
+
+    if( ( f = fopen( filename, "rb" ) ) == NULL )
+    {
+        printf( "failed to open: %s\n", filename );
+        return( 1 );
+    }
+
+    nb_err1 = nb_err2 = 0;
+    nb_tot1 = nb_tot2 = 0;
+
+    memset( line, 0, sizeof( line ) );
+
+    n = sizeof( line );
+
+    while( fgets( line, n - 1, f ) != NULL )
+    {
+        n = strlen( line );
+
+        if( n < 36 )
+            continue;
+
+        if( line[32] != ' ' || line[33] != ' ' )
+            continue;
+
+        if( line[n - 1] == '\n' ) { n--; line[n] = '\0'; }
+        if( line[n - 1] == '\r' ) { n--; line[n] = '\0'; }
+
+        nb_tot1++;
+
+        if( md5_wrapper( line + 34, sum ) != 0 )
+        {
+            nb_err1++;
+            continue;
+        }
+
+        nb_tot2++;
+
+        for( i = 0; i < 16; i++ )
+            sprintf( buf + i * 2, "%02x", sum[i] );
+
+        if( memcmp( line, buf, 32 ) != 0 )
+        {
+            nb_err2++;
+            fprintf( stderr, "wrong checksum: %s\n", line + 34 );
+        }
+
+        n = sizeof( line );
+    }
+
+    if( nb_err1 != 0 )
+    {
+        printf( "WARNING: %d (out of %d) input files could "
+                "not be read\n", nb_err1, nb_tot1 );
+    }
+
+    if( nb_err2 != 0 )
+    {
+        printf( "WARNING: %d (out of %d) computed checksums did "
+                "not match\n", nb_err2, nb_tot2 );
+    }
+
+    return( nb_err1 != 0 || nb_err2 != 0 );
+}
+
+int main( int argc, char *argv[] )
+{
+    int ret, i;
+
+    if( argc == 1 )
+    {
+        printf( "print mode:  md5sum <file> <file> ...\n" );
+        printf( "check mode:  md5sum -c <checksum file>\n" );
+
+#ifdef WIN32
+        printf( "\n  Press Enter to exit this program.\n" );
+        fflush( stdout ); getchar();
+#endif
+
+        return( 1 );
+    }
+
+    if( argc == 3 && strcmp( "-c", argv[1] ) == 0 )
+        return( md5_check( argv[2] ) );
+
+    ret = 0;
+    for( i = 1; i < argc; i++ )
+        ret |= md5_print( argv[i] );
+
+    return( ret );
+}
diff --git a/programs/hash/sha1sum.c b/programs/hash/sha1sum.c
new file mode 100644
index 0000000..33c3142
--- /dev/null
+++ b/programs/hash/sha1sum.c
@@ -0,0 +1,156 @@
+/*
+ *  sha1sum demonstration program
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "xyssl/sha1.h"
+
+static int sha1_wrapper( char *filename, unsigned char *sum )
+{
+    int ret = sha1_file( filename, sum );
+
+    if( ret == 1 )
+        fprintf( stderr, "failed to open: %s\n", filename );
+
+    if( ret == 2 )
+        fprintf( stderr, "failed to read: %s\n", filename );
+
+    return( ret );
+}
+
+static int sha1_print( char *filename )
+{
+    int i;
+    unsigned char sum[20];
+
+    if( sha1_wrapper( filename, sum ) != 0 )
+        return( 1 );
+
+    for( i = 0; i < 20; i++ )
+        printf( "%02x", sum[i] );
+
+    printf( "  %s\n", filename );
+    return( 0 );
+}
+
+static int sha1_check( char *filename )
+{
+    int i;
+    size_t n;
+    FILE *f;
+    int nb_err1, nb_err2;
+    int nb_tot1, nb_tot2;
+    unsigned char sum[20];
+    char buf[41], line[1024];
+
+    if( ( f = fopen( filename, "rb" ) ) == NULL )
+    {
+        printf( "failed to open: %s\n", filename );
+        return( 1 );
+    }
+
+    nb_err1 = nb_err2 = 0;
+    nb_tot1 = nb_tot2 = 0;
+
+    memset( line, 0, sizeof( line ) );
+
+    n = sizeof( line );
+
+    while( fgets( line, n - 1, f ) != NULL )
+    {
+        n = strlen( line );
+
+        if( n < 44 )
+            continue;
+
+        if( line[40] != ' ' || line[41] != ' ' )
+            continue;
+
+        if( line[n - 1] == '\n' ) { n--; line[n] = '\0'; }
+        if( line[n - 1] == '\r' ) { n--; line[n] = '\0'; }
+
+        nb_tot1++;
+
+        if( sha1_wrapper( line + 42, sum ) != 0 )
+        {
+            nb_err1++;
+            continue;
+        }
+
+        nb_tot2++;
+
+        for( i = 0; i < 20; i++ )
+            sprintf( buf + i * 2, "%02x", sum[i] );
+
+        if( memcmp( line, buf, 40 ) != 0 )
+        {
+            nb_err2++;
+            fprintf( stderr, "wrong checksum: %s\n", line + 42 );
+        }
+
+        n = sizeof( line );
+    }
+
+    if( nb_err1 != 0 )
+    {
+        printf( "WARNING: %d (out of %d) input files could "
+                "not be read\n", nb_err1, nb_tot1 );
+    }
+
+    if( nb_err2 != 0 )
+    {
+        printf( "WARNING: %d (out of %d) computed checksums did "
+                "not match\n", nb_err2, nb_tot2 );
+    }
+
+    return( nb_err1 != 0 || nb_err2 != 0 );
+}
+
+int main( int argc, char *argv[] )
+{
+    int ret, i;
+
+    if( argc == 1 )
+    {
+        printf( "print mode:  sha1sum <file> <file> ...\n" );
+        printf( "check mode:  sha1sum -c <checksum file>\n" );
+
+#ifdef WIN32
+        printf( "\n  Press Enter to exit this program.\n" );
+        fflush( stdout ); getchar();
+#endif
+
+        return( 1 );
+    }
+
+    if( argc == 3 && strcmp( "-c", argv[1] ) == 0 )
+        return( sha1_check( argv[2] ) );
+
+    ret = 0;
+    for( i = 1; i < argc; i++ )
+        ret |= sha1_print( argv[i] );
+
+    return( ret );
+}
diff --git a/programs/hash/sha2sum.c b/programs/hash/sha2sum.c
new file mode 100644
index 0000000..c0d42a8
--- /dev/null
+++ b/programs/hash/sha2sum.c
@@ -0,0 +1,156 @@
+/*
+ *  sha2sum demonstration program
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "xyssl/sha2.h"
+
+static int sha2_wrapper( char *filename, unsigned char *sum )
+{
+    int ret = sha2_file( filename, sum, 0 );
+
+    if( ret == 1 )
+        fprintf( stderr, "failed to open: %s\n", filename );
+
+    if( ret == 2 )
+        fprintf( stderr, "failed to read: %s\n", filename );
+
+    return( ret );
+}
+
+static int sha2_print( char *filename )
+{
+    int i;
+    unsigned char sum[32];
+
+    if( sha2_wrapper( filename, sum ) != 0 )
+        return( 1 );
+
+    for( i = 0; i < 32; i++ )
+        printf( "%02x", sum[i] );
+
+    printf( "  %s\n", filename );
+    return( 0 );
+}
+
+static int sha2_check( char *filename )
+{
+    int i;
+    size_t n;
+    FILE *f;
+    int nb_err1, nb_err2;
+    int nb_tot1, nb_tot2;
+    unsigned char sum[32];
+    char buf[65], line[1024];
+
+    if( ( f = fopen( filename, "rb" ) ) == NULL )
+    {
+        printf( "failed to open: %s\n", filename );
+        return( 1 );
+    }
+
+    nb_err1 = nb_err2 = 0;
+    nb_tot1 = nb_tot2 = 0;
+
+    memset( line, 0, sizeof( line ) );
+
+    n = sizeof( line );
+
+    while( fgets( line, n - 1, f ) != NULL )
+    {
+        n = strlen( line );
+
+        if( n < 68 )
+            continue;
+
+        if( line[64] != ' ' || line[65] != ' ' )
+            continue;
+
+        if( line[n - 1] == '\n' ) { n--; line[n] = '\0'; }
+        if( line[n - 1] == '\r' ) { n--; line[n] = '\0'; }
+
+        nb_tot1++;
+
+        if( sha2_wrapper( line + 66, sum ) != 0 )
+        {
+            nb_err1++;
+            continue;
+        }
+
+        nb_tot2++;
+
+        for( i = 0; i < 32; i++ )
+            sprintf( buf + i * 2, "%02x", sum[i] );
+
+        if( memcmp( line, buf, 64 ) != 0 )
+        {
+            nb_err2++;
+            fprintf( stderr, "wrong checksum: %s\n", line + 66 );
+        }
+
+        n = sizeof( line );
+    }
+
+    if( nb_err1 != 0 )
+    {
+        printf( "WARNING: %d (out of %d) input files could "
+                "not be read\n", nb_err1, nb_tot1 );
+    }
+
+    if( nb_err2 != 0 )
+    {
+        printf( "WARNING: %d (out of %d) computed checksums did "
+                "not match\n", nb_err2, nb_tot2 );
+    }
+
+    return( nb_err1 != 0 || nb_err2 != 0 );
+}
+
+int main( int argc, char *argv[] )
+{
+    int ret, i;
+
+    if( argc == 1 )
+    {
+        printf( "print mode:  sha2sum <file> <file> ...\n" );
+        printf( "check mode:  sha2sum -c <checksum file>\n" );
+
+#ifdef WIN32
+        printf( "\n  Press Enter to exit this program.\n" );
+        fflush( stdout ); getchar();
+#endif
+
+        return( 1 );
+    }
+
+    if( argc == 3 && strcmp( "-c", argv[1] ) == 0 )
+        return( sha2_check( argv[2] ) );
+
+    ret = 0;
+    for( i = 1; i < argc; i++ )
+        ret |= sha2_print( argv[i] );
+
+    return( ret );
+}
diff --git a/programs/pkey/dh_client.c b/programs/pkey/dh_client.c
new file mode 100644
index 0000000..2122078
--- /dev/null
+++ b/programs/pkey/dh_client.c
@@ -0,0 +1,249 @@
+/*
+ *  Diffie-Hellman-Merkle key exchange (client side)
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "xyssl/net.h"
+#include "xyssl/aes.h"
+#include "xyssl/dhm.h"
+#include "xyssl/rsa.h"
+#include "xyssl/sha1.h"
+#include "xyssl/havege.h"
+
+#define SERVER_NAME "localhost"
+#define SERVER_PORT 11999
+
+int main( void )
+{
+    FILE *f;
+
+    int ret, n, buflen;
+    int server_fd = -1;
+
+    unsigned char *p, *end;
+    unsigned char buf[1024];
+    unsigned char hash[20];
+
+    havege_state hs;
+    rsa_context rsa;
+    dhm_context dhm;
+    aes_context aes;
+
+    memset( &rsa, 0, sizeof( rsa ) );
+    memset( &dhm, 0, sizeof( dhm ) );
+
+    /*
+     * 1. Setup the RNG
+     */
+    printf( "\n  . Seeding the random number generator" );
+    fflush( stdout );
+
+    havege_init( &hs );
+
+    /*
+     * 2. Read the server's public RSA key
+     */
+    printf( "\n  . Reading public key from rsa_pub.txt" );
+    fflush( stdout );
+
+    if( ( f = fopen( "rsa_pub.txt", "rb" ) ) == NULL )
+    {
+        ret = 1;
+        printf( " failed\n  ! Could not open rsa_pub.txt\n" \
+                "  ! Please run rsa_genkey first\n\n" );
+        goto exit;
+    }
+
+    rsa_init( &rsa, RSA_PKCS_V15, 0, NULL, NULL );
+
+    if( ( ret = mpi_read_file( &rsa.N, 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.E, 16, f ) ) != 0 )
+    {
+        printf( " failed\n  ! mpi_read_file returned %d\n\n", ret );
+        goto exit;
+    }
+
+    rsa.len = ( mpi_msb( &rsa.N ) + 7 ) >> 3;
+
+    fclose( f );
+
+    /*
+     * 3. Initiate the connection
+     */
+    printf( "\n  . Connecting to tcp/%s/%d", SERVER_NAME,
+                                             SERVER_PORT );
+    fflush( stdout );
+
+    if( ( ret = net_connect( &server_fd, SERVER_NAME,
+                                         SERVER_PORT ) ) != 0 )
+    {
+        printf( " failed\n  ! net_connect returned %d\n\n", ret );
+        goto exit;
+    }
+
+    /*
+     * 4a. First get the buffer length
+     */
+    printf( "\n  . Receiving the server's DH parameters" );
+    fflush( stdout );
+
+    memset( buf, 0, sizeof( buf ) );
+
+    if( ( ret = net_recv( &server_fd, buf, 2 ) ) != 2 )
+    {
+        printf( " failed\n  ! net_recv returned %d\n\n", ret );
+        goto exit;
+    }
+
+    n = buflen = ( buf[0] << 8 ) | buf[1];
+    if( buflen < 1 || buflen > (int) sizeof( buf ) )
+    {
+        printf( " failed\n  ! Got an invalid buffer length\n\n" );
+        goto exit;
+    }
+
+    /*
+     * 4b. Get the DHM parameters: P, G and Ys = G^Xs mod P
+     */
+    memset( buf, 0, sizeof( buf ) );
+
+    if( ( ret = net_recv( &server_fd, buf, n ) ) != n )
+    {
+        printf( " failed\n  ! net_recv returned %d\n\n", ret );
+        goto exit;
+    }
+
+    p = buf, end = buf + buflen;
+
+    if( ( ret = dhm_read_params( &dhm, &p, end ) ) != 0 )
+    {
+        printf( " failed\n  ! dhm_read_params returned %d\n\n", ret );
+        goto exit;
+    }
+
+    if( dhm.len < 64 || dhm.len > 256 )
+    {
+        ret = 1;
+        printf( " failed\n  ! Invalid DHM modulus size\n\n" );
+        goto exit;
+    }
+
+    /*
+     * 5. Check that the server's RSA signature matches
+     *    the SHA-1 hash of (P,G,Ys)
+     */
+    printf( "\n  . Verifying the server's RSA signature" );
+    fflush( stdout );
+
+    if( ( n = (int)( end - p ) ) != rsa.len )
+    {
+        ret = 1;
+        printf( " failed\n  ! Invalid RSA signature size\n\n" );
+        goto exit;
+    }
+
+    sha1( buf, (int)( p - 2 - buf ), hash );
+
+    if( ( ret = rsa_pkcs1_verify( &rsa, RSA_PUBLIC, RSA_SHA1,
+                                  0, hash, p ) ) != 0 )
+    {
+        printf( " failed\n  ! rsa_pkcs1_verify returned %d\n\n", ret );
+        goto exit;
+    }
+
+    /*
+     * 6. Send our public value: Yc = G ^ Xc mod P
+     */
+    printf( "\n  . Sending own public value to server" );
+    fflush( stdout );
+
+    n = dhm.len;
+    if( ( ret = dhm_make_public( &dhm, 256, buf, n,
+                                 havege_rand, &hs ) ) != 0 )
+    {
+        printf( " failed\n  ! dhm_make_public returned %d\n\n", ret );
+        goto exit;
+    }
+
+    if( ( ret = net_send( &server_fd, buf, n ) ) != n )
+    {
+        printf( " failed\n  ! net_send returned %d\n\n", ret );
+        goto exit;
+    }
+
+    /*
+     * 7. Derive the shared secret: K = Ys ^ Xc mod P
+     */
+    printf( "\n  . Shared secret: " );
+    fflush( stdout );
+
+    n = dhm.len;
+    if( ( ret = dhm_calc_secret( &dhm, buf, &n ) ) != 0 )
+    {
+        printf( " failed\n  ! dhm_calc_secret returned %d\n\n", ret );
+        goto exit;
+    }
+
+    for( n = 0; n < 16; n++ )
+        printf( "%02x", buf[n] );
+
+    /*
+     * 8. Setup the AES-256 decryption key
+     *
+     * This is an overly simplified example; best practice is
+     * to hash the shared secret with a random value to derive
+     * the keying material for the encryption/decryption keys,
+     * IVs and MACs.
+     */
+    printf( "...\n  . Receiving and decrypting the ciphertext" );
+    fflush( stdout );
+
+    aes_setkey_dec( &aes, buf, 256 );
+
+    memset( buf, 0, sizeof( buf ) );
+
+    if( ( ret = net_recv( &server_fd, buf, 16 ) ) != 16 )
+    {
+        printf( " failed\n  ! net_recv returned %d\n\n", ret );
+        goto exit;
+    }
+
+    aes_crypt_ecb( &aes, AES_DECRYPT, buf, buf );
+    buf[16] = '\0';
+    printf( "\n  . Plaintext is \"%s\"\n\n", (char *) buf );
+
+exit:
+
+    net_close( server_fd );
+    rsa_free( &rsa );
+    dhm_free( &dhm );
+
+#ifdef WIN32
+    printf( "  + Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( ret );
+}
diff --git a/programs/pkey/dh_genprime.c b/programs/pkey/dh_genprime.c
new file mode 100644
index 0000000..09d9b1d
--- /dev/null
+++ b/programs/pkey/dh_genprime.c
@@ -0,0 +1,122 @@
+/*
+ *  Diffie-Hellman-Merkle key exchange (prime generation)
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <stdio.h>
+
+#include "xyssl/bignum.h"
+#include "xyssl/config.h"
+#include "xyssl/havege.h"
+
+/*
+ * Note: G = 4 is always a quadratic residue mod P,
+ * so it is a generator of order Q (with P = 2*Q+1).
+ */
+#define DH_P_SIZE 1024
+#define GENERATOR "4"
+
+int main( void )
+{
+    int ret = 1;
+
+#if defined(XYSSL_GENPRIME)
+    mpi G, P, Q;
+    havege_state hs;
+    FILE *fout;
+
+    mpi_init( &G, &P, &Q, NULL );
+    mpi_read_string( &G, 10, GENERATOR );
+
+    printf( "\n  . Seeding the random number generator..." );
+    fflush( stdout );
+
+    havege_init( &hs );
+
+    printf( " ok\n  . Generating the modulus, please wait..." );
+    fflush( stdout );
+
+    /*
+     * This can take a long time...
+     */
+    if( ( ret = mpi_gen_prime( &P, DH_P_SIZE, 1,
+                               havege_rand, &hs ) ) != 0 )
+    {
+        printf( " failed\n  ! mpi_gen_prime returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n  . Verifying that Q = (P-1)/2 is prime..." );
+    fflush( stdout );
+
+    if( ( ret = mpi_sub_int( &Q, &P, 1 ) ) != 0 )
+    {
+        printf( " failed\n  ! mpi_sub_int returned %d\n\n", ret );
+        goto exit;
+    }
+
+    if( ( ret = mpi_div_int( &Q, NULL, &Q, 2 ) ) != 0 )
+    {
+        printf( " failed\n  ! mpi_div_int returned %d\n\n", ret );
+        goto exit;
+    }
+
+    if( ( ret = mpi_is_prime( &Q, havege_rand, &hs ) ) != 0 )
+    {
+        printf( " failed\n  ! mpi_is_prime returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n  . Exporting the value in dh_prime.txt..." );
+    fflush( stdout );
+
+    if( ( fout = fopen( "dh_prime.txt", "wb+" ) ) == NULL )
+    {
+        ret = 1;
+        printf( " failed\n  ! Could not create dh_prime.txt\n\n" );
+        goto exit;
+    }
+
+    if( ( ret = mpi_write_file( "P = ", &P, 16, fout ) != 0 ) ||
+        ( ret = mpi_write_file( "G = ", &G, 16, fout ) != 0 ) )
+    {
+        printf( " failed\n  ! mpi_write_file returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n\n" );
+    fclose( fout );
+
+exit:
+
+    mpi_free( &Q, &P, &G, NULL );
+#else
+    printf( "\n  ! Prime-number generation is not available.\n\n" );
+#endif
+
+#ifdef WIN32
+    printf( "  Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( ret );
+}
diff --git a/programs/pkey/dh_prime.txt b/programs/pkey/dh_prime.txt
new file mode 100644
index 0000000..e62c279
--- /dev/null
+++ b/programs/pkey/dh_prime.txt
@@ -0,0 +1,2 @@
+P = C3CF8BCFD9E88B0CC35EC526F3D63FA001DC9392E6CA81F3B414173955C582758B52038FAFBF402B8C29DC32F5231B0D2E25B252850C7DCDBFF46D0E7989E51DEA07A53BCF7947D4C95EBA28F9CBAFB0267EC3BCF57B15A49964236B56773851D6621E546F410D504F13827218CD14A1FDB69522DC72DD67D880E51B2E00894F

+G = 04

diff --git a/programs/pkey/dh_server.c b/programs/pkey/dh_server.c
new file mode 100644
index 0000000..4990dcf
--- /dev/null
+++ b/programs/pkey/dh_server.c
@@ -0,0 +1,252 @@
+/*
+ *  Diffie-Hellman-Merkle key exchange (server side)
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "xyssl/net.h"
+#include "xyssl/aes.h"
+#include "xyssl/dhm.h"
+#include "xyssl/rsa.h"
+#include "xyssl/sha1.h"
+#include "xyssl/havege.h"
+
+#define SERVER_PORT 11999
+#define PLAINTEXT "==Hello there!=="
+
+int main( void )
+{
+    FILE *f;
+
+    int ret, n, buflen;
+    int listen_fd = -1;
+    int client_fd = -1;
+
+    unsigned char buf[1024];
+    unsigned char hash[20];
+    unsigned char buf2[2];
+
+    havege_state hs;
+    rsa_context rsa;
+    dhm_context dhm;
+    aes_context aes;
+
+    memset( &rsa, 0, sizeof( rsa ) );
+    memset( &dhm, 0, sizeof( dhm ) );
+
+    /*
+     * 1. Setup the RNG
+     */
+    printf( "\n  . Seeding the random number generator" );
+    fflush( stdout );
+
+    havege_init( &hs );
+
+    /*
+     * 2a. Read the server's private RSA key
+     */
+    printf( "\n  . Reading private key from rsa_priv.txt" );
+    fflush( stdout );
+
+    if( ( f = fopen( "rsa_priv.txt", "rb" ) ) == NULL )
+    {
+        ret = 1;
+        printf( " failed\n  ! Could not open rsa_priv.txt\n" \
+                "  ! Please run rsa_genkey first\n\n" );
+        goto exit;
+    }
+
+    rsa_init( &rsa, RSA_PKCS_V15, 0, NULL, NULL );
+
+    if( ( ret = mpi_read_file( &rsa.N , 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.E , 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.D , 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.P , 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.Q , 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.DP, 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.DQ, 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.QP, 16, f ) ) != 0 )
+    {
+        printf( " failed\n  ! mpi_read_file returned %d\n\n", ret );
+        goto exit;
+    }
+
+    rsa.len = ( mpi_msb( &rsa.N ) + 7 ) >> 3;
+    
+    fclose( f );
+
+    /*
+     * 2b. Get the DHM modulus and generator
+     */
+    printf( "\n  . Reading DH parameters from dh_prime.txt" );
+    fflush( stdout );
+
+    if( ( f = fopen( "dh_prime.txt", "rb" ) ) == NULL )
+    {
+        ret = 1;
+        printf( " failed\n  ! Could not open dh_prime.txt\n" \
+                "  ! Please run dh_genprime first\n\n" );
+        goto exit;
+    }
+
+    if( mpi_read_file( &dhm.P, 16, f ) != 0 ||
+        mpi_read_file( &dhm.G, 16, f ) != 0 )
+    {
+        printf( " failed\n  ! Invalid DH parameter file\n\n" );
+        goto exit;
+    }
+
+    fclose( f );
+
+    /*
+     * 3. Wait for a client to connect
+     */
+    printf( "\n  . Waiting for a remote connection" );
+    fflush( stdout );
+
+    if( ( ret = net_bind( &listen_fd, NULL, SERVER_PORT ) ) != 0 )
+    {
+        printf( " failed\n  ! net_bind returned %d\n\n", ret );
+        goto exit;
+    }
+
+    if( ( ret = net_accept( listen_fd, &client_fd, NULL ) ) != 0 )
+    {
+        printf( " failed\n  ! net_accept returned %d\n\n", ret );
+        goto exit;
+    }
+
+    /*
+     * 4. Setup the DH parameters (P,G,Ys)
+     */
+    printf( "\n  . Sending the server's DH parameters" );
+    fflush( stdout );
+
+    memset( buf, 0, sizeof( buf ) );
+
+    if( ( ret = dhm_make_params( &dhm, 256, buf, &n,
+                                 havege_rand, &hs ) ) != 0 )
+    {
+        printf( " failed\n  ! dhm_make_params returned %d\n\n", ret );
+        goto exit;
+    }
+
+    /*
+     * 5. Sign the parameters and send them
+     */
+    sha1( buf, n, hash );
+
+    buf[n    ] = (unsigned char)( rsa.len >> 8 );
+    buf[n + 1] = (unsigned char)( rsa.len      );
+
+    if( ( ret = rsa_pkcs1_sign( &rsa, RSA_PRIVATE, RSA_SHA1,
+                                0, hash, buf + n + 2 ) ) != 0 )
+    {
+        printf( " failed\n  ! rsa_pkcs1_sign returned %d\n\n", ret );
+        goto exit;
+    }
+
+    buflen = n + 2 + rsa.len;
+    buf2[0] = (unsigned char)( buflen >> 8 );
+    buf2[1] = (unsigned char)( buflen      );
+
+    if( ( ret = net_send( &client_fd, buf2, 2 ) ) != 2 ||
+        ( ret = net_send( &client_fd, buf, buflen ) ) != buflen )
+    {
+        printf( " failed\n  ! net_send returned %d\n\n", ret );
+        goto exit;
+    }
+
+    /*
+     * 6. Get the client's public value: Yc = G ^ Xc mod P
+     */
+    printf( "\n  . Receiving the client's public value" );
+    fflush( stdout );
+
+    memset( buf, 0, sizeof( buf ) );
+    n = dhm.len;
+
+    if( ( ret = net_recv( &client_fd, buf, n ) ) != n )
+    {
+        printf( " failed\n  ! net_recv returned %d\n\n", ret );
+        goto exit;
+    }
+
+    if( ( ret = dhm_read_public( &dhm, buf, dhm.len ) ) != 0 )
+    {
+        printf( " failed\n  ! dhm_read_public returned %d\n\n", ret );
+        goto exit;
+    }
+
+    /*
+     * 7. Derive the shared secret: K = Ys ^ Xc mod P
+     */
+    printf( "\n  . Shared secret: " );
+    fflush( stdout );
+
+    if( ( ret = dhm_calc_secret( &dhm, buf, &n ) ) != 0 )
+    {
+        printf( " failed\n  ! dhm_calc_secret returned %d\n\n", ret );
+        goto exit;
+    }
+
+    for( n = 0; n < 16; n++ )
+        printf( "%02x", buf[n] );
+
+    /*
+     * 8. Setup the AES-256 encryption key
+     *
+     * This is an overly simplified example; best practice is
+     * to hash the shared secret with a random value to derive
+     * the keying material for the encryption/decryption keys
+     * and MACs.
+     */
+    printf( "...\n  . Encrypting and sending the ciphertext" );
+    fflush( stdout );
+
+    aes_setkey_enc( &aes, buf, 256 );
+    memcpy( buf, PLAINTEXT, 16 );
+    aes_crypt_ecb( &aes, AES_ENCRYPT, buf, buf );
+
+    if( ( ret = net_send( &client_fd, buf, 16 ) ) != 16 )
+    {
+        printf( " failed\n  ! net_send returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( "\n\n" );
+
+exit:
+
+    net_close( client_fd );
+    rsa_free( &rsa );
+    dhm_free( &dhm );
+
+#ifdef WIN32
+    printf( "  + Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( ret );
+}
diff --git a/programs/pkey/mpi_demo.c b/programs/pkey/mpi_demo.c
new file mode 100644
index 0000000..699fa5a
--- /dev/null
+++ b/programs/pkey/mpi_demo.c
@@ -0,0 +1,76 @@
+/*
+ *  Simple MPI demonstration program
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <stdio.h>
+
+#include "xyssl/bignum.h"
+
+int main( void )
+{
+    mpi E, P, Q, N, H, D, X, Y, Z;
+
+    mpi_init( &E, &P, &Q, &N, &H,
+              &D, &X, &Y, &Z, NULL );
+
+    mpi_read_string( &P, 10, "2789" );
+    mpi_read_string( &Q, 10, "3203" );
+    mpi_read_string( &E, 10,  "257" );
+    mpi_mul_mpi( &N, &P, &Q );
+
+    printf( "\n  Public key:\n\n" );
+    mpi_write_file( "  N = ", &N, 10, NULL );
+    mpi_write_file( "  E = ", &E, 10, NULL );
+
+    printf( "\n  Private key:\n\n" );
+    mpi_write_file( "  P = ", &P, 10, NULL );
+    mpi_write_file( "  Q = ", &Q, 10, NULL );
+
+    mpi_sub_int( &P, &P, 1 );
+    mpi_sub_int( &Q, &Q, 1 );
+    mpi_mul_mpi( &H, &P, &Q );
+    mpi_inv_mod( &D, &E, &H );
+
+    mpi_write_file( "  D = E^-1 mod (P-1)*(Q-1) = ",
+                    &D, 10, NULL );
+
+    mpi_read_string( &X, 10, "55555" );
+    mpi_exp_mod( &Y, &X, &E, &N, NULL );
+    mpi_exp_mod( &Z, &Y, &D, &N, NULL );
+
+    printf( "\n  RSA operation:\n\n" );
+    mpi_write_file( "  X (plaintext)  = ", &X, 10, NULL );
+    mpi_write_file( "  Y (ciphertext) = X^E mod N = ", &Y, 10, NULL );
+    mpi_write_file( "  Z (decrypted)  = Y^D mod N = ", &Z, 10, NULL );
+    printf( "\n" );
+
+    mpi_free( &Z, &Y, &X, &D, &H,
+              &N, &Q, &P, &E, NULL );
+
+#ifdef WIN32
+    printf( "  Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( 0 );
+}
diff --git a/programs/pkey/rsa_genkey.c b/programs/pkey/rsa_genkey.c
new file mode 100644
index 0000000..0619f15
--- /dev/null
+++ b/programs/pkey/rsa_genkey.c
@@ -0,0 +1,130 @@
+/*
+ *  Example RSA key generation program
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <stdio.h>
+
+#include "xyssl/havege.h"
+#include "xyssl/bignum.h"
+#include "xyssl/x509.h"
+#include "xyssl/rsa.h"
+
+#define KEY_SIZE 1024
+#define EXPONENT 65537
+
+int main( void )
+{
+    int ret;
+    rsa_context rsa;
+    havege_state hs;
+    FILE *fpub  = NULL;
+    FILE *fpriv = NULL;
+    x509_raw cert;
+
+    printf( "\n  . Seeding the random number generator..." );
+    fflush( stdout );
+
+    havege_init( &hs );
+
+    printf( " ok\n  . Generating the RSA key [ %d-bit ]...", KEY_SIZE );
+    fflush( stdout );
+
+    rsa_init( &rsa, RSA_PKCS_V15, 0, havege_rand, &hs );
+    
+    if( ( ret = rsa_gen_key( &rsa, KEY_SIZE, EXPONENT ) ) != 0 )
+    {
+        printf( " failed\n  ! rsa_gen_key returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n  . Exporting the public  key in rsa_pub.txt...." );
+    fflush( stdout );
+
+    if( ( fpub = fopen( "rsa_pub.txt", "wb+" ) ) == NULL )
+    {
+        printf( " failed\n  ! could not open rsa_pub.txt for writing\n\n" );
+        ret = 1;
+        goto exit;
+    }
+
+    if( ( ret = mpi_write_file( "N = ", &rsa.N, 16, fpub ) ) != 0 ||
+        ( ret = mpi_write_file( "E = ", &rsa.E, 16, fpub ) ) != 0 )
+    {
+        printf( " failed\n  ! mpi_write_file returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n  . Exporting the private key in rsa_priv.txt..." );
+    fflush( stdout );
+
+    if( ( fpriv = fopen( "rsa_priv.txt", "wb+" ) ) == NULL )
+    {
+        printf( " failed\n  ! could not open rsa_priv.txt for writing\n" );
+        ret = 1;
+        goto exit;
+    }
+
+    if( ( ret = mpi_write_file( "N = " , &rsa.N , 16, fpriv ) ) != 0 ||
+        ( ret = mpi_write_file( "E = " , &rsa.E , 16, fpriv ) ) != 0 ||
+        ( ret = mpi_write_file( "D = " , &rsa.D , 16, fpriv ) ) != 0 ||
+        ( ret = mpi_write_file( "P = " , &rsa.P , 16, fpriv ) ) != 0 ||
+        ( ret = mpi_write_file( "Q = " , &rsa.Q , 16, fpriv ) ) != 0 ||
+        ( ret = mpi_write_file( "DP = ", &rsa.DP, 16, fpriv ) ) != 0 ||
+        ( ret = mpi_write_file( "DQ = ", &rsa.DQ, 16, fpriv ) ) != 0 ||
+        ( ret = mpi_write_file( "QP = ", &rsa.QP, 16, fpriv ) ) != 0 )
+    {
+        printf( " failed\n  ! mpi_write_file returned %d\n\n", ret );
+        goto exit;
+    }
+/*
+    printf( " ok\n  . Generating the certificate..." );
+
+    x509write_init_raw( &cert );
+    x509write_add_pubkey( &cert, &rsa );
+    x509write_add_subject( &cert, "CN='localhost'" );
+    x509write_add_validity( &cert, "2007-09-06 17:00:32",
+                                   "2010-09-06 17:00:32" );
+    x509write_create_selfsign( &cert, &rsa );
+    x509write_crtfile( &cert, "cert.der", X509_OUTPUT_DER );
+    x509write_crtfile( &cert, "cert.pem", X509_OUTPUT_PEM );
+    x509write_free_raw( &cert );
+*/
+    printf( " ok\n\n" );
+
+exit:
+
+    if( fpub  != NULL )
+        fclose( fpub );
+
+    if( fpriv != NULL )
+        fclose( fpriv );
+
+    rsa_free( &rsa );
+
+#ifdef WIN32
+    printf( "  Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( ret );
+}
diff --git a/programs/pkey/rsa_priv.txt b/programs/pkey/rsa_priv.txt
new file mode 100644
index 0000000..06b2e4d
--- /dev/null
+++ b/programs/pkey/rsa_priv.txt
@@ -0,0 +1,8 @@
+N = 807E3526556FADF8D4CA64074ADA36862646D5ECB24E363821306588722AF2B58058CFB88E8C0BEA5C7084F3055D232F110E59C8837A0D132A4B907E91DB4A4924134A85E7445935E55A772C0B72E12C94501D9DF66B71BA030F842531721AEF43AE48F9505BF7504CDEEA3CAA6F94530835648D770AE2E6C628DD484D10AA57

+E = 010001

+D = 56B3D2AD612D10993D0CAC5E7755B340E6071A46B3322F47C4AD6175A683F06E2482C8F761C88229CBE268F38B0503BEB8A59453C6D3CE8AC6196310E4DEB1CA939DF7F7EE26C4697EEDD1E5122795BFC83861DE2E3EC9E3E84F42B3A9DD25EB09B30FDDFFACCE5091493BC5577530CE9CD9C8BA244EC5FD3DF91BCECFD73961

+P = F8DAD6A5651CED9011D979A076D70C4FBD095AAE2E53EF51415832C63AD61618F0BB369F29D1363345FE481FE6C28F0830FE33A1C41F8743A4E02DD682A2E099

+Q = 842EABF3171F972DE7D6B571B70F969F8F1C305851785BB042CDAE3B794014659A744EA7D16D881B7168463CEEAF52BA0F78755BBE89CFE1361076CE3E20886F

+DP = B1C694047FE1548CD1538D21E703E595A933DF86032E8F0E7B21E8D3D8004CB4F074ADA6B296F4A35863395F20D8E8992F76C9A7CC95C169BF852EF9C9455631

+DQ = 143C54E49D289FEB4E2FC78D461A23D3FF83B03F0511E8EF7DFAA0EEC7EC3073318716B7884F3D63FE239985208144A7E950669F09F76D14AC432EFCF9F3DF0F

+QP = C2F98F412476BDA2B14F5882D929090C62BB24ED74E8B78A3BE287EABDB3FADC445D041F1DE04EBE2D39A8913DAF03C23FF632D1B3FB6CCBDD65B2A576F127F5

diff --git a/programs/pkey/rsa_pub.txt b/programs/pkey/rsa_pub.txt
new file mode 100644
index 0000000..dddb25c
--- /dev/null
+++ b/programs/pkey/rsa_pub.txt
@@ -0,0 +1,2 @@
+N = 807E3526556FADF8D4CA64074ADA36862646D5ECB24E363821306588722AF2B58058CFB88E8C0BEA5C7084F3055D232F110E59C8837A0D132A4B907E91DB4A4924134A85E7445935E55A772C0B72E12C94501D9DF66B71BA030F842531721AEF43AE48F9505BF7504CDEEA3CAA6F94530835648D770AE2E6C628DD484D10AA57

+E = 010001

diff --git a/programs/pkey/rsa_sign.c b/programs/pkey/rsa_sign.c
new file mode 100644
index 0000000..0e7077e
--- /dev/null
+++ b/programs/pkey/rsa_sign.c
@@ -0,0 +1,130 @@
+/*
+ *  RSA/SHA-1 signature creation program
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "xyssl/rsa.h"
+#include "xyssl/sha1.h"
+
+int main( int argc, char *argv[] )
+{
+    FILE *f;
+    int ret, i;
+    rsa_context rsa;
+    unsigned char hash[20];
+    unsigned char buf[512];
+
+    ret = 1;
+
+    if( argc != 2 )
+    {
+        printf( "usage: rsa_sign <filename>\n" );
+
+#ifdef WIN32
+        printf( "\n" );
+#endif
+
+        goto exit;
+    }
+
+    printf( "\n  . Reading private key from rsa_priv.txt" );
+    fflush( stdout );
+
+    if( ( f = fopen( "rsa_priv.txt", "rb" ) ) == NULL )
+    {
+        ret = 1;
+        printf( " failed\n  ! Could not open rsa_priv.txt\n" \
+                "  ! Please run rsa_genkey first\n\n" );
+        goto exit;
+    }
+
+    rsa_init( &rsa, RSA_PKCS_V15, 0, NULL, NULL );
+    
+    if( ( ret = mpi_read_file( &rsa.N , 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.E , 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.D , 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.P , 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.Q , 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.DP, 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.DQ, 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.QP, 16, f ) ) != 0 )
+    {
+        printf( " failed\n  ! mpi_read_file returned %d\n\n", ret );
+        goto exit;
+    }
+
+    rsa.len = ( mpi_msb( &rsa.N ) + 7 ) >> 3;
+
+    fclose( f );
+
+    /*
+     * Compute the SHA-1 hash of the input file,
+     * then calculate the RSA signature of the hash.
+     */
+    printf( "\n  . Generating the RSA/SHA-1 signature" );
+    fflush( stdout );
+
+    if( ( ret = sha1_file( argv[1], hash ) ) != 0 )
+    {
+        printf( " failed\n  ! Could not open or read %s\n\n", argv[1] );
+        goto exit;
+    }
+
+    if( ( ret = rsa_pkcs1_sign( &rsa, RSA_PRIVATE, RSA_SHA1,
+                                20, hash, buf ) ) != 0 )
+    {
+        printf( " failed\n  ! rsa_pkcs1_sign returned %d\n\n", ret );
+        goto exit;
+    }
+
+    /*
+     * Write the signature into <filename>-sig.txt
+     */
+    memcpy( argv[1] + strlen( argv[1] ), ".sig", 5 );
+
+    if( ( f = fopen( argv[1], "wb+" ) ) == NULL )
+    {
+        ret = 1;
+        printf( " failed\n  ! Could not create %s\n\n", argv[1] );
+        goto exit;
+    }
+
+    for( i = 0; i < rsa.len; i++ )
+        fprintf( f, "%02X%s", buf[i],
+                 ( i + 1 ) % 16 == 0 ? "\r\n" : " " );
+
+    fclose( f );
+
+    printf( "\n  . Done (created \"%s\")\n\n", argv[1] );
+
+exit:
+
+#ifdef WIN32
+    printf( "  + Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( ret );
+}
diff --git a/programs/pkey/rsa_verify.c b/programs/pkey/rsa_verify.c
new file mode 100644
index 0000000..aacc664
--- /dev/null
+++ b/programs/pkey/rsa_verify.c
@@ -0,0 +1,133 @@
+/*
+ *  RSA/SHA-1 signature verification program
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "xyssl/rsa.h"
+#include "xyssl/sha1.h"
+
+int main( int argc, char *argv[] )
+{
+    FILE *f;
+    int ret, i, c;
+    rsa_context rsa;
+    unsigned char hash[20];
+    unsigned char buf[512];
+
+    ret = 1;
+    if( argc != 2 )
+    {
+        printf( "usage: rsa_verify <filename>\n" );
+
+#ifdef WIN32
+        printf( "\n" );
+#endif
+
+        goto exit;
+    }
+
+    printf( "\n  . Reading public key from rsa_pub.txt" );
+    fflush( stdout );
+
+    if( ( f = fopen( "rsa_pub.txt", "rb" ) ) == NULL )
+    {
+        printf( " failed\n  ! Could not open rsa_pub.txt\n" \
+                "  ! Please run rsa_genkey first\n\n" );
+        goto exit;
+    }
+
+    rsa_init( &rsa, RSA_PKCS_V15, 0, NULL, NULL );
+
+    if( ( ret = mpi_read_file( &rsa.N, 16, f ) ) != 0 ||
+        ( ret = mpi_read_file( &rsa.E, 16, f ) ) != 0 )
+    {
+        printf( " failed\n  ! mpi_read_file returned %d\n\n", ret );
+        goto exit;
+    }
+
+    rsa.len = ( mpi_msb( &rsa.N ) + 7 ) >> 3;
+
+    fclose( f );
+
+    /*
+     * Extract the RSA signature from the text file
+     */
+    ret = 1;
+    i = strlen( argv[1] );
+    memcpy( argv[1] + i, ".sig", 5 );
+
+    if( ( f = fopen( argv[1], "rb" ) ) == NULL )
+    {
+        printf( "\n  ! Could not open %s\n\n", argv[1] );
+        goto exit;
+    }
+
+    argv[1][i] = '\0', i = 0;
+
+    while( fscanf( f, "%02X", &c ) > 0 &&
+           i < (int) sizeof( buf ) )
+        buf[i++] = (unsigned char) c;
+
+    fclose( f );
+
+    if( i != rsa.len )
+    {
+        printf( "\n  ! Invalid RSA signature format\n\n" );
+        goto exit;
+    }
+
+    /*
+     * Compute the SHA-1 hash of the input file and compare
+     * it with the hash decrypted from the RSA signature.
+     */
+    printf( "\n  . Verifying the RSA/SHA-1 signature" );
+    fflush( stdout );
+
+    if( ( ret = sha1_file( argv[1], hash ) ) != 0 )
+    {
+        printf( " failed\n  ! Could not open or read %s\n\n", argv[1] );
+        goto exit;
+    }
+
+    if( ( ret = rsa_pkcs1_verify( &rsa, RSA_PUBLIC, RSA_SHA1,
+                                  20, hash, buf ) ) != 0 )
+    {
+        printf( " failed\n  ! rsa_pkcs1_verify returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( "\n  . OK (the decrypted SHA-1 hash matches)\n\n" );
+
+    ret = 0;
+
+exit:
+
+#ifdef WIN32
+    printf( "  + Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( ret );
+}
diff --git a/programs/ssl/CA-HOWTO.txt b/programs/ssl/CA-HOWTO.txt
new file mode 100644
index 0000000..6f05211
--- /dev/null
+++ b/programs/ssl/CA-HOWTO.txt
@@ -0,0 +1,144 @@
+

+

+

+                How to setup your own Certificate Authority

+                ===========================================

+

+

+Note: this howto requires the openssl binary, as well as classic

+UNIX tools (cat, touch, echo). If you use Windows, please consider

+installing Cygwin -- see http://cygwin.com/

+

+

+    1. Configure OpenSSL

+    --------------------

+

+First of all, create sslconf.txt in the current directory

+(a basic example is provided at the end of this file).

+

+cat > sslconf.txt <<"EOF"

+[paste contents here]

+EOF

+

+Then you need to create the database and a starting serial number:

+

+touch index

+echo "01" > serial

+mkdir newcerts

+

+

+    2. Generate the CA certificate

+    ------------------------------

+

+openssl req -config sslconf.txt -days 3653 -x509 -newkey rsa:2048 \

+            -set_serial 0 -text -keyout test-ca.key -out test-ca.crt

+

+

+    3. Generate the private keys and certificate requests

+    -----------------------------------------------------

+

+openssl genrsa -out server1.key 2048

+openssl genrsa -out server2.key 2048

+openssl genrsa -out client1.key 2048

+openssl genrsa -out client2.key 2048

+

+openssl req -config sslconf.txt -new -key server1.key -out server1.req

+openssl req -config sslconf.txt -new -key server2.key -out server2.req

+openssl req -config sslconf.txt -new -key client1.key -out client1.req

+openssl req -config sslconf.txt -new -key client2.key -out client2.req

+

+

+    4. Issue and sign the certificates

+    ----------------------------------

+

+openssl ca -config sslconf.txt -in server1.req -out server1.crt

+openssl ca -config sslconf.txt -in server2.req -out server2.crt

+openssl ca -config sslconf.txt -in client1.req -out client1.crt

+openssl ca -config sslconf.txt -in client2.req -out client2.crt

+

+

+    5. To revoke a certificate and update the CRL

+    ---------------------------------------------

+

+openssl ca -config sslconf.txt -revoke server1.crt

+openssl ca -config sslconf.txt -revoke client1.crt

+openssl ca -config sslconf.txt -gencrl -out crl.pem

+

+

+    6. To display a certificate and verify its validity

+    ---------------------------------------------------

+

+openssl x509 -in server2.crt -text -noout

+cat test-ca.crt crl.pem > ca_crl.pem

+openssl verify -CAfile ca_crl.pem -crl_check server2.crt

+rm ca_crl.pem

+

+

+    7. To export a certificate into a .pfx file

+    -------------------------------------------

+

+openssl pkcs12 -export -in client2.crt -inkey client2.key \

+                      -out client2.pfx

+

+

+##================================================================

+##============== Example OpenSSL configuration file ==============

+##================================================================

+

+#  References:

+#

+#  /etc/ssl/openssl.conf

+#  http://www.openssl.org/docs/apps/config.html

+#  http://www.openssl.org/docs/apps/x509v3_config.html

+

+[ ca ]

+default_ca              = my_ca

+

+[ my_ca ]

+certificate             = test-ca.crt

+private_key             = test-ca.key

+database                = index

+serial                  = serial

+

+new_certs_dir           = newcerts

+default_crl_days        = 60

+default_days            = 730

+default_md              = sha1

+policy                  = my_policy

+x509_extensions         = v3_usr

+

+[ my_policy ]

+countryName             = optional

+stateOrProvinceName     = optional

+organizationName        = match

+organizationalUnitName  = optional

+commonName              = supplied

+emailAddress            = optional

+

+[ req ]

+distinguished_name      = my_req_dn

+x509_extensions         = v3_ca

+

+[ my_req_dn ]

+countryName             = Country Name..............

+countryName_min         = 2

+countryName_max         = 2

+stateOrProvinceName     = State or Province Name....

+localityName            = Locality Name.............

+0.organizationName      = Organization Name.........

+organizationalUnitName  = Org. Unit Name............

+commonName              = Common Name (required)....

+commonName_max          = 64

+emailAddress            = Email Address.............

+emailAddress_max        = 64

+

+[ v3_ca ]

+basicConstraints        = CA:TRUE

+subjectKeyIdentifier    = hash

+authorityKeyIdentifier  = keyid:always,issuer:always

+

+[ v3_usr ]

+basicConstraints        = CA:FALSE

+subjectKeyIdentifier    = hash

+authorityKeyIdentifier  = keyid,issuer

+

diff --git a/programs/ssl/ssl_client1.c b/programs/ssl/ssl_client1.c
new file mode 100644
index 0000000..e752d87
--- /dev/null
+++ b/programs/ssl/ssl_client1.c
@@ -0,0 +1,172 @@
+/*
+ *  SSL client demonstration program
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "xyssl/net.h"
+#include "xyssl/ssl.h"
+#include "xyssl/havege.h"
+
+#define SERVER_PORT 443
+/*
+#define SERVER_NAME "localhost"
+#define GET_REQUEST "GET / HTTP/1.0\r\n\r\n"
+*/
+#define SERVER_NAME "xyssl.org"
+#define GET_REQUEST \
+    "GET /hello/ HTTP/1.1\r\n" \
+    "Host: xyssl.org\r\n\r\n"
+
+#define DEBUG_LEVEL 0
+
+void my_debug( void *ctx, int level, char *str )
+{
+    if( level < DEBUG_LEVEL )
+    {
+        fprintf( (FILE *) ctx, "%s", str );
+        fflush(  (FILE *) ctx  );
+    }
+}
+
+int main( void )
+{
+    int ret, len, server_fd;
+    unsigned char buf[1024];
+    havege_state hs;
+    ssl_context ssl;
+    ssl_session ssn;
+
+    /*
+     * 0. Initialize the RNG and the session data
+     */
+    havege_init( &hs );
+    memset( &ssn, 0, sizeof( ssl_session ) );
+
+    /*
+     * 1. Start the connection
+     */
+    printf( "\n  . Connecting to tcp/%s/%4d...", SERVER_NAME,
+                                                 SERVER_PORT );
+    fflush( stdout );
+
+    if( ( ret = net_connect( &server_fd, SERVER_NAME,
+                                         SERVER_PORT ) ) != 0 )
+    {
+        printf( " failed\n  ! net_connect returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 2. Setup stuff
+     */
+    printf( "  . Setting up the SSL/TLS structure..." );
+    fflush( stdout );
+
+    if( ( ret = ssl_init( &ssl ) ) != 0 )
+    {
+        printf( " failed\n  ! ssl_init returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    ssl_set_endpoint( &ssl, SSL_IS_CLIENT );
+    ssl_set_authmode( &ssl, SSL_VERIFY_NONE );
+
+    ssl_set_rng( &ssl, havege_rand, &hs );
+    ssl_set_dbg( &ssl, my_debug, stdout );
+    ssl_set_bio( &ssl, net_recv, &server_fd,
+                       net_send, &server_fd );
+
+    ssl_set_ciphers( &ssl, ssl_default_ciphers );
+    ssl_set_session( &ssl, 1, 600, &ssn );
+
+    /*
+     * 3. Write the GET request
+     */
+    printf( "  > Write to server:" );
+    fflush( stdout );
+
+    len = sprintf( (char *) buf, GET_REQUEST );
+
+    while( ( ret = ssl_write( &ssl, buf, len ) ) <= 0 )
+    {
+        if( ret != XYSSL_ERR_NET_TRY_AGAIN )
+        {
+            printf( " failed\n  ! ssl_write returned %d\n\n", ret );
+            goto exit;
+        }
+    }
+
+    len = ret;
+    printf( " %d bytes written\n\n%s", len, (char *) buf );
+
+    /*
+     * 7. Read the HTTP response
+     */
+    printf( "  < Read from server:" );
+    fflush( stdout );
+
+    do
+    {
+        len = sizeof( buf ) - 1;
+        memset( buf, 0, sizeof( buf ) );
+        ret = ssl_read( &ssl, buf, len );
+
+        if( ret == XYSSL_ERR_NET_TRY_AGAIN )
+            continue;
+
+        if( ret == XYSSL_ERR_SSL_PEER_CLOSE_NOTIFY )
+            break;
+
+        if( ret <= 0 )
+        {
+            printf( "failed\n  ! ssl_read returned %d\n\n", ret );
+            break;
+        }
+
+        len = ret;
+        printf( " %d bytes read\n\n%s", len, (char *) buf );
+    }
+    while( 0 );
+
+    ssl_close_notify( &ssl );
+
+exit:
+
+    net_close( server_fd );
+    ssl_free( &ssl );
+
+    memset( &ssl, 0, sizeof( ssl ) );
+
+#ifdef WIN32
+    printf( "  + Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( ret );
+}
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
new file mode 100644
index 0000000..a19c37b
--- /dev/null
+++ b/programs/ssl/ssl_client2.c
@@ -0,0 +1,283 @@
+/*
+ *  SSL client with certificate authentication
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "xyssl/net.h"
+#include "xyssl/ssl.h"
+#include "xyssl/havege.h"
+#include "xyssl/certs.h"
+#include "xyssl/x509.h"
+
+#define SERVER_PORT 443
+/*
+#define SERVER_NAME "localhost"
+#define GET_REQUEST "GET / HTTP/1.0\r\n\r\n"
+*/
+#define SERVER_NAME "xyssl.org"
+#define GET_REQUEST \
+    "GET /hello/ HTTP/1.1\r\n" \
+    "Host: xyssl.org\r\n\r\n"
+
+#define DEBUG_LEVEL 0
+
+void my_debug( void *ctx, int level, char *str )
+{
+    if( level < DEBUG_LEVEL )
+    {
+        fprintf( (FILE *) ctx, "%s", str );
+        fflush(  (FILE *) ctx  );
+    }
+}
+
+int main( void )
+{
+    int ret, len, server_fd;
+    unsigned char buf[1024];
+    havege_state hs;
+    ssl_context ssl;
+    ssl_session ssn;
+    x509_cert cacert;
+    x509_cert clicert;
+    rsa_context rsa;
+
+    /*
+     * 0. Initialize the RNG and the session data
+     */
+    havege_init( &hs );
+    memset( &ssn, 0, sizeof( ssl_session ) );
+
+    /*
+     * 1.1. Load the trusted CA
+     */
+    printf( "\n  . Loading the CA root certificate ..." );
+    fflush( stdout );
+
+    memset( &cacert, 0, sizeof( x509_cert ) );
+
+    /*
+     * Alternatively, you may load the CA certificates from a .pem or
+     * .crt file by calling x509parse_crtfile( &cacert, "myca.crt" ).
+     */
+    ret = x509parse_crt( &cacert, (unsigned char *) xyssl_ca_crt,
+                         strlen( xyssl_ca_crt ) );
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  x509parse_crt returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 1.2. Load own certificate and private key
+     *
+     * (can be skipped if client authentication is not required)
+     */
+    printf( "  . Loading the client cert. and key..." );
+    fflush( stdout );
+
+    memset( &clicert, 0, sizeof( x509_cert ) );
+
+    ret = x509parse_crt( &clicert, (unsigned char *) test_cli_crt,
+                         strlen( test_cli_crt ) );
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  x509parse_crt returned %d\n\n", ret );
+        goto exit;
+    }
+
+    ret = x509parse_key( &rsa, (unsigned char *) test_cli_key,
+                         strlen( test_cli_key ), NULL, 0 );
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  x509parse_key returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 2. Start the connection
+     */
+    printf( "  . Connecting to tcp/%s/%-4d...", SERVER_NAME,
+                                                SERVER_PORT );
+    fflush( stdout );
+
+    if( ( ret = net_connect( &server_fd, SERVER_NAME,
+                                         SERVER_PORT ) ) != 0 )
+    {
+        printf( " failed\n  ! net_connect returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 3. Setup stuff
+     */
+    printf( "  . Setting up the SSL/TLS structure..." );
+    fflush( stdout );
+
+    havege_init( &hs );
+
+    if( ( ret = ssl_init( &ssl ) ) != 0 )
+    {
+        printf( " failed\n  ! ssl_init returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    ssl_set_endpoint( &ssl, SSL_IS_CLIENT );
+    ssl_set_authmode( &ssl, SSL_VERIFY_OPTIONAL );
+
+    ssl_set_rng( &ssl, havege_rand, &hs );
+    ssl_set_bio( &ssl, net_recv, &server_fd,
+                       net_send, &server_fd );
+
+    ssl_set_ciphers( &ssl, ssl_default_ciphers );
+    ssl_set_session( &ssl, 1, 600, &ssn );
+
+    ssl_set_ca_chain( &ssl, &cacert, SERVER_NAME );
+    ssl_set_own_cert( &ssl, &clicert, &rsa );
+
+    ssl_set_hostname( &ssl, SERVER_NAME );
+
+    /*
+     * 4. Handshake
+     */
+    printf( "  . Performing the SSL/TLS handshake..." );
+    fflush( stdout );
+
+    while( ( ret = ssl_handshake( &ssl ) ) != 0 )
+    {
+        if( ret != XYSSL_ERR_NET_TRY_AGAIN )
+        {
+            printf( " failed\n  ! ssl_handshake returned %d\n\n", ret );
+            goto exit;
+        }
+    }
+
+    printf( " ok\n    [ Cipher is %s ]\n",
+            ssl_get_cipher( &ssl ) );
+
+    /*
+     * 5. Verify the server certificate
+     */
+    printf( "  . Verifying peer X.509 certificate..." );
+
+    if( ( ret = ssl_get_verify_result( &ssl ) ) != 0 )
+    {
+        printf( " failed\n" );
+
+        if( ( ret & BADCERT_EXPIRED ) != 0 )
+            printf( "  ! server certificate has expired\n" );
+
+        if( ( ret & BADCERT_REVOKED ) != 0 )
+            printf( "  ! server certificate has been revoked\n" );
+
+        if( ( ret & BADCERT_CN_MISMATCH ) != 0 )
+            printf( "  ! CN mismatch (expected CN=%s)\n", SERVER_NAME );
+
+        if( ( ret & BADCERT_NOT_TRUSTED ) != 0 )
+            printf( "  ! self-signed or not signed by a trusted CA\n" );
+
+        printf( "\n" );
+    }
+    else
+        printf( " ok\n" );
+
+    printf( "  . Peer certificate information    ...\n" );
+    printf( x509parse_cert_info( "      ", ssl.peer_cert ) );
+
+    /*
+     * 6. Write the GET request
+     */
+    printf( "  > Write to server:" );
+    fflush( stdout );
+
+    len = sprintf( (char *) buf, GET_REQUEST );
+
+    while( ( ret = ssl_write( &ssl, buf, len ) ) <= 0 )
+    {
+        if( ret != XYSSL_ERR_NET_TRY_AGAIN )
+        {
+            printf( " failed\n  ! ssl_write returned %d\n\n", ret );
+            goto exit;
+        }
+    }
+
+    len = ret;
+    printf( " %d bytes written\n\n%s", len, (char *) buf );
+
+    /*
+     * 7. Read the HTTP response
+     */
+    printf( "  < Read from server:" );
+    fflush( stdout );
+
+    do
+    {
+        len = sizeof( buf ) - 1;
+        memset( buf, 0, sizeof( buf ) );
+        ret = ssl_read( &ssl, buf, len );
+
+        if( ret == XYSSL_ERR_NET_TRY_AGAIN )
+            continue;
+
+        if( ret == XYSSL_ERR_SSL_PEER_CLOSE_NOTIFY )
+            break;
+
+        if( ret <= 0 )
+        {
+            printf( "failed\n  ! ssl_read returned %d\n\n", ret );
+            break;
+        }
+
+        len = ret;
+        printf( " %d bytes read\n\n%s", len, (char *) buf );
+    }
+    while( 0 );
+
+    ssl_close_notify( &ssl );
+
+exit:
+
+    net_close( server_fd );
+    x509_free( &clicert );
+    x509_free( &cacert );
+    rsa_free( &rsa );
+    ssl_free( &ssl );
+
+    memset( &ssl, 0, sizeof( ssl ) );
+
+#ifdef WIN32
+    printf( "  + Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( ret );
+}
diff --git a/programs/ssl/ssl_server.c b/programs/ssl/ssl_server.c
new file mode 100644
index 0000000..565fed2
--- /dev/null
+++ b/programs/ssl/ssl_server.c
@@ -0,0 +1,399 @@
+/*
+ *  SSL server demonstration program
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "xyssl/havege.h"
+#include "xyssl/certs.h"
+#include "xyssl/x509.h"
+#include "xyssl/ssl.h"
+#include "xyssl/net.h"
+
+#define HTTP_RESPONSE \
+    "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \
+    "<h2><p><center>Successful connection using: %s\r\n"
+
+/*
+ * Computing a "safe" DH-1024 prime can take a very
+ * long time, so a precomputed value is provided below.
+ * You may run dh_genprime to generate a new value.
+ */
+char *my_dhm_P = 
+    "E4004C1F94182000103D883A448B3F80" \
+    "2CE4B44A83301270002C20D0321CFD00" \
+    "11CCEF784C26A400F43DFB901BCA7538" \
+    "F2C6B176001CF5A0FD16D2C48B1D0C1C" \
+    "F6AC8E1DA6BCC3B4E1F96B0564965300" \
+    "FFA1D0B601EB2800F489AA512C4B248C" \
+    "01F76949A60BB7F00A40B1EAB64BDD48" \
+    "E8A700D60B7F1200FA8E77B0A979DABF";
+
+char *my_dhm_G = "4";
+
+/*
+ * Sorted by order of preference
+ */
+int my_ciphers[] =
+{
+    SSL_EDH_RSA_AES_256_SHA,
+    SSL_EDH_RSA_DES_168_SHA,
+    SSL_RSA_AES_256_SHA,
+    SSL_RSA_AES_128_SHA,
+    SSL_RSA_DES_168_SHA,
+    SSL_RSA_RC4_128_SHA,
+    SSL_RSA_RC4_128_MD5,
+    0
+};
+
+#define DEBUG_LEVEL 0
+
+void my_debug( void *ctx, int level, char *str )
+{
+    if( level < DEBUG_LEVEL )
+    {
+        fprintf( (FILE *) ctx, "%s", str );
+        fflush(  (FILE *) ctx  );
+    }
+}
+
+/*
+ * These session callbacks use a simple chained list
+ * to store and retrieve the session information.
+ */
+ssl_session *s_list_1st = NULL;
+ssl_session *cur, *prv;
+
+static int my_get_session( ssl_context *ssl )
+{
+    time_t t = time( NULL );
+
+    if( ssl->resume == 0 )
+        return( 1 );
+
+    cur = s_list_1st;
+    prv = NULL;
+
+    while( cur != NULL )
+    {
+        prv = cur;
+        cur = cur->next;
+
+        if( ssl->timeout != 0 && t - prv->start > ssl->timeout )
+            continue;
+
+        if( ssl->session->cipher != prv->cipher ||
+            ssl->session->length != prv->length )
+            continue;
+
+        if( memcmp( ssl->session->id, prv->id, prv->length ) != 0 )
+            continue;
+
+        memcpy( ssl->session->master, prv->master, 48 );
+        return( 0 );
+    }
+
+    return( 1 );
+}
+
+static int my_set_session( ssl_context *ssl )
+{
+    time_t t = time( NULL );
+
+    cur = s_list_1st;
+    prv = NULL;
+
+    while( cur != NULL )
+    {
+        if( ssl->timeout != 0 && t - cur->start > ssl->timeout )
+            break; /* expired, reuse this slot */
+
+        if( memcmp( ssl->session->id, cur->id, cur->length ) == 0 )
+            break; /* client reconnected */
+
+        prv = cur;
+        cur = cur->next;
+    }
+
+    if( cur == NULL )
+    {
+        cur = (ssl_session *) malloc( sizeof( ssl_session ) );
+        if( cur == NULL )
+            return( 1 );
+
+        if( prv == NULL )
+              s_list_1st = cur;
+        else  prv->next  = cur;
+    }
+
+    memcpy( cur, ssl->session, sizeof( ssl_session ) );
+
+    return( 0 );
+}
+
+int main( void )
+{
+    int ret, len;
+    int listen_fd;
+    int client_fd;
+    unsigned char buf[1024];
+
+    havege_state hs;
+    ssl_context ssl;
+    ssl_session ssn;
+    x509_cert srvcert;
+    rsa_context rsa;
+
+    /*
+     * 1. Load the certificates and private RSA key
+     */
+    printf( "\n  . Loading the server cert. and key..." );
+    fflush( stdout );
+
+    memset( &srvcert, 0, sizeof( x509_cert ) );
+
+    /*
+     * This demonstration program uses embedded test certificates.
+     * Instead, you may want to use x509parse_crtfile() to read the
+     * server and CA certificates, as well as x509parse_keyfile().
+     */
+    ret = x509parse_crt( &srvcert, (unsigned char *) test_srv_crt,
+                         strlen( test_srv_crt ) );
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  x509parse_crt returned %d\n\n", ret );
+        goto exit;
+    }
+
+    ret = x509parse_crt( &srvcert, (unsigned char *) test_ca_crt,
+                         strlen( test_ca_crt ) );
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  x509parse_crt returned %d\n\n", ret );
+        goto exit;
+    }
+
+    ret =  x509parse_key( &rsa, (unsigned char *) test_srv_key,
+                          strlen( test_srv_key ), NULL, 0 );
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  x509parse_key returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 2. Setup the listening TCP socket
+     */
+    printf( "  . Bind on https://localhost:4433/ ..." );
+    fflush( stdout );
+
+    if( ( ret = net_bind( &listen_fd, NULL, 4433 ) ) != 0 )
+    {
+        printf( " failed\n  ! net_bind returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 3. Wait until a client connects
+     */
+#ifdef WIN32
+    ShellExecute( NULL, "open", "https://localhost:4433/",
+                  NULL, NULL, SW_SHOWNORMAL );
+#endif
+
+    client_fd = -1;
+    memset( &ssl, 0, sizeof( ssl ) );
+
+accept:
+
+    net_close( client_fd );
+    ssl_free( &ssl );
+
+    printf( "  . Waiting for a remote connection ..." );
+    fflush( stdout );
+
+    if( ( ret = net_accept( listen_fd, &client_fd, NULL ) ) != 0 )
+    {
+        printf( " failed\n  ! net_accept returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 4. Setup stuff
+     */
+    printf( "  . Setting up the RNG and SSL data...." );
+    fflush( stdout );
+
+    havege_init( &hs );
+
+    if( ( ret = ssl_init( &ssl ) ) != 0 )
+    {
+        printf( " failed\n  ! ssl_init returned %d\n\n", ret );
+        goto accept;
+    }
+
+    printf( " ok\n" );
+
+    ssl_set_endpoint( &ssl, SSL_IS_SERVER );
+    ssl_set_authmode( &ssl, SSL_VERIFY_NONE );
+
+    ssl_set_rng( &ssl, havege_rand, &hs );
+    ssl_set_dbg( &ssl, my_debug, stdout );
+    ssl_set_bio( &ssl, net_recv, &client_fd,
+                       net_send, &client_fd );
+    ssl_set_scb( &ssl, my_get_session,
+                       my_set_session );
+
+    ssl_set_ciphers( &ssl, my_ciphers );
+    ssl_set_session( &ssl, 1, 0, &ssn );
+
+    memset( &ssn, 0, sizeof( ssl_session ) );
+
+    ssl_set_ca_chain( &ssl, srvcert.next, NULL );
+    ssl_set_own_cert( &ssl, &srvcert, &rsa );
+    ssl_set_dh_param( &ssl, my_dhm_P, my_dhm_G );
+
+    /*
+     * 5. Handshake
+     */
+    printf( "  . Performing the SSL/TLS handshake..." );
+    fflush( stdout );
+
+    while( ( ret = ssl_handshake( &ssl ) ) != 0 )
+    {
+        if( ret != XYSSL_ERR_NET_TRY_AGAIN )
+        {
+            printf( " failed\n  ! ssl_handshake returned %d\n\n", ret );
+            goto accept;
+        }
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 6. Read the HTTP Request
+     */
+    printf( "  < Read from client:" );
+    fflush( stdout );
+
+    do
+    {
+        len = sizeof( buf ) - 1;
+        memset( buf, 0, sizeof( buf ) );
+        ret = ssl_read( &ssl, buf, len );
+
+        if( ret == XYSSL_ERR_NET_TRY_AGAIN )
+            continue;
+
+        if( ret <= 0 )
+        {
+            switch( ret )
+            {
+                case XYSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
+                    printf( " connection was closed gracefully\n" );
+                    break;
+
+                case XYSSL_ERR_NET_CONN_RESET:
+                    printf( " connection was reset by peer\n" );
+                    break;
+
+                default:
+                    printf( " ssl_read returned %d\n", ret );
+                    break;
+            }
+
+            break;
+        }
+
+        len = ret;
+        printf( " %d bytes read\n\n%s", len, (char *) buf );
+    }
+    while( 0 );
+
+    /*
+     * 7. Write the 200 Response
+     */
+    printf( "  > Write to client:" );
+    fflush( stdout );
+
+    len = sprintf( (char *) buf, HTTP_RESPONSE,
+                   ssl_get_cipher( &ssl ) );
+
+    while( ( ret = ssl_write( &ssl, buf, len ) ) <= 0 )
+    {
+        if( ret == XYSSL_ERR_NET_CONN_RESET )
+        {
+            printf( " failed\n  ! peer closed the connection\n\n" );
+            goto accept;
+        }
+
+        if( ret != XYSSL_ERR_NET_TRY_AGAIN )
+        {
+            printf( " failed\n  ! ssl_write returned %d\n\n", ret );
+            goto exit;
+        }
+    }
+
+    len = ret;
+    printf( " %d bytes written\n\n%s\n", len, (char *) buf );
+
+    ssl_close_notify( &ssl );
+    goto accept;
+
+exit:
+
+    net_close( client_fd );
+    x509_free( &srvcert );
+    rsa_free( &rsa );
+    ssl_free( &ssl );
+
+    cur = s_list_1st;
+    while( cur != NULL )
+    {
+        prv = cur;
+        cur = cur->next;
+        memset( prv, 0, sizeof( ssl_session ) );
+        free( prv );
+    }
+
+    memset( &ssl, 0, sizeof( ssl_context ) );
+
+#ifdef WIN32
+    printf( "  Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( ret );
+}
diff --git a/programs/ssl/test-ca/client1.crt b/programs/ssl/test-ca/client1.crt
new file mode 100644
index 0000000..679bbea
--- /dev/null
+++ b/programs/ssl/test-ca/client1.crt
@@ -0,0 +1,76 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 3 (0x3)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: O=XySSL, CN=XySSL Test CA
+        Validity
+            Not Before: Nov 29 19:50:42 2007 GMT
+            Not After : Nov 28 19:50:42 2009 GMT
+        Subject: O=XySSL, CN=Test User 1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:a7:2b:e9:c3:d5:68:7c:e7:4b:23:20:31:c8:0e:
+                    be:9f:c8:e6:b6:a7:09:c5:59:67:ab:6d:e9:f3:7e:
+                    b2:e7:3b:1c:99:28:33:e0:b8:e9:8b:ee:45:a3:de:
+                    91:f8:03:59:34:f1:b6:e0:b3:62:33:45:87:64:8e:
+                    59:d3:34:4f:f9:fb:3c:64:53:a2:f2:53:20:97:a3:
+                    2b:fe:6d:c4:f3:38:83:02:92:c8:cb:8f:9e:d9:d3:
+                    5e:87:36:ec:17:b3:50:5b:68:b7:03:04:e2:90:2f:
+                    d4:0e:48:40:b1:ad:11:28:de:8a:a9:4c:df:20:05:
+                    47:8a:ef:ba:24:09:fa:ec:f6:d4:f1:0f:a1:31:b7:
+                    f0:54:d5:d5:23:19:1e:41:6d:b7:96:17:81:ff:b3:
+                    1e:83:92:76:4b:7c:ce:b1:8f:18:b0:69:20:60:f9:
+                    41:8b:04:ae:89:84:a8:20:48:ae:f3:1f:50:ec:1c:
+                    61:97:bd:81:50:54:61:5d:23:c3:c2:84:ed:19:1b:
+                    ee:0f:22:38:28:de:51:04:41:6d:e1:82:43:76:e7:
+                    7b:40:fd:84:ea:9e:e8:d8:da:c2:72:c4:31:c6:b0:
+                    ca:ce:ac:7b:5c:fa:43:15:5f:41:1c:21:be:dc:96:
+                    95:d6:77:16:ef:1d:51:8d:10:65:aa:f5:9e:f8:47:
+                    6a:41
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                F2:C4:96:02:CF:BF:C1:AA:B0:D2:1A:DA:E7:F3:4B:2C:5D:D1:DF:14
+            X509v3 Authority Key Identifier: 
+                keyid:F2:67:B1:5D:5F:51:5E:DA:51:89:E9:D9:E9:6B:CA:8B:AF:A5:2E:69
+
+    Signature Algorithm: sha1WithRSAEncryption
+        ca:29:3f:44:90:8d:9c:c6:0d:f9:e2:a9:50:d8:e5:d6:0a:e0:
+        be:6e:48:fb:e8:7a:f4:5f:50:dc:6b:d1:76:a5:f9:88:91:96:
+        62:e5:66:89:da:eb:17:01:f7:d0:d2:f7:3b:35:78:dd:80:45:
+        d0:64:32:13:67:20:a8:fc:d8:62:e1:44:d4:ae:41:37:2e:e7:
+        63:94:37:66:61:3b:38:e9:7d:8a:b6:18:d4:b7:2c:59:ea:46:
+        a0:ed:ab:84:79:04:be:da:0f:9e:2d:68:34:a0:06:63:fa:33:
+        61:bc:8a:00:07:62:c3:81:11:0d:28:d9:80:8f:51:a2:db:be:
+        23:16:a4:37:65:18:72:34:17:c2:a9:63:e3:5f:f4:0e:7c:58:
+        5e:e4:a5:44:8f:6b:23:ba:18:4e:e3:0c:25:2a:86:ee:5d:c2:
+        a2:e7:92:8d:a8:84:77:ef:b5:9c:af:2c:53:5d:4c:1b:eb:96:
+        a4:56:27:f5:bf:cb:82:91:51:6e:8a:f4:49:6a:84:39:44:a3:
+        23:7e:d0:83:ce:2b:4a:5f:18:1b:d1:1f:74:14:6f:91:da:1a:
+        ee:95:1d:ee:c7:9e:77:a2:df:1c:22:72:c2:08:bc:98:60:a0:
+        d6:5f:eb:d8:e8:ad:b3:f5:05:c4:1a:9b:a9:8d:29:83:7e:26:
+        62:fa:e3:79
+-----BEGIN CERTIFICATE-----
+MIIDFjCCAf6gAwIBAgIBAzANBgkqhkiG9w0BAQUFADAoMQ4wDAYDVQQKEwVYeVNT
+TDEWMBQGA1UEAxMNWHlTU0wgVGVzdCBDQTAeFw0wNzExMjkxOTUwNDJaFw0wOTEx
+MjgxOTUwNDJaMCYxDjAMBgNVBAoTBVh5U1NMMRQwEgYDVQQDEwtUZXN0IFVzZXIg
+MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKcr6cPVaHznSyMgMcgO
+vp/I5ranCcVZZ6tt6fN+suc7HJkoM+C46YvuRaPekfgDWTTxtuCzYjNFh2SOWdM0
+T/n7PGRTovJTIJejK/5txPM4gwKSyMuPntnTXoc27BezUFtotwME4pAv1A5IQLGt
+ESjeiqlM3yAFR4rvuiQJ+uz21PEPoTG38FTV1SMZHkFtt5YXgf+zHoOSdkt8zrGP
+GLBpIGD5QYsEromEqCBIrvMfUOwcYZe9gVBUYV0jw8KE7Rkb7g8iOCjeUQRBbeGC
+Q3bne0D9hOqe6NjawnLEMcawys6se1z6QxVfQRwhvtyWldZ3Fu8dUY0QZar1nvhH
+akECAwEAAaNNMEswCQYDVR0TBAIwADAdBgNVHQ4EFgQU8sSWAs+/waqw0hra5/NL
+LF3R3xQwHwYDVR0jBBgwFoAU8mexXV9RXtpRienZ6WvKi6+lLmkwDQYJKoZIhvcN
+AQEFBQADggEBAMopP0SQjZzGDfniqVDY5dYK4L5uSPvoevRfUNxr0Xal+YiRlmLl
+Zona6xcB99DS9zs1eN2ARdBkMhNnIKj82GLhRNSuQTcu52OUN2ZhOzjpfYq2GNS3
+LFnqRqDtq4R5BL7aD54taDSgBmP6M2G8igAHYsOBEQ0o2YCPUaLbviMWpDdlGHI0
+F8KpY+Nf9A58WF7kpUSPayO6GE7jDCUqhu5dwqLnko2ohHfvtZyvLFNdTBvrlqRW
+J/W/y4KRUW6K9ElqhDlEoyN+0IPOK0pfGBvRH3QUb5HaGu6VHe7Hnnei3xwicsII
+vJhgoNZf69jorbP1BcQam6mNKYN+JmL643k=
+-----END CERTIFICATE-----
diff --git a/programs/ssl/test-ca/client1.key b/programs/ssl/test-ca/client1.key
new file mode 100644
index 0000000..1b78404
--- /dev/null
+++ b/programs/ssl/test-ca/client1.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEApyvpw9VofOdLIyAxyA6+n8jmtqcJxVlnq23p836y5zscmSgz
+4Ljpi+5Fo96R+ANZNPG24LNiM0WHZI5Z0zRP+fs8ZFOi8lMgl6Mr/m3E8ziDApLI
+y4+e2dNehzbsF7NQW2i3AwTikC/UDkhAsa0RKN6KqUzfIAVHiu+6JAn67PbU8Q+h
+MbfwVNXVIxkeQW23lheB/7Meg5J2S3zOsY8YsGkgYPlBiwSuiYSoIEiu8x9Q7Bxh
+l72BUFRhXSPDwoTtGRvuDyI4KN5RBEFt4YJDdud7QP2E6p7o2NrCcsQxxrDKzqx7
+XPpDFV9BHCG+3JaV1ncW7x1RjRBlqvWe+EdqQQIDAQABAoIBAQCmgiHUMnNhvYtk
+kEOlbbJHOvc6RQSBcjzFTrRxGOifUox4rMeHdQcCnrD0uNMRglxPVNb/1wzf3sgt
+y3AC458pcinEEF5EGbJj913xjWpXjBlJ7eRchVAGzPbhnT3pmWxXr+Rh+HKmhU0l
+cKgnkSd/WrIoUW4I2dlZtM/l557seI3Mz34MdWfPgMRdHUFhOa0iJakHtYt1/o4/
+adxjoIdwAjerru0g918frKb3vi13ir67UMrh/A0uUPsVMi/hSZvuT0c2C+Kd+xtH
+e0ttWZ6x8eBEzsimghz2YuaQs4OyPwZHP0unRRpN+Am453b2VjnKPF/S2qFCNOMq
+jWnxyKrBAoGBANx93if4pTTwYeQop4EtYWmfr2OEX9syZzIbv4i1cPQTQo7stDGA
+wX32ytFYvQwm7GZmmHp1buPrfOrYgmD5T29wfjETNqttKxzmJ+aXa30t7UnTH04H
+NCU7O4xAVrFcNeZ4+7o6CwbjHKzflaJXeWlkl/X8hWXUiMAGz6nOKcfpAoGBAMIX
+1cCRTYqfM804Yql1F23b2nX8fFy6VqbWk/ViFWKwamdn0+C3ffLuULnK0s6Xya3G
+/6Ecr/6/+H+KlSNRhenOHHasdhA02QwlEgHFXHG53NSCLLTXjf/LAUNyOvjlnL8P
+tWDqBOWJg4M9aMvsxdv7ALPa/pd7d7kodDvccXCZAoGAI16pkX3oeoqJGYGQBT/T
+XY85Ilysx8vZFAexfOumN/ES/zxnV32RDHTXaiezA80GpRKWKSbHaBZxjna2y3mS
+zYydIaA0Z+F2RgeBpRLrMkR4yRvt7KVpLwPGdKQphAAHwXXs453GAQ/TnMOtDEK9
+/jMd0V71wzUJzswI6fNhbmkCgYByIiX16PvaCigiA4gw8cPnPCNIwkI3HPQbg47Z
++uVsdST8zZdQS1Zq5izeNCCmj6du4tgrW306ppRwG4P7ktLWW/ds6Zk7ingfpiTi
+mbX0wkDTTgEQDrlXs354tNFsz0jPKWOVK8fZWnXVVOUtFXx8ESuml56iYV5TqTBA
+iy7B8QKBgFrmftKKVycQ3EofuhVz2TlxBK+SLnhjNyGyLm6mIgyn09g837ObxMkC
+s/zkUNoZVEW1qcFg10yyqB5F5r94h1qwyTRFPQoBHU88JHMBAkyWMy3yR9z/ca+r
+AzK+oYwtRcRsLdWaMN+nHkJESRZg8QPvT6YJlvRHMEExYndqovRJ
+-----END RSA PRIVATE KEY-----
diff --git a/programs/ssl/test-ca/client2.crt b/programs/ssl/test-ca/client2.crt
new file mode 100644
index 0000000..14a90ca
--- /dev/null
+++ b/programs/ssl/test-ca/client2.crt
@@ -0,0 +1,76 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 4 (0x4)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: O=XySSL, CN=XySSL Test CA
+        Validity
+            Not Before: Nov 29 19:50:48 2007 GMT
+            Not After : Nov 28 19:50:48 2009 GMT
+        Subject: O=XySSL, CN=Test User 2
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:e5:7b:e1:94:06:e5:dd:20:0a:0d:6a:4f:9e:2c:
+                    43:ea:74:f8:af:90:ab:60:7e:45:17:27:d9:1b:1d:
+                    90:44:97:42:45:67:22:32:d5:eb:97:4e:76:ef:45:
+                    99:3f:80:29:c5:45:94:7d:43:c0:0b:01:bd:ac:9c:
+                    9d:cf:ff:3f:ea:1e:04:1c:2a:70:94:ff:6b:d1:63:
+                    6f:cd:b0:5f:1d:bf:d6:45:f2:e1:32:17:18:87:b4:
+                    79:39:52:01:23:50:5d:8d:10:89:02:c7:e8:a8:67:
+                    a5:14:41:0f:1a:d7:25:2b:91:f8:6a:c6:5d:e3:b0:
+                    fe:30:7c:47:56:95:93:e1:e8:e4:74:e5:1f:bf:00:
+                    32:49:8e:f7:1d:29:07:68:4c:8e:ca:6f:84:96:37:
+                    37:3d:ee:92:1d:15:b3:18:30:ef:a0:46:b1:6e:7b:
+                    ec:d4:a6:27:8d:11:f9:35:31:9c:91:04:c8:e2:8a:
+                    ac:4f:cb:b4:49:b0:92:2b:82:59:4e:69:00:62:51:
+                    4f:5d:10:72:54:03:5c:24:39:8a:fb:39:6b:c1:da:
+                    84:10:15:c3:04:cb:31:26:91:b8:0a:b1:b5:32:69:
+                    ec:0f:64:a7:51:53:dc:64:13:b1:c2:ec:fc:55:0a:
+                    d8:f5:22:e7:c4:d9:4f:73:8d:85:b6:cc:8b:2a:51:
+                    76:e3
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                72:A9:55:09:13:A6:61:1E:1D:9F:00:BA:AF:93:D9:8D:69:86:1D:20
+            X509v3 Authority Key Identifier: 
+                keyid:F2:67:B1:5D:5F:51:5E:DA:51:89:E9:D9:E9:6B:CA:8B:AF:A5:2E:69
+
+    Signature Algorithm: sha1WithRSAEncryption
+        68:32:9c:c5:ea:15:03:a3:2a:5b:e0:3b:ef:02:72:72:5e:5f:
+        57:b3:32:1f:a8:46:93:33:38:75:92:5f:41:e3:99:97:3a:f2:
+        0d:7d:2b:71:81:31:a7:ff:15:28:e8:f1:fe:d4:c1:83:2b:0b:
+        1a:1b:6c:b3:81:01:e1:4c:77:51:8b:09:2d:7f:da:52:2c:f5:
+        9e:38:a7:59:b8:cc:dc:f5:42:d4:3f:7f:22:96:7e:4a:89:f0:
+        cc:6e:77:f0:ee:79:d3:82:20:7a:0c:17:e2:c8:14:77:81:cd:
+        bf:34:27:76:7c:c2:eb:4f:93:dd:0a:a3:ee:2e:b9:f6:8a:d2:
+        7f:0b:f0:69:0f:90:05:6e:d6:ca:23:91:6d:38:68:28:2b:c7:
+        2d:99:17:c7:2a:1b:a6:1b:78:ea:68:56:cb:2e:83:d4:98:54:
+        1f:a5:77:cd:88:59:9c:bd:a2:88:70:4e:f4:68:f0:0e:70:45:
+        9c:c0:ef:d4:48:f0:14:cc:24:b5:47:40:08:07:2f:df:78:0b:
+        0b:50:f6:49:85:41:8c:48:12:78:3a:67:67:d9:82:09:0f:54:
+        a5:fe:14:7c:d4:21:60:a2:45:2b:ea:97:df:38:cc:f5:5a:cd:
+        4d:62:5a:a1:cf:51:cb:93:36:2e:c7:17:ec:77:89:06:f2:c9:
+        55:70:96:f3
+-----BEGIN CERTIFICATE-----
+MIIDFjCCAf6gAwIBAgIBBDANBgkqhkiG9w0BAQUFADAoMQ4wDAYDVQQKEwVYeVNT
+TDEWMBQGA1UEAxMNWHlTU0wgVGVzdCBDQTAeFw0wNzExMjkxOTUwNDhaFw0wOTEx
+MjgxOTUwNDhaMCYxDjAMBgNVBAoTBVh5U1NMMRQwEgYDVQQDEwtUZXN0IFVzZXIg
+MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOV74ZQG5d0gCg1qT54s
+Q+p0+K+Qq2B+RRcn2RsdkESXQkVnIjLV65dOdu9FmT+AKcVFlH1DwAsBvaycnc//
+P+oeBBwqcJT/a9Fjb82wXx2/1kXy4TIXGIe0eTlSASNQXY0QiQLH6KhnpRRBDxrX
+JSuR+GrGXeOw/jB8R1aVk+Ho5HTlH78AMkmO9x0pB2hMjspvhJY3Nz3ukh0Vsxgw
+76BGsW577NSmJ40R+TUxnJEEyOKKrE/LtEmwkiuCWU5pAGJRT10QclQDXCQ5ivs5
+a8HahBAVwwTLMSaRuAqxtTJp7A9kp1FT3GQTscLs/FUK2PUi58TZT3ONhbbMiypR
+duMCAwEAAaNNMEswCQYDVR0TBAIwADAdBgNVHQ4EFgQUcqlVCROmYR4dnwC6r5PZ
+jWmGHSAwHwYDVR0jBBgwFoAU8mexXV9RXtpRienZ6WvKi6+lLmkwDQYJKoZIhvcN
+AQEFBQADggEBAGgynMXqFQOjKlvgO+8CcnJeX1ezMh+oRpMzOHWSX0HjmZc68g19
+K3GBMaf/FSjo8f7UwYMrCxobbLOBAeFMd1GLCS1/2lIs9Z44p1m4zNz1QtQ/fyKW
+fkqJ8Mxud/DuedOCIHoMF+LIFHeBzb80J3Z8wutPk90Ko+4uufaK0n8L8GkPkAVu
+1sojkW04aCgrxy2ZF8cqG6YbeOpoVssug9SYVB+ld82IWZy9oohwTvRo8A5wRZzA
+79RI8BTMJLVHQAgHL994CwtQ9kmFQYxIEng6Z2fZggkPVKX+FHzUIWCiRSvql984
+zPVazU1iWqHPUcuTNi7HF+x3iQbyyVVwlvM=
+-----END CERTIFICATE-----
diff --git a/programs/ssl/test-ca/client2.key b/programs/ssl/test-ca/client2.key
new file mode 100644
index 0000000..8696e10
--- /dev/null
+++ b/programs/ssl/test-ca/client2.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEA5XvhlAbl3SAKDWpPnixD6nT4r5CrYH5FFyfZGx2QRJdCRWci
+MtXrl05270WZP4ApxUWUfUPACwG9rJydz/8/6h4EHCpwlP9r0WNvzbBfHb/WRfLh
+MhcYh7R5OVIBI1BdjRCJAsfoqGelFEEPGtclK5H4asZd47D+MHxHVpWT4ejkdOUf
+vwAySY73HSkHaEyOym+Eljc3Pe6SHRWzGDDvoEaxbnvs1KYnjRH5NTGckQTI4oqs
+T8u0SbCSK4JZTmkAYlFPXRByVANcJDmK+zlrwdqEEBXDBMsxJpG4CrG1MmnsD2Sn
+UVPcZBOxwuz8VQrY9SLnxNlPc42FtsyLKlF24wIDAQABAoIBAENov1uPJyhsR+em
+6dpJoG2XjJFtypmencbugpyvc3higioG4InUQs8AUnl4lUqM6Dg1dyfQpfHVwhSZ
+MNYvYWPxCz4GzWlHGjG4ptfhzh7cAiIr9TCUjjUWs2E+EG2CJujQCZ8Sf+ov/9LS
+RZCZ0CZbS4B54oyGqjQt3Xq2l2kNRODdKbaSK3zZWp9nMNyu0iUpmAtgh6FliARI
+pPr7oUHNxnmkF5JHyLFaGBtr33FZnmh8q9/gGnqEujkd6ynNwERCDVBZiBolVoCm
+sIoC5kBZjaY//I+0dZoBqDsSOGUupdICiy1dHeC8Nc0GIX79pVLNLabCeQbxxOBg
+QTN25FECgYEA8vnRvr6Hq53otreRO5RWFRnpGC0QS+nZArLxuva33IK5srN8CBbD
+qMyszUiG7URHtQudvG9uno2X8fZmvRxRp42NTo3xCUX6HQmbo7o2B1RvQnJ/k+NF
+A9IjqWS0jzneKo7jpoRhKPVolubADGZh7E9IRF+I0ajyOatv6eOB0RkCgYEA8cjr
+9Lg80TSiY4v1z0KzFVRmYsUj2OlkYqSF9XMTIQGO2mGn8ApDh/OzpnxCSK0RjLeR
+WUu3/6pCxUjM4ddOi81hiX51gkx6TC0SZ5jXPUm+NZVfkln8uYmvXE/4qSMZVvnl
+iJnhOV8wNfwhriHQv22+OkoDD1Ul5Cv0GZZim1sCgYEA8BDEm6HEilvKwj080ZEO
+PGsNU0WzBE5Yi8Ih9IgvwT+oGlgcBCH5z53qXil6ppMABnEjuDqhISblKbw6Zj7E
+rre9FhBIRtFM/cOwc2RYXYWfKBfY1VWHqu7FLWjCvYB/ca0cYDoLhVxzqiTzO00t
+Ez6COIvrsrsqGLC6Mm0GpoECgYEA22QQTtdaQA69hwx5uF5yd1lFKjxuAaYNs8BL
+2WNYqStrv1a7dwEpM9R7YAcCckWwVfo/hkJBrFiHC9K6LfcbS5nJ9mPsJpZUpoiD
+WcODExa15JMszHSg8I4xs9bQ8FBr7tMEZwYSKufnrCSjPwlqDDl9UhDUY/ZEUp1b
+elhOE18CgYEAprkUGSy8JHB/Y23U/DUEfHLvUy9W1HjOYXe/SOL+z3TQV3vg/FVr
+VJJ+PIUoSaHkCm9Vm5J4uZaRf5NhajgLPKiIDxvR6oeeU7kC4Pi55voJ6spnCS0+
+xp7hjCLiFeWNqNlF9y6YCmaEM+ULVfw5WerNeeZs36T6iVu5CIiVgsY=
+-----END RSA PRIVATE KEY-----
diff --git a/programs/ssl/test-ca/client2.pfx b/programs/ssl/test-ca/client2.pfx
new file mode 100644
index 0000000..9d7c25c
--- /dev/null
+++ b/programs/ssl/test-ca/client2.pfx
Binary files differ
diff --git a/programs/ssl/test-ca/crl.pem b/programs/ssl/test-ca/crl.pem
new file mode 100644
index 0000000..87b42ba
--- /dev/null
+++ b/programs/ssl/test-ca/crl.pem
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBmDCBgTANBgkqhkiG9w0BAQUFADAoMQ4wDAYDVQQKEwVYeVNTTDEWMBQGA1UE
+AxMNWHlTU0wgVGVzdCBDQRcNMDcxMTI5MTk1MTA4WhcNMDgwMTI4MTk1MTA4WjAo
+MBICAQEXDTA3MTEyOTE5NTA1N1owEgIBAxcNMDcxMTI5MTk1MTAxWjANBgkqhkiG
+9w0BAQUFAAOCAQEATos7dzWxTxm51ZbI48LRseHgz/976mt/E1UZ5WoeoFMmW9qG
+oGmRexrfgzABz1s0S+fjunSibH5lPN4WLTTQ5vY/wzbLFE/ysXMB82b7EVf0fdVC
+9V1805XVOfSr5CBYTdTk1XQ8/ihKHi+TEJMGgXjC4V09qVrKVXO3dmD71MAr4Bcv
+n9ZSWnXuAIELyGfZaHrPjQf9cGc1awsFfdBbkmFrEOuL3Q7oKLae2oENknSWcMhy
+cJTkQuzNI2HwCzR2U1TA4YUrPuNTLaQ58FiI0hEFjTjtgreMirqn9LROJjKzb/xs
+Afi6pbrGefpkTZEZsnbvXxCKcej1tRYjCfgoIQ==
+-----END X509 CRL-----
diff --git a/programs/ssl/test-ca/index b/programs/ssl/test-ca/index
new file mode 100644
index 0000000..f14f2ef
--- /dev/null
+++ b/programs/ssl/test-ca/index
@@ -0,0 +1,4 @@
+R	091128195030Z	071129195057Z	01	unknown	/O=XySSL/CN=server1.test
+V	091128195038Z		02	unknown	/O=XySSL/CN=localhost
+R	091128195042Z	071129195101Z	03	unknown	/O=XySSL/CN=Test User 1
+V	091128195048Z		04	unknown	/O=XySSL/CN=Test User 2
diff --git a/programs/ssl/test-ca/index.attr b/programs/ssl/test-ca/index.attr
new file mode 100644
index 0000000..3a7e39e
--- /dev/null
+++ b/programs/ssl/test-ca/index.attr
@@ -0,0 +1 @@
+unique_subject = no
diff --git a/programs/ssl/test-ca/newcerts/01.pem b/programs/ssl/test-ca/newcerts/01.pem
new file mode 100644
index 0000000..fb7dcd4
--- /dev/null
+++ b/programs/ssl/test-ca/newcerts/01.pem
@@ -0,0 +1,76 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: O=XySSL, CN=XySSL Test CA
+        Validity
+            Not Before: Nov 29 19:50:30 2007 GMT
+            Not After : Nov 28 19:50:30 2009 GMT
+        Subject: O=XySSL, CN=server1.test
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:c6:ca:48:5e:2b:f2:79:4b:32:0c:38:01:e1:4c:
+                    1c:d1:24:bb:ea:de:b8:2f:fb:7a:01:da:4b:3c:13:
+                    0b:d1:12:c0:69:dc:f3:37:2b:fd:b7:a3:b7:49:f2:
+                    57:c2:6d:f8:be:90:f6:7e:fa:80:37:89:17:b8:4c:
+                    85:22:36:f4:36:51:9f:91:6b:48:01:9e:bb:e6:8e:
+                    99:be:ab:45:01:c2:6f:f0:0f:ad:22:ba:83:06:38:
+                    aa:b2:3c:e7:f4:aa:c9:32:30:32:db:1c:1a:96:87:
+                    eb:2f:53:0d:97:2d:75:3c:bc:75:74:e5:04:51:67:
+                    4e:4e:81:d0:00:4c:ff:47:e7:c3:ca:1f:5d:1c:65:
+                    00:89:0b:d2:78:a5:d3:d2:8f:5c:f8:fe:e5:54:9d:
+                    64:83:bc:12:dc:38:cc:b4:68:3e:2b:c6:b9:d0:ef:
+                    b1:e8:bc:cf:5a:b5:b3:1f:47:0a:b1:0f:79:06:97:
+                    73:3b:75:f0:6e:26:1d:36:88:4a:e9:64:b6:e6:58:
+                    f8:92:12:a6:7c:08:cc:7b:69:47:6e:c6:65:ae:d8:
+                    31:39:30:3d:ca:0a:4b:2c:c2:01:3e:e9:05:c6:6e:
+                    1f:ce:38:21:22:f4:f5:00:1e:18:0e:d5:48:1a:6e:
+                    d5:22:82:af:be:09:a7:47:03:0b:d3:4d:52:5e:34:
+                    d1:15
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                F7:AB:E7:C0:58:5F:E0:01:C5:A4:26:83:44:CC:1E:7A:91:C9:44:65
+            X509v3 Authority Key Identifier: 
+                keyid:F2:67:B1:5D:5F:51:5E:DA:51:89:E9:D9:E9:6B:CA:8B:AF:A5:2E:69
+
+    Signature Algorithm: sha1WithRSAEncryption
+        06:9b:8d:63:8c:bb:8a:2b:1a:87:ae:3a:27:34:bc:24:60:f0:
+        95:12:0e:f5:4c:e6:e4:1f:bd:e2:83:a3:d4:1e:dd:ed:8e:c1:
+        93:bc:e6:20:96:34:65:73:ac:bb:85:64:54:49:53:82:da:27:
+        8d:86:e5:a3:12:a5:b6:8e:c6:40:87:0b:1a:a4:02:fe:47:a9:
+        bf:36:39:b1:54:a7:63:1f:92:b2:1a:4f:9e:05:98:e6:f5:b1:
+        16:fb:47:bb:57:1f:31:35:8e:f8:36:d1:36:48:6a:25:c8:0e:
+        1c:3d:02:90:cd:cd:1e:68:d2:af:09:e2:69:51:ce:3a:11:67:
+        20:40:44:c9:9a:4d:9c:3c:af:07:22:dc:99:77:71:40:46:d7:
+        fe:3c:00:30:fc:67:50:89:73:aa:04:4c:ef:e2:44:c1:2e:88:
+        83:89:83:80:47:88:47:ca:1b:db:67:7e:e7:a8:0a:54:b8:72:
+        f4:96:3f:eb:c1:ba:21:c1:fe:07:eb:ce:4d:b0:80:d6:d9:cf:
+        2d:e9:8e:c2:2f:6f:cc:8b:a9:13:fd:48:50:5e:2f:86:cd:9e:
+        8b:ad:16:7f:69:ab:b7:7b:7f:c6:d8:49:f8:06:d0:8a:37:71:
+        75:d8:4f:3f:02:29:3e:9e:29:cc:f6:e7:c3:10:42:77:6c:34:
+        63:f3:be:57
+-----BEGIN CERTIFICATE-----
+MIIDFzCCAf+gAwIBAgIBATANBgkqhkiG9w0BAQUFADAoMQ4wDAYDVQQKEwVYeVNT
+TDEWMBQGA1UEAxMNWHlTU0wgVGVzdCBDQTAeFw0wNzExMjkxOTUwMzBaFw0wOTEx
+MjgxOTUwMzBaMCcxDjAMBgNVBAoTBVh5U1NMMRUwEwYDVQQDEwxzZXJ2ZXIxLnRl
+c3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGykheK/J5SzIMOAHh
+TBzRJLvq3rgv+3oB2ks8EwvREsBp3PM3K/23o7dJ8lfCbfi+kPZ++oA3iRe4TIUi
+NvQ2UZ+Ra0gBnrvmjpm+q0UBwm/wD60iuoMGOKqyPOf0qskyMDLbHBqWh+svUw2X
+LXU8vHV05QRRZ05OgdAATP9H58PKH10cZQCJC9J4pdPSj1z4/uVUnWSDvBLcOMy0
+aD4rxrnQ77HovM9atbMfRwqxD3kGl3M7dfBuJh02iErpZLbmWPiSEqZ8CMx7aUdu
+xmWu2DE5MD3KCksswgE+6QXGbh/OOCEi9PUAHhgO1UgabtUigq++CadHAwvTTVJe
+NNEVAgMBAAGjTTBLMAkGA1UdEwQCMAAwHQYDVR0OBBYEFPer58BYX+ABxaQmg0TM
+HnqRyURlMB8GA1UdIwQYMBaAFPJnsV1fUV7aUYnp2elryouvpS5pMA0GCSqGSIb3
+DQEBBQUAA4IBAQAGm41jjLuKKxqHrjonNLwkYPCVEg71TObkH73ig6PUHt3tjsGT
+vOYgljRlc6y7hWRUSVOC2ieNhuWjEqW2jsZAhwsapAL+R6m/NjmxVKdjH5KyGk+e
+BZjm9bEW+0e7Vx8xNY74NtE2SGolyA4cPQKQzc0eaNKvCeJpUc46EWcgQETJmk2c
+PK8HItyZd3FARtf+PAAw/GdQiXOqBEzv4kTBLoiDiYOAR4hHyhvbZ37nqApUuHL0
+lj/rwbohwf4H685NsIDW2c8t6Y7CL2/Mi6kT/UhQXi+GzZ6LrRZ/aau3e3/G2En4
+BtCKN3F12E8/Aik+ninM9ufDEEJ3bDRj875X
+-----END CERTIFICATE-----
diff --git a/programs/ssl/test-ca/newcerts/02.pem b/programs/ssl/test-ca/newcerts/02.pem
new file mode 100644
index 0000000..72b06f7
--- /dev/null
+++ b/programs/ssl/test-ca/newcerts/02.pem
@@ -0,0 +1,76 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 2 (0x2)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: O=XySSL, CN=XySSL Test CA
+        Validity
+            Not Before: Nov 29 19:50:38 2007 GMT
+            Not After : Nov 28 19:50:38 2009 GMT
+        Subject: O=XySSL, CN=localhost
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:cc:d4:56:38:49:e6:d6:7f:50:e7:d2:05:c8:99:
+                    25:32:45:71:dd:1c:e1:72:3d:68:94:c0:68:e2:2e:
+                    95:94:87:03:5b:fc:70:69:c4:b3:a0:94:e6:71:02:
+                    18:b1:00:5b:bd:90:ee:08:d0:cd:33:d2:fb:5e:ca:
+                    d6:c2:58:ed:f0:51:b7:54:ac:a4:99:22:8b:a3:07:
+                    bb:d7:41:14:de:0a:5a:92:9d:2d:08:1c:5f:bf:9b:
+                    dc:02:bb:c2:ca:06:b8:f2:8d:04:67:52:ca:9c:3a:
+                    15:a3:ba:30:2f:51:07:4d:8c:69:5c:8c:9f:41:56:
+                    03:ca:b4:88:b8:ce:0f:f0:28:67:19:dd:4c:96:64:
+                    8d:1c:07:b2:c6:cb:58:bf:d9:2b:42:39:ed:28:80:
+                    30:61:23:0e:95:d7:27:11:6f:7e:bc:bc:7b:73:01:
+                    c3:9a:56:fb:e6:ae:88:a8:96:5a:0f:bb:a5:b1:9d:
+                    d5:4a:74:00:26:68:08:3d:67:92:49:58:ab:e2:6a:
+                    00:45:83:3b:e1:e3:e6:c7:2c:c0:40:b9:ca:68:0b:
+                    a4:8f:ba:6d:53:af:6f:7a:57:84:4f:d8:b0:ae:0c:
+                    ce:23:1b:25:32:13:b6:3a:97:74:ca:af:2c:96:76:
+                    34:b2:24:6e:39:45:13:ec:be:16:db:b8:41:71:06:
+                    00:ed
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                B1:B0:EA:31:9D:5C:4F:00:7F:CD:0D:1F:78:A9:18:5D:96:DE:AA:B1
+            X509v3 Authority Key Identifier: 
+                keyid:F2:67:B1:5D:5F:51:5E:DA:51:89:E9:D9:E9:6B:CA:8B:AF:A5:2E:69
+
+    Signature Algorithm: sha1WithRSAEncryption
+        2b:9f:5d:f7:8c:42:89:45:d9:19:6f:d1:87:71:c7:74:ec:13:
+        c1:c3:7d:51:b5:6d:c3:f8:f4:cc:8a:d5:3b:ee:59:0e:0b:b8:
+        bf:7f:a3:4a:69:cb:ea:54:fc:58:98:34:05:0a:62:aa:73:61:
+        f2:15:8c:20:93:61:0b:9f:fd:64:d1:7d:87:b3:e5:43:1b:71:
+        36:b4:4c:b1:19:38:04:35:e7:f6:52:e5:3c:d0:a5:2d:55:99:
+        9e:5b:df:d5:60:6c:59:ac:e4:f7:4e:f7:55:ce:da:1c:9c:5e:
+        35:a8:d5:41:47:09:e0:df:7d:75:7e:8e:41:2c:93:34:bf:d2:
+        5e:5b:15:15:05:02:4d:24:1e:c4:5b:03:52:ab:0a:ac:6d:72:
+        00:3c:de:f9:0f:84:73:dc:b2:e6:52:6c:82:af:26:97:5a:58:
+        50:89:a3:c7:d9:5d:a5:8a:3c:e0:e8:3e:63:eb:4f:ff:fd:45:
+        b2:ec:a1:fb:45:03:0f:37:d0:a1:8d:42:bf:23:91:66:2e:09:
+        61:18:3e:5b:e7:b7:e4:6e:e0:2d:88:0d:c2:2a:e6:19:fa:35:
+        05:0d:8b:a4:f3:fb:05:54:98:87:66:5a:a2:f3:56:b5:39:7c:
+        1c:28:50:06:4a:3c:60:5a:e8:ec:19:4e:7e:cd:b1:56:5e:a3:
+        4d:f8:6c:72
+-----BEGIN CERTIFICATE-----
+MIIDFDCCAfygAwIBAgIBAjANBgkqhkiG9w0BAQUFADAoMQ4wDAYDVQQKEwVYeVNT
+TDEWMBQGA1UEAxMNWHlTU0wgVGVzdCBDQTAeFw0wNzExMjkxOTUwMzhaFw0wOTEx
+MjgxOTUwMzhaMCQxDjAMBgNVBAoTBVh5U1NMMRIwEAYDVQQDEwlsb2NhbGhvc3Qw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDM1FY4SebWf1Dn0gXImSUy
+RXHdHOFyPWiUwGjiLpWUhwNb/HBpxLOglOZxAhixAFu9kO4I0M0z0vteytbCWO3w
+UbdUrKSZIoujB7vXQRTeClqSnS0IHF+/m9wCu8LKBrjyjQRnUsqcOhWjujAvUQdN
+jGlcjJ9BVgPKtIi4zg/wKGcZ3UyWZI0cB7LGy1i/2StCOe0ogDBhIw6V1ycRb368
+vHtzAcOaVvvmroiolloPu6WxndVKdAAmaAg9Z5JJWKviagBFgzvh4+bHLMBAucpo
+C6SPum1Tr296V4RP2LCuDM4jGyUyE7Y6l3TKryyWdjSyJG45RRPsvhbbuEFxBgDt
+AgMBAAGjTTBLMAkGA1UdEwQCMAAwHQYDVR0OBBYEFLGw6jGdXE8Af80NH3ipGF2W
+3qqxMB8GA1UdIwQYMBaAFPJnsV1fUV7aUYnp2elryouvpS5pMA0GCSqGSIb3DQEB
+BQUAA4IBAQArn133jEKJRdkZb9GHccd07BPBw31RtW3D+PTMitU77lkOC7i/f6NK
+acvqVPxYmDQFCmKqc2HyFYwgk2ELn/1k0X2Hs+VDG3E2tEyxGTgENef2UuU80KUt
+VZmeW9/VYGxZrOT3TvdVztocnF41qNVBRwng3311fo5BLJM0v9JeWxUVBQJNJB7E
+WwNSqwqsbXIAPN75D4Rz3LLmUmyCryaXWlhQiaPH2V2lijzg6D5j60///UWy7KH7
+RQMPN9ChjUK/I5FmLglhGD5b57fkbuAtiA3CKuYZ+jUFDYuk8/sFVJiHZlqi81a1
+OXwcKFAGSjxgWujsGU5+zbFWXqNN+Gxy
+-----END CERTIFICATE-----
diff --git a/programs/ssl/test-ca/newcerts/03.pem b/programs/ssl/test-ca/newcerts/03.pem
new file mode 100644
index 0000000..679bbea
--- /dev/null
+++ b/programs/ssl/test-ca/newcerts/03.pem
@@ -0,0 +1,76 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 3 (0x3)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: O=XySSL, CN=XySSL Test CA
+        Validity
+            Not Before: Nov 29 19:50:42 2007 GMT
+            Not After : Nov 28 19:50:42 2009 GMT
+        Subject: O=XySSL, CN=Test User 1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:a7:2b:e9:c3:d5:68:7c:e7:4b:23:20:31:c8:0e:
+                    be:9f:c8:e6:b6:a7:09:c5:59:67:ab:6d:e9:f3:7e:
+                    b2:e7:3b:1c:99:28:33:e0:b8:e9:8b:ee:45:a3:de:
+                    91:f8:03:59:34:f1:b6:e0:b3:62:33:45:87:64:8e:
+                    59:d3:34:4f:f9:fb:3c:64:53:a2:f2:53:20:97:a3:
+                    2b:fe:6d:c4:f3:38:83:02:92:c8:cb:8f:9e:d9:d3:
+                    5e:87:36:ec:17:b3:50:5b:68:b7:03:04:e2:90:2f:
+                    d4:0e:48:40:b1:ad:11:28:de:8a:a9:4c:df:20:05:
+                    47:8a:ef:ba:24:09:fa:ec:f6:d4:f1:0f:a1:31:b7:
+                    f0:54:d5:d5:23:19:1e:41:6d:b7:96:17:81:ff:b3:
+                    1e:83:92:76:4b:7c:ce:b1:8f:18:b0:69:20:60:f9:
+                    41:8b:04:ae:89:84:a8:20:48:ae:f3:1f:50:ec:1c:
+                    61:97:bd:81:50:54:61:5d:23:c3:c2:84:ed:19:1b:
+                    ee:0f:22:38:28:de:51:04:41:6d:e1:82:43:76:e7:
+                    7b:40:fd:84:ea:9e:e8:d8:da:c2:72:c4:31:c6:b0:
+                    ca:ce:ac:7b:5c:fa:43:15:5f:41:1c:21:be:dc:96:
+                    95:d6:77:16:ef:1d:51:8d:10:65:aa:f5:9e:f8:47:
+                    6a:41
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                F2:C4:96:02:CF:BF:C1:AA:B0:D2:1A:DA:E7:F3:4B:2C:5D:D1:DF:14
+            X509v3 Authority Key Identifier: 
+                keyid:F2:67:B1:5D:5F:51:5E:DA:51:89:E9:D9:E9:6B:CA:8B:AF:A5:2E:69
+
+    Signature Algorithm: sha1WithRSAEncryption
+        ca:29:3f:44:90:8d:9c:c6:0d:f9:e2:a9:50:d8:e5:d6:0a:e0:
+        be:6e:48:fb:e8:7a:f4:5f:50:dc:6b:d1:76:a5:f9:88:91:96:
+        62:e5:66:89:da:eb:17:01:f7:d0:d2:f7:3b:35:78:dd:80:45:
+        d0:64:32:13:67:20:a8:fc:d8:62:e1:44:d4:ae:41:37:2e:e7:
+        63:94:37:66:61:3b:38:e9:7d:8a:b6:18:d4:b7:2c:59:ea:46:
+        a0:ed:ab:84:79:04:be:da:0f:9e:2d:68:34:a0:06:63:fa:33:
+        61:bc:8a:00:07:62:c3:81:11:0d:28:d9:80:8f:51:a2:db:be:
+        23:16:a4:37:65:18:72:34:17:c2:a9:63:e3:5f:f4:0e:7c:58:
+        5e:e4:a5:44:8f:6b:23:ba:18:4e:e3:0c:25:2a:86:ee:5d:c2:
+        a2:e7:92:8d:a8:84:77:ef:b5:9c:af:2c:53:5d:4c:1b:eb:96:
+        a4:56:27:f5:bf:cb:82:91:51:6e:8a:f4:49:6a:84:39:44:a3:
+        23:7e:d0:83:ce:2b:4a:5f:18:1b:d1:1f:74:14:6f:91:da:1a:
+        ee:95:1d:ee:c7:9e:77:a2:df:1c:22:72:c2:08:bc:98:60:a0:
+        d6:5f:eb:d8:e8:ad:b3:f5:05:c4:1a:9b:a9:8d:29:83:7e:26:
+        62:fa:e3:79
+-----BEGIN CERTIFICATE-----
+MIIDFjCCAf6gAwIBAgIBAzANBgkqhkiG9w0BAQUFADAoMQ4wDAYDVQQKEwVYeVNT
+TDEWMBQGA1UEAxMNWHlTU0wgVGVzdCBDQTAeFw0wNzExMjkxOTUwNDJaFw0wOTEx
+MjgxOTUwNDJaMCYxDjAMBgNVBAoTBVh5U1NMMRQwEgYDVQQDEwtUZXN0IFVzZXIg
+MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKcr6cPVaHznSyMgMcgO
+vp/I5ranCcVZZ6tt6fN+suc7HJkoM+C46YvuRaPekfgDWTTxtuCzYjNFh2SOWdM0
+T/n7PGRTovJTIJejK/5txPM4gwKSyMuPntnTXoc27BezUFtotwME4pAv1A5IQLGt
+ESjeiqlM3yAFR4rvuiQJ+uz21PEPoTG38FTV1SMZHkFtt5YXgf+zHoOSdkt8zrGP
+GLBpIGD5QYsEromEqCBIrvMfUOwcYZe9gVBUYV0jw8KE7Rkb7g8iOCjeUQRBbeGC
+Q3bne0D9hOqe6NjawnLEMcawys6se1z6QxVfQRwhvtyWldZ3Fu8dUY0QZar1nvhH
+akECAwEAAaNNMEswCQYDVR0TBAIwADAdBgNVHQ4EFgQU8sSWAs+/waqw0hra5/NL
+LF3R3xQwHwYDVR0jBBgwFoAU8mexXV9RXtpRienZ6WvKi6+lLmkwDQYJKoZIhvcN
+AQEFBQADggEBAMopP0SQjZzGDfniqVDY5dYK4L5uSPvoevRfUNxr0Xal+YiRlmLl
+Zona6xcB99DS9zs1eN2ARdBkMhNnIKj82GLhRNSuQTcu52OUN2ZhOzjpfYq2GNS3
+LFnqRqDtq4R5BL7aD54taDSgBmP6M2G8igAHYsOBEQ0o2YCPUaLbviMWpDdlGHI0
+F8KpY+Nf9A58WF7kpUSPayO6GE7jDCUqhu5dwqLnko2ohHfvtZyvLFNdTBvrlqRW
+J/W/y4KRUW6K9ElqhDlEoyN+0IPOK0pfGBvRH3QUb5HaGu6VHe7Hnnei3xwicsII
+vJhgoNZf69jorbP1BcQam6mNKYN+JmL643k=
+-----END CERTIFICATE-----
diff --git a/programs/ssl/test-ca/newcerts/04.pem b/programs/ssl/test-ca/newcerts/04.pem
new file mode 100644
index 0000000..14a90ca
--- /dev/null
+++ b/programs/ssl/test-ca/newcerts/04.pem
@@ -0,0 +1,76 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 4 (0x4)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: O=XySSL, CN=XySSL Test CA
+        Validity
+            Not Before: Nov 29 19:50:48 2007 GMT
+            Not After : Nov 28 19:50:48 2009 GMT
+        Subject: O=XySSL, CN=Test User 2
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:e5:7b:e1:94:06:e5:dd:20:0a:0d:6a:4f:9e:2c:
+                    43:ea:74:f8:af:90:ab:60:7e:45:17:27:d9:1b:1d:
+                    90:44:97:42:45:67:22:32:d5:eb:97:4e:76:ef:45:
+                    99:3f:80:29:c5:45:94:7d:43:c0:0b:01:bd:ac:9c:
+                    9d:cf:ff:3f:ea:1e:04:1c:2a:70:94:ff:6b:d1:63:
+                    6f:cd:b0:5f:1d:bf:d6:45:f2:e1:32:17:18:87:b4:
+                    79:39:52:01:23:50:5d:8d:10:89:02:c7:e8:a8:67:
+                    a5:14:41:0f:1a:d7:25:2b:91:f8:6a:c6:5d:e3:b0:
+                    fe:30:7c:47:56:95:93:e1:e8:e4:74:e5:1f:bf:00:
+                    32:49:8e:f7:1d:29:07:68:4c:8e:ca:6f:84:96:37:
+                    37:3d:ee:92:1d:15:b3:18:30:ef:a0:46:b1:6e:7b:
+                    ec:d4:a6:27:8d:11:f9:35:31:9c:91:04:c8:e2:8a:
+                    ac:4f:cb:b4:49:b0:92:2b:82:59:4e:69:00:62:51:
+                    4f:5d:10:72:54:03:5c:24:39:8a:fb:39:6b:c1:da:
+                    84:10:15:c3:04:cb:31:26:91:b8:0a:b1:b5:32:69:
+                    ec:0f:64:a7:51:53:dc:64:13:b1:c2:ec:fc:55:0a:
+                    d8:f5:22:e7:c4:d9:4f:73:8d:85:b6:cc:8b:2a:51:
+                    76:e3
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                72:A9:55:09:13:A6:61:1E:1D:9F:00:BA:AF:93:D9:8D:69:86:1D:20
+            X509v3 Authority Key Identifier: 
+                keyid:F2:67:B1:5D:5F:51:5E:DA:51:89:E9:D9:E9:6B:CA:8B:AF:A5:2E:69
+
+    Signature Algorithm: sha1WithRSAEncryption
+        68:32:9c:c5:ea:15:03:a3:2a:5b:e0:3b:ef:02:72:72:5e:5f:
+        57:b3:32:1f:a8:46:93:33:38:75:92:5f:41:e3:99:97:3a:f2:
+        0d:7d:2b:71:81:31:a7:ff:15:28:e8:f1:fe:d4:c1:83:2b:0b:
+        1a:1b:6c:b3:81:01:e1:4c:77:51:8b:09:2d:7f:da:52:2c:f5:
+        9e:38:a7:59:b8:cc:dc:f5:42:d4:3f:7f:22:96:7e:4a:89:f0:
+        cc:6e:77:f0:ee:79:d3:82:20:7a:0c:17:e2:c8:14:77:81:cd:
+        bf:34:27:76:7c:c2:eb:4f:93:dd:0a:a3:ee:2e:b9:f6:8a:d2:
+        7f:0b:f0:69:0f:90:05:6e:d6:ca:23:91:6d:38:68:28:2b:c7:
+        2d:99:17:c7:2a:1b:a6:1b:78:ea:68:56:cb:2e:83:d4:98:54:
+        1f:a5:77:cd:88:59:9c:bd:a2:88:70:4e:f4:68:f0:0e:70:45:
+        9c:c0:ef:d4:48:f0:14:cc:24:b5:47:40:08:07:2f:df:78:0b:
+        0b:50:f6:49:85:41:8c:48:12:78:3a:67:67:d9:82:09:0f:54:
+        a5:fe:14:7c:d4:21:60:a2:45:2b:ea:97:df:38:cc:f5:5a:cd:
+        4d:62:5a:a1:cf:51:cb:93:36:2e:c7:17:ec:77:89:06:f2:c9:
+        55:70:96:f3
+-----BEGIN CERTIFICATE-----
+MIIDFjCCAf6gAwIBAgIBBDANBgkqhkiG9w0BAQUFADAoMQ4wDAYDVQQKEwVYeVNT
+TDEWMBQGA1UEAxMNWHlTU0wgVGVzdCBDQTAeFw0wNzExMjkxOTUwNDhaFw0wOTEx
+MjgxOTUwNDhaMCYxDjAMBgNVBAoTBVh5U1NMMRQwEgYDVQQDEwtUZXN0IFVzZXIg
+MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOV74ZQG5d0gCg1qT54s
+Q+p0+K+Qq2B+RRcn2RsdkESXQkVnIjLV65dOdu9FmT+AKcVFlH1DwAsBvaycnc//
+P+oeBBwqcJT/a9Fjb82wXx2/1kXy4TIXGIe0eTlSASNQXY0QiQLH6KhnpRRBDxrX
+JSuR+GrGXeOw/jB8R1aVk+Ho5HTlH78AMkmO9x0pB2hMjspvhJY3Nz3ukh0Vsxgw
+76BGsW577NSmJ40R+TUxnJEEyOKKrE/LtEmwkiuCWU5pAGJRT10QclQDXCQ5ivs5
+a8HahBAVwwTLMSaRuAqxtTJp7A9kp1FT3GQTscLs/FUK2PUi58TZT3ONhbbMiypR
+duMCAwEAAaNNMEswCQYDVR0TBAIwADAdBgNVHQ4EFgQUcqlVCROmYR4dnwC6r5PZ
+jWmGHSAwHwYDVR0jBBgwFoAU8mexXV9RXtpRienZ6WvKi6+lLmkwDQYJKoZIhvcN
+AQEFBQADggEBAGgynMXqFQOjKlvgO+8CcnJeX1ezMh+oRpMzOHWSX0HjmZc68g19
+K3GBMaf/FSjo8f7UwYMrCxobbLOBAeFMd1GLCS1/2lIs9Z44p1m4zNz1QtQ/fyKW
+fkqJ8Mxud/DuedOCIHoMF+LIFHeBzb80J3Z8wutPk90Ko+4uufaK0n8L8GkPkAVu
+1sojkW04aCgrxy2ZF8cqG6YbeOpoVssug9SYVB+ld82IWZy9oohwTvRo8A5wRZzA
+79RI8BTMJLVHQAgHL994CwtQ9kmFQYxIEng6Z2fZggkPVKX+FHzUIWCiRSvql984
+zPVazU1iWqHPUcuTNi7HF+x3iQbyyVVwlvM=
+-----END CERTIFICATE-----
diff --git a/programs/ssl/test-ca/serial b/programs/ssl/test-ca/serial
new file mode 100644
index 0000000..eeee65e
--- /dev/null
+++ b/programs/ssl/test-ca/serial
@@ -0,0 +1 @@
+05
diff --git a/programs/ssl/test-ca/server1.crt b/programs/ssl/test-ca/server1.crt
new file mode 100644
index 0000000..fb7dcd4
--- /dev/null
+++ b/programs/ssl/test-ca/server1.crt
@@ -0,0 +1,76 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: O=XySSL, CN=XySSL Test CA
+        Validity
+            Not Before: Nov 29 19:50:30 2007 GMT
+            Not After : Nov 28 19:50:30 2009 GMT
+        Subject: O=XySSL, CN=server1.test
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:c6:ca:48:5e:2b:f2:79:4b:32:0c:38:01:e1:4c:
+                    1c:d1:24:bb:ea:de:b8:2f:fb:7a:01:da:4b:3c:13:
+                    0b:d1:12:c0:69:dc:f3:37:2b:fd:b7:a3:b7:49:f2:
+                    57:c2:6d:f8:be:90:f6:7e:fa:80:37:89:17:b8:4c:
+                    85:22:36:f4:36:51:9f:91:6b:48:01:9e:bb:e6:8e:
+                    99:be:ab:45:01:c2:6f:f0:0f:ad:22:ba:83:06:38:
+                    aa:b2:3c:e7:f4:aa:c9:32:30:32:db:1c:1a:96:87:
+                    eb:2f:53:0d:97:2d:75:3c:bc:75:74:e5:04:51:67:
+                    4e:4e:81:d0:00:4c:ff:47:e7:c3:ca:1f:5d:1c:65:
+                    00:89:0b:d2:78:a5:d3:d2:8f:5c:f8:fe:e5:54:9d:
+                    64:83:bc:12:dc:38:cc:b4:68:3e:2b:c6:b9:d0:ef:
+                    b1:e8:bc:cf:5a:b5:b3:1f:47:0a:b1:0f:79:06:97:
+                    73:3b:75:f0:6e:26:1d:36:88:4a:e9:64:b6:e6:58:
+                    f8:92:12:a6:7c:08:cc:7b:69:47:6e:c6:65:ae:d8:
+                    31:39:30:3d:ca:0a:4b:2c:c2:01:3e:e9:05:c6:6e:
+                    1f:ce:38:21:22:f4:f5:00:1e:18:0e:d5:48:1a:6e:
+                    d5:22:82:af:be:09:a7:47:03:0b:d3:4d:52:5e:34:
+                    d1:15
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                F7:AB:E7:C0:58:5F:E0:01:C5:A4:26:83:44:CC:1E:7A:91:C9:44:65
+            X509v3 Authority Key Identifier: 
+                keyid:F2:67:B1:5D:5F:51:5E:DA:51:89:E9:D9:E9:6B:CA:8B:AF:A5:2E:69
+
+    Signature Algorithm: sha1WithRSAEncryption
+        06:9b:8d:63:8c:bb:8a:2b:1a:87:ae:3a:27:34:bc:24:60:f0:
+        95:12:0e:f5:4c:e6:e4:1f:bd:e2:83:a3:d4:1e:dd:ed:8e:c1:
+        93:bc:e6:20:96:34:65:73:ac:bb:85:64:54:49:53:82:da:27:
+        8d:86:e5:a3:12:a5:b6:8e:c6:40:87:0b:1a:a4:02:fe:47:a9:
+        bf:36:39:b1:54:a7:63:1f:92:b2:1a:4f:9e:05:98:e6:f5:b1:
+        16:fb:47:bb:57:1f:31:35:8e:f8:36:d1:36:48:6a:25:c8:0e:
+        1c:3d:02:90:cd:cd:1e:68:d2:af:09:e2:69:51:ce:3a:11:67:
+        20:40:44:c9:9a:4d:9c:3c:af:07:22:dc:99:77:71:40:46:d7:
+        fe:3c:00:30:fc:67:50:89:73:aa:04:4c:ef:e2:44:c1:2e:88:
+        83:89:83:80:47:88:47:ca:1b:db:67:7e:e7:a8:0a:54:b8:72:
+        f4:96:3f:eb:c1:ba:21:c1:fe:07:eb:ce:4d:b0:80:d6:d9:cf:
+        2d:e9:8e:c2:2f:6f:cc:8b:a9:13:fd:48:50:5e:2f:86:cd:9e:
+        8b:ad:16:7f:69:ab:b7:7b:7f:c6:d8:49:f8:06:d0:8a:37:71:
+        75:d8:4f:3f:02:29:3e:9e:29:cc:f6:e7:c3:10:42:77:6c:34:
+        63:f3:be:57
+-----BEGIN CERTIFICATE-----
+MIIDFzCCAf+gAwIBAgIBATANBgkqhkiG9w0BAQUFADAoMQ4wDAYDVQQKEwVYeVNT
+TDEWMBQGA1UEAxMNWHlTU0wgVGVzdCBDQTAeFw0wNzExMjkxOTUwMzBaFw0wOTEx
+MjgxOTUwMzBaMCcxDjAMBgNVBAoTBVh5U1NMMRUwEwYDVQQDEwxzZXJ2ZXIxLnRl
+c3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGykheK/J5SzIMOAHh
+TBzRJLvq3rgv+3oB2ks8EwvREsBp3PM3K/23o7dJ8lfCbfi+kPZ++oA3iRe4TIUi
+NvQ2UZ+Ra0gBnrvmjpm+q0UBwm/wD60iuoMGOKqyPOf0qskyMDLbHBqWh+svUw2X
+LXU8vHV05QRRZ05OgdAATP9H58PKH10cZQCJC9J4pdPSj1z4/uVUnWSDvBLcOMy0
+aD4rxrnQ77HovM9atbMfRwqxD3kGl3M7dfBuJh02iErpZLbmWPiSEqZ8CMx7aUdu
+xmWu2DE5MD3KCksswgE+6QXGbh/OOCEi9PUAHhgO1UgabtUigq++CadHAwvTTVJe
+NNEVAgMBAAGjTTBLMAkGA1UdEwQCMAAwHQYDVR0OBBYEFPer58BYX+ABxaQmg0TM
+HnqRyURlMB8GA1UdIwQYMBaAFPJnsV1fUV7aUYnp2elryouvpS5pMA0GCSqGSIb3
+DQEBBQUAA4IBAQAGm41jjLuKKxqHrjonNLwkYPCVEg71TObkH73ig6PUHt3tjsGT
+vOYgljRlc6y7hWRUSVOC2ieNhuWjEqW2jsZAhwsapAL+R6m/NjmxVKdjH5KyGk+e
+BZjm9bEW+0e7Vx8xNY74NtE2SGolyA4cPQKQzc0eaNKvCeJpUc46EWcgQETJmk2c
+PK8HItyZd3FARtf+PAAw/GdQiXOqBEzv4kTBLoiDiYOAR4hHyhvbZ37nqApUuHL0
+lj/rwbohwf4H685NsIDW2c8t6Y7CL2/Mi6kT/UhQXi+GzZ6LrRZ/aau3e3/G2En4
+BtCKN3F12E8/Aik+ninM9ufDEEJ3bDRj875X
+-----END CERTIFICATE-----
diff --git a/programs/ssl/test-ca/server1.key b/programs/ssl/test-ca/server1.key
new file mode 100644
index 0000000..b418c6d
--- /dev/null
+++ b/programs/ssl/test-ca/server1.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAxspIXivyeUsyDDgB4Uwc0SS76t64L/t6AdpLPBML0RLAadzz
+Nyv9t6O3SfJXwm34vpD2fvqAN4kXuEyFIjb0NlGfkWtIAZ675o6ZvqtFAcJv8A+t
+IrqDBjiqsjzn9KrJMjAy2xwalofrL1MNly11PLx1dOUEUWdOToHQAEz/R+fDyh9d
+HGUAiQvSeKXT0o9c+P7lVJ1kg7wS3DjMtGg+K8a50O+x6LzPWrWzH0cKsQ95Bpdz
+O3XwbiYdNohK6WS25lj4khKmfAjMe2lHbsZlrtgxOTA9ygpLLMIBPukFxm4fzjgh
+IvT1AB4YDtVIGm7VIoKvvgmnRwML001SXjTRFQIDAQABAoIBAHw0n4rXgqTuqtKf
+m+0dFVRH03IovoScZ9sIfcGHVPbI9JgwiXaLcfdvv3HgjZzaAXVwNdOYyMvqSHvK
+s9Rw6Z2W2lCN62u3tkeUCdPsRy2WQ0KHSPJN/tfASEcdbwCcRSGqo9vrb2FmgzgK
+eI9gw8OzLOBgx5XlKjQ7P68wbMCLoQ4z7UZQkqWRhBrO6r2yR6/+y91OgrFixp/D
+rpsWvvW4+EmPihYceA8CTqqZSz7DKcNvNyPqCFRav+856m/9oBxKOkuuvoR3811c
+GSn+c8Np/bbKQxZ6YA94QujoKMXO8i8ZEnRfMKa/NbBMpa1jSRTd/5uA6/CI+bUB
+io1nLgECgYEA4eVuezN7SvMN8ihB61Hg6fGwa2YiTPkCp7WWeRHB8f+2iq0hFCAn
+yu9YsyafVMVPwoebEMCkqaIrlrKdL0w3xUjDNwhgSyAQyXUnSQFwa3IkhLWNkj5P
+pQCAeZy9PEGwolPQKBNVaU+J7p7ipOv9VAyBmyqUq4XXwpYcdyH6NbUCgYEA4Ugd
+Kt3/iOJpv1PMIQpXI926lXbH6hquqlQbpb35YlNgC4N8eC/r4Q/yW7FI0kD72ipO
+EUlSFne8FJHPluNe6GahF9np6M48ogmv6QhiOFf5T+6kVXdJ+akqYhcWC5m/hArT
+/q27+PwTpYBwIwf54PaM/k9iOz0zH9bqY3TvSeECgYEAmChicroKokF1c1eKj2dn
+iC00GCODlzVjhHPcF1DOwqLr4h0b2uKN6zOtG384c3E0eGO/H1mjkF+b3LYTCnjc
+WBba54bM1c2TgR9YhuRhRP5teraP1aIDI7Fi2IerL5tPzweFfnkHXxgkYIbFQzFy
+QdrqsgnMenx9CKT0J4rLbsECgYA5a2gDxRGckhjh6zncMgaD3b/w2JWb1bEvOMDT
+PdiSdy3DwX+4In68npPnSwiEjouiz6WWQlnp4BrQI1oF224VThNBQQmdjPNnWZC8
+lKZ0NfgVp327SuxP9g4XckrsKgPmY9wkzaNbkuRvCo2KYD4QWMcXCqS+9JpTQzP6
+pZNYAQKBgQC5mvSC9zxQYX9Ia9PDL4q6AjdG0XweZuYHk2/bQ1LQjM7qI1mescol
+CXbNXUxhw2XAXkw8BFAfPJ3npIL7FX0htEiYx7KqpCYN7IXSpQ6xexZn6nEm+mBz
+VMWO8Roj95S3tyZOTzbmuUNbQsfLZlQ2hUeUBvJ5UH+LBFivjxy0pw==
+-----END RSA PRIVATE KEY-----
diff --git a/programs/ssl/test-ca/server2.crt b/programs/ssl/test-ca/server2.crt
new file mode 100644
index 0000000..72b06f7
--- /dev/null
+++ b/programs/ssl/test-ca/server2.crt
@@ -0,0 +1,76 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 2 (0x2)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: O=XySSL, CN=XySSL Test CA
+        Validity
+            Not Before: Nov 29 19:50:38 2007 GMT
+            Not After : Nov 28 19:50:38 2009 GMT
+        Subject: O=XySSL, CN=localhost
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:cc:d4:56:38:49:e6:d6:7f:50:e7:d2:05:c8:99:
+                    25:32:45:71:dd:1c:e1:72:3d:68:94:c0:68:e2:2e:
+                    95:94:87:03:5b:fc:70:69:c4:b3:a0:94:e6:71:02:
+                    18:b1:00:5b:bd:90:ee:08:d0:cd:33:d2:fb:5e:ca:
+                    d6:c2:58:ed:f0:51:b7:54:ac:a4:99:22:8b:a3:07:
+                    bb:d7:41:14:de:0a:5a:92:9d:2d:08:1c:5f:bf:9b:
+                    dc:02:bb:c2:ca:06:b8:f2:8d:04:67:52:ca:9c:3a:
+                    15:a3:ba:30:2f:51:07:4d:8c:69:5c:8c:9f:41:56:
+                    03:ca:b4:88:b8:ce:0f:f0:28:67:19:dd:4c:96:64:
+                    8d:1c:07:b2:c6:cb:58:bf:d9:2b:42:39:ed:28:80:
+                    30:61:23:0e:95:d7:27:11:6f:7e:bc:bc:7b:73:01:
+                    c3:9a:56:fb:e6:ae:88:a8:96:5a:0f:bb:a5:b1:9d:
+                    d5:4a:74:00:26:68:08:3d:67:92:49:58:ab:e2:6a:
+                    00:45:83:3b:e1:e3:e6:c7:2c:c0:40:b9:ca:68:0b:
+                    a4:8f:ba:6d:53:af:6f:7a:57:84:4f:d8:b0:ae:0c:
+                    ce:23:1b:25:32:13:b6:3a:97:74:ca:af:2c:96:76:
+                    34:b2:24:6e:39:45:13:ec:be:16:db:b8:41:71:06:
+                    00:ed
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                B1:B0:EA:31:9D:5C:4F:00:7F:CD:0D:1F:78:A9:18:5D:96:DE:AA:B1
+            X509v3 Authority Key Identifier: 
+                keyid:F2:67:B1:5D:5F:51:5E:DA:51:89:E9:D9:E9:6B:CA:8B:AF:A5:2E:69
+
+    Signature Algorithm: sha1WithRSAEncryption
+        2b:9f:5d:f7:8c:42:89:45:d9:19:6f:d1:87:71:c7:74:ec:13:
+        c1:c3:7d:51:b5:6d:c3:f8:f4:cc:8a:d5:3b:ee:59:0e:0b:b8:
+        bf:7f:a3:4a:69:cb:ea:54:fc:58:98:34:05:0a:62:aa:73:61:
+        f2:15:8c:20:93:61:0b:9f:fd:64:d1:7d:87:b3:e5:43:1b:71:
+        36:b4:4c:b1:19:38:04:35:e7:f6:52:e5:3c:d0:a5:2d:55:99:
+        9e:5b:df:d5:60:6c:59:ac:e4:f7:4e:f7:55:ce:da:1c:9c:5e:
+        35:a8:d5:41:47:09:e0:df:7d:75:7e:8e:41:2c:93:34:bf:d2:
+        5e:5b:15:15:05:02:4d:24:1e:c4:5b:03:52:ab:0a:ac:6d:72:
+        00:3c:de:f9:0f:84:73:dc:b2:e6:52:6c:82:af:26:97:5a:58:
+        50:89:a3:c7:d9:5d:a5:8a:3c:e0:e8:3e:63:eb:4f:ff:fd:45:
+        b2:ec:a1:fb:45:03:0f:37:d0:a1:8d:42:bf:23:91:66:2e:09:
+        61:18:3e:5b:e7:b7:e4:6e:e0:2d:88:0d:c2:2a:e6:19:fa:35:
+        05:0d:8b:a4:f3:fb:05:54:98:87:66:5a:a2:f3:56:b5:39:7c:
+        1c:28:50:06:4a:3c:60:5a:e8:ec:19:4e:7e:cd:b1:56:5e:a3:
+        4d:f8:6c:72
+-----BEGIN CERTIFICATE-----
+MIIDFDCCAfygAwIBAgIBAjANBgkqhkiG9w0BAQUFADAoMQ4wDAYDVQQKEwVYeVNT
+TDEWMBQGA1UEAxMNWHlTU0wgVGVzdCBDQTAeFw0wNzExMjkxOTUwMzhaFw0wOTEx
+MjgxOTUwMzhaMCQxDjAMBgNVBAoTBVh5U1NMMRIwEAYDVQQDEwlsb2NhbGhvc3Qw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDM1FY4SebWf1Dn0gXImSUy
+RXHdHOFyPWiUwGjiLpWUhwNb/HBpxLOglOZxAhixAFu9kO4I0M0z0vteytbCWO3w
+UbdUrKSZIoujB7vXQRTeClqSnS0IHF+/m9wCu8LKBrjyjQRnUsqcOhWjujAvUQdN
+jGlcjJ9BVgPKtIi4zg/wKGcZ3UyWZI0cB7LGy1i/2StCOe0ogDBhIw6V1ycRb368
+vHtzAcOaVvvmroiolloPu6WxndVKdAAmaAg9Z5JJWKviagBFgzvh4+bHLMBAucpo
+C6SPum1Tr296V4RP2LCuDM4jGyUyE7Y6l3TKryyWdjSyJG45RRPsvhbbuEFxBgDt
+AgMBAAGjTTBLMAkGA1UdEwQCMAAwHQYDVR0OBBYEFLGw6jGdXE8Af80NH3ipGF2W
+3qqxMB8GA1UdIwQYMBaAFPJnsV1fUV7aUYnp2elryouvpS5pMA0GCSqGSIb3DQEB
+BQUAA4IBAQArn133jEKJRdkZb9GHccd07BPBw31RtW3D+PTMitU77lkOC7i/f6NK
+acvqVPxYmDQFCmKqc2HyFYwgk2ELn/1k0X2Hs+VDG3E2tEyxGTgENef2UuU80KUt
+VZmeW9/VYGxZrOT3TvdVztocnF41qNVBRwng3311fo5BLJM0v9JeWxUVBQJNJB7E
+WwNSqwqsbXIAPN75D4Rz3LLmUmyCryaXWlhQiaPH2V2lijzg6D5j60///UWy7KH7
+RQMPN9ChjUK/I5FmLglhGD5b57fkbuAtiA3CKuYZ+jUFDYuk8/sFVJiHZlqi81a1
+OXwcKFAGSjxgWujsGU5+zbFWXqNN+Gxy
+-----END CERTIFICATE-----
diff --git a/programs/ssl/test-ca/server2.key b/programs/ssl/test-ca/server2.key
new file mode 100644
index 0000000..72a355c
--- /dev/null
+++ b/programs/ssl/test-ca/server2.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAzNRWOEnm1n9Q59IFyJklMkVx3Rzhcj1olMBo4i6VlIcDW/xw
+acSzoJTmcQIYsQBbvZDuCNDNM9L7XsrWwljt8FG3VKykmSKLowe710EU3gpakp0t
+CBxfv5vcArvCyga48o0EZ1LKnDoVo7owL1EHTYxpXIyfQVYDyrSIuM4P8ChnGd1M
+lmSNHAeyxstYv9krQjntKIAwYSMOldcnEW9+vLx7cwHDmlb75q6IqJZaD7ulsZ3V
+SnQAJmgIPWeSSVir4moARYM74ePmxyzAQLnKaAukj7ptU69veleET9iwrgzOIxsl
+MhO2Opd0yq8slnY0siRuOUUT7L4W27hBcQYA7QIDAQABAoIBAFSSyBbtzLZ8Uzek
+7GZrdYRQUDdwGVZGLMxete/ONEzjgmuUzAWgBlsjoBLBPti2wSqAkQhqzo+7abc2
+IX6VoYk89Gmt7zibnvRt2Q2D/c3AkK1A4LscnBxNioZGaKNqKytbNppDAQ2Ini7A
+Tez7k/xdIZPpLEiZ727fJCTKUKJkDhY0WlxFT4btMLJNZ4SyW6HGO+hKFzxdAtur
+QoNQcWfy2FBICPeI4ZopVyMUaR3skIUJQWDAi2dqSkSevoD67o4/fF4nDxs7DZWV
+ZQV6/WQ3IZHgTFc15g5qI1693ttmggytXXY2Kp41qOzGFNyrAgfj5IZef8SME2cJ
+bp/6QIECgYEA/0TWDUd6u7Z1vRRPqzXQtmGfsLry+0nYd1Q0/IvPwsVDtLxaXGcl
+rkhqVgxY7vP4rzU1PvjNEWKtWlD+qpv+OK7nVWeGVlmeb0ZEb+mz+qNm0inum64k
+VEYDQadVX3UHLP+Uquv7iUowtrOrPrRVkFdoo7S8dzIRuU3ONkLvXeUCgYEAzWqE
+sAh+KOw0YWZdAj9HFOjCOA1gaDrcQF13Cyoh3ZEIFK0J7nNkh8CZVFx7D5W1u6B0
+fAmoolMO3I4PfjbuwayMELjLdpii7a10/DC6BmtVCM3+sfpJtB7LmL13MVkPpNEv
+4BKFADTaxhbflemydXqUA/Cx4KBf7OhZK16+pmkCgYA9Kul/1Rj70gT0geF1TTft
+/Aaf+qwuuss8DNmFipsGOO64aEneynilAoU4iUzmNV/p2/4eUNAS0mpnsfDUQPzx
+6DdWp6/xERh94YCUsJOIA4+n3JRoiZn696vgF5DFhu1pQvUE3/cuNrDllrf6FoxK
+Qie40p42kbDdjl9TcUaaYQKBgAdfO0PWCjENyRN1yQC7pKFreQzp7fvPoPfuYsdT
+y8NX4SJc025rVcBJeTc92mzEwrDpIUUSU6r/sBjaQFQXRJpOxvgSqbqn37EH+JrU
+ZNi2IWcffXSFtv9v236vzgdHWvhfSYiRIZTQUMmrKHsI2A6/R3CcwsV8+/RUol6c
+F9uBAoGBAOV3xH5x9nVEecWO0vGC3/kTPYgox5pLEhCv298LcYRVgft7ajZS7C9A
+/inksiXGKtIuv6jCGbQULuzBdCGOQfAOInQ9HstX01cC+kJqTdb7/g8e/qWNAaIU
+/SyXap7wY6Nw0VloTBNmaEo4ZErRl1ytzbYCSa9VZrzOPIl8LUMn
+-----END RSA PRIVATE KEY-----
diff --git a/programs/ssl/test-ca/sslconf.txt b/programs/ssl/test-ca/sslconf.txt
new file mode 100644
index 0000000..f468f1f
--- /dev/null
+++ b/programs/ssl/test-ca/sslconf.txt
@@ -0,0 +1,60 @@
+##================================================================

+##============== Example OpenSSL configuration file ==============

+##================================================================

+

+#  References:

+#

+#  /etc/ssl/openssl.conf

+#  http://www.openssl.org/docs/apps/config.html

+#  http://www.openssl.org/docs/apps/x509v3_config.html

+

+[ ca ]

+default_ca              = my_ca

+

+[ my_ca ]

+certificate             = test-ca.crt

+private_key             = test-ca.key

+database                = index

+serial                  = serial

+

+new_certs_dir           = newcerts

+default_crl_days        = 60

+default_days            = 730

+default_md              = sha1

+policy                  = my_policy

+x509_extensions         = v3_usr

+

+[ my_policy ]

+countryName             = optional

+stateOrProvinceName     = optional

+organizationName        = match

+organizationalUnitName  = optional

+commonName              = supplied

+emailAddress            = optional

+

+[ req ]

+distinguished_name      = my_req_dn

+x509_extensions         = v3_ca

+

+[ my_req_dn ]

+countryName             = Country Name..............

+countryName_min         = 2

+countryName_max         = 2

+stateOrProvinceName     = State or Province Name....

+localityName            = Locality Name.............

+0.organizationName      = Organization Name.........

+organizationalUnitName  = Org. Unit Name............

+commonName              = Common Name (required)....

+commonName_max          = 64

+emailAddress            = Email Address.............

+emailAddress_max        = 64

+

+[ v3_ca ]

+basicConstraints        = CA:TRUE

+subjectKeyIdentifier    = hash

+authorityKeyIdentifier  = keyid:always,issuer:always

+

+[ v3_usr ]

+basicConstraints        = CA:FALSE

+subjectKeyIdentifier    = hash

+authorityKeyIdentifier  = keyid,issuer

diff --git a/programs/ssl/test-ca/test-ca.crt b/programs/ssl/test-ca/test-ca.crt
new file mode 100644
index 0000000..54b3d11
--- /dev/null
+++ b/programs/ssl/test-ca/test-ca.crt
@@ -0,0 +1,79 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 0 (0x0)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: O=XySSL, CN=XySSL Test CA
+        Validity
+            Not Before: Nov 29 19:49:14 2007 GMT
+            Not After : Nov 29 19:49:14 2017 GMT
+        Subject: O=XySSL, CN=XySSL Test CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:d1:f4:8c:48:85:e1:15:a8:92:f4:43:e4:e4:f8:
+                    ee:e7:63:bb:0a:50:39:09:0b:2f:09:be:4c:da:9d:
+                    f9:30:40:03:76:27:94:db:73:8a:af:77:bf:73:3a:
+                    e2:a5:9b:aa:0d:fd:26:b3:d1:37:98:e8:bc:21:82:
+                    86:17:92:90:bf:4d:d1:73:95:f4:a3:a8:07:be:51:
+                    15:2a:40:3b:29:d7:43:c0:f3:5e:1c:4a:37:34:f3:
+                    34:1f:06:d3:73:8a:4f:80:a1:e7:74:03:e3:b5:77:
+                    1f:63:54:ef:9b:9b:65:6b:d3:b5:0f:5f:6a:85:dc:
+                    ea:4f:5b:19:59:4d:e1:29:f5:ac:a7:8d:32:b3:83:
+                    0c:7f:f5:7d:44:ba:d4:82:ed:23:be:ae:51:c5:a8:
+                    57:1d:d9:53:f0:33:2f:36:3c:21:2c:cc:18:c4:6b:
+                    4f:57:ad:03:1e:80:92:a7:c8:15:8d:1c:e0:03:18:
+                    ae:d9:08:06:45:9a:af:72:68:f7:02:69:e6:01:e7:
+                    91:34:5f:ba:e7:7d:2e:4f:79:d7:c4:39:52:cc:3b:
+                    dc:8d:d9:2f:f3:67:94:5e:ed:3a:f8:1e:ad:39:e1:
+                    b4:df:f0:fb:5c:4d:4e:98:62:ac:5d:e5:45:ae:3a:
+                    b4:1a:a7:07:bd:40:c4:43:ba:64:58:c3:a0:e1:5b:
+                    93:77
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:TRUE
+            X509v3 Subject Key Identifier: 
+                F2:67:B1:5D:5F:51:5E:DA:51:89:E9:D9:E9:6B:CA:8B:AF:A5:2E:69
+            X509v3 Authority Key Identifier: 
+                keyid:F2:67:B1:5D:5F:51:5E:DA:51:89:E9:D9:E9:6B:CA:8B:AF:A5:2E:69
+                DirName:/O=XySSL/CN=XySSL Test CA
+                serial:00
+
+    Signature Algorithm: sha1WithRSAEncryption
+        30:cf:17:9e:93:3b:0d:ec:3a:37:c3:fe:66:b2:eb:92:56:a4:
+        da:f6:c7:b1:95:e6:a5:a1:88:e5:b3:fd:d7:a3:ae:48:44:89:
+        4b:3e:ad:70:24:93:c8:5f:88:86:b0:c5:89:75:d7:14:86:9d:
+        af:66:d5:1c:de:cb:1d:45:12:fd:ba:61:61:a3:f0:f8:fa:8b:
+        12:2e:b2:75:62:8c:93:71:37:04:ba:ce:5e:0d:eb:bd:c2:41:
+        b5:d9:59:c8:d0:09:32:c4:58:bb:71:8d:0c:78:ee:b1:b0:9a:
+        f1:5c:05:49:79:82:84:bf:c2:19:fa:43:4b:e7:40:0a:20:86:
+        58:2d:a8:6e:9d:d4:16:d8:e8:88:5f:84:59:0b:fb:50:8b:40:
+        7d:7b:8a:e5:27:5d:c6:1c:51:3c:86:50:8f:22:1a:fa:c4:9b:
+        c2:84:68:9f:7d:96:15:47:94:de:3a:5c:cf:33:45:ba:92:44:
+        46:9c:a1:f5:42:4a:db:c1:e5:27:2a:1f:9f:cc:28:4c:94:53:
+        e6:b4:c6:0f:db:f5:65:19:e6:75:f2:ec:10:d1:99:27:94:9a:
+        fc:a1:0c:31:11:a8:28:4c:4c:88:10:58:60:05:83:33:e2:a9:
+        26:2d:5e:24:a5:76:63:12:23:4f:f1:6a:60:bd:38:fa:65:f4:
+        a9:da:f1:75
+-----BEGIN CERTIFICATE-----
+MIIDTTCCAjWgAwIBAgIBADANBgkqhkiG9w0BAQUFADAoMQ4wDAYDVQQKEwVYeVNT
+TDEWMBQGA1UEAxMNWHlTU0wgVGVzdCBDQTAeFw0wNzExMjkxOTQ5MTRaFw0xNzEx
+MjkxOTQ5MTRaMCgxDjAMBgNVBAoTBVh5U1NMMRYwFAYDVQQDEw1YeVNTTCBUZXN0
+IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0fSMSIXhFaiS9EPk
+5Pju52O7ClA5CQsvCb5M2p35MEADdieU23OKr3e/czripZuqDf0ms9E3mOi8IYKG
+F5KQv03Rc5X0o6gHvlEVKkA7KddDwPNeHEo3NPM0HwbTc4pPgKHndAPjtXcfY1Tv
+m5tla9O1D19qhdzqT1sZWU3hKfWsp40ys4MMf/V9RLrUgu0jvq5RxahXHdlT8DMv
+NjwhLMwYxGtPV60DHoCSp8gVjRzgAxiu2QgGRZqvcmj3AmnmAeeRNF+6530uT3nX
+xDlSzDvcjdkv82eUXu06+B6tOeG03/D7XE1OmGKsXeVFrjq0GqcHvUDEQ7pkWMOg
+4VuTdwIDAQABo4GBMH8wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8mexXV9RXtpR
+ienZ6WvKi6+lLmkwUAYDVR0jBEkwR4AU8mexXV9RXtpRienZ6WvKi6+lLmmhLKQq
+MCgxDjAMBgNVBAoTBVh5U1NMMRYwFAYDVQQDEw1YeVNTTCBUZXN0IENBggEAMA0G
+CSqGSIb3DQEBBQUAA4IBAQAwzxeekzsN7Do3w/5msuuSVqTa9sexlealoYjls/3X
+o65IRIlLPq1wJJPIX4iGsMWJddcUhp2vZtUc3ssdRRL9umFho/D4+osSLrJ1YoyT
+cTcEus5eDeu9wkG12VnI0AkyxFi7cY0MeO6xsJrxXAVJeYKEv8IZ+kNL50AKIIZY
+LahundQW2OiIX4RZC/tQi0B9e4rlJ13GHFE8hlCPIhr6xJvChGiffZYVR5TeOlzP
+M0W6kkRGnKH1QkrbweUnKh+fzChMlFPmtMYP2/VlGeZ18uwQ0ZknlJr8oQwxEago
+TEyIEFhgBYMz4qkmLV4kpXZjEiNP8WpgvTj6ZfSp2vF1
+-----END CERTIFICATE-----
diff --git a/programs/ssl/test-ca/test-ca.key b/programs/ssl/test-ca/test-ca.key
new file mode 100644
index 0000000..7814b49
--- /dev/null
+++ b/programs/ssl/test-ca/test-ca.key
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,FED222215EA5FD24
+
+jP877McdF++j3XBbkQtSyNc4W8dQ4oueOHs5oLN04HDgg3brbfvm0m5GyZCmMa3C
+B9rp2BqX9agR7zfzPVi3c9DS/piYFi26gaDCwucsBq6jPTFuICAJYnMaXRmZPrvz
+DPzlL5hrDOVpDWJl5l2Vv3T1Ag4CtEFaP6DRcfwGNyUeN8P6Api2i/XmIXNv47gl
+QsVNQx/rL+veOj/ayFB084CbxzlOX6STMsL/TVPuFjP4vvBTyVBeseFRWAw97bog
+nrphjK6eOBMnF25XbF+cg5vzagPsPYh/3wOuZfLFAwcKrTm8KM493xYRacBmRcon
+CjUrxAoo7QmdTSBBzd4kRalNS+Mj9QaIqgFBZSFCieYgezU4603GTPpYKDIf993P
+xHTqGMln78Uk+JT95MdfUWojk/rPaJ5XprLaOkhnAPEeTcYwH5kYsbmn3tBfpfdM
+i4sW6ISDcBLDHvM9JEbUCaCcPP8fIiNwACrZg25RBmMAx+ZdQ6fQpiQ/K2KmByyl
+01Vh5VC+mnUQ2W/Gkp5G6SS/ROkbTwQIJhzAAZodK+818x6lz2rRg5srEEWi1RWp
+l3043nNcSMdmxJ6Bcd/ErxWeWa5P8rk4UlapJQF4f9Z6JxAj9kds+gBF4OMf9WvB
+d6v2I6u3kX/iwXN/SLTF3yrDPIhIyQsJT06UuoXtKJz4vu/IjY2lMK1DFeF/dq9s
+kKyqZ9NyimiuxTV8O2dZe0xjk60XDh1vkHmhfnwAMV8XHRqjclgYdcZgQM1+Ze50
+scLx3PmqwWlLZ6rYMkeM/ekiLmPknz37/w3Gns2pwHNIClIimH4zkkxSOCXXH+9i
+gVgjtcj9nhf8MpJIaNYA7Q2hm9kfA2Vul2EAR8auv1str41haCMrkVLm6c/eomJP
+ScLCRr61DGYM4n084enkiWG6iyIwLcZ7ocTTzuxKUKWr34+JQy4Ex11tVbAicPmE
+7Mz3JTsuR9b2tXrLQaNh7PlXtbs56vcXqQ4ScaJu58kcGiAdDZkeKRyo0ibeer+e
+qd1VGMhrI0St5OJOxMusRJT+hljOf4k96OugI2t39BWN8fQVLAKWYLJZDkDq2kSl
+y/Hz1iKxV01M60luHDAoj3AhsN9p7IocV9jPzk+jxXVqjAzJawl4xyBRPlS/2bSw
+rOe+ZgKdzhlUR9OoU4/ZiGu35XJHZPZf2rxLAhXfgnAT+3A9Ft/WVXp/d9N4hJuU
+Qz1Ln6HyohjMOcPjrz70OXrq7kra4Cevs7rmK773LxDtw+pPfDWMasuy9lSeIulR
++riSNLrffYWXGPINnhVhqmyj6SwcKZUY/eosEwvorWAC5krt+juVzJjKTOzczTvX
+ETQCSXmLG5M+oiiYzH0zqLVUkqHvW4flNYsvkQw4V2BLarzwMNq2lF35WAU6VA9J
+bYw/3iAl7zZEJuE7+e5ObL/sWt6GwFf78QVMgsKonoxtDQ4B7DjVGw/WTKlon9fV
+4jSZhlw81nX5GhnvrnkYhiD2Y+6ZEzcUIoB4WjzBLQ2B4rf6jy686Tl52yuydZpU
+s10dX8yDbqUPBkzi3uvocFOKZd80hHq+3cy4IKP40fB1fwUcQlAj2bKgOPYg+oGB
+-----END RSA PRIVATE KEY-----
diff --git a/programs/test/benchmark.c b/programs/test/benchmark.c
new file mode 100644
index 0000000..9869cc4
--- /dev/null
+++ b/programs/test/benchmark.c
@@ -0,0 +1,253 @@
+/*
+ *  Benchmark demonstration program
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "xyssl/config.h"
+
+#include "xyssl/md4.h"
+#include "xyssl/md5.h"
+#include "xyssl/sha1.h"
+#include "xyssl/sha2.h"
+#include "xyssl/arc4.h"
+#include "xyssl/des.h"
+#include "xyssl/aes.h"
+#include "xyssl/rsa.h"
+#include "xyssl/timing.h"
+
+#define BUFSIZE 1024
+
+static int myrand( void *rng_state )
+{
+    if( rng_state != NULL )
+        rng_state  = NULL;
+
+    return( rand() );
+}
+
+unsigned char buf[BUFSIZE];
+
+int main( void )
+{
+    int keysize;
+    unsigned long i, j, tsc;
+    unsigned char tmp[32];
+#if defined(XYSSL_ARC4_C)
+    arc4_context arc4;
+#endif
+#if defined(XYSSL_DES_C)
+    des3_context des3;
+    des_context des;
+#endif
+#if defined(XYSSL_AES_C)
+    aes_context aes;
+#endif
+#if defined(XYSSL_RSA_C)
+    rsa_context rsa;
+#endif
+
+    memset( buf, 0xAA, sizeof( buf ) );
+
+    printf( "\n" );
+
+#if defined(XYSSL_MD4_C)
+    printf( "  MD4       :  " );
+    fflush( stdout );
+
+    set_alarm( 1 );
+    for( i = 1; ! alarmed; i++ )
+        md4( buf, BUFSIZE, tmp );
+
+    tsc = hardclock();
+    for( j = 0; j < 1024; j++ )
+        md4( buf, BUFSIZE, tmp );
+
+    printf( "%9lu Kb/s,  %9lu cycles/byte\n", i * BUFSIZE / 1024,
+                    ( hardclock() - tsc ) / ( j * BUFSIZE ) );
+#endif
+
+#if defined(XYSSL_MD5_C)
+    printf( "  MD5       :  " );
+    fflush( stdout );
+
+    set_alarm( 1 );
+    for( i = 1; ! alarmed; i++ )
+        md5( buf, BUFSIZE, tmp );
+
+    tsc = hardclock();
+    for( j = 0; j < 1024; j++ )
+        md5( buf, BUFSIZE, tmp );
+
+    printf( "%9lu Kb/s,  %9lu cycles/byte\n", i * BUFSIZE / 1024,
+                    ( hardclock() - tsc ) / ( j * BUFSIZE ) );
+#endif
+
+#if defined(XYSSL_SHA1_C)
+    printf( "  SHA-1     :  " );
+    fflush( stdout );
+
+    set_alarm( 1 );
+    for( i = 1; ! alarmed; i++ )
+        sha1( buf, BUFSIZE, tmp );
+
+    tsc = hardclock();
+    for( j = 0; j < 1024; j++ )
+        sha1( buf, BUFSIZE, tmp );
+
+    printf( "%9lu Kb/s,  %9lu cycles/byte\n", i * BUFSIZE / 1024,
+                    ( hardclock() - tsc ) / ( j * BUFSIZE ) );
+#endif
+
+#if defined(XYSSL_SHA2_C)
+    printf( "  SHA-256   :  " );
+    fflush( stdout );
+
+    set_alarm( 1 );
+    for( i = 1; ! alarmed; i++ )
+        sha2( buf, BUFSIZE, tmp, 0 );
+
+    tsc = hardclock();
+    for( j = 0; j < 1024; j++ )
+        sha2( buf, BUFSIZE, tmp, 0 );
+
+    printf( "%9lu Kb/s,  %9lu cycles/byte\n", i * BUFSIZE / 1024,
+                    ( hardclock() - tsc ) / ( j * BUFSIZE ) );
+#endif
+
+#if defined(XYSSL_ARC4_C)
+    printf( "  ARC4      :  " );
+    fflush( stdout );
+
+    arc4_setup( &arc4, tmp, 32 );
+
+    set_alarm( 1 );
+    for( i = 1; ! alarmed; i++ )
+        arc4_crypt( &arc4, buf, BUFSIZE );
+
+    tsc = hardclock();
+    for( j = 0; j < 1024; j++ )
+        arc4_crypt( &arc4, buf, BUFSIZE );
+
+    printf( "%9lu Kb/s,  %9lu cycles/byte\n", i * BUFSIZE / 1024,
+                    ( hardclock() - tsc ) / ( j * BUFSIZE ) );
+#endif
+
+#if defined(XYSSL_DES_C)
+    printf( "  3DES      :  " );
+    fflush( stdout );
+
+    des3_set3key_enc( &des3, tmp );
+
+    set_alarm( 1 );
+    for( i = 1; ! alarmed; i++ )
+        des3_crypt_cbc( &des3, DES_ENCRYPT, BUFSIZE, tmp, buf, buf );
+
+    tsc = hardclock();
+    for( j = 0; j < 1024; j++ )
+        des3_crypt_cbc( &des3, DES_ENCRYPT, BUFSIZE, tmp, buf, buf );
+
+    printf( "%9lu Kb/s,  %9lu cycles/byte\n", i * BUFSIZE / 1024,
+                    ( hardclock() - tsc ) / ( j * BUFSIZE ) );
+
+    printf( "  DES       :  " );
+    fflush( stdout );
+
+    des_setkey_enc( &des, tmp );
+
+    set_alarm( 1 );
+    for( i = 1; ! alarmed; i++ )
+        des_crypt_cbc( &des, DES_ENCRYPT, BUFSIZE, tmp, buf, buf );
+
+    tsc = hardclock();
+    for( j = 0; j < 1024; j++ )
+        des_crypt_cbc( &des, DES_ENCRYPT, BUFSIZE, tmp, buf, buf );
+
+    printf( "%9lu Kb/s,  %9lu cycles/byte\n", i * BUFSIZE / 1024,
+                    ( hardclock() - tsc ) / ( j * BUFSIZE ) );
+#endif
+
+#if defined(XYSSL_AES_C)
+    for( keysize = 128; keysize <= 256; keysize += 64 )
+    {
+        printf( "  AES-%d   :  ", keysize );
+        fflush( stdout );
+
+        memset( buf, 0, sizeof( buf ) );
+        memset( tmp, 0, sizeof( tmp ) );
+        aes_setkey_enc( &aes, tmp, keysize );
+
+        set_alarm( 1 );
+
+        for( i = 1; ! alarmed; i++ )
+            aes_crypt_cbc( &aes, AES_ENCRYPT, BUFSIZE, tmp, buf, buf );
+
+        tsc = hardclock();
+        for( j = 0; j < 4096; j++ )
+            aes_crypt_cbc( &aes, AES_ENCRYPT, BUFSIZE, tmp, buf, buf );
+
+        printf( "%9lu Kb/s,  %9lu cycles/byte\n", i * BUFSIZE / 1024,
+                        ( hardclock() - tsc ) / ( j * BUFSIZE ) );
+    }
+#endif
+
+#if defined(XYSSL_RSA_C)
+    rsa_init( &rsa, RSA_PKCS_V15, 0, myrand, NULL );
+    rsa_gen_key( &rsa, 1024, 65537 );
+
+    printf( "  RSA-1024  :  " );
+    fflush( stdout );
+    set_alarm( 3 );
+
+    for( i = 1; ! alarmed; i++ )
+    {
+        buf[0] = 0;
+        rsa_public( &rsa, buf, buf );
+    }
+
+    printf( "%9lu  public/s\n", i / 3 );
+
+    printf( "  RSA-1024  :  " );
+    fflush( stdout );
+    set_alarm( 3 );
+
+    for( i = 1; ! alarmed; i++ )
+    {
+        buf[0] = 0;
+        rsa_private( &rsa, buf, buf );
+    }
+
+    printf( "%9lu private/s\n\n", i / 3 );
+
+    rsa_free( &rsa );
+#endif
+
+#ifdef WIN32
+    printf( "  Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( 0 );
+}
diff --git a/programs/test/selftest.c b/programs/test/selftest.c
new file mode 100644
index 0000000..6fc0e1f
--- /dev/null
+++ b/programs/test/selftest.c
@@ -0,0 +1,131 @@
+/*
+ *  Self-test demonstration program
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "xyssl/config.h"
+
+#include "xyssl/md2.h"
+#include "xyssl/md4.h"
+#include "xyssl/md5.h"
+#include "xyssl/sha1.h"
+#include "xyssl/sha2.h"
+#include "xyssl/sha4.h"
+#include "xyssl/arc4.h"
+#include "xyssl/des.h"
+#include "xyssl/aes.h"
+#include "xyssl/base64.h"
+#include "xyssl/bignum.h"
+#include "xyssl/rsa.h"
+#include "xyssl/x509.h"
+
+int main( int argc, char *argv[] )
+{
+    int ret, v;
+
+    if( argc == 2 && strcmp( argv[1], "-quiet" ) == 0 )
+        v = 0;
+    else
+    {
+        v = 1;
+        printf( "\n" );
+    }
+
+#if defined(XYSSL_MD2_C)
+    if( ( ret = md2_self_test( v ) ) != 0 )
+        return( ret );
+#endif
+
+#if defined(XYSSL_MD4_C)
+    if( ( ret = md4_self_test( v ) ) != 0 )
+        return( ret );
+#endif
+
+#if defined(XYSSL_MD5_C)
+    if( ( ret = md5_self_test( v ) ) != 0 )
+        return( ret );
+#endif
+
+#if defined(XYSSL_SHA1_C)
+    if( ( ret = sha1_self_test( v ) ) != 0 )
+        return( ret );
+#endif
+
+#if defined(XYSSL_SHA2_C)
+    if( ( ret = sha2_self_test( v ) ) != 0 )
+        return( ret );
+#endif
+
+#if defined(XYSSL_SHA4_C)
+    if( ( ret = sha4_self_test( v ) ) != 0 )
+        return( ret );
+#endif
+
+#if defined(XYSSL_ARC4_C)
+    if( ( ret = arc4_self_test( v ) ) != 0 )
+        return( ret );
+#endif
+
+#if defined(XYSSL_DES_C)
+    if( ( ret = des_self_test( v ) ) != 0 )
+        return( ret );
+#endif
+
+#if defined(XYSSL_AES_C)
+    if( ( ret = aes_self_test( v ) ) != 0 )
+        return( ret );
+#endif
+
+#if defined(XYSSL_BASE64_C)
+    if( ( ret = base64_self_test( v ) ) != 0 )
+        return( ret );
+#endif
+
+#if defined(XYSSL_BIGNUM_C)
+    if( ( ret = mpi_self_test( v ) ) != 0 )
+        return( ret );
+#endif
+
+#if defined(XYSSL_RSA_C)
+    if( ( ret = rsa_self_test( v ) ) != 0 )
+        return( ret );
+#endif
+
+#if defined(XYSSL_X509_C)
+    if( ( ret = x509_self_test( v ) ) != 0 )
+        return( ret );
+#endif
+
+    if( v != 0 )
+    {
+        printf( "  [ All tests passed ]\n\n" );
+#ifdef WIN32
+        printf( "  Press Enter to exit this program.\n" );
+        fflush( stdout ); getchar();
+#endif
+    }
+
+    return( ret );
+}
diff --git a/programs/test/ssl_test.c b/programs/test/ssl_test.c
new file mode 100644
index 0000000..44ff7d8
--- /dev/null
+++ b/programs/test/ssl_test.c
@@ -0,0 +1,580 @@
+/*
+ *  SSL/TLS stress testing program
+ *
+ *  Copyright (C) 2006-2007  Christophe Devine
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "xyssl/net.h"
+#include "xyssl/ssl.h"
+#include "xyssl/havege.h"
+#include "xyssl/timing.h"
+#include "xyssl/certs.h"
+
+#define OPMODE_NONE             0
+#define OPMODE_CLIENT           1
+#define OPMODE_SERVER           2
+
+#define IOMODE_BLOCK            0
+#define IOMODE_NONBLOCK         1
+
+#define COMMAND_READ            1
+#define COMMAND_WRITE           2
+#define COMMAND_BOTH            3
+
+#define DFL_OPMODE              OPMODE_NONE
+#define DFL_IOMODE              IOMODE_BLOCK
+#define DFL_SERVER_NAME         "localhost"
+#define DFL_SERVER_PORT         4433
+#define DFL_COMMAND             COMMAND_READ
+#define DFL_BUFFER_SIZE         1024
+#define DFL_MAX_BYTES           0
+#define DFL_DEBUG_LEVEL         0
+#define DFL_CONN_TIMEOUT        0
+#define DFL_MAX_CONNECTIONS     0
+#define DFL_SESSION_REUSE       1
+#define DFL_SESSION_LIFETIME    86400
+#define DFL_FORCE_CIPHER        0
+
+/*
+ * server-specific data
+ */
+char *dhm_G = "4";
+char *dhm_P = 
+"E4004C1F94182000103D883A448B3F802CE4B44A83301270002C20D0321CFD00" \
+"11CCEF784C26A400F43DFB901BCA7538F2C6B176001CF5A0FD16D2C48B1D0C1C" \
+"F6AC8E1DA6BCC3B4E1F96B0564965300FFA1D0B601EB2800F489AA512C4B248C" \
+"01F76949A60BB7F00A40B1EAB64BDD48E8A700D60B7F1200FA8E77B0A979DABF";
+
+int server_fd = -1;
+
+/*
+ * global options
+ */
+struct options
+{
+    int opmode;                 /* operation mode (client or server)    */
+    int iomode;                 /* I/O mode (blocking or non-blocking)  */
+    char *server_name;          /* hostname of the server (client only) */
+    int server_port;            /* port on which the ssl service runs   */
+    int command;                /* what to do: read or write operation  */
+    int buffer_size;            /* size of the send/receive buffer      */
+    int max_bytes;              /* max. # of bytes before a reconnect   */
+    int debug_level;            /* level of debugging                   */
+    int conn_timeout;           /* max. delay before a reconnect        */
+    int max_connections;        /* max. number of reconnections         */
+    int session_reuse;          /* flag to reuse the keying material    */
+    int session_lifetime;       /* if reached, session data is expired  */
+    int force_cipher[2];        /* protocol/cipher to use, or all       */
+};
+
+/*
+ * Although this PRNG has good statistical properties (eg. passes
+ * DIEHARD), it is not cryptographically secure.
+ */
+unsigned long int lcppm5( unsigned long int *state )
+{
+    unsigned long int u, v;
+
+    u = v = state[4] ^ 1;
+    state[u & 3] ^= u;
+    u ^= (v << 12) ^ (v >> 12);
+    u ^= v * state[0]; v >>= 8;
+    u ^= v * state[1]; v >>= 8;
+    u ^= v * state[2]; v >>= 8;
+    u ^= v * state[3];
+    u &= 0xFFFFFFFF;
+    state[4] = u;
+
+    return( u );
+}
+
+void my_debug( void *ctx, int level, char *str )
+{
+    if( level < ((struct options *) ctx)->debug_level )
+        fprintf( stderr, "%s", str );
+}
+
+/*
+ * perform a single SSL connection
+ */
+static int ssl_test( struct options *opt )
+{
+    int ret, i;
+    int client_fd;
+    int bytes_to_read;
+    int bytes_to_write;
+    int offset_to_read;
+    int offset_to_write;
+
+    long int nb_read;
+    long int nb_written;
+
+    unsigned long read_state[5];
+    unsigned long write_state[5];
+
+    unsigned char *read_buf;
+    unsigned char *write_buf;
+
+    struct hr_time t;
+    havege_state hs;
+    ssl_context ssl;
+    ssl_session ssn;
+    x509_cert srvcert;
+    rsa_context rsa;
+
+    ret = 1;
+
+    havege_init( &hs );
+    get_timer( &t, 1 );
+
+    memset( read_state, 0, sizeof( read_state ) );
+    memset( write_state, 0, sizeof( write_state ) );
+
+    memset( &srvcert, 0, sizeof( x509_cert ) );
+    memset( &rsa, 0, sizeof( rsa_context ) );
+
+    if( opt->opmode == OPMODE_CLIENT )
+    {
+        if( ( ret = net_connect( &client_fd, opt->server_name,
+                                             opt->server_port ) ) != 0 )
+        {
+            printf( "  ! net_connect returned %d\n\n", ret );
+            return( ret );
+        }
+
+        if( ( ret = ssl_init( &ssl ) ) != 0 )
+        {
+            printf( "  ! ssl_init returned %d\n\n", ret );
+            return( ret );
+        }
+
+        ssl_set_endpoint( &ssl, SSL_IS_CLIENT );
+    }
+
+    if( opt->opmode == OPMODE_SERVER )
+    {
+        ret =  x509parse_crt( &srvcert, (unsigned char *) test_srv_crt,
+                              strlen( test_srv_crt ) );
+        if( ret != 0 )
+        {
+            printf( "  !  x509parse_crt returned %d\n\n", ret );
+            goto exit;
+        }
+
+        ret =  x509parse_crt( &srvcert, (unsigned char *) test_ca_crt,
+                              strlen( test_ca_crt ) );
+        if( ret != 0 )
+        {
+            printf( "  !  x509parse_crt returned %d\n\n", ret );
+            goto exit;
+        }
+
+        ret =  x509parse_key( &rsa, (unsigned char *) test_srv_key,
+                              strlen( test_srv_key ), NULL, 0 );
+        if( ret != 0 )
+        {
+            printf( "  !  x509parse_key returned %d\n\n", ret );
+            goto exit;
+        }
+
+        if( server_fd < 0 )
+        {
+            if( ( ret = net_bind( &server_fd, NULL,
+                                   opt->server_port ) ) != 0 )
+            {
+                printf( "  ! net_bind returned %d\n\n", ret );
+                return( ret );
+            }
+        }
+
+        if( ( ret = net_accept( server_fd, &client_fd, NULL ) ) != 0 )
+        {
+            printf( "  ! net_accept returned %d\n\n", ret );
+            return( ret );
+        }
+
+        if( ( ret = ssl_init( &ssl ) ) != 0 )
+        {
+            printf( "  ! ssl_init returned %d\n\n", ret );
+            return( ret );
+        }
+
+        ssl_set_endpoint( &ssl, SSL_IS_SERVER );
+        ssl_set_dh_param( &ssl, dhm_P, dhm_G );
+        ssl_set_ca_chain( &ssl, srvcert.next, NULL );
+        ssl_set_own_cert( &ssl, &srvcert, &rsa );
+    }
+
+    ssl_set_authmode( &ssl, SSL_VERIFY_NONE );
+
+    ssl_set_rng( &ssl, havege_rand, &hs );
+    ssl_set_dbg( &ssl, my_debug, opt );
+    ssl_set_bio( &ssl, net_recv, &client_fd,
+                       net_send, &client_fd );
+
+    ssl_set_session( &ssl, opt->session_reuse,
+                           opt->session_lifetime, &ssn );
+
+    if( opt->force_cipher[0] == DFL_FORCE_CIPHER )
+          ssl_set_ciphers( &ssl, ssl_default_ciphers );
+    else  ssl_set_ciphers( &ssl, opt->force_cipher );
+
+    if( opt->iomode == IOMODE_NONBLOCK )
+        net_set_nonblock( client_fd );
+
+     read_buf = (unsigned char *) malloc( opt->buffer_size );
+    write_buf = (unsigned char *) malloc( opt->buffer_size );
+
+    if( read_buf == NULL || write_buf == NULL )
+    {
+        printf( "  ! malloc(%d bytes) failed\n\n", opt->buffer_size );
+        goto exit;
+    }
+
+    nb_read = bytes_to_read = 0;
+    nb_written = bytes_to_write = 0;
+
+    while( 1 )
+    {
+        if( opt->command & COMMAND_WRITE )
+        {
+            if( bytes_to_write == 0 )
+            {
+                while( bytes_to_write == 0 )
+                    bytes_to_write = rand() % opt->buffer_size;
+
+                for( i = 0; i < bytes_to_write; i++ )
+                    write_buf[i] = (unsigned char) lcppm5( write_state );
+
+                offset_to_write = 0;
+            }
+
+            ret = ssl_write( &ssl, write_buf + offset_to_write,
+                             bytes_to_write );
+
+            if( ret >= 0 )
+            {
+                nb_written += ret;
+                bytes_to_write  -= ret;
+                offset_to_write += ret;
+            }
+
+            if( ret == XYSSL_ERR_SSL_PEER_CLOSE_NOTIFY ||
+                ret == XYSSL_ERR_NET_CONN_RESET )
+            {
+                ret = 0;
+                goto exit;
+            }
+
+            if( ret < 0 && ret != XYSSL_ERR_NET_TRY_AGAIN )
+            {
+                printf( "  ! ssl_write returned %d\n\n", ret );
+                break;
+            }
+        }
+
+        if( opt->command & COMMAND_READ )
+        {
+            if( bytes_to_read == 0 )
+            {
+                bytes_to_read = rand() % opt->buffer_size;
+                offset_to_read = 0;
+            }
+
+            ret = ssl_read( &ssl, read_buf + offset_to_read,
+                            bytes_to_read );
+
+            if( ret >= 0 )
+            {
+                for( i = 0; i < ret; i++ )
+                {
+                    if( read_buf[offset_to_read + i] !=
+                        (unsigned char) lcppm5( read_state ) )
+                    {
+                        ret = 1;
+                        printf( "  ! plaintext mismatch\n\n" );
+                        goto exit;
+                    }
+                }
+
+                nb_read += ret;
+                bytes_to_read -= ret;
+                offset_to_read += ret;
+            }
+
+            if( ret == XYSSL_ERR_SSL_PEER_CLOSE_NOTIFY ||
+                ret == XYSSL_ERR_NET_CONN_RESET )
+            {
+                ret = 0;
+                goto exit;
+            }
+
+            if( ret < 0 && ret != XYSSL_ERR_NET_TRY_AGAIN )
+            {
+                printf( "  ! ssl_read returned %d\n\n", ret );
+                break;
+            }
+        }
+
+        ret = 0;
+
+        if( opt->max_bytes != 0 &&
+            ( opt->max_bytes <= nb_read ||
+              opt->max_bytes <= nb_written ) )
+            break;
+
+        if( opt->conn_timeout != 0 &&
+            opt->conn_timeout <= (int) get_timer( &t, 0 ) )
+            break;
+    }
+
+exit:
+
+    fflush( stdout );
+
+    if( read_buf != NULL )
+        free( read_buf );
+
+    if( write_buf != NULL )
+        free( write_buf );
+
+    ssl_close_notify( &ssl );
+    x509_free( &srvcert );
+    rsa_free( &rsa );
+    ssl_free( &ssl );
+    net_close( client_fd );
+
+    return( ret );
+}
+
+#define USAGE \
+    "\n usage: ssl_test opmode=<> command=<>...\n"               \
+    "\n acceptable parameters:\n"                                \
+    "    opmode=client/server        default: <none>\n"          \
+    "    iomode=block/nonblock       default: block\n"           \
+    "    server_name=%%s              default: localhost\n"      \
+    "    server_port=%%d              default: 4433\n"           \
+    "    command=read/write/both     default: read\n"            \
+    "    buffer_size=%%d (bytes)      default: 1024\n"           \
+    "    max_bytes=%%d (bytes)        default: 0 (no limit)\n"   \
+    "    debug_level=%%d              default: 0 (disabled)\n"   \
+    "    conn_timeout=%%d (ms)        default: 0 (no timeout)\n" \
+    "    max_connections=%%d          default: 0 (no limit)\n"   \
+    "    session_reuse=on/off        default: on (enabled)\n"    \
+    "    session_lifetime=%%d (s)     default: 86400\n"          \
+    "    force_cipher=<name>         default: all enabled\n"     \
+    " acceptable cipher names:\n"                                \
+    "    SSL_RSA_RC4_128_MD5         SSL_RSA_RC4_128_SHA\n"      \
+    "    SSL_RSA_DES_168_SHA         SSL_EDH_RSA_DES_168_SHA\n"  \
+    "    SSL_RSA_AES_128_SHA         SSL_EDH_RSA_AES_256_SHA\n"  \
+    "    SSL_RSA_AES_256_SHA\n\n"
+
+int main( int argc, char *argv[] )
+{
+    int i, j, n;
+    int ret = 1;
+    int nb_conn;
+    char *p, *q;
+    struct options opt;
+
+    if( argc == 1 )
+    {
+    usage:
+        printf( USAGE );
+        goto exit;
+    }
+
+    opt.opmode                  = DFL_OPMODE;
+    opt.iomode                  = DFL_IOMODE;
+    opt.server_name             = DFL_SERVER_NAME;
+    opt.server_port             = DFL_SERVER_PORT;
+    opt.command                 = DFL_COMMAND;
+    opt.buffer_size             = DFL_BUFFER_SIZE;
+    opt.max_bytes               = DFL_MAX_BYTES;
+    opt.debug_level             = DFL_DEBUG_LEVEL;
+    opt.conn_timeout            = DFL_CONN_TIMEOUT;
+    opt.max_connections         = DFL_MAX_CONNECTIONS;
+    opt.session_reuse           = DFL_SESSION_REUSE;
+    opt.session_lifetime        = DFL_SESSION_LIFETIME;
+    opt.force_cipher[0]         = DFL_FORCE_CIPHER;
+
+    for( i = 1; i < argc; i++ )
+    {
+        n = strlen( argv[i] );
+
+        for( j = 0; j < n; j++ )
+        {
+            if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' )
+                argv[i][j] |= 0x20;
+        }
+
+        p = argv[i];
+        if( ( q = strchr( p, '=' ) ) == NULL )
+            continue;
+        *q++ = '\0';
+
+        if( strcmp( p, "opmode" ) == 0 )
+        {
+            if( strcmp( q, "client" ) == 0 )
+                opt.opmode = OPMODE_CLIENT;
+            else
+            if( strcmp( q, "server" ) == 0 )
+                opt.opmode = OPMODE_SERVER;
+            else goto usage;
+        }
+
+        if( strcmp( p, "iomode" ) == 0 )
+        {
+            if( strcmp( q, "block" ) == 0 )
+                opt.iomode = IOMODE_BLOCK;
+            else
+            if( strcmp( q, "nonblock" ) == 0 )
+                opt.iomode = IOMODE_NONBLOCK;
+            else goto usage;
+        }
+
+        if( strcmp( p, "server_name" ) == 0 )
+            opt.server_name = q;
+
+        if( strcmp( p, "server_port" ) == 0 )
+        {
+            opt.server_port = atoi( q );
+            if( opt.server_port < 1 || opt.server_port > 65535 )
+                goto usage;
+        }
+
+        if( strcmp( p, "command" ) == 0 )
+        {
+            if( strcmp( q, "read" ) == 0 )
+                opt.command = COMMAND_READ;
+            else
+            if( strcmp( q, "write" ) == 0 )
+                opt.command = COMMAND_WRITE;
+            else
+            if( strcmp( q, "both" ) == 0 )
+            {
+                opt.iomode  = IOMODE_NONBLOCK;
+                opt.command = COMMAND_BOTH;
+            }
+            else goto usage;
+        }
+
+        if( strcmp( p, "buffer_size" ) == 0 )
+        {
+            opt.buffer_size = atoi( q );
+            if( opt.buffer_size < 1 || opt.buffer_size > 1048576 )
+                goto usage;
+        }
+
+        if( strcmp( p, "max_bytes" ) == 0 )
+            opt.max_bytes = atoi( q );
+
+        if( strcmp( p, "debug_level" ) == 0 )
+            opt.debug_level = atoi( q );
+
+        if( strcmp( p, "conn_timeout" ) == 0 )
+            opt.conn_timeout = atoi( q );
+
+        if( strcmp( p, "max_connections" ) == 0 )
+            opt.max_connections = atoi( q );
+
+        if( strcmp( p, "session_reuse" ) == 0 )
+        {
+            if( strcmp( q, "on" ) == 0 )
+                opt.session_reuse = 1;
+            else
+            if( strcmp( q, "off" ) == 0 )
+                opt.session_reuse = 0;
+            else
+                goto usage;
+        }
+
+        if( strcmp( p, "session_lifetime" ) == 0 )
+            opt.session_lifetime = atoi( q );
+
+        if( strcmp( p, "force_cipher" ) == 0 )
+        {
+            opt.force_cipher[0] = -1;
+
+            if( strcmp( q, "ssl_rsa_rc4_128_md5" ) == 0 )
+                opt.force_cipher[0] = SSL_RSA_RC4_128_MD5;
+
+            if( strcmp( q, "ssl_rsa_rc4_128_sha" ) == 0 )
+                opt.force_cipher[0] = SSL_RSA_RC4_128_SHA;
+
+            if( strcmp( q, "ssl_rsa_des_168_sha" ) == 0 )
+                opt.force_cipher[0] = SSL_RSA_DES_168_SHA;
+
+            if( strcmp( q, "ssl_edh_rsa_des_168_sha" ) == 0 )
+                opt.force_cipher[0] = SSL_EDH_RSA_DES_168_SHA;
+
+            if( strcmp( q, "ssl_rsa_aes_128_sha" ) == 0 )
+                opt.force_cipher[0] = SSL_RSA_AES_128_SHA;
+
+            if( strcmp( q, "ssl_rsa_aes_256_sha" ) == 0 )
+                opt.force_cipher[0] = SSL_RSA_AES_256_SHA;
+
+            if( strcmp( q, "ssl_edh_rsa_aes_256_sha" ) == 0 )
+                opt.force_cipher[0] = SSL_EDH_RSA_AES_256_SHA;
+
+            if( opt.force_cipher[0] < 0 )
+                goto usage;
+
+            opt.force_cipher[1] = 0;
+        }
+    }
+
+    switch( opt.opmode )
+    {
+        case OPMODE_CLIENT:
+            break;
+
+        case OPMODE_SERVER:
+            break;
+
+        default:
+            goto usage;
+    }
+
+    nb_conn = 0;
+
+    do {
+        nb_conn++;
+        ret = ssl_test( &opt );
+        if( opt.max_connections != 0 &&
+            opt.max_connections <= nb_conn )
+            break;
+    }
+    while( ret == 0 );
+
+exit:
+
+#ifdef WIN32
+    printf( "  Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( ret );
+}
diff --git a/visualc/_build.dsw b/visualc/_build.dsw
new file mode 100644
index 0000000..2d568c2
--- /dev/null
+++ b/visualc/_build.dsw
@@ -0,0 +1,368 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00

+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!

+

+###############################################################################

+

+Project: "_build_all"=".\_build_all.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name aescrypt2

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name hello

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name md5sum

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name sha1sum

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name sha2sum

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name benchmark

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name dh_client

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name dh_genprime

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name dh_server

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name mpi_demo

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name rsa_genkey

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name rsa_sign

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name rsa_verify

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name selftest

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name ssl_client1

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name ssl_client2

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name ssl_server

+    End Project Dependency

+    Begin Project Dependency

+    Project_Dep_Name ssl_test

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "aescrypt2"=".\aescrypt2.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "benchmark"=".\benchmark.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "dh_client"=".\dh_client.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "dh_genprime"=".\dh_genprime.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "dh_server"=".\dh_server.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "hello"=".\hello.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "md5sum"=".\md5sum.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "mpi_demo"=".\mpi_demo.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "rsa_genkey"=".\rsa_genkey.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "rsa_sign"=".\rsa_sign.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "rsa_verify"=".\rsa_verify.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "selftest"=".\selftest.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "sha1sum"=".\sha1sum.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "sha2sum"=".\sha2sum.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "ssl_client1"=".\ssl_client1.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "ssl_client2"=".\ssl_client2.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "ssl_server"=".\ssl_server.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "ssl_test"=".\ssl_test.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+    Begin Project Dependency

+    Project_Dep_Name xyssl

+    End Project Dependency

+}}}

+

+###############################################################################

+

+Project: "xyssl"=".\xyssl.dsp" - Package Owner=<4>

+

+Package=<5>

+{{{

+}}}

+

+Package=<4>

+{{{

+}}}

+

+###############################################################################

+

+Global:

+

+Package=<5>

+{{{

+}}}

+

+Package=<3>

+{{{

+}}}

+

+###############################################################################

+

diff --git a/visualc/_build_all.dsp b/visualc/_build_all.dsp
new file mode 100644
index 0000000..15663bf
--- /dev/null
+++ b/visualc/_build_all.dsp
@@ -0,0 +1,63 @@
+# Microsoft Developer Studio Project File - Name="_build_all" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Generic Project" 0x010a

+

+CFG=_build_all - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "_build_all.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "_build_all.mak" CFG="_build_all - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "_build_all - Win32 Release" (based on "Win32 (x86) Generic Project")

+!MESSAGE "_build_all - Win32 Debug" (based on "Win32 (x86) Generic Project")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+MTL=midl.exe

+

+!IF  "$(CFG)" == "_build_all - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+

+!ELSEIF  "$(CFG)" == "_build_all - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+

+!ENDIF 

+

+# Begin Target

+

+# Name "_build_all - Win32 Release"

+# Name "_build_all - Win32 Debug"

+# End Target

+# End Project

diff --git a/visualc/aescrypt2.dsp b/visualc/aescrypt2.dsp
new file mode 100644
index 0000000..9ca26c5
--- /dev/null
+++ b/visualc/aescrypt2.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="aescrypt2" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=aescrypt2 - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "aescrypt2.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "aescrypt2.mak" CFG="aescrypt2 - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "aescrypt2 - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "aescrypt2 - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "aescrypt2 - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "aescrypt2 - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "aescrypt2 - Win32 Release"

+# Name "aescrypt2 - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\aes\aescrypt2.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/benchmark.dsp b/visualc/benchmark.dsp
new file mode 100644
index 0000000..4a063e5
--- /dev/null
+++ b/visualc/benchmark.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="benchmark" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=benchmark - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "benchmark.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "benchmark.mak" CFG="benchmark - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "benchmark - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "benchmark - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "benchmark - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "benchmark - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "benchmark - Win32 Release"

+# Name "benchmark - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\test\benchmark.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/dh_client.dsp b/visualc/dh_client.dsp
new file mode 100644
index 0000000..58a138b
--- /dev/null
+++ b/visualc/dh_client.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="dh_client" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=dh_client - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "dh_client.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "dh_client.mak" CFG="dh_client - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "dh_client - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "dh_client - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "dh_client - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "dh_client - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "dh_client - Win32 Release"

+# Name "dh_client - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\pkey\dh_client.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/dh_genprime.dsp b/visualc/dh_genprime.dsp
new file mode 100644
index 0000000..a17511c
--- /dev/null
+++ b/visualc/dh_genprime.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="dh_genprime" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=dh_genprime - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "dh_genprime.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "dh_genprime.mak" CFG="dh_genprime - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "dh_genprime - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "dh_genprime - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "dh_genprime - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "dh_genprime - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "dh_genprime - Win32 Release"

+# Name "dh_genprime - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\pkey\dh_genprime.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/dh_prime.txt b/visualc/dh_prime.txt
new file mode 100644
index 0000000..e62c279
--- /dev/null
+++ b/visualc/dh_prime.txt
@@ -0,0 +1,2 @@
+P = C3CF8BCFD9E88B0CC35EC526F3D63FA001DC9392E6CA81F3B414173955C582758B52038FAFBF402B8C29DC32F5231B0D2E25B252850C7DCDBFF46D0E7989E51DEA07A53BCF7947D4C95EBA28F9CBAFB0267EC3BCF57B15A49964236B56773851D6621E546F410D504F13827218CD14A1FDB69522DC72DD67D880E51B2E00894F

+G = 04

diff --git a/visualc/dh_server.dsp b/visualc/dh_server.dsp
new file mode 100644
index 0000000..23f03f2
--- /dev/null
+++ b/visualc/dh_server.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="dh_server" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=dh_server - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "dh_server.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "dh_server.mak" CFG="dh_server - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "dh_server - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "dh_server - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "dh_server - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "dh_server - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "dh_server - Win32 Release"

+# Name "dh_server - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\pkey\dh_server.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/hello.dsp b/visualc/hello.dsp
new file mode 100644
index 0000000..29c0fdf
--- /dev/null
+++ b/visualc/hello.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="hello" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=hello - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "hello.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "hello.mak" CFG="hello - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "hello - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "hello - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "hello - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "hello - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "hello - Win32 Release"

+# Name "hello - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\hash\hello.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/md5sum.dsp b/visualc/md5sum.dsp
new file mode 100644
index 0000000..aa86c46
--- /dev/null
+++ b/visualc/md5sum.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="md5sum" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=md5sum - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "md5sum.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "md5sum.mak" CFG="md5sum - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "md5sum - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "md5sum - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "md5sum - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "md5sum - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "md5sum - Win32 Release"

+# Name "md5sum - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\hash\md5sum.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/mpi_demo.dsp b/visualc/mpi_demo.dsp
new file mode 100644
index 0000000..6579004
--- /dev/null
+++ b/visualc/mpi_demo.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="mpi_demo" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=mpi_demo - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "mpi_demo.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "mpi_demo.mak" CFG="mpi_demo - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "mpi_demo - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "mpi_demo - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "mpi_demo - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "mpi_demo - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "mpi_demo - Win32 Release"

+# Name "mpi_demo - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\pkey\mpi_demo.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/rsa_genkey.dsp b/visualc/rsa_genkey.dsp
new file mode 100644
index 0000000..4305df8
--- /dev/null
+++ b/visualc/rsa_genkey.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="rsa_genkey" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=rsa_genkey - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "rsa_genkey.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "rsa_genkey.mak" CFG="rsa_genkey - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "rsa_genkey - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "rsa_genkey - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "rsa_genkey - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "rsa_genkey - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "rsa_genkey - Win32 Release"

+# Name "rsa_genkey - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\pkey\rsa_genkey.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/rsa_priv.txt b/visualc/rsa_priv.txt
new file mode 100644
index 0000000..7dac359
--- /dev/null
+++ b/visualc/rsa_priv.txt
@@ -0,0 +1,8 @@
+N=6F440E8C8510107B2040ADEC23C2052769FF89E5EAE061AD5FCE8556E051DBF25FBA31DC83AAFCDFACA70912B8BA8CC73EC67132AB66CE79D2F91A190D57CC42C148728B33190D85E311F1744BF6DB95E7C2DBDC8C3FC291825527BC5556E67FFAD2CAB926A6FBF2B47BC746BEC67A8C205C3AFD4028FC0864F5EEEB27FFA91B

+E=010001

+D=0D277AA0DA4A5FE86E93B6FC27EE1435E8AE315B613D4DCEF578B102E85A452A8E6EB0DE65229DEAC3BAABB3EEEAFF21BF262ED3D2B7C0C95E4BDCEE0149D3F81746F38B0D2A36390258BEC37C337E1608859E0133C686E139B6F5162E38F204C61CFBD30ED0F4314B2B079B36EC163225262D618BC4EA0CDF533E7308C41E41

+P=D831261F5EDE9AFD544C95B2BAAF93BEC1032F4426DC048ACA686ED0813A2779B04D09398D3761786781B3B740B16ADAA81D4918ABCBD61F5FD5D726A7DAD843

+Q=83C0E71E39D1ED34E12EC9B54F7EB6ACC5E27B566348B17A9B1B6A60F2ABBD1E137C0B3E7CE3693D215A3312C774B5E177713727D005331148C9FEFA511F2A49

+DP=87C8C6D2E939134B8D48D4B4FF000BE1C14488C95B46D12B82D978D0487A08152C20166D293EE15F48537456E2B10C15ED8507461190E319AD8D97A655C2E415

+DQ=067720E04AD6125DD5EF05D6EFDFB7F7227ECAAEA2909EA4F59792D0CF17BE600B74BAD8862862B1AD414FE04C095E238248FBFBE82959282FFA3998EF022881

+QP=8C2FAEF2C7F8FEE6C6F2B4F811DA5745A3328E5B06256C5F7E8F924EC6E552718095A2F9B4B52DE5B7B22F697FB3CC6D72ED6415555CDC2C4B193D2296249488

diff --git a/visualc/rsa_pub.txt b/visualc/rsa_pub.txt
new file mode 100644
index 0000000..483685d
--- /dev/null
+++ b/visualc/rsa_pub.txt
@@ -0,0 +1,2 @@
+N=6F440E8C8510107B2040ADEC23C2052769FF89E5EAE061AD5FCE8556E051DBF25FBA31DC83AAFCDFACA70912B8BA8CC73EC67132AB66CE79D2F91A190D57CC42C148728B33190D85E311F1744BF6DB95E7C2DBDC8C3FC291825527BC5556E67FFAD2CAB926A6FBF2B47BC746BEC67A8C205C3AFD4028FC0864F5EEEB27FFA91B

+E=010001

diff --git a/visualc/rsa_sign.dsp b/visualc/rsa_sign.dsp
new file mode 100644
index 0000000..47bfe56
--- /dev/null
+++ b/visualc/rsa_sign.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="rsa_sign" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=rsa_sign - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "rsa_sign.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "rsa_sign.mak" CFG="rsa_sign - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "rsa_sign - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "rsa_sign - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "rsa_sign - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "rsa_sign - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "rsa_sign - Win32 Release"

+# Name "rsa_sign - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\pkey\rsa_sign.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/rsa_verify.dsp b/visualc/rsa_verify.dsp
new file mode 100644
index 0000000..59507f6
--- /dev/null
+++ b/visualc/rsa_verify.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="rsa_verify" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=rsa_verify - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "rsa_verify.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "rsa_verify.mak" CFG="rsa_verify - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "rsa_verify - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "rsa_verify - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "rsa_verify - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "rsa_verify - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "rsa_verify - Win32 Release"

+# Name "rsa_verify - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\pkey\rsa_verify.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/selftest.dsp b/visualc/selftest.dsp
new file mode 100644
index 0000000..05217b7
--- /dev/null
+++ b/visualc/selftest.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="selftest" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=selftest - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "selftest.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "selftest.mak" CFG="selftest - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "selftest - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "selftest - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "selftest - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "selftest - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "selftest - Win32 Release"

+# Name "selftest - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\test\selftest.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/sha1sum.dsp b/visualc/sha1sum.dsp
new file mode 100644
index 0000000..b8ceafc
--- /dev/null
+++ b/visualc/sha1sum.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="sha1sum" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=sha1sum - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "sha1sum.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "sha1sum.mak" CFG="sha1sum - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "sha1sum - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "sha1sum - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "sha1sum - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "sha1sum - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "sha1sum - Win32 Release"

+# Name "sha1sum - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\hash\sha1sum.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/sha2sum.dsp b/visualc/sha2sum.dsp
new file mode 100644
index 0000000..b050258
--- /dev/null
+++ b/visualc/sha2sum.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="sha2sum" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=sha2sum - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "sha2sum.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "sha2sum.mak" CFG="sha2sum - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "sha2sum - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "sha2sum - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "sha2sum - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "sha2sum - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "sha2sum - Win32 Release"

+# Name "sha2sum - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\hash\sha2sum.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/ssl_client1.dsp b/visualc/ssl_client1.dsp
new file mode 100644
index 0000000..a7585f2
--- /dev/null
+++ b/visualc/ssl_client1.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="ssl_client1" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=ssl_client1 - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "ssl_client1.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "ssl_client1.mak" CFG="ssl_client1 - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "ssl_client1 - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "ssl_client1 - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "ssl_client1 - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "ssl_client1 - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "ssl_client1 - Win32 Release"

+# Name "ssl_client1 - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\ssl\ssl_client1.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/ssl_client2.dsp b/visualc/ssl_client2.dsp
new file mode 100644
index 0000000..adc370f
--- /dev/null
+++ b/visualc/ssl_client2.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="ssl_client2" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=ssl_client2 - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "ssl_client2.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "ssl_client2.mak" CFG="ssl_client2 - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "ssl_client2 - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "ssl_client2 - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "ssl_client2 - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "ssl_client2 - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "ssl_client2 - Win32 Release"

+# Name "ssl_client2 - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\ssl\ssl_client2.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/ssl_server.dsp b/visualc/ssl_server.dsp
new file mode 100644
index 0000000..45fb8b1
--- /dev/null
+++ b/visualc/ssl_server.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="ssl_server" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=ssl_server - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "ssl_server.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "ssl_server.mak" CFG="ssl_server - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "ssl_server - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "ssl_server - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "ssl_server - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "ssl_server - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "ssl_server - Win32 Release"

+# Name "ssl_server - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\ssl\ssl_server.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/ssl_test.dsp b/visualc/ssl_test.dsp
new file mode 100644
index 0000000..ec2fb60
--- /dev/null
+++ b/visualc/ssl_test.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="ssl_test" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Console Application" 0x0103

+

+CFG=ssl_test - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "ssl_test.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "ssl_test.mak" CFG="ssl_test - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "ssl_test - Win32 Release" (based on "Win32 (x86) Console Application")

+!MESSAGE "ssl_test - Win32 Debug" (based on "Win32 (x86) Console Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "ssl_test - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386

+

+!ELSEIF  "$(CFG)" == "ssl_test - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept

+

+!ENDIF 

+

+# Begin Target

+

+# Name "ssl_test - Win32 Release"

+# Name "ssl_test - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\programs\test\ssl_test.c

+# ADD CPP /I "../include"

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# End Group

+# End Target

+# End Project

diff --git a/visualc/xyssl.dsp b/visualc/xyssl.dsp
new file mode 100644
index 0000000..1c69355
--- /dev/null
+++ b/visualc/xyssl.dsp
@@ -0,0 +1,276 @@
+# Microsoft Developer Studio Project File - Name="xyssl" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Static Library" 0x0104

+

+CFG=xyssl - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "xyssl.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "xyssl.mak" CFG="xyssl - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "xyssl - Win32 Release" (based on "Win32 (x86) Static Library")

+!MESSAGE "xyssl - Win32 Debug" (based on "Win32 (x86) Static Library")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "xyssl - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c

+# ADD CPP /nologo /W3 /GX /O2 /I "../include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c

+# ADD BASE RSC /l 0x40c /d "NDEBUG"

+# ADD RSC /l 0x40c /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LIB32=link.exe -lib

+# ADD BASE LIB32 /nologo

+# ADD LIB32 /nologo

+

+!ELSEIF  "$(CFG)" == "xyssl - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir ""

+# PROP BASE Intermediate_Dir "temp"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir ""

+# PROP Intermediate_Dir "temp"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c

+# ADD CPP /nologo /W3 /Gm /GX /Z7 /Od /I "../include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c

+# ADD BASE RSC /l 0x40c /d "_DEBUG"

+# ADD RSC /l 0x40c /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LIB32=link.exe -lib

+# ADD BASE LIB32 /nologo

+# ADD LIB32 /nologo

+

+!ENDIF 

+

+# Begin Target

+

+# Name "xyssl - Win32 Release"

+# Name "xyssl - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=..\library\aes.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\arc4.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\base64.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\bignum.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\certs.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\debug.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\des.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\dhm.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\havege.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\md2.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\md4.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\md5.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\net.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\padlock.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\rsa.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\sha1.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\sha2.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\sha4.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\ssl_cli.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\ssl_srv.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\ssl_tls.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\timing.c

+# End Source File

+# Begin Source File

+

+SOURCE=..\library\x509parse.c

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# Begin Source File

+

+SOURCE=..\include\xyssl\aes.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\arc4.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\base64.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\bignum.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\bn_mul.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\certs.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\config.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\debug.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\des.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\dhm.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\havege.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\md2.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\md4.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\md5.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\net.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\padlock.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\rsa.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\sha1.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\sha2.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\sha4.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\ssl.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\timing.h

+# End Source File

+# Begin Source File

+

+SOURCE=..\include\xyssl\x509.h

+# End Source File

+# End Group

+# End Target

+# End Project