- Renamed include directory to polarssl

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 );
+}